When you run your own server, nothing routes through a third party: your domain, your box, your data. There are no accounts and no database to manage. You decide who can reach it at the firewall, and the whole thing is small enough to read if you want to know exactly what it does.

These steps assume DigitalOcean. It is what the hosted service runs on, so the DNS records, the API token, and provision.sh are written for it. viaduct itself is not tied to any host: any box with a domain works, you would just point DNS and issue the wildcard certificate the way your own provider does it.

What you need

A small Ubuntu droplet (1 GB of RAM is plenty), a domain you can point at it, and a DigitalOcean API token so Caddy can issue a wildcard certificate over DNS. The token lives only on the droplet, never in the repo.

1. Point DNS at the box

Two records: the apex to the droplet's IP, and a wildcard so every tunnel subdomain resolves to the same box.

A      your-domain.com    → <droplet-ip>
CNAME  *.your-domain.com  → your-domain.com

2. Run the script

SSH in, clone the repo, and run the provisioner. It installs Caddy for public HTTPS with automatic wildcard TLS, sets up viaductd under systemd, and locks the firewall down to the ports it needs. It prompts for your DigitalOcean token as it goes.

$ git clone https://github.com/webmull/viaduct
$ cd viaduct && ./deploy/provision.sh

3. Point the client at it

Everything else works exactly as it does against the hosted service, just aim the client at your server on port 4443:

$ viaduct http 8080 --server your-domain.com:4443

Set server once in ~/.config/viaduct/config.toml and you can drop the flag entirely.

The tunnel port has no auth, by design. Public HTTPS rides through Caddy on 443, but tunnel connections are not HTTP, so viaductd terminates TLS itself on port 4443. Anyone who can reach that port can open a tunnel, so restrict it to your own users' source IPs at the firewall unless you are happy to leave it internet-open. If you front the server with something other than Caddy, start viaductd with --trust-peer-ip so --allow-ip reads the real address.

Rehearse it first

You do not have to learn this on a live box. deploy/local/ runs the whole provisioning flow locally so you can watch it work before pointing it at a real droplet. The annotated, step-by-step breakdown of what the script does lives in the deployment guide, and the README covers the rest.

← Back to the docs