sish 4.0.0 on AWS User Guide
Overview
This guide covers launching and verifying sish 4.0.0 on Ubuntu 24.04 from cloudimg on Amazon EC2. It is one version of the cloudimg Hardened WireGuard VPN & VPN, Proxy and Remote Access AMIs listing on AWS Marketplace; you pick it as the software version when you subscribe and launch. The other VPN, proxy and remote access servers in the listing are described on the listing's guide hub.
sish is an open-source, self-hosted alternative to services such as ngrok. It runs its own SSH server: a developer on any machine with a standard OpenSSH client runs ssh -p 2222 -R myapp:80:localhost:8080 <your-sish-host>, and the web app listening on port 8080 of their laptop becomes reachable as https://myapp.<your-domain>/ and http://myapp.<your-domain>/. No special client software is needed. sish is a headless service with no web console to log in to.
What cloudimg adds
- The current upstream release, unmodified. This image ships sish 4.0.0, the upstream release binary for Linux x86-64. The release tarball's SHA-256 checksum (the value upstream publishes) and the binary's own checksum are pinned in the build; the build record is in
/usr/local/share/doc/sish/BUILD-PROVENANCE.txt. - No open tunnelling, no default key. Authentication is forced on and only public keys are accepted (no passwords). The image ships with no authorized key at all. Each instance's first boot generates its own tunnel key (the key that may open tunnels), sish's own SSH host key, and a TLS certificate for the tunnel domain, so no two instances share a key.
- Works out of the box. First boot reads the instance's public IPv4 address from the instance metadata service and uses
<public-ip>.sslip.ioas the tunnel domain, a free public wildcard DNS name that resolves to that address, sohttps://myapp.<public-ip>.sslip.io/works with no DNS setup. One command switches to your own domain. - HTTPS by default. sish terminates TLS on port 443 with the per-instance certificate (an end-entity certificate for the domain and its wildcard, not a certificate authority). You verify it by its fingerprint, or replace it with a certificate from your own CA.
- Hardened service. sish runs as an unprivileged
sishuser that owns and can write no file, with only the capability to bind ports 80 and 443, a read-only system, a private/tmpand a restricted set of system calls. Its admin and service web consoles are off. - No route to instance metadata. sish is blocked from the EC2 instance metadata service at the system level, and tunnel clients cannot use sish to reach it:
ssh -L/ssh -Wthrough sish reach only other clients' named tunnels, never an arbitrary address. - Raw TCP forwards stay private. A client's
ssh -R <port>for a port other than 80 and 443 is bound on the instance's loopback address only, on a port of 1024 or above. A tunnel client can never open a port on the instance's network interfaces or a privileged port.
Prerequisites
- An AWS account and permission to launch EC2 instances
- An EC2 key pair in the Region you launch in
- An OpenSSH client on each machine that will open tunnels (macOS, Linux and Windows 10/11 include one)
Recommended instance type: m5.large. A tunnel server for a small team runs comfortably on t3.small or larger.
Connecting to your instance
| Version | Operating system | SSH user |
|---|---|---|
| sish 4.0.0 on Ubuntu 24.04 | Ubuntu 24.04 LTS | ubuntu |
| Port | Protocol | Purpose | Who should reach it |
|---|---|---|---|
| 22 | TCP | SSH administration of the instance (the system SSH server) | Your administrators |
| 2222 | TCP | sish's own SSH server: tunnel clients connect here with ssh -R |
The machines that open tunnels |
| 80 | TCP | HTTP to your tunnels (http://<name>.<domain>/) |
Whoever should use your tunnelled apps |
| 443 | TCP | HTTPS to your tunnels (https://<name>.<domain>/) |
Whoever should use your tunnelled apps |
Step 1: Launch the instance
Option A: AWS Marketplace console
- Open the cloudimg Hardened WireGuard VPN & VPN, Proxy and Remote Access AMIs listing on AWS Marketplace and choose View purchase options, then Subscribe. One subscription covers every version in the listing.
- Once the subscription is active, choose Launch your software.
- Choose One-click launch from AWS Marketplace (or Launch from EC2 Console for the full launch wizard). In Version, choose sish 4.0.0 on Ubuntu 24.04, then choose your Region.
- Pick an instance type (
m5.largerecommended; the software charge is $0.04 per vCPU per hour) and your key pair. - Security group: the listing's default group opens 22, 2222, 80 and 443. Restrict port 22 to your own IP address, and port 2222 to the machines that will open tunnels.
- Choose a subnet that gives the instance a public IPv4 address (needed for the default
sslip.iodomain), leave the metadata defaults (the image already requires IMDSv2), then choose Launch.
Option B: AWS CLI
Run this on your own workstation. It creates a security group, then launches the instance. Replace the AMI ID with the one shown for your Region on the Marketplace launch page, and the VPC, subnet, key pair and CIDR ranges with your own:
SG=$(aws ec2 create-security-group --group-name sish \
--description "sish tunnel server" --vpc-id vpc-0123456789abcdef0 \
--query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22 --cidr <your-mgmt-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 2222 --cidr <your-client-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 80 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 443 --cidr 0.0.0.0/0
aws ec2 run-instances \
--image-id ami-0123456789abcdef0 \
--instance-type m5.large \
--key-name my-key-pair \
--security-group-ids "$SG" \
--subnet-id subnet-0123456789abcdef0 \
--associate-public-ip-address \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=sish}]'
You do not need --metadata-options: the AMI already makes IMDSv2 required. To keep the same tunnel domain across stop and start, associate an Elastic IP address and run sudo sish-set-domain --default once afterwards (see Step 8).
Step 2: Connect and read the instance details
Connect as ubuntu with the key pair you chose:
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>
First boot finishes within a minute of launch. It generates the tunnel key, the host key and the TLS certificate, writes the configuration for this instance's domain, starts sish and waits for ports 2222, 80 and 443. The details are in /root/sish-credentials.txt, readable only by root. It holds fingerprints and URLs, not key material:
sudo cat /root/sish-credentials.txt
# sish 4.0.0 - written by sish-firstboot on this instance. No key material is stored in this file.
# Tunnel key (private half): /root/sish-tunnel-key (0600 root). Copy it to your client machine, then shred it here.
# Open a tunnel: ssh -p 2222 -i <key> -R myapp:80:localhost:8080 203.0.113.10.sslip.io -> https://myapp.203.0.113.10.sslip.io/
# Self-test: sudo sish-selftest Change the domain: sudo sish-set-domain tunnels.example.com
# Guide: https://www.cloudimg.co.uk/guides/sish-4-0-0-on-ubuntu-24-04-aws/
SISH_DOMAIN=203.0.113.10.sslip.io
SISH_HOST=203.0.113.10
SISH_SSH_PORT=2222
SISH_TUNNEL_KEY_FILE=/root/sish-tunnel-key
SISH_TUNNEL_KEY_FINGERPRINT=SHA256:q8T2n0kXc4Vd7mR1hZ5yLwE9aJ3uB6sPfG0tKxNcY2E
SISH_HOST_KEY_FINGERPRINT=SHA256:Hk4wP9sQ2bV7nL1xR6tY3mC8dF0gJ5aZ2eU4iO7kWq0
SISH_TLS_CERT_SHA256=3A:91:5C:0E:7D:22:B8:4F:61:A0:9E:3D:C7:58:14:F2:6B:0D:93:E8:5A:27:C1:4E:80:BF:36:D9:72:1A:E5:0C
SISH_EXAMPLE_HTTPS_URL=https://myapp.203.0.113.10.sslip.io/
SISH_EXAMPLE_HTTP_URL=http://myapp.203.0.113.10.sslip.io/
Your values differ: every instance has its own domain, keys and certificate.
Step 3: Confirm sish is running
systemctl is-active sish sish-firstboot
sudo ss -Htlnp | awk '{print $4, $6}'
active
active
127.0.0.54:53 users:(("systemd-resolve",pid=368,fd=17))
127.0.0.53%lo:53 users:(("systemd-resolve",pid=368,fd=15))
0.0.0.0:22 users:(("sshd",pid=888,fd=3),("systemd",pid=1,fd=86))
[::]:22 users:(("sshd",pid=888,fd=4),("systemd",pid=1,fd=87))
*:80 users:(("sish",pid=6466,fd=8))
*:2222 users:(("sish",pid=6466,fd=3))
*:443 users:(("sish",pid=6466,fd=9))
sish owns 2222, 80 and 443. The system SSH server keeps port 22 for administration, and nothing else listens on the network.
Step 4: Run the self-test
The self-test opens a real tunnel through sish on the instance itself with the tunnel key, fetches it over HTTPS (verified against the per-instance certificate) and over HTTP, and checks that an unknown key is refused, that only public-key authentication is offered and that ssh -W through sish reaches neither the metadata service nor the instance's own SSH server:
sudo sish-selftest
[sish-selftest] host key pinned; tunnel https://selftest3f0a12.203.0.113.10.sslip.io/ answers over TLS with the per-instance certificate, and over HTTP
[sish-selftest] served certificate fingerprint = /etc/sish/ssl/sish.crt
[sish-selftest] ssh -W through sish reaches a client's named alias (control) but neither the metadata service nor the instance's own SSH server
[sish-selftest] an unauthorized key is refused
[sish-selftest] password and keyboard-interactive authentication are not offered (publickey only)
SELFTEST_OK
Step 5: Copy the tunnel key to your workstation
Run this on your workstation. It copies the instance's tunnel key, which is the key that may open tunnels, into a file only you can read:
umask 077
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<SISH_HOST> 'sudo cat /root/sish-tunnel-key' > ~/.ssh/sish-tunnel-key
ssh-keygen -l -f ~/.ssh/sish-tunnel-key
The fingerprint ssh-keygen prints must equal SISH_TUNNEL_KEY_FINGERPRINT in the credentials file. Keep this key private: anyone who holds it can open tunnels on your server. Once it is safely on your workstation you can remove the server's copy (the authorized public half stays in /etc/sish/pubkeys/):
sudo shred -u /root/sish-tunnel-key
To let other people or machines open tunnels, prefer giving each one its own key instead of sharing this one: see Step 7.
Step 6: Open your first tunnel
On your workstation, start any local web app, for example on port 8080, then:
ssh -p 2222 -i ~/.ssh/sish-tunnel-key -R myapp:80:localhost:8080 <SISH_DOMAIN>
The first time you connect, SSH shows sish's host key fingerprint. Accept it only if it equals SISH_HOST_KEY_FINGERPRINT in the credentials file. sish then prints the URLs of your tunnel, and while the SSH session stays open, https://myapp.<SISH_DOMAIN>/ and http://myapp.<SISH_DOMAIN>/ serve your local app to anyone who can reach ports 80 and 443. Press Ctrl+C to close the tunnel. Add -N to run without a session, and -o ServerAliveInterval=30 to keep long-lived tunnels open through NAT devices.
Browsers warn about the certificate because it is self-signed. Compare the fingerprint the browser shows (SHA-256) with SISH_TLS_CERT_SHA256, or install a CA-issued certificate as shown in Step 8. Do not add the self-signed certificate to a trust store. On the instance, this prints the fingerprint of the certificate sish actually serves:
openssl s_client -connect 127.0.0.1:443 -servername myapp.<SISH_DOMAIN> </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256
sha256 Fingerprint=3A:91:5C:0E:7D:22:B8:4F:61:A0:9E:3D:C7:58:14:F2:6B:0D:93:E8:5A:27:C1:4E:80:BF:36:D9:72:1A:E5:0C
Step 7: Authorize more keys
sish accepts the OpenSSH public keys in the files in /etc/sish/pubkeys/ and notices new files within seconds, without a restart. To let a colleague open tunnels, ask for their public key (for example id_ed25519.pub), copy it to the instance, and install it:
sudo install -o root -g sish -m 0640 your-laptop.pub /etc/sish/pubkeys/your-laptop.pub
To revoke a key, delete its file from /etc/sish/pubkeys/: sish refuses that key within seconds. Tunnels it already has open stay up until they disconnect; sudo systemctl restart sish ends every open tunnel. List the authorized keys and their fingerprints with:
sudo sh -c 'for k in /etc/sish/pubkeys/*.pub; do ssh-keygen -l -f "$k"; done'
Step 8: Use your own domain
To serve tunnels under a domain of your own, create two DNS records that point at the instance's public IP address (an Elastic IP address keeps it stable): tunnels.example.com and the wildcard *.tunnels.example.com. Then:
sudo sish-set-domain tunnels.example.com
This re-renders /etc/sish/config.yml for the new domain, generates a new self-signed certificate for tunnels.example.com and *.tunnels.example.com, updates /root/sish-credentials.txt and restarts sish. The tunnel key, the host key and every authorized key are kept. sudo sish-set-domain --default returns to <public-ip>.sslip.io, which you should also run after the public IP address changes (for example after you associate an Elastic IP address).
To use a certificate from your own certificate authority or a public CA, obtain a certificate that covers the domain and its wildcard, then replace the self-signed pair and restart sish:
sudo install -o root -g sish -m 0644 your-fullchain.pem /etc/sish/ssl/sish.crt
sudo install -o root -g sish -m 0640 your-privkey.pem /etc/sish/ssl/sish.key
sudo systemctl restart sish
Keep the file names sish.crt and sish.key. A wildcard certificate requires the DNS-01 challenge with public CAs such as Let's Encrypt.
Step 9: TCP forwards and aliases (optional)
A forward for a port other than 80 and 443, for example a database on your laptop:
ssh -p 2222 -i ~/.ssh/sish-tunnel-key -N -R 5432:localhost:5432 <SISH_DOMAIN>
is bound by sish on 127.0.0.1 only, on a random free port between 1024 and 65535. sish prints it as TCP: <domain>:<port>, but in this image that port is not reachable from the network: reach it from the instance itself, or through the system SSH server (ssh -L). sish never binds a tunnel client's port on the instance's network interfaces or below 1024. The listeners sish holds right now:
sudo ss -Htlnp | grep '"sish"'
A named alias (-R mydb:5432:localhost:5432) creates no port at all: another authorized client connects to it with ssh -p 2222 -i <key> -W mydb:5432 <SISH_DOMAIN>. Aliases are the only thing a client's ssh -L or ssh -W can reach through sish.
To publish raw TCP ports to the network, change tcp-address in /usr/local/lib/cloudimg/sish-config.yml.template and /etc/sish/config.yml, restart sish and open the port range in the security group. Only do so if every key holder should be able to open public ports on this instance.
Step 10: Logs
sudo journalctl -u sish-firstboot --no-pager -o cat | tail -3
systemctl status sish --no-pager | head -5
sish runs in the foreground under systemd, so its messages go to the journal (sudo journalctl -u sish). It logs SSH login attempts with the client address and public key, the tunnels opened and closed, and the connections made to them.
How the secure start works
sish.service only starts once first boot has written /var/lib/cloudimg/sish-ready. Before each start, a preflight run as root checks that the configuration is rendered for a real domain, forces public-key authentication, keeps the consoles off and raw TCP forwards on loopback, that /etc/sish/keys holds exactly the per-instance host key, that at least one key is authorized, that the TLS certificate is an end-entity certificate, and that nothing under /etc/sish is writable by anyone but root. If a check fails, sish does not start. Run it against the current configuration with:
sudo /usr/local/sbin/sish-preflight && echo preflight OK
preflight OK
Security recommendations
- Restrict port 2222 to the networks your tunnel clients connect from, and port 22 to your administrators.
- Give each person or machine its own key in
/etc/sish/pubkeys/and delete a key's file when it should stop working. Remove/root/sish-tunnel-keyfrom the server once you have copied it. - Remember that a tunnel publishes a local service to anyone who can reach ports 80 and 443. Protect the app itself with its own login, or restrict ports 80 and 443 in the security group to the people who should use it.
- Keep the instance patched. Ubuntu security updates install automatically every day; sish itself is updated by launching a newer version from the listing.
Support and licensing
sish is free software under the MIT License. The licence text and the build record are in /usr/local/share/doc/sish/. The source of this release is at https://github.com/antoniomika/sish/tree/v4.0.0.
sish is developed by Antonio Mika and contributors (https://github.com/antoniomika/sish). cloudimg is not affiliated with or endorsed by the sish project. For help with this image, contact cloudimg support through the AWS Marketplace listing.