sish
Overview
sish is an open source, self-hosted SSH tunneling 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 with a command they already know: an ordinary ssh remote forward. End users need no custom client, no third-party relay sits in the path, and there is no per-seat bill.
This guide covers deploying and configuring the SecureAnyCloud sish image on Ubuntu 24.04 on Azure. The image installs sish 2.23.0 from the official prebuilt release binary and runs it under systemd as the sish.service tunnel server. Its SSH tunnel ingress listens on port 2222, kept separate from the standard SSH service on port 22 that you use to manage the VM. It terminates HTTP and HTTPS for your tunnels on ports 80 and 443, and 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, with 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. It 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. The server refuses to start until this setup completes, so there is never an open, unauthenticated window.
What you get:
- 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:80and: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 and 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 - 24/7 SecureAnyCloud support
Prerequisites
Before you deploy this image, make sure you have:
- An active Azure subscription, an SSH public key, and a VNet and subnet in the target region
- A subscription to the sish listing on Azure Marketplace
- Network Security Group rules that allow 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, so larger sizes are only needed for very high concurrent tunnel throughput.
Deploy from the Azure Portal
Search for sish in the Marketplace, select the SecureAnyCloud publisher and click Create. Configure the Network Security Group to allow TCP 2222 (tunnel ingress) and TCP 80 and TCP 443 (the public HTTP and HTTPS routers) from wherever your clients and users are. Also allow TCP 22 for administration.
Deploy from the Azure CLI
RG="sish-prod"; LOCATION="eastus"; VM_NAME="sish1" IMAGE_URN="sac1647283583153:sish-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION"
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:sish-ubuntu-24-04:default:latest
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$IMAGE_URN" \
--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 1004First 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. It 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. Connect over SSH as azureuser and read the credentials:
sudo cat /root/sish-credentials.txtThe 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, because anyone who has it can open tunnels through your server.
Confirm the server is running
Confirm that sish.service is active, that sish --version reports 2.23.0, and that ss shows the server listening on :2222 for the tunnel ingress and on :80 and :443 for the HTTP and HTTPS routers. The standard SSH management service stays 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}'Open your first tunnel
To publish a local service, run an ssh remote forward from the machine the service runs on. Use your tunnel key and point 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 URLs 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. Replace 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.
Prove a tunnel round-trips: run the self-test
The image ships a tunnel self-test. It starts a small local HTTP service, opens an authenticated tunnel through sish, fetches the assigned public URL and confirms that the local service's response comes back through the tunnel. Everything is self-contained on this one VM, with no external client required. The test also proves that an unauthenticated tunnel attempt is rejected.
sudo bash /opt/sish/tunnel-selftest.shThe test prints SISH_SELFTEST_OK when the round trip succeeds and the unauthenticated attempt is correctly refused.
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 place it in /etc/sish/pubkeys/:
scp teammate.pub azureuser@<public-ip>:/tmp/
sudo install -m 0640 /tmp/teammate.pub /etc/sish/pubkeys/teammate.pubsish picks up the new key within a second, and no restart is needed. Remove a key from that directory to revoke access just as quickly.
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/Use your own domain and Let's Encrypt
The default tunnel domain is <public-ip>.sslip.io, which resolves out of the box. To use your own domain, point a wildcard DNS record (for example *.tunnels.example.com) at this VM's public IP. Then set your 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.serviceWith 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 that the NSG allows TCP 2222 from the client and that the client uses the correct private tunnel key. Check the server logs with sudo journalctl -u sish -n 50.
A tunnel URL returns nothing. Confirm that 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 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
SecureAnyCloud 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 sales@secureanycloud.com.
All product and company names are trademarks or registered trademarks of their respective holders. Use of these names does not imply any affiliation with or endorsement by them.
Deploy on Azure
Launch sish 2.23.0 on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
sish is an open source, self-hosted SSH tunneling 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 with a command they already know: an ordinary ssh remote forward. End users need no custom client, no third-party relay sits in the path, and there is no per-seat SaaS bill.
This guide covers deploying and using the SecureAnyCloud sish image on AWS. The image installs sish 2.23.0 from the official prebuilt release tarball and runs it under systemd as a hardened service. sish's SSH tunnel ingress listens on port 2222, kept separate from the standard SSH service on port 22 that you use to manage the instance. It terminates HTTP and HTTPS for your tunnels on ports 80 and 443.
There is no web interface and no database. A single flat config file (/etc/sish/config.yml) plus the per-instance key and certificate material under /etc/sish is the whole configuration.
Secure by default, with no known credentials. A tunnel server that anyone can connect to is an abuse risk, so this image forces authentication on and ships an empty authorized key list. On the first boot of every instance, 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. It then writes your private tunnel key to a root-only credentials file.
Only that key, plus any additional public keys you choose to add, may open a tunnel. The server refuses to start until this per-instance setup has completed, so there is never an open, unauthenticated window.
What you get:
- sish 2.23.0 from the official prebuilt release binary, run under systemd as a hardened service (
sish.service) - An SSH tunnel ingress on
:2222, kept separate from the management SSH service on:22, plus HTTP and HTTPS tunnel routers on:80and:443 - Secure by default: authentication forced on, a per-instance authorized tunnel key generated on first boot, and the server gated so it cannot start before that key exists
- A per-instance TLS certificate for HTTPS out of the box, with a documented one-line switch to browser-trusted Let's Encrypt certificates for your own domain
- A per-instance
<public-ip>.sslip.iotunnel domain, so public URLs resolve with no DNS setup at all - A shipped self-test (
/opt/sish/tunnel-selftest.sh) that proves the server tunnels a real request end to end, entirely on the instance - 24/7 SecureAnyCloud support
Connecting to your instance
Connect over SSH on port 22 as the default login user for the AMI variant you launched. This is the management SSH service and is separate from sish's own tunnel ingress on port 2222.
On Ubuntu 24.04 LTS, the SSH login user is ubuntu. The service is sish.service, the config is at /etc/sish/config.yml and the credentials are at /root/sish-credentials.txt.
ssh -i /path/to/key.pem ubuntu@<public-ip>Prerequisites
Before you launch this image, make sure you have:
- An AWS account and a key pair in the target region
- A subscription to the sish listing on AWS Marketplace
- A security group that allows TCP 22 (admin) from your address, TCP 2222 (tunnel clients) from the machines that will open tunnels, and TCP 80 and TCP 443 (public HTTP and HTTPS routers) from the audience that will reach your tunnel URLs
Recommended instance type: m5.large (2 vCPU, 8 GB RAM) is ample for a team sharing preview links and running staging or demo environments. sish is a single lightweight Go binary, so larger sizes are only needed for very high concurrent tunnel volumes.
Launch from AWS Marketplace
Search for sish in AWS Marketplace and select the SecureAnyCloud listing. Click Continue to Subscribe, then Continue to Configuration and Continue to Launch. Choose the m5.large instance type, your key pair and a security group.
Configure the security group to allow TCP 22 for administration, TCP 2222 for the clients that will open tunnels, and TCP 80 and TCP 443 for the audience that will reach your public tunnel URLs.
Verify the service is running
Connect over SSH as ubuntu and confirm that the service is active and listening. sish's tunnel ingress is on :2222 and its HTTP and HTTPS routers are on :80 and :443. The management sshd stays on :22.
systemctl is-active sish.service
sudo ss -tlnp | grep -E ':2222 |:80 |:443 |:22 'To confirm the installed version at any time, run:
/opt/sish/sish --versionProve the tunnel works end to end
The image ships a self-test that starts a tiny local HTTP origin, opens an authenticated tunnel through sish and fetches the assigned public tunnel URL through the HTTP router. It confirms that the origin's response round-trips back. Everything runs on this one instance, with no external client. The test then proves that an unauthenticated key is rejected.
sudo bash /opt/sish/tunnel-selftest.shA successful run prints round-trip OK, confirms the unauthenticated tunnel was REJECTED, and ends with SISH_SELFTEST_OK.
Read your per-instance credentials
On first boot, sish generates a unique authorized tunnel key for this instance and records the details in a root-only credentials file. Read it to find your per-instance tunnel domain, the SSH ingress port and the path to your private tunnel key.
sudo cat /root/sish-credentials.txtThe file records sish.domain (your per-instance <public-ip>.sslip.io tunnel domain), sish.ssh_ingress_port (2222), and sish.tunnel_key_path (the path to your private tunnel key). The private key itself lives at /root/sish-tunnel-key with 0600 root:root permissions. Copy it to any machine that should be allowed to open tunnels, and keep it secret.
Open your first tunnel
From any machine that holds your tunnel key, publish a local service on a public subdomain with an ordinary ssh remote forward. Point it at your per-instance domain (the sish.domain value above) and choose the subdomain you want. For example, to expose a local web app running on port 8080:
ssh -p 2222 -i /path/to/your-tunnel-key -R myapp:80:localhost:8080 <your-domain>Your app is now reachable at http://myapp.<your-domain> and, using the per-instance certificate, at https://myapp.<your-domain>. The default domain is <public-ip>.sslip.io, so the URL resolves with no DNS setup at all.
sish also forwards raw TCP and routes TLS by SNI. Expose a TCP service on a chosen external port, or create a private alias that is reachable only through authenticated SSH:
ssh -p 2222 -i /path/to/your-tunnel-key -R 9000:localhost:5432 <your-domain>Authorize additional clients
sish watches the authorized keys directory and reloads it automatically. To let a teammate open tunnels, drop their public key into /etc/sish/pubkeys on the server. They can then open tunnels from their own machine with their matching private key.
sudo install -m 0640 teammate.pub /etc/sish/pubkeys/teammate.pub ssh -p 2222 -i /path/to/their-tunnel-key -R demo:80:localhost:3000 <your-domain>The image ships zero authorized keys, and only keys present in /etc/sish/pubkeys may open tunnels. An unknown key is rejected with Permission denied (publickey).
Use a real domain with browser-trusted HTTPS
The default per-instance certificate is self-signed, so browsers show a warning. To avoid the warning, point a wildcard DNS record (for example *.tunnel.example.com) at this instance's public IP. Then enable sish's on-demand Let's Encrypt certificates and set your domain in /etc/sish/config.yml:
domain: "tunnel.example.com" https-ondemand-certificate: true https-ondemand-certificate-email: "you@example.com"Then restart the service to pick up the new configuration. Run:
# after pointing your wildcard DNS record at this instance and editing config.yml
sudo systemctl restart sish
# applies your <your-domain> certificate settingssish will obtain a browser trusted certificate for each tunnel subdomain on first request.
Security group and firewall
Restrict the security group to your use case:
- TCP 22: administration, from your address only
- TCP 2222: the sish SSH tunnel ingress, from the machines that will open tunnels
- TCP 80 and TCP 443: the public HTTP and HTTPS tunnel routers, from the audience that will reach your tunnel URLs
The tunnel ingress on 2222 is separate from the management SSH service on 22. You can therefore lock administration down to your own network while still letting clients open tunnels, without exposing the management port more widely.
Support
SecureAnyCloud provides 24/7 technical support for this sish product by email (sales@secureanycloud.com) and live chat. We help with deployment and first-boot configuration, retrieving your per-instance tunnel domain and authorized key, authorizing additional users, pointing a wildcard DNS record at the server, enabling Let's Encrypt for browser-trusted HTTPS, configuring HTTP, TCP, TLS and SNI tunnels and private aliases, tuning binding, load-balancing and rate-limiting policies, configuring firewall and security group rules, monitoring and log inspection, and sish version upgrades. Critical issues receive a one-hour average response time. For billing, subscription changes or refund requests, contact sales@secureanycloud.com.
Deploy on AWS
Launch sish with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com