Networking AWS

Zoraxy 3.3.4 on AWS User Guide

| Product: Zoraxy 3.3.4 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using Zoraxy 3.3.4 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 page.

Zoraxy is a self-hosted reverse proxy with a web management UI. You add a host name (for example app.example.com), point it at a backend (10.0.1.20:8080), and Zoraxy serves it on ports 80 and 443, with Let's Encrypt or your own certificates, redirects, virtual directories, load balancing across several backends, access rules (IP and country allow and block lists), basic authentication, rate limits, uptime monitoring and traffic statistics. It also proxies raw TCP and UDP streams.

What the cloudimg image adds:

  • No first-visitor admin. Stock Zoraxy shows a "create the admin account" form to whoever opens it first. On this image the first boot of your instance creates the admin account admin with a password unique to the instance, through Zoraxy's own setup endpoint, on a private copy of Zoraxy that has no network access at all. Only then do Zoraxy and its web front start, so the create-account form is never reachable from the network. The password is written only to a file readable by root.
  • The management UI over HTTPS on port 8443 only. Zoraxy's management UI listens on 127.0.0.1:8000 (the loopback address). nginx serves it over HTTPS on port 8443 with a certificate generated on your instance, answers only for this instance's own names, hands Zoraxy the real client address and refuses a request that changes something when it comes from another site. Plain HTTP to port 8443 is refused before it reaches Zoraxy.
  • HTTPS for your sites from the first boot. Zoraxy serves ports 80 and 443. Until you add your own certificates, port 443 answers with a fallback certificate generated on your instance. Stock Zoraxy writes and serves a fallback certificate and private key that are compiled into every copy of Zoraxy (the same key everywhere); this image never writes or serves that pair, and Zoraxy refuses to start if it ever appears.
  • Zoraxy runs as an unprivileged user. The stock install runs Zoraxy as root. Here it runs as the system user zoraxy with a single extra privilege, binding ports 80 and 443, in a read-only view of the system that can write only to /var/lib/zoraxy.
  • Instance metadata blocked. Zoraxy connects to addresses you or your rules give it (proxy backends, uptime checks, stream proxies, the network tools, certificate authorities and DNS providers, the plugin store). It cannot reach the EC2 instance metadata service (169.254.169.254 and fd00:ec2::254), so a mistaken or malicious rule can never read the instance's metadata or IAM role credentials. The AMI is registered IMDSv2 only.
  • Web SSH is off. Zoraxy's Web SSH tool runs a bundled 2017 terminal program that, while a session is open, listens on every network interface with write access and no password. It is disabled on this image; Step 9 explains how to turn it on and what that means.
  • The internal web server stays local. Zoraxy's built-in static web server (the "Welcome to Zoraxy" default page) listens on 127.0.0.1:5487 only, with directory listing off, and mDNS discovery is off.
  • Patched libraries. cloudimg compiles Zoraxy 3.3.4 from the unmodified upstream source with Go 1.27.3 and four newer Go libraries (HTTP/2, SSH, gRPC and CSRF protection fixes); the official 3.3.4 download is built with Go 1.25.0 and carries 72 known Go vulnerabilities. Step 11 has the details and how to rebuild it yourself.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: Zoraxy 3.3.4 (built from the v3.3.4 source with Go 1.27.3), nginx 1.24 (from Ubuntu 24.04, for the management UI only), cloud-init and the AWS Systems Manager agent.

Default user: ubuntu · Architecture: x86_64 · Root volume: 8 GiB gp3

The Zoraxy management UI over HTTPS on port 8443 showing the status page

Security posture

  • Per-instance secrets only. The admin password, Zoraxy's session key and CSRF key, and both TLS keys (management UI and fallback) are generated on your instance's first boot. Two instances launched from the same AMI share none of them.
  • Fails closed. Zoraxy and nginx start only after first boot has created the admin and written a ready marker. A start-up check refuses to start Zoraxy unless its account store holds exactly the account admin and its fallback certificate is this instance's own. If first boot cannot finish, both stay stopped and first boot tries again on the next boot.
  • End-entity certificates. Both self-signed certificates can only vouch for this instance's own names (they are not certificate authorities). Compare their fingerprints with the ones in the credentials file, or replace them with CA-issued certificates. Do not add them to a trust store.
  • Per-instance identity. SSH host keys and the machine ID are generated fresh on every instance.

Prerequisites

  1. An AWS account and permission to launch EC2 instances
  2. An EC2 key pair in the Region you launch in
  3. A security group that allows TCP 22 (SSH) and TCP 8443 (the Zoraxy management UI) from your admin network only, and TCP 80 and TCP 443 (the sites Zoraxy proxies, and Let's Encrypt HTTP validation) from the networks that use them. Never open 8000 or 5487: they listen on the loopback address only.

Recommended instance type: m5.large. Zoraxy is light; size the instance for your traffic.

Connecting to your instance

Version Operating system SSH user
Zoraxy 3.3.4 on Ubuntu 24.04 Ubuntu 24.04 LTS ubuntu

Step 1: Launch the instance

Option A: AWS Marketplace console

  1. 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.
  2. Once the subscription is active, choose Launch your software.
  3. Choose One-click launch from AWS Marketplace (or Launch from EC2 Console for the full launch wizard). In Version, choose Zoraxy 3.3.4 on Ubuntu 24.04, then choose your Region.
  4. Pick an instance type (m5.large recommended) and your key pair.
  5. Security group: the listing's default group allows SSH (22), HTTP (80), HTTPS (443) and the management UI (8443). Restrict 22 and 8443 to your own addresses.
  6. Choose your VPC and a public subnet (or attach an Elastic IP later), 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 that allows SSH and the management UI from your admin address and HTTP and HTTPS from everyone, 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 range with your own:

SG=$(aws ec2 create-security-group --group-name zoraxy \
  --description "Zoraxy reverse proxy" --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 8443 --cidr <your-mgmt-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=zoraxy}]'

You do not need --metadata-options: the AMI already makes IMDSv2 required. First boot takes under a minute after the instance is running.

Step 2: Connect and check the services

Connect as ubuntu with the key pair you chose:

ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>
systemctl is-active zoraxy nginx
sudo test -f /var/lib/cloudimg/zoraxy-firstboot.done && echo FIRSTBOOT_DONE
ps -o user= -C zoraxy
active
active
FIRSTBOOT_DONE
zoraxy

zoraxy-firstboot ran once on the first boot; zoraxy is the reverse proxy (running as the user zoraxy) and nginx serves its management UI. The listening sockets:

sudo ss -lntp | awk 'NR>1 {print $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | grep -v '127.0.0.5' | sort
*:443 users:(("zoraxy"))
*:80 users:(("zoraxy"))
0.0.0.0:22 users:(("sshd"),("systemd"))
0.0.0.0:8443 users:(("nginx"),("nginx"),("nginx"))
127.0.0.1:5487 users:(("zoraxy"))
127.0.0.1:8000 users:(("zoraxy"))
[::]:22 users:(("sshd"),("systemd"))
[::]:8443 users:(("nginx"),("nginx"),("nginx"))

Ports 80 and 443 are Zoraxy (your sites), 8443 is nginx (the management UI), and 8000 (the UI itself) and 5487 (the default page) are on the loopback address only. nginx starts one worker per vCPU, so the number of nginx entries depends on the instance type.

Step 3: Get your URL and admin password

The URL and the admin password are in a file only root can read:

sudo cat /root/zoraxy-credentials.txt
# Zoraxy 3.3.4 - generated on first boot by zoraxy-firstboot.service.
# Every value below is unique to this instance; nothing was baked into the image. Keep this file private.

# Management UI (HTTPS on port 8443, self-signed certificate unique to this instance). Sign in as admin, then change
# the password (Utilities -> Change Password) to another long random one.
ZORAXY_URL=https://<public-ip>:8443/
ZORAXY_ADMIN_USERNAME=admin
ZORAXY_ADMIN_PASSWORD=<generated password>
ZORAXY_HOST=<public-ip>
# The certificate served on 8443 (/etc/nginx/cloudimg/tls/zoraxy-mgmt.crt), to compare with your browser's warning:
MGMT_TLS_CERT_SHA256=<fingerprint>
# Zoraxy's fallback certificate on 443 (/var/lib/zoraxy/tmp/localhost.pem) until you add your own:
FALLBACK_TLS_CERT_SHA256=<fingerprint>

# Self-test: sudo zoraxy-selftest     New admin password: sudo zoraxy-reset-admin     Own DNS name: sudo zoraxy-set-host <name>
# Guide: https://www.cloudimg.co.uk/guides/zoraxy-3-3-4-on-ubuntu-24-04-aws/

The self-test checks the whole instance in one go (services, listeners, the HTTPS front, the admin password, the fallback certificate) and prints no secret:

sudo zoraxy-selftest
SELFTEST_OK zoraxy=active nginx=active host=<public-ip> accounts=1

Step 4: Sign in

Open https://<public-ip>:8443/ in your browser. The certificate is self-signed, so the browser warns once: compare the SHA-256 fingerprint it shows with MGMT_TLS_CERT_SHA256 from the credentials file, then continue. Sign in as admin with the password from the file.

The Zoraxy sign-in page served over HTTPS on port 8443

Use the instance's public IPv4 address or its public DNS name (both are in the certificate). The management UI answers only for this instance's own names: a request for any other host name on 8443 is dropped. To reach it under your own DNS name, see Step 8. If you prefer not to open 8443 at all, close it in the security group and use an SSH tunnel instead:

ssh -i ~/.ssh/my-key-pair.pem -L 8443:127.0.0.1:8443 ubuntu@<public-ip>

and open https://localhost:8443/ (keep the local port 8443: the UI checks that the address in your browser matches the one it serves).

After signing in, change the password (Utilities, Change Password). Zoraxy stores its admin password as an unsalted SHA-512 hash and does not slow down repeated failed logins, so keep the new password long and random (the generated one is 24 random letters and digits) and keep 8443 restricted to your admin addresses.

Step 5: Proxy your first site

  1. Point a DNS record for your site (for example app.example.com) at the instance's public IP address.
  2. In the management UI, open Create Proxy Rule (under Reverse Proxy). Enter the host name as Matching Keyword / Domain and the backend as Target IP Address or Domain Name with port (for example 10.0.1.20:8080), tick Proxy Target require TLS Connection only if the backend itself speaks HTTPS, then Create Endpoint.
  3. Zoraxy now serves http://app.example.com and https://app.example.com (with the fallback certificate until you add a real one in Step 6).

The HTTP Proxy list in the Zoraxy management UI

You can check a rule from the instance itself without DNS, by sending the host name Zoraxy expects to the loopback address:

curl -sk --resolve app.example.com:443:127.0.0.1 https://app.example.com/

A host name Zoraxy has no rule for gets Zoraxy's default site, the "Welcome to Zoraxy" page from its local web server (you can change the default site under Default Site). It never gets the management UI:

curl -sk --resolve unknown.invalid:443:127.0.0.1 https://unknown.invalid/ | grep -o 'Zoraxy Static Web Server' | head -1
Zoraxy Static Web Server

Client addresses. Zoraxy adds the client's address to the end of the X-Forwarded-For header it sends to your backend, keeping any value the client sent in front of it, and it passes on an X-Real-Ip (and CF-Connecting-IP) header the client sent unchanged. A backend that trusts those headers can therefore be given a false address. For every rule whose backend logs or uses the client address, open HTTP Proxy, the rule's Edit, then Custom Headers, and add two headers in the Zoraxy » Origin direction: X-Real-Ip with the value $remote_ip and X-Forwarded-For with the value $remote_ip. Zoraxy then replaces whatever the client sent with the address of the connection. (cloudimg checked both behaviours on the build instance: by default a forged X-Real-Ip: 6.6.6.6 reached the backend; with the two headers the backend saw only the real address.) If your instance sits behind a load balancer, use the load balancer's own header instead.

Step 6: Certificates

  • Let's Encrypt: open ACME Client (under Security). Enter your email address and the domain, keep the HTTP challenge (port 80 must be open to the internet) or choose a DNS provider, and request the certificate. Zoraxy renews it automatically.
  • Your own certificate: upload the certificate and key under TLS / SSL certificates; Zoraxy picks the certificate whose names match each host.
  • The fallback certificate (for names no certificate of yours matches) is generated on your instance; its fingerprint is FALLBACK_TLS_CERT_SHA256 in the credentials file. You can set one of your own certificates as the default in the same page.

Step 7: Outbound connections Zoraxy makes

Zoraxy connects out only for features you use, plus two fixed checks. All of them run inside the zoraxy service, which cannot reach the instance metadata service:

Feature Connects to Advice
Proxy rules, load balancing, stream proxy (TCP/UDP) the backends you configure keep backends in your VPC; restrict the instance's security group egress if you can
Uptime monitor every rule's backend, on a timer as above
Network tools (ping, whois, port scan, IP scan, Wake-on-LAN) the addresses you type admin only; the tools are under Network Tools
Forward proxy (off by default) any address a client asks for leave it off unless you need it; if you turn it on, never open its port (5587) in the security group
ACME / Let's Encrypt and DNS providers the CA and your DNS provider's API needed for certificates
Plugin store GitHub (plugin downloads) plugins are programs that run with Zoraxy's permissions: install only ones you trust
SSO / forward authentication the auth server you configure as above
Public IP check checkip.amazonaws.com, at start and every 12 hours fixed; harmless

The traceroute tool needs a raw-socket privilege the service does not have, so it reports an error; use traceroute over SSH instead.

Step 8: Your own DNS name for the management UI

Point a DNS record (for example proxy-admin.example.com) at the instance, then:

sudo zoraxy-set-host proxy-admin.example.com

It re-issues the management UI's self-signed certificate for that name (and the instance's own address), updates the names nginx answers on and prints the new fingerprint. Run sudo zoraxy-set-host with no argument to go back to the instance's own address. To use a CA-issued certificate for the management UI instead, replace /etc/nginx/cloudimg/tls/zoraxy-mgmt.crt and .key (keep the same names and modes) and run sudo systemctl reload nginx.

Step 9: Web SSH

Zoraxy's Web SSH utility opens an SSH session in the browser by running a bundled terminal program (gotty, last released in 2017, built with Go 1.15). While a session is open that program listens on a port from 14810 upwards on every network interface, with write access and no password, until the first client connects. The security group blocks those ports by default, but anyone in your VPC could reach them. Web SSH is therefore disabled on this image: the directory Zoraxy unpacks it into is mounted so programs there cannot run, and starting a session does nothing. Use SSH directly, or an SSH tunnel for the UI (Step 4).

If you decide you need it, remove the NoExecPaths= line from the service (sudo systemctl edit --full zoraxy.service), run sudo systemctl restart zoraxy, and never open ports 14810 and up in the security group.

Step 10: Security checks

You can repeat the main checks yourself. The admin account exists and the create-account endpoint refuses a second one:

curl -s http://127.0.0.1:8000/api/auth/userCount; echo
1

Plain HTTP to the management port is refused by nginx before it reaches Zoraxy:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8443/
400

Zoraxy and nginx cannot reach the instance metadata service (the first command runs inside the zoraxy service's own control group and must fail; the second, from your shell, is the control and gets a token):

CG=$(systemctl show -p ControlGroup --value zoraxy.service)
sudo bash -c "echo \$\$ > /sys/fs/cgroup${CG}/cgroup.procs; curl -s -m 5 -o /dev/null -w 'from zoraxy: %{http_code}\n' -X PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 60' http://169.254.169.254/latest/api/token" || true
curl -s -m 5 -o /dev/null -w 'from your shell: %{http_code}\n' -X PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 60' http://169.254.169.254/latest/api/token
from zoraxy: 000
from your shell: 200

Zoraxy runs as zoraxy with only the privilege to bind ports below 1024:

systemctl show -p User -p AmbientCapabilities -p NoNewPrivileges zoraxy.service
AmbientCapabilities=cap_net_bind_service
User=zoraxy
NoNewPrivileges=yes

The certificate on 443 for an unknown name is this instance's own fallback, not the one compiled into Zoraxy:

sudo openssl x509 -in /var/lib/zoraxy/tmp/localhost.pem -noout -fingerprint -sha256
openssl s_client -connect 127.0.0.1:443 -servername unknown.invalid </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256

Both lines show the same fingerprint, which is FALLBACK_TLS_CERT_SHA256 from the credentials file.

Step 11: Versions, provenance and file locations

zoraxy -version
sha256sum /usr/local/bin/zoraxy
grep -E 'dependency raises|toolchain' /usr/share/doc/zoraxy/BUILD-PROVENANCE.txt
Zoraxy - Version 3.3.4
a5f1d30cf90fc958c54435bb3c48a500d5a649d9471e73fa6aae2a7cdc48c509  /usr/local/bin/zoraxy
toolchain         go1.27.3 (official tarball, sha256 pinned), CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOAMD64=v1
dependency raises golang.org/x/net v0.62.0, golang.org/x/crypto v0.58.0, google.golang.org/grpc v1.83.2, github.com/gorilla/csrf v1.7.3

The binary is Zoraxy's unmodified v3.3.4 source (commit 304e6f0) built with upstream's own build flags, Go 1.27.3 and four newer Go libraries: golang.org/x/net 0.62.0, golang.org/x/crypto 0.58.0, google.golang.org/grpc 1.83.2 and github.com/gorilla/csrf 1.7.3. No Zoraxy source file is changed. The build is reproducible: /usr/share/doc/zoraxy/ holds the go.mod and go.sum used, the module list (buildinfo.txt), the vulnerability scan of the build (govulncheck-binary.txt, no findings) and the exact build steps (BUILD-PROVENANCE.txt, SOURCE).

Path What
/usr/local/bin/zoraxy Zoraxy
/var/lib/zoraxy/ all of Zoraxy's state: sys.db (accounts and settings), conf/ (proxy rules, certificates), log/, www/ (the default site)
/etc/systemd/system/zoraxy.service the service (user, privileges, sandbox; the IMDS block is in zoraxy.service.d/)
/etc/nginx/conf.d/cloudimg-zoraxy-mgmt.conf the HTTPS front for the management UI on 8443
/etc/nginx/cloudimg/tls/ the management UI's certificate and key
/root/zoraxy-credentials.txt URL, admin password and fingerprints (root only)
/usr/share/doc/zoraxy/ licence, source offer and build provenance

Step 12: Passwords, backup and maintenance

  • Lost the admin password: sudo zoraxy-reset-admin stops Zoraxy and its web front, removes the account, creates admin again with a new random password, starts both and writes the new password to /root/zoraxy-credentials.txt. The UI is unreachable while it runs, so nobody can create an account in between.
  • Backup: Zoraxy's Utilities, System Backup & Restore exports the configuration; or stop Zoraxy (sudo systemctl stop zoraxy) and copy /var/lib/zoraxy. Snapshots of the EBS volume work too.
  • Updates: Ubuntu security updates install automatically. Zoraxy itself is updated by replacing the binary; cloudimg publishes new versions of this image as Zoraxy releases them.

Step 13: Security recommendations

  • Restrict ports 22 and 8443 to your admin addresses, and use the SSH tunnel (Step 4) if you can.
  • Change the admin password to a long random one and keep it in a password manager.
  • Add the two client-address headers (Step 5) to every rule whose backend uses the client address.
  • Leave Web SSH and the forward proxy off unless you need them; install only plugins you trust.
  • Give the instance an IAM role only if something on it needs one: Zoraxy itself needs none.

Support and licensing

Zoraxy is free software under the GNU Affero General Public License v3 (/usr/share/doc/zoraxy/LICENSE). The corresponding source of the binary on this image is Zoraxy's unmodified v3.3.4 source plus the go.mod and go.sum in /usr/share/doc/zoraxy/; cloudimg makes no other change. Zoraxy embeds components under MIT, Apache-2.0, BSD and MPL-2.0 licences. Zoraxy is a trademark of its authors; cloudimg is not affiliated with or endorsed by the Zoraxy project.

cloudimg provides support for this image (the build, first boot, security settings and the AWS integration). Contact us at support@cloudimg.co.uk.