Sish Installation

A) open 2222 on the router so that it can be gotten to on .26

service nameexternal portinternal portinternal ip address
sish-tunnel22222222192.168.1.26

Sish setup

1. Confirm architecture first (.26) (don't guess — this determines which binary to grab):

bash

uname -m

x86_64 → amd64 build. aarch64/arm64 → arm64 build. (Given .26 has been running general-purpose Linux services this whole time, x86_64 is likely, but confirm rather than assume — exactly the kind of check that avoids a wasted download.)

2. Install sish (.26) (adjust filename to match step 1's result):

bash

cd /tmp
# for x86_64:
cd /tmp
rm -f sish_linux_amd64.tar.gz   # clear out the bad 9-byte file first
curl -LO https://github.com/antoniomika/sish/releases/download/v2.23.0/sish-2.23.0.linux-amd64.tar.gz
tar xzf sish-2.23.0.linux-amd64.tar.gz
ls

# confirm - 
ls sish-2.23.0.linux-amd64/
# single binary install it 

# all ok then

sudo mv sish-2.23.0.linux-amd64/sish /usr/local/bin/sish
sudo chmod +x /usr/local/bin/sish
sish --version

Quick heads up before you get to step 2's last line: sish --version sometimes exits non-zero on binaries that only support --help for version info, so if sish --version errors out instead of printing a string, try sish --help | head -5 instead — that'll still confirm the binary runs even if --version isn't wired up the way you'd expect.

keep it tidy

rm -rf /tmp/sish-2.23.0.linux-amd64 /tmp/sish-2.23.0.linux-amd64.tar.gz

3. Create the service user + dirs (.26):

bash

sudo useradd -r -d /etc/sish -s /sbin/nologin sish
sudo mkdir -p /etc/sish/keys /etc/sish/pubkeys
sudo chown -R sish:sish /etc/sish

4. Create / Add your public key on the razer (.21) (from wherever you'll run the tunnel command — same place LM Studio is runing: if running on a mac

ssh-keygen -t ed25519 -f ~/.ssh/sish_ed25519 -C "sish tunnel key"

on running on a pc

ssh-keygen -t ed25519 -f $env:USERPROFILE\.ssh\sish_ed25519 -C "sish tunnel key"

This creates ~/.ssh/sish_ed25519 (private) and ~/.ssh/sish_ed25519.pub (public). Good instinct to use a dedicated key here rather than your general SSH identity — keeps this tunnel-only key revocable independently if it ever needs to be pulled, without touching your regular SSH access anywhere else.

4a. Copy the pub for the key over to .26 machine – (where sish runs and checks incoming keys):

scp $env:USERPROFILE\.ssh\sish_ed25519.pub spiffy-root@192.168.1.26:/tmp/sish_ed25519.pub

then move it 

[spiffy-root@proxy tmp]$ sudo mv sish_ed25519.pub /etc/sish/pubkeys/sish_ed25519.pub
[sudo] password for spiffy-root:
[spiffy-root@proxy tmp]$ cd /etc/sish/pubkeys/
[spiffy-root@proxy pubkeys]$ ls
sish_ed25519.pub
[spiffy-root@proxy pubkeys]$


check ownership
ls -la /etc/sish/pubkeys/sish_ed25519.pub
id sish

++++++++++++++++

# !!!!!!!!!!!!!to fix - or run anyway since we need it for the sish/keys directory anyway

sudo useradd -r -d /etc/sish -s /sbin/nologin sish
sudo mkdir -p /etc/sish/keys /etc/sish/pubkeys
sudo chown -R sish:sish /etc/sish

bash

# on your Mac:
cat ~/.ssh/sish_ed25519.pub
# copy the output, then on .26:
sudo nano /etc/sish/pubkeys/sish_ed25519.pub
# paste it, save
sudo chown sish:sish /etc/sish/pubkeys/sish_ed25519.pub
# on a PC
# ===== 4a. Drop pubkey in (.26) =====
sudo nano /etc/sish/pubkeys/sish_ed25519.pub
# paste, save
sudo chown sish:sish /etc/sish/pubkeys/sish_ed25519.pub


#Via PowerShellOpen PowerShell and run: 
Get-Content ~/.ssh/sish_ed25519.pub | Set-Clipboard 
# (replace id_rsa.pub with your actual public key file name if different, such as id_ed25519.pub).

#Via Command PromptOpen Command Prompt and run: 
clip < %USERPROFILE%\.ssh\sish_ed25519.pub

#Via Git BashOpen Git Bash and run: 
cat ~/.ssh/sish_ed25519.pub | clip



5. systemd unit (.26):

bash

sudo nano /etc/systemd/system/sish.service

Add the sish.service file

[Unit]
Description=sish - self-hosted SSH tunnel broker (replaces localhost.run)
After=network.target

[Service]
Type=simple
User=sish
Group=sish
ExecStart=/usr/local/bin/sish \
  --ssh-address=:2222 \
  --http-address=127.0.0.1:8081 \
  --https=false \
  --authentication-keys-directory=/etc/sish/pubkeys \
  --private-keys-directory=/etc/sish/keys \
  --bind-random-ports=false \
  --domain=shawns-machine.com
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

The load and check it:

bash

sudo systemctl daemon-reload
sudo systemctl enable --now sish
sudo systemctl status sish

Confirm it says active (running) before moving on.

6. nginx conf — paste the regex-based router conf into /etc/nginx/conf.d/sish-router.shawns-machine.com.conf

# Routes any {name}-aitunnel.shawns-machine.com to sish, which multiplexes
# by Host header to whichever SSH tunnel registered that name. sish does
# NOT terminate its own TLS here — nginx does (matches the existing
# Apache:8090-behind-nginx pattern on .9), so sish's http port stays on
# loopback only, never exposed directly.
server {
    listen 443 ssl http2;
    server_name ~^(?<sish_sub>.+)-aitunnel\.shawns-machine\.com$;

    ssl_certificate /etc/letsencrypt/live/shawns-machine.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/shawns-machine.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
        proxy_pass http://127.0.0.1:8081; #8080 is used by apache
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 120s;
    }
}
server {
    listen 80;
    server_name ~^(?<sish_sub>.+)-aitunnel\.shawns-machine\.com$;
    return 301 https://$host$request_uri;
}

then:

bash

sudo nginx -t

Paste me that output before reloading — same checkpoint discipline as before.

7. If clean:

bash

sudo systemctl reload nginx

8. Firewall check — confirm 2222 is actually reachable from outside before testing (this is the step most likely to silently block you):

bash

sudo firewall-cmd --list-ports    # if firewalld
# or
sudo iptables -L -n | grep 2222   # if raw iptables

If 2222 isn't open: sudo firewall-cmd --permanent --add-port=2222/tcp && sudo firewall-cmd --reload

9. Test — run from your Razer – same machine as LM Studio, or explicit IP. LMStudio is installed, against the throwaway test subdomain, not the live one:

ssh -i ~/.ssh/sish_ed25519 -p 2222 -R test-aitunnel:80:192.168.1.21:1234 -N tunnel@shawns-machine.com

Everything downstream (the systemd unit, nginx conf, test command) is unaffected by the key's name — only the file path in step 4 changes. When you get to the actual tunnel command, point -i at the private key explicitly, since it's not your default identity:

1. Yes — Run it directly on the Razer PC (192.168.1.21), where localhost:1234 correctly points at LM Studio itself. If you ever run the tunnel command from a different LAN machine, swap localhost for 192.168.1.21 explicitly — same distinction as before.

2. The username is not a real account on any machine — it doesn't need to exist anywhere. This is the key fact: sish is its own SSH server implementation. It intercepts the SSH handshake, checks the presented public key against files in /etc/sish/pubkeys/, and that's the entire auth decision. It never consults /etc/passwd, never asks .9 or .26's actual OS for a user named "shawn," "sish," or anything else. The username string in user@host is just a label sish's SSH layer sees — in this case it's essentially unused since we're explicitly naming the tunnel (test-aitunnel:80:...) rather than asking sish to auto-generate a subdomain from the username.

So it can be anything — shawn@, sish@, tunnel@, doesn't matter, and it doesn't need to match the key filename either (sish_ed25519 was just what we called the key file on disk; unrelated). I'd pick something that won't confuse future-you into thinking it's a real account — tunnel@shawns-machine.com reads clearest for that reason, but it's a naming choice, not a technical requirement.

On the two versions you pasted back — the one without -i only works if the key is either your default identity (~/.ssh/id_ed25519,

ssh -R test-aitunnel:80:localhost:1234 -p 2222 -N shawn@shawns-machine.com

which sish tries automatically) or already loaded in ssh-agent.

Since you deliberately named it sish_ed25519 (non-default), you do still need -i unless you add it to ssh-agent (ssh-add ~/.ssh/sish_ed25519) or drop a Host entry in ~/.ssh/config. Simplest for a one-off test — keep -i explicit:

bash

ssh -i ~/.ssh/sish_ed25519 -p 2222 -R test-aitunnel:80:192.168.1.21:1234 -N tunnel@shawns-machine.com
  1. While that's running, from your phone on cellular:
https://test-aitunnel.shawns-machine.com/v1/models

Same three models = the whole chain (SSH → sish → nginx → public HTTPS) is proven.

Once that works, you've validated the pattern SPI-516/517 depend on — want me to log the completed setup + test result to SPI-517 once you confirm step 10?

commands only

Good consolidation — and good thing we're doing one final pass, because there's a real bug in it: step 6's nginx conf still has proxy_pass http://127.0.0.1:8080 — that's the old port, the one that turned out to belong to httpd. If you ran this as pasted, nginx would route tunnel traffic straight into Apache instead of sish, and you'd get either a confusing wrong-content response or a 404 — not an obvious "wrong port" error, which makes it the nastiest kind of bug to chase after the fact. Needs to be 8081 to match the corrected systemd unit from step 5.

One more small inconsistency, cosmetic but worth fixing: step 4a's Windows block references id_rsa.pub (a generic example) instead of your actual sish_ed25519.pub — copy-paste residue from wherever that snippet came from. Corrected below.

Here's the clean, fully consistent version, front to back:

# ===== 1. Confirm architecture (.26) =====
uname -m
# x86_64 confirmed already

# ===== 2. Install sish (.26) =====
cd /tmp
rm -f sish_linux_amd64.tar.gz   # clear out the bad 9-byte file first
curl -LO https://github.com/antoniomika/sish/releases/download/v2.23.0/sish-2.23.0.linux-amd64.tar.gz
tar xzf sish-2.23.0.linux-amd64.tar.gz
ls

# all ok then

sudo mv sish /usr/local/bin/sish
sudo chmod +x /usr/local/bin/sish
sish --version

# ===== 3. Service user + dirs (.26) =====
sudo useradd -r -d /etc/sish -s /sbin/nologin sish
sudo mkdir -p /etc/sish/keys /etc/sish/pubkeys
sudo chown -R sish:sish /etc/sish
# ===== 4. Generate keypair (Razer PC, PowerShell) =====
ssh-keygen -t ed25519 -f $env:USERPROFILE\.ssh\sish_ed25519 -C "sish tunnel key"

# Get the public key to copy over:
Get-Content $env:USERPROFILE\.ssh\sish_ed25519.pub | Set-Clipboard
# ===== 4a. Drop pubkey in (.26) =====
sudo nano /etc/sish/pubkeys/sish_ed25519.pub
# paste, save
sudo chown sish:sish /etc/sish/pubkeys/sish_ed25519.pub
# ===== 5. systemd unit (.26) =====
sudo nano /etc/systemd/system/sish.service
[Unit]
Description=sish - self-hosted SSH tunnel broker (replaces localhost.run)
After=network.target

[Service]
Type=simple
User=sish
Group=sish
ExecStart=/usr/local/bin/sish \
  --ssh-address=:2222 \
  --http-address=127.0.0.1:8081 \
  --https=false \
  --authentication-keys-directory=/etc/sish/pubkeys \
  --private-keys-directory=/etc/sish/keys \
  --bind-random-ports=false \
  --domain=shawns-machine.com
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now sish
sudo systemctl status sish
# confirm: active (running)
# ===== 6. nginx conf (.26) — CORRECTED to 8081 =====
sudo nano /etc/nginx/conf.d/sish-router.shawns-machine.com.conf
# Routes any {name}-aitunnel.shawns-machine.com to sish, which multiplexes
# by Host header to whichever SSH tunnel registered that name. sish does
# NOT terminate its own TLS here — nginx does (matches the existing
# Apache:8090-behind-nginx pattern on .9), so sish's http port stays on
# loopback only, never exposed directly. NOTE: 8081, not 8080 — 8080 is
# already httpd on this box.
server {
    listen 443 ssl http2;
    server_name ~^(?<sish_sub>.+)-aitunnel\.shawns-machine\.com$;

    ssl_certificate /etc/letsencrypt/live/shawns-machine.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/shawns-machine.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
        proxy_pass http://127.0.0.1:8081;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 120s;
    }
}
server {
    listen 80;
    server_name ~^(?<sish_sub>.+)-aitunnel\.shawns-machine\.com$;
    return 301 https://$host$request_uri;
}
sudo nginx -t

Paste that output here before reloading.

# ===== 7. If clean =====
sudo systemctl reload nginx
# ===== 8. Firewall — already confirmed done, 2222/tcp is open =====
sudo firewall-cmd --list-ports
# should show: 80/tcp 443/tcp 2222/tcp 808o/tcp - 8081 is a loopback so does not need to be opened in firewall
# ===== 9. Test (Razer PC, PowerShell) =====
ssh -i $env:USERPROFILE\.ssh\sish_ed25519 -p 2222 -R test-aitunnel:80:localhost:1234 -N tunnel@shawns-machine.com

(localhost:1234 is correct here since this runs on the Razer PC, where LM Studio actually listens — no need for the LAN IP when you're already on the box.)

# ===== 10. From your phone, cellular data =====
https://test-aitunnel.shawns-machine.com/v1/models

Same three models = fully proven, end to end.

Go ahead and run 1-6, paste me the nginx -t output at the checkpoint before reloading.