Tailscale Funnel for personal-domain HTTPS without opening ports on your router

You want to share a thing on your home server with someone outside your house. Maybe you wrote a small status page, or you want a friend to grab a file, or you’re showing a client a Caddy-served Astro preview. The traditional answer is “set up port forwarding on your router, get a Let’s Encrypt cert, configure dynamic DNS,” which sounds simple until you realise your ISP gave you CGNAT (no public IP at all), or your router is a black box you don’t fully control, or you just don’t want a hole in your firewall.

Tailscale Funnel solves this. It exposes a service on your machine to the public internet via Tailscale’s edge network — no router config, no port forwarding, no public IP requirement. The traffic goes out from your machine to Tailscale’s edge, which then accepts inbound HTTPS from the world and tunnels it back. Real TLS cert. Real public hostname (a subdomain of your tailnet). Free for personal use.

What Funnel actually is

Tailscale’s standard product is a private mesh VPN — only your tailnet devices can talk to each other. Funnel is a feature that opts a specific port on a specific node into being publicly reachable, fronted by Tailscale’s edge. The flow:

  1. You enable Funnel on a node and a port (e.g. 443).
  2. Tailscale assigns the node a public hostname like laptop-yourname.tail-scale.ts.net.
  3. Tailscale issues a real Let’s Encrypt cert for that hostname automatically.
  4. Public requests to https://laptop-yourname.tail-scale.ts.net hit Tailscale’s edge.
  5. The edge tunnels the request through your existing Tailscale connection to your node.
  6. Your local server (Caddy / nginx / whatever) handles it as if it were on localhost.

From your router’s perspective, nothing’s listening — just an outbound Tailscale connection. From the public’s perspective, you have an HTTPS endpoint with a valid cert.

Step 1 — install Tailscale + log in

# Linux
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up

# macOS — install the Mac App Store app instead and click sign in
# Windows — download the installer from tailscale.com

Sign in with Google / GitHub / Microsoft / your-own-OIDC. The node appears in your tailnet’s admin console. By default it has a 100.x.y.z private IP and is reachable only from your other tailnet devices.

Step 2 — enable Funnel on your tailnet

Funnel is opt-in at the tailnet level. In your Tailscale admin consoleDNS, enable HTTPS Certificates. Then → Access Controls, add a Funnel rule:

// in your tailnet's ACL JSON, alongside other rules:
"nodeAttrs": [
  {
    "target": ["autogroup:member"],
    "attr":   ["funnel"]
  }
]

This grants every member of your tailnet permission to expose Funnel on their nodes. (You can scope it more tightly — only specific tags or users.) Save the ACL.

Step 3 — expose a port

Suppose your laptop is running Caddy on 127.0.0.1:8080. Tailscale Funnel proxies port 443 to that local address:

# Bring up Funnel on port 443, proxy to your local 8080:
sudo tailscale funnel --bg 8080
# > Available on the internet:
# > https://laptop-yourname.tail-scale.ts.net/
# > |-- proxy http://127.0.0.1:8080

# Show all current Funnels:
tailscale funnel status

# Take it down:
sudo tailscale funnel --bg --https=443 off

The cert provisioning is automatic and finishes in ~30 seconds the first time. Curl it from anywhere:

curl -i https://laptop-yourname.tail-scale.ts.net/
# HTTP/2 200
# server: Caddy
# ...your content...

Using your own domain

The default Funnel hostname is <node>.<tailnet>.ts.net, which is fine for tools but not great for sharing with non-technical people. To use your own domain (e.g. preview.example.com), front Funnel with Caddy and a CNAME:

  1. At your DNS provider, create a CNAME: preview.example.com → laptop-yourname.tail-scale.ts.net.
  2. In your local Caddyfile, accept both hostnames so the request matches whichever Host header arrives:
# /etc/caddy/Caddyfile
preview.example.com, laptop-yourname.tail-scale.ts.net {
    reverse_proxy 127.0.0.1:3000   # your real app
}

The Tailscale-issued cert covers the .ts.net hostname; Caddy issues its own Let’s Encrypt cert (via the standard HTTP-01 challenge over the Funnel) for preview.example.com. Now visitors hitting either URL get clean HTTPS.

When Funnel is the right choice (and when it isn’t)

  • Right choice: sharing a personal site, demoing a project, hosting a small status page or webhook receiver, exposing a Plex Web UI behind real TLS for a friend, exposing your home Vaultwarden so the iOS app can sync from outside, anything with light-to-moderate traffic.
  • Wrong choice: a high-traffic public website. Tailscale’s free tier has bandwidth limits (~1 GB/month per node on the free plan in 2026). Above that you’d need to pay or offload to a normal host.
  • Wrong choice: anything you want to keep private. Funnel makes the port public; the auth layer is whatever your app provides. If your service has no auth, putting Funnel in front of it puts it on the public internet for anyone with the URL.
  • Subtle gotcha: traffic flows through Tailscale’s edge servers (typically AWS / GCP regions). You’re trusting Tailscale not to inspect your unencrypted-on-their-side data — though Funnel only sees TLS-encrypted bytes by default, so the trust ask is small.

A safer default: Serve, then Funnel only when needed

Tailscale also has tailscale serve — same shape but tailnet-only (no public access). For most personal infra, serve is the right default and you only switch to funnel for the specific port you want public:

# Tailnet-only (private to your devices):
sudo tailscale serve 8080

# Toggle to public:
sudo tailscale funnel --bg 8080

# Toggle back:
sudo tailscale funnel --bg --https=443 off
# Service is back to tailnet-only via the previous serve config.

End-state: a single command turns any local port into a public HTTPS endpoint with a real cert, no router config, works on CGNAT, switches off in one command. The cost is a free Tailscale account and ~10 minutes of setup. For sharing things from your homelab without standing up a VPS or opening firewall holes, this is the simplest answer that exists in 2026.

Photo: Wi-Fi router with neon-lit antennas by Jakub Zerdzicki on Pexels.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.