Documentation
Getting started
Everything you need to put a local port on a public URL. Install once, then start a tunnel, pin a stable URL, or watch requests live. Every command below is copy-paste ready.
Install
viaduct needs Python 3.11 or newer and
pipx,
which keeps the CLI in its own isolated environment and on your
PATH.
$ pipx install git+https://github.com/webmull/viaduct
That installs both the viaduct client and the
viaductd server. Confirm it is on your path:
$ viaduct --version
Start a tunnel
Point viaduct http at any local port. It prints a public
HTTPS URL and forwards traffic to that port until you stop it.
- Run your app on some local port, for example a dev server on
8080. - Open the tunnel with the command below.
- Share the printed URL. Every request to it rides the tunnel to your
localhost.
$ viaduct http 8080
✓ tunnel live https://sunny-otter.viaduct.sh → http://localhost:8080 press q to stop
502 page until your app comes up, so
you can start them in either order.
Stop the tunnel with q or Ctrl+C. On a drop it
reconnects on its own, and by default each reconnect gets a fresh URL.
To keep the same one, pin it.
Keep the same URL (--pin)
Add --pin to keep the same public URL for a given port
across reconnects and restarts. Useful for a webhook endpoint you
register once, or a demo link you want to stay put.
$ viaduct http 8080 --pin
✓ tunnel live https://amber-stoat-cfb1.viaduct.sh → http://localhost:8080 press q to stop
~/.config/viaduct/pin.key. Different ports get different
stable names; delete that file to rotate to a new one.
Inspect requests (--inspect)
Add --inspect to print each request as it happens: method,
path, status, and timing. Ideal for debugging webhooks without leaving
your terminal.
$ viaduct http 8080 --inspect
✓ tunnel live https://funny-otter.viaduct.sh → http://localhost:8080 14:02:01 GET / 200 5ms 14:02:04 POST /webhooks/stripe 200 61ms 14:02:06 GET /favicon.ico 404 1ms 14:02:09 GET /ws 101 3ms
Combine flags
Flags stack. Pin a stable URL and watch its traffic at the same time:
$ viaduct http 8080 --pin --inspect
The order does not matter, and the local port can be any port your app listens on.
Custom domains (bring your own)
Serve a tunnel on your own domain with a single CNAME. There's no extra flag, the mapping lives in your DNS.
- Pin the tunnel so it has a stable name:
viaduct http 8080 --pingives you something likefunny-otter-9a1c2b3d4e5f.viaduct.sh. - Add a CNAME at your registrar (the exact screen differs per provider): point
demo.example.comat thatfunny-otter-9a1c2b3d4e5f.viaduct.shname. - Open it. The first request auto-provisions an HTTPS certificate, then
https://demo.example.comserves your local app.
*.viaduct.sh name rather than straight at an IP. And because
the certificate is only issued once your domain already points here, you
can only serve domains whose DNS you actually control.
Regions
viaduct.sh operates tunnel nodes in four regions. Run your tunnel on
the one nearest your traffic with --region; with no flag
you get London by default.
| Region | --region | Tunnel URL |
|---|---|---|
| London (default) | lon | name.viaduct.sh |
| New York | nyc | name.nyc.viaduct.sh |
| Singapore | sg | name.sg.viaduct.sh |
| Sydney | syd | name.syd.viaduct.sh |
$ viaduct http 8080 --region nyc # -> name.nyc.viaduct.sh
$ viaduct http 8080 --region sg # -> name.sg.viaduct.sh
List them any time with viaduct regions.
All options
Every flag on viaduct http:
| Option | Default | Description |
|---|---|---|
--server host:port | viaduct.sh:4443 | The viaductd server to dial. |
--region lon|nyc|sg|syd | none | Pick a server region; a shortcut for --server. |
--pin | off | Keep the same public URL across reconnects (stable subdomain). |
--inspect | off | Log each request: method, path, status, and time. |
--pool-size N | 40 | Idle data connections kept ready for incoming requests. |
--tls / --no-tls | on, off for localhost | TLS to the tunnel port. |
--tls-ca PATH | none | Extra CA bundle to trust (for a self-signed server). |
Flags can also live in ~/.config/viaduct/config.toml instead of the command line:
server = "viaduct.sh:4443"
tls = true
Stop and update
Stop a running tunnel with q or Ctrl+C. It drains in-flight requests before exiting.
Update to the latest release at any time:
$ viaduct upgrade
viaduct upgrade follows the stable release
channel. On an interactive terminal the client also shows a one-line
notice, at most once a day, when a newer release exists.
Run your own server
The client defaults to the hosted viaduct.sh, but the point
of viaduct is that you run your own. One Ubuntu droplet runs Caddy
(public HTTPS) and viaductd, and one script sets it all up.
Then point the client at it:
$ viaduct http 8080 --server your-domain.com:4443