Tunnels
Expose a database, RDP, SMB, or any TCP service on a fixed 127.0.0.1 port routed through one profile — configured once in the app and kept alive for you.
View as MarkdownWhat a tunnel is#
A tunnel is a stable loopback endpoint — 127.0.0.1:<port> — that relays a TCP service through exactly one profile. You point your client (a database GUI, psql, an RDP or SMB client) at the loopback address once, and TailMux keeps the tunnel alive whenever the owning profile is up. It is the same idea as an SSH port-forward, but managed for you and bound to a single tailnet — a tunnel never falls back to another profile.
Define tunnels in the app under Open → Tunnels, or see them at a glance in the menu bar with a start/stop switch. Each tunnel belongs to a profile and comes in one of two modes.
Native tunnels#
A native tunnel relays TCP straight through the profile's node. Use it for anything the profile can already reach: a tailnet host, a machine behind a subnet router, or a service behind a Tailscale app connector. No SSH, no credentials.
Set the target to the service's host:port, for example a Postgres database:
1Profile: work2Target: db.internal.example:54323Endpoint: 127.0.0.1:15432 (assigned for you)Then point the client at the endpoint:
$psql "postgresql://app@127.0.0.1:15432/appdb"SSH-bastion tunnels#
Some services are reachable only from inside a remote network — for example a database that only a jump host can see. An SSH tunnel forwards through a bastion: TailMux runs a background ssh -L whose transport to the bastion is itself routed through the profile, and the forward to the target happens on the bastion.
Set the bastion (a tailnet node of the profile), the SSH user, and how to authenticate:
- SSH agent — uses your running agent and default identities. Nothing is stored.
- Private key — pick a key from
~/.ssh(or browse for one). - Password — stored in your macOS Keychain and provided to
sshin the background. It is never written to the config file.
1Profile: work2Target: db.internal.example:5432 (resolved on the bastion)3Bastion: bastion.example.ts.net4User: deploy5Auth: Private keyThe local endpoint#
The endpoint is the 127.0.0.1 address your client connects to. Leave it blank and TailMux assigns a fixed free port from the tunnel base (default 43300, configurable under Settings → Profile defaults). The port is stable across restarts, so you configure your client once. Copy it from the tunnel row with one click.
Managing tunnels#
- Tunnels start automatically when their profile is running and are shown live in the menu bar with their state and active-connection count.
- The menu-bar switch (or the Tunnels page) starts and stops a tunnel; a stopped tunnel stays stopped across restarts.
- Editing a tunnel applies immediately — no router restart, unlike routing changes. If the background
sshcan't connect, the tunnel shows an error you can hover for the reason.
Prerequisites#
A tunnel can only reach what its profile can resolve and reach. Two setup steps come up often:
Notes#
- A tunnel is bound to one profile and never bridges to another — the same isolation guarantee as the rest of TailMux.
- Native tunnels suit anything the profile can dial; SSH tunnels are the fallback for targets reachable only through a jump host.
- For an interactive SSH session to a server, use tailmux ssh; use a tunnel to expose a long-running service on a local port.