Exposing Local Development Servers Securely with Tailscale Serve
Sometimes you need a local service reachable from another device, maybe to test something on a phone, show work-in-progress to a teammate, or run an integration test across machines. Tools like ngrok have been the go-to solution, but there’s a simpler option if you already use Tailscale: Tailscale Serve.
This post covers how I used Tailscale Serve to make a local Dockerized Rails + Ember setup available from my laptop, without editing my docker-compose.yml.
The Problem: Ports Bound to 127.0.0.1
Take this example docker-compose.yml snippet:
Both services are bound to localhost only. That means they’re accessible from the host machine, but not from your LAN or other devices on your Tailnet. Changing to 0.0.0.0:3000 would solve that, but sometimes you don’t want to (or can’t) touch your compose files.
The Tailscale Serve Solution
Tailscale Serve lets you proxy a port from your machine to the rest of your Tailnet without changing your app’s binding. Think of it as a built-in, self-hosted ngrok.
Step 1: Install and log into Tailscale
On your dev machine (e.g., Arch Linux host):
Do the same on your macOS laptop (download from tailscale.com/download).
Step 2: Serve your local services
Forward your Rails app running on localhost:3000:
| |
And your Ember app on port 4200:
| |
Step 3: Access from another device
On your Mac (or any device logged into the same tailnet):
- Use the Tailscale IP:
http://100.x.x.x:3000 - Or, if you’ve enabled MagicDNS, use the hostname:
http://archmachine.tailnet-name.ts.net:3000
That’s it: no config changes, no firewall rules, no router port forwards.
Going Further: TLS & Public Sharing
- Want HTTPS? Tailscale can terminate TLS for you:
| |
Now you can visit https://archmachine.tailnet-name.ts.net/ with a valid cert.
- Want to share outside your tailnet? Tailscale’s Funnel feature routes traffic from the public internet to your local service, with ACLs.
Why Tailscale Serve instead of ngrok?
You already use Tailscale for secure networking, so there are no extra accounts to manage. Traffic stays inside your Tailnet and end-to-end encrypted. MagicDNS gives you stable hostnames, and it works across every machine in your tailnet by default. There are no tunnels to spin up.
It’s basically an ngrok alternative that was already on your VPN.