Deployment guide

WebSSH 1.6.3

Overview

This guide covers the deployment, secure configuration and day-to-day use of WebSSH 1.6.3 on Ubuntu 24.04 on Azure, using SecureAnyCloud Azure Marketplace images. WebSSH is an open-source, web-based SSH client. It serves a browser terminal, built on Tornado and xterm.js. You enter a target host, port, username and a password or private key, and WebSSH opens a real SSH session to that host and streams it back to the page. You can reach a shell from any modern browser with no local SSH client installed.

WebSSH is an SSH relay, and this image is built to ship it safely. By default, the upstream wssh server binds 0.0.0.0:8888 with no authentication. Anyone who reaches the page can attempt an SSH connection to any host and port they type. That is an open pivot, SSRF and brute-force-relay surface. The SecureAnyCloud image closes it by design.

The Security section below is the most important part of this guide. WebSSH can connect outward to anything you type, so you are responsible for restricting who can reach the front door and where it may connect. Read it before you expose the instance.

What you get:

  • WebSSH bound to loopback only (127.0.0.1:8888). It is never a public listener.
  • nginx as the only public listener (TCP 80, and optionally 443). It gates the entire UI and the terminal WebSocket behind per-VM HTTP Basic Auth.
  • A password generated uniquely on first boot and written to /root/webssh-credentials.txt (mode 0600, root only). No shared or default password is baked into the image. The shipped image carries only a fail-closed entry that denies everyone until first boot generates the real password.
  • WebSSH 1.6.3 (official huashengdun/webssh, MIT licence) in a dedicated Python virtual environment at /opt/webssh/venv.
  • The webssh.service systemd unit, which runs wssh bound to 127.0.0.1:8888 (loopback only) as a dedicated webssh system user.
  • An nginx reverse proxy on TCP 80 that fronts the UI and the terminal WebSocket behind per-VM HTTP Basic Auth. It also serves an unauthenticated static /healthz for load-balancer probes.
  • The webssh-firstboot.service systemd oneshot, which generates a per-VM Basic Auth password (bcrypt .htpasswd) and proves the front-door gate on first boot.
  • A fail-closed credential entry in the shipped image, so no known password is ever present.
  • Tornado CSRF protection retained, --fbidhttp=false for the behind-nginx topology, and --origin=same cross-origin protection.
  • An Ubuntu 24.04 LTS base with the latest security patches applied at build time, and unattended-upgrades armed.
  • The Azure Linux Agent for seamless cloud integration and SSH key injection.
  • 24/7 SecureAnyCloud support with a guaranteed 24 hour response SLA.

Prerequisites

Before you deploy this image, make sure you have:

  • An active Azure subscription, an SSH public key, and a VNet and subnet in your target region.
  • A subscription to the WebSSH listing on Azure Marketplace.
  • A clear view of which hosts you intend to administer through WebSSH and which client networks should be allowed to reach it. You lock the instance down to those below.
  • Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is comfortable, because WebSSH is a light, stateless gateway. For many concurrent terminals, use Standard_B2ms or Standard_D2s_v5.
1

Deploy from the Azure Portal

Search for WebSSH in the Marketplace, select the SecureAnyCloud publisher, and choose Create. Configure the network security group as tightly as you can:

  • TCP 22 (SSH) for administration, from your management network only.
  • TCP 80 (WebSSH UI, behind Basic Auth) from your trusted client networks only. Never open it to 0.0.0.0/0 on a public instance.
  • TCP 443 is optional. Open it if you put your own TLS certificate in front of nginx, which is recommended for production (see Security).
2

Deploy from the Azure CLI

az group create --name webssh-rg --location eastus
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:webssh-ubuntu-24-04:default:latest
az vm create \
  --resource-group webssh-rg \
  --name webssh-vm \
  --image sac1647283583153:webssh-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

Then restrict inbound access to your own management CIDR instead of the whole internet:

az network nsg rule create \
  --resource-group webssh-rg --nsg-name webssh-vmNSG \
  --name allow-webssh-ui --priority 1010 \
  --destination-port-ranges 80 --access Allow --protocol Tcp \
  --source-address-prefixes <your-mgmt-cidr>
3

First boot and retrieving your per-VM password

On first boot, webssh-firstboot.service generates a unique password for the admin front-door account, writes it to /root/webssh-credentials.txt, starts nginx and proves the gate. SSH in as azureuser and read it:

sudo cat /root/webssh-credentials.txt

You will see the WEBSSH_URL, the admin username and the per-VM WEBSSH_PASSWORD, along with security notes. Confirm that the services are healthy and that WebSSH is bound to loopback only, with nginx as the only public listener:

systemctl is-active webssh.service nginx.service
sudo ss -tlnp | grep -E ':8888|:80 ' curl -s -o /dev/null -w 'unauthenticated /healthz -> HTTP %{http_code}\n' http://127.0.0.1/healthz

The credentials file is mode 0600. The image ships only a fail-closed bcrypt entry in /etc/nginx/.webssh.htpasswd, and no plaintext password is ever stored in the image.

4

Sign in and open an SSH session

Open WEBSSH_URL (http://<your-vm-public-ip>/) in a browser. Your browser prompts for the front-door credentials. Sign in as admin with the per-VM password from Step 3. The WebSSH connect form then appears.

Enter the target host you want to reach: its hostname or IP, the SSH port (22 by default), the username, and either a password or an uploaded private key. You can also add an optional passphrase and a TOTP code for servers that use 2FA.

Choose Connect. WebSSH opens a real SSH session to that host and drops you into a live xterm.js terminal in the browser. The terminal is a full interactive shell, so you can run commands exactly as you would in any SSH client.

5

Security: you are running an SSH relay

WebSSH attempts to connect to any host and port that a signed-in user types. Treat the instance as what it is, an SSH relay, and control both ends.

The front door only opens with the per-VM password

The whole UI and the terminal WebSocket sit behind per-VM HTTP Basic Auth. Without the password, the front door is closed to everyone. A wrong password is rejected, and only the per-VM password reaches the terminal. You can prove this from the VM:

PW=$(sudo grep '^WEBSSH_PASSWORD=' /root/webssh-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'no password -> HTTP %{http_code}\n' http://127.0.0.1/
curl -s -o /dev/null -w 'wrong password -> HTTP %{http_code}\n' -u admin:wrong-pw http://127.0.0.1/
curl -s -o /dev/null -w 'per-VM pw -> HTTP %{http_code}\n' -u "admin:$PW" http://127.0.0.1/

Restrict who can reach it (inbound)

  • Keep the per-VM password secret, and rotate it if it is ever shared (see below).
  • Lock inbound TCP 80/443 to trusted source IPs in the Azure NSG, or keep the instance on a private network reachable only over a VPN or Bastion. Do not expose it wide open to 0.0.0.0/0.

Restrict where it can connect (outbound and egress)

By design, WebSSH lets the browser choose the destination, so an unrestricted instance can reach anything routable from the VM. Constrain egress to only the hosts you administer. An Azure NSG outbound rule is the cleanest control. On the VM itself, you can also use UFW, for example to allow SSH only to a specific management subnet:

sudo ufw default deny outgoing
sudo ufw allow out to <your-mgmt-cidr> port 22 proto tcp
sudo ufw allow out 53
sudo ufw enable

Encrypt the front door for production

The image serves the UI over plain HTTP on port 80 by default. For any production or internet-facing use, put your own TLS certificate in front of nginx (port 443). This encrypts the Basic Auth password and the terminal traffic in transit.

SecureAnyCloud ships nginx-ssl-certbot-ubuntu-24-04 as a one-step option. Alternatively, add a listen 443 ssl server block with your certificate to /etc/nginx/sites-available/sac-webssh.

Managing the service

Check the service status and read recent logs:

systemctl status webssh.service --no-pager sudo journalctl -u webssh.service --no-pager -n 20

To restart the stack after a configuration change, run sudo systemctl restart webssh.service nginx.service. To follow the logs live, use sudo journalctl -u webssh.service -f.

Rotate the front-door password by writing a fresh bcrypt entry. nginx reads the file on every request, so no restart is needed:

NEWPW=$(openssl rand -base64 18)
sudo htpasswd -bB /etc/nginx/.webssh.htpasswd admin "$NEWPW" echo "New WebSSH admin password: $NEWPW"

Store the new password somewhere safe. It replaces the one in /root/webssh-credentials.txt.

Verifying the install

Confirm the pinned versions and that both services are active:

/opt/webssh/venv/bin/wssh --version nginx -v systemctl is-active webssh.service nginx.service

Troubleshooting

The browser never prompts for a password, or the page is open. Check that you are reaching the instance through nginx on port 80, not WebSSH's loopback :8888 directly. WebSSH must never be published on a public interface. Confirm that ss -tlnp | grep 8888 shows 127.0.0.1:8888 only.

"Connection refused" or a red status when you choose Connect. WebSSH could not reach the target host and port, or your egress rules block it. Confirm the target is reachable from the VM (ssh <user>@<host>), and review your NSG and UFW outbound rules.

HTTP 401 with the right password. The password in /root/webssh-credentials.txt is current only if you have not rotated it. If you rotated it, use the new value.

Host key warning on connect. WebSSH uses the upstream default warning host-key policy (trust-on-first-use). It accepts unknown target host keys with a logged warning, which you can review in journalctl -u webssh.service.

Support

Every SecureAnyCloud image includes 24/7 support with a guaranteed 24 hour response SLA. Contact support through the Azure Marketplace listing or at secureanycloud.com.

Deploy on Azure

Launch WebSSH 1.6.3 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

Deploy on Azure