Install the control plane
One command on a fresh Debian or Ubuntu VPS. About five minutes, most of it waiting for the certificate.
Before you start
- A VPS with a public IPv4 address. Two dedicated cores and four gigabytes of memory run a few hundred devices.
- A DNS name for the console, for example
mesh.example.com, pointing at that address. If the name is on Cloudflare, keep the record DNS only (grey cloud): the proxy breaks the gRPC connections clients use. - Ports
443(TCP and UDP) and3478(UDP) reachable from the internet. - Root access.
Run the installer
curl -fsSL https://tzxmesh.com/install.sh | sh
It asks for the domain and the owner email, then:
- installs Docker Engine and the Compose plugin from Docker's repository if they are missing;
- writes
/opt/tzxmesh/app: the compose file, the reverse-proxy config, the control-plane config, and a.envwith freshly generated secrets (mode 600); - starts Caddy, the control plane, the console and Postgres; Caddy obtains the TLS certificate;
- prints the console address and the owner's initial password.
Non-interactive installs pass the two answers as variables:
TZX_DOMAIN=mesh.example.com [email protected] sh install.sh
Prefer to read the script first? Open install.sh. It is short, and everything it writes lands in one directory on your server.
First sign-in
- Open
https://mesh.example.comand sign in with the owner email and the printed password. - Change the password.
- Go to Settings → Authentication and switch Peer Approval on. From now on every new device waits in Warden until you admit it.
What you get
| Service | Container | Notes |
|---|---|---|
| Reverse proxy + TLS | tzxmesh-caddy | routes API, sign-in and gRPC to the control plane, everything else to the console |
| Control plane | tzxmesh-server | management, signalling, relay, STUN and the built-in identity provider in one process |
| Console | tzxmesh-dashboard | static web app |
| Database | tzxmesh-postgres | two databases: the control plane and the identity provider |
If something is off
- No certificate. The domain must resolve to this server's public IP before Caddy can prove ownership. Check with
dig +short mesh.example.com, thendocker compose logs caddyin/opt/tzxmesh/app. - Devices connect only through the relay. UDP 3478 or the WireGuard ports are blocked somewhere; direct paths need them.
- Re-running the installer keeps your secrets and data; it only rewrites the generated files.