Si
Networking Azure

sish on Ubuntu 24.04 on Azure User Guide

| Product: sish 2.23.0 on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of sish on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. sish is an open source, self hosted SSH tunnelling server, a drop in alternative to ngrok and serveo that you run on your own infrastructure. It runs an SSH server whose only job is forwarding and multiplexing, so anyone can expose a local service on a public URL using a command they already know: an ordinary ssh remote forward. There is no custom client to install for end users, no third party relay in the path, and no per seat bill.

The image installs sish 2.23.0 from the official prebuilt release binary, run under systemd as the sish.service tunnel server. Its SSH tunnel ingress listens on port 2222, kept deliberately separate from the standard SSH service on port 22 that you use to manage the VM, and it terminates HTTP and HTTPS for your tunnels on ports 80 and 443. sish handles its own HTTPS from a per instance certificate. There is no web interface and no database: the flat /etc/sish/config.yml plus the per instance key material is the whole configuration.

Secure by default — no known credentials. A tunnel server that anyone can connect to is an abuse risk, so this image forces authentication on and ships the authorized key list empty. On the first boot of every VM a one shot service generates a unique SSH host identity for the server, a unique authorized tunnel key for you, and a per instance TLS certificate, then writes your private tunnel key to a root only credentials file and renders the config with this VM's tunnel domain. Only that key, plus any additional public keys you choose to add, may open a tunnel, and the server refuses to start until this setup completes, so there is never an open, unauthenticated window.

What is included:

  • sish 2.23.0 from the official prebuilt release binary, run under systemd as sish.service

  • An SSH tunnel ingress on :2222 (separate from the management SSH service on :22) and HTTP and HTTPS tunnel routers on :80 and :443

  • HTTP(S), TCP, TLS and alias tunnels multiplexed from many clients through one server

  • A per instance tunnel domain of the form <public-ip>.sslip.io, so tunnel URLs resolve out of the box with no DNS setup

  • Authentication forced on with an empty authorized key list, so only keys you authorize may open a tunnel

  • A unique per instance authorized tunnel key generated on first boot, written to /root/sish-credentials.txt (root only)

  • A built in tunnel self test (/opt/sish/tunnel-selftest.sh) that proves a real tunnel round trips, self contained on the one VM

Prerequisites

  • Active Azure subscription, SSH public key, VNet + subnet in target region

  • Subscription to the sish listing on Azure Marketplace

  • Network Security Group rules allowing TCP 22 (VM administration), TCP 2222 (the sish tunnel ingress your clients connect to), and TCP 80 and TCP 443 (the HTTP and HTTPS tunnel routers your public URLs are served on)

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is ample for a personal or small team tunnel server. sish is a lightweight Go daemon; larger sizes are only needed for very high concurrent tunnel throughput.

Step 1: Deploy from the Azure Portal

Search sish in Marketplace, select the cloudimg publisher, and click Create. Configure the Network Security Group to allow TCP 2222 (tunnel ingress), TCP 80 and TCP 443 (the public HTTP and HTTPS routers) from wherever your clients and users are, and TCP 22 for administration.

Step 2: Deploy from the Azure CLI

RG="sish-prod"; LOCATION="eastus"; VM_NAME="sish1"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/sish-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az vm create \
  --resource-group "$RG" --name "$VM_NAME" \
  --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values "$SSH_KEY" \
  --public-ip-sku Standard
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 2222 --priority 1001
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 80 --priority 1002
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 443 --priority 1003
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1004

Step 3: First boot — retrieve your tunnel domain and authorized key

On first boot the image generates a unique SSH host identity for the server, a unique authorized tunnel key for you and a per instance TLS certificate, resolves this VM's public IP, renders /etc/sish/config.yml with a per instance <public-ip>.sslip.io tunnel domain, and starts sish. This completes within seconds. SSH in as azureuser and read the credentials:

sudo cat /root/sish-credentials.txt

The file records your per instance sish.domain (the tunnel domain your public URLs are subdomains of), the sish.ssh_ingress_port (2222), and sish.tunnel_key_path — the path to your private tunnel key on the server (/root/sish-tunnel-key). Copy that key to any machine you want to open tunnels from. Keep it private — anyone who has it can open tunnels through your server.

Step 4: Confirm the server is running

sish.service is active, sish --version reports 2.23.0, and ss confirms the server is listening on :2222 for the tunnel ingress and :80 and :443 for the HTTP and HTTPS routers, while the standard SSH management service is still on :22.

systemctl is-active sish.service
/opt/sish/sish --version | head -3
sudo ss -tlnp | grep -E ':2222|:80 |:443|:22 ' | awk '{print $1, $4}'

sish.service reports active, the sish binary reports version 2.23.0, and ss shows the server listening on port 2222 for the SSH tunnel ingress and ports 80 and 443 for the HTTP and HTTPS tunnel routers, with the standard SSH management service still listening on port 22 so VM administration is never disturbed

Step 5: Open your first tunnel

To publish a local service, run an ssh remote forward from the machine the service runs on, using your tunnel key and pointing at your server's tunnel domain. For an HTTP app on local port 8080, request a subdomain (myapp here):

ssh -p 2222 -i sish-tunnel-key -R myapp:80:localhost:8080 <your-domain>

sish prints the public URL your app is now reachable at — http://myapp.<your-domain> and https://myapp.<your-domain>. Replace <your-domain> with the sish.domain value from your credentials file and sish-tunnel-key with the copy of your private tunnel key. Leave the command running for as long as you want the tunnel open. You can also forward a raw TCP service with -R 0:localhost:<port> (sish assigns a public port) or create a private alias reachable only through authenticated SSH.

the sish server log showing an authenticated tunnel client connect on the ingress port and bind an HTTP forward, and the tunnel client output listing the assigned public HTTP and HTTPS URLs on a subdomain of this instance sslip.io tunnel domain that the local service is now reachable at

Step 6: Prove a tunnel round trips — run the self test

The image ships a tunnel self test that starts a small local HTTP service, opens an authenticated tunnel through sish, then fetches the assigned public URL and confirms the local service's response comes back through the tunnel — all self contained on this one VM, with no external client required. It also proves that an unauthenticated tunnel attempt is rejected.

sudo bash /opt/sish/tunnel-selftest.sh

It prints SISH_SELFTEST_OK when the round trip succeeds and the unauthenticated attempt is correctly refused.

the sish tunnel self test output showing the origin token forwarded through the sish tunnel round trip on a subdomain of the instance tunnel domain, then the unauthenticated tunnel correctly rejected because authentication is enforced, ending with the success marker confirming the server forwards a real tunnel end to end and refuses unauthorized clients

Step 7: Authorize more clients

sish watches its authorized keys directory and reloads it automatically. To let a teammate open tunnels, copy their SSH public key onto the server and drop it into /etc/sish/pubkeys/:

scp teammate.pub azureuser@<public-ip>:/tmp/
sudo install -m 0640 /tmp/teammate.pub /etc/sish/pubkeys/teammate.pub

sish picks up the new key within a second — no restart needed. Remove a key from that directory to revoke access just as quickly.

Step 8: Secure by default

This image ships with no known credentials. Authentication is forced on in /etc/sish/config.yml, and the authorized key list is generated per VM at first boot and stored root only, so only keys you authorize may open a tunnel. The tunnel ingress on :2222 is kept separate from the management SSH service on :22.

grep -E '^authentication:|^ssh-address:|^domain:' /etc/sish/config.yml
sudo ls -1 /etc/sish/pubkeys/

the sish config showing authentication set to true, the tunnel ingress bound to port 2222 and the per instance tunnel domain, and the authorized keys directory listing the single unique per instance tunnel key generated at first boot, confirming the server is secure by default with authentication enforced and no shared or default credential

Step 9: Use your own domain and Let's Encrypt

The default tunnel domain is <public-ip>.sslip.io, which resolves out of the box. For production, point a wildcard DNS record (for example *.tunnels.example.com) at this VM's public IP, then set your own domain and enable on demand Let's Encrypt certificates for browser trusted HTTPS by editing /etc/sish/config.yml:

# set your domain and enable Let's Encrypt (browser trusted HTTPS), then restart sish
# edit /etc/sish/config.yml on the server: domain: "tunnels.<your-domain>"
# add: https-ondemand-certificate: true and https-ondemand-certificate-accept-terms: true
sudo systemctl restart sish.service

With a real wildcard record and on demand certificates, every new subdomain gets a valid certificate automatically the first time it is requested.

Troubleshooting

  • A client cannot connect to the ingress. Confirm the NSG allows TCP 2222 from the client, and that the client is using the correct private tunnel key. Check the server logs with sudo journalctl -u sish -n 50.

  • A tunnel URL returns nothing. Confirm the NSG allows TCP 80 and TCP 443, that the ssh -R tunnel is still running on the client, and that the local service it points at is actually up. The sish.domain in the URL must match your server's configured domain.

  • Check server health. sudo systemctl status sish and sudo journalctl -u sish show service logs; sudo /opt/sish/tunnel-selftest.sh proves the full round trip end to end on the server itself.

Support

cloudimg provides 24/7 technical support for this sish image. Our engineers help with pointing a wildcard domain at the server, enabling Let's Encrypt, authorizing additional users, configuring HTTP, TCP, TLS and alias tunnels, tuning binding and rate limiting policies, firewall and NSG rules, and sish version upgrades. Critical issues receive a one hour average response time. Contact support@cloudimg.co.uk.

All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.