Deployment guide

Termix

Overview

Termix is a self-hosted server management platform that runs in your browser. It gives you a full SSH terminal with tabs and split panes, an SFTP file manager, port-forwarding tunnels, and RDP, VNC and Telnet remote desktop sessions. Everything runs from one interface, against servers you own.

Connections live in a central inventory with folders and tags, so a team can keep one organised view of its fleet instead of scattering host entries across everyone's laptops. Credentials, including SSH private keys, are stored in an encrypted database rather than in plain configuration files.

This SecureAnyCloud image serves Termix 2.5.1 on a hardened Ubuntu 24.04 LTS base, patched at build time, behind nginx on port 80. The guacamole proxy is included, so remote desktop works out of the box.

The image is secure by default. It ships with no user account at all, so the first time you open it, you create your own administrator with your own password. There are no shared or default credentials anywhere in the image. The encryption keys that protect your stored credentials are generated on your own VM at first boot and are never baked into the image.

What you get:

  • Termix 2.5.1, built from the pinned upstream release, managed by systemd
  • Browser-based SSH terminal, SFTP file manager, tunnels, and RDP, VNC and Telnet sessions
  • nginx serving the web interface on :80 and proxying every backend service
  • guacd, the remote desktop proxy, so RDP and VNC work without extra setup
  • No default account: you create the first administrator on the first visit
  • Four independent 256-bit secrets generated per VM at first boot, never shared between VMs
  • An encrypted credential store, with each user's data key unlocked only by their own password
  • Every backend service bound to loopback, so only SSH and the web interface are reachable
  • Trust-on-first-use host key verification before any session opens
  • termix.service, nginx.service and guacd.service as enabled systemd units
  • 24/7 SecureAnyCloud support

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.

Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting size. Size up for more concurrent sessions.

Configure the network security group (NSG) to allow inbound 22/tcp from your management network and 80/tcp for the web interface.

Read this before you boot the VM. Termix stores SSH credentials and private keys for your other machines and gives shell access to them through a browser, so treat this VM as a privileged host. The image deliberately ships with no account. Termix's create administrator form is therefore available to whoever reaches port 80 first, and the first account created is granted administrator.

Scope the inbound rule for 80/tcp to your own IP address before you boot the VM, and create your administrator immediately after first boot. Once your administrator exists, you can close sign-ups from Settings.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Termix by SecureAnyCloud, and select Create.

On the Basics tab, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22), then add a custom rule for port 80 scoped to your own IP.

Then select Review + create and Create.

Step 2 - Deploy from the Azure CLI

Accept the Marketplace terms once per subscription, then create the VM.

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

Open the web interface port, restricted to your own address:

az network nsg rule create \
  --resource-group <your-rg> \
  --nsg-name termixNSG \
  --name allow-termix-ui \
  --priority 900 \
  --source-address-prefixes <your-ip>/32 \
  --destination-port-ranges 80 \
  --access Allow --protocol Tcp

Step 3 - Confirm the services are running

SSH in as azureuser and confirm that the stack is active. Termix's own services all listen on loopback and are reached through nginx. The only ports open to the network are 22 for SSH and 80 for the web interface.

systemctl is-active termix nginx guacd
sudo ss -tlnH | awk '{print $4}' | grep -vE '^(127\.|\[::1\])' | sort -u
sudo ss -tlnH | awk '{print $4}' | grep -E '^127\.0\.0\.1:(300[0-9][0-9]|4822)$' | sort -t: -k2 -n

Step 4 - Read the first-visit info note

Termix ships with no user account. On the first boot of every VM, a one-shot service writes an instance info note. It records the web interface URL and the security steps to take. The note contains no password, because you set your own on first visit.

sudo sed -n '1,12p' /root/termix-credentials.txt

Confirm from the command line that no account is baked into the image. setup_required is true only while the user count is zero, which is exactly the create-administrator state:

curl -s -o /dev/null -w 'GET / -> HTTP %{http_code}\n' http://127.0.0.1/
curl -s http://127.0.0.1/users/setup-required; echo

The four secrets that protect your credential store are generated on this VM at first boot and are not shipped in the image. They live in a file readable only by the termix service account:

sudo stat -c 'mode=%a owner=%U:%G %n' /var/lib/termix/.env

Step 5 - Create your administrator on first visit

Browse to http://<vm-public-ip>/. The image ships with no account, so Termix opens on its Create Account form. Choose a username and a strong password of at least six characters, confirm it, and select Sign Up.

This one screen is where you secure the instance. There are no default credentials to change, because none ship. The first account created is automatically the administrator.

Step 6 - Explore the dashboard

Sign in with the account you just created. The dashboard shows the running version, uptime, database health and your host totals, with quick actions for adding a host or a credential.

The sidebar on the left carries every feature: Hosts, Credentials, Connections, Quick Connect, Serial, SSH Tools, Snippets, History, Session Logs, Split Screen, Network Graph, Alerts and Admin.

Step 7 - Add your first server

Select Add Host. On the General tab, choose the SSH protocol, enter the address or hostname of a server you want to manage, and give it a friendly name.

On the SSH tab, set the port, the username to log in as, and the authentication method: either a password or an SSH private key. Save the host, and it appears in the Hosts list on the left.

Nothing is preconfigured in the image, so this list starts empty. The host you add is your own server, reached from this VM. The VM therefore needs network access to it on the relevant port.

Step 8 - Open a shell in the browser

Select the host you just added. The first time you connect, Termix shows a Verify SSH host key dialog with the server's SHA256 fingerprint.

This is trust-on-first-use verification, and it protects you from a man-in-the-middle attack on your own network. Check that the fingerprint matches the server you expect, then choose Accept & Continue. Termix remembers it for future connections.

The terminal then opens as a tab, and you have a full interactive shell. The screenshot below shows a live session with real command output after running uname -a && whoami && uptime.

Step 9 - Store credentials centrally

Open Credentials to keep SSH keys and passwords in one place and reuse them across hosts, instead of repeating them in every host entry.

Credentials are written to the encrypted database. Each user's data key is unlocked only by their own password when they sign in, so the server cannot read your stored credentials while you are signed out.

Step 10 - Close sign-ups

Self-registration is enabled by default so that you can create the first administrator. Once you have, open Admin and turn user registration off, unless you intend to let other people sign up.

This is the single most important thing to do after your first sign-in.

Step 11 - Confirm access control

Every route and every websocket refuses an anonymous caller. These checks send complete, well-formed requests, so a refusal is a real authorisation decision and not a validation error.

curl -s -o /dev/null -w 'GET /host/db/host -> HTTP %{http_code}\n' http://127.0.0.1/host/db/host
curl -s -o /dev/null -w 'GET /users/me -> HTTP %{http_code}\n' http://127.0.0.1/users/me
curl -s -o /dev/null -w 'GET /credentials/ -> HTTP %{http_code}\n' http://127.0.0.1/credentials/

The websocket endpoints matter most for a browser terminal, because that is where an interactive shell would be handed out. They verify your session inside the connection handler. When the session is missing, they close the connection with policy violation code 1008.

curl cannot show you this. A websocket rejection happens after the HTTP handshake succeeds. curl therefore reports HTTP 101 and exits, whether the application then accepted the connection or closed it. The result would look identical if the endpoint were wide open.

The check below completes the handshake and then reports what the application actually did with the connection:

node -e 'const h=require("http"),c=require("crypto");const r=h.request({host:"127.0.0.1",port:80,path:"/ssh/websocket/",headers:{Connection:"Upgrade",Upgrade:"websocket","Sec-WebSocket-Key":c.randomBytes(16).toString("base64"),"Sec-WebSocket-Version":"13"}});let d=0;const f=s=>{if(!d){d=1;console.log("terminal websocket with no session -> "+s);process.exit(0)}};const cc=b=>b&&b.length&&(b[0]&15)===8?"refused, close code "+b.readUInt16BE(2):null;r.on("upgrade",(x,s,hd)=>{const e=cc(hd);if(e)return f(e);s.setTimeout(6000);s.on("data",b=>{const v=cc(b);if(v)f(v)});s.on("close",()=>f("refused, socket closed"));s.on("timeout",()=>f("OPEN - NOT REFUSED"))});r.on("response",x=>f("refused, HTTP "+x.statusCode));r.end();setTimeout(()=>f("TIMEOUT"),9000)'

Step 12 - Verify the stack

Confirm the Termix version, the enabled services and the data directory permissions:

jq -r '"Termix " + .version' /opt/termix/package.json
systemctl is-enabled termix termix-firstboot nginx guacd
sudo stat -c 'mode=%a owner=%U:%G %n' /var/lib/termix

Step 13 - Where your data lives

Termix stores everything under /var/lib/termix: the host inventory, saved credentials, user accounts, session history and the per-VM encryption keys. The directory is owned by the dedicated termix service account with mode 0700. The application itself is under /opt/termix and holds no state.

sudo ls -la /var/lib/termix | head -8

Back up that directory as a unit. It contains both the encrypted database and the .env file holding the keys that decrypt it. A backup without .env cannot be restored.

Step 14 - Put TLS in front of it

The image serves plain HTTP on port 80. Until you terminate TLS, your Termix password and everything you type into a terminal cross the network in clear text. Treat TLS as required for anything beyond a short-lived test.

Point a DNS name at the VM's public IP and open 443/tcp in the NSG. Then issue a certificate with certbot, which edits the nginx site in place:

sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d termix.your-domain.com --redirect --agree-tos -m you@your-domain.com

Certbot installs a renewal timer automatically. When it completes, reach Termix at https://termix.your-domain.com/.

Security notes

  • No default credentials. The image ships with zero user accounts. You create the first administrator on first visit. Until you do, that form is open to anyone who can reach port 80, so scope the NSG rule to your own IP address before first boot.
  • Per-VM encryption keys. The four secrets that sign sessions and encrypt the credential store are generated from the system random source on your own VM at first boot. They are written to /var/lib/termix/.env with mode 0600. Nothing is baked into the image, so no two customer VMs share key material.
  • Encrypted credential store. Saved SSH keys and passwords are encrypted at rest. Each user's data encryption key is unwrapped only when they sign in with their password, so stored credentials are not readable while that user is signed out.
  • Loopback-only backend. All twelve Termix backend services and the guacamole proxy are bound to 127.0.0.1 and reached through nginx. The only network-reachable ports are 22 and 80.
  • Authenticated websockets. The terminal, container console, serial and tunnel websockets each verify your session inside the connection handler and close with code 1008 without one. The terminal and serial endpoints also require an unlocked data key, so a session alone is not enough to reach stored credentials.
  • Host key verification. Termix verifies the SSH host key of every server on first connection and asks you to confirm the fingerprint before opening a session.
  • Close sign-ups from Admin once your administrator account exists.
  • Patching. The image is patched at build time and unattended-upgrades remains enabled, so security updates continue to apply on your VM.

Support

SecureAnyCloud provides 24/7 support for this image. Contact sales@secureanycloud.com and include the VM name, the region and the output of systemctl status termix nginx guacd.

Deploy on Azure

Launch Termix 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