← Back to all explanations

Tailscale HTTPS & Serve

How to get automatic HTTPS certificates for your private services

Overview

Tailscale provides automatic HTTPS certificates for devices on your tailnet. This solves a common problem: you have a local service (like a web app on your home server) that you want to access securely, but getting TLS certificates for private IPs or local hostnames is normally impossible.

Why HTTPS matters: Many modern web APIs (like WebAuthn/passkeys, geolocation, camera access, notifications) require a "secure context" — meaning HTTPS. Without it, these features are disabled by browsers.

How It Works

The Problem

Normally, to get an HTTPS certificate you need:

This doesn't work for private services because:

Tailscale's Solution

Tailscale gives every device on your tailnet a unique DNS name under *.ts.net:

your-machine.your-tailnet.ts.net

Since Tailscale controls the ts.net domain, they can issue valid certificates for your devices through Let's Encrypt.

Your Deviceamd-miniserver
Tailscale MagicDNSamd-miniserver.tail0489.ts.net
Let's Encrypt CertificateValid HTTPS for your domain

Tailscale Serve

tailscale serve is a built-in reverse proxy that:

Basic Usage

# Serve a local HTTP app over HTTPS
sudo tailscale serve --bg https / http://localhost:3004

# Now accessible at:
# https://your-machine.your-tailnet.ts.net/

What Happens

┌─────────────────────────────────────────────────────────────────┐ │ Your Tailnet │ │ │ │ ┌──────────────┐ ┌──────────────────────────────────┐ │ │ │ │ HTTPS │ amd-miniserver │ │ │ │ iPhone │────────▶│ ┌─────────────────────────────┐ │ │ │ │ (Safari) │ │ │ tailscale serve │ │ │ │ │ │ │ │ (reverse proxy) │ │ │ │ └──────────────┘ │ │ │ │ │ │ │ │ - TLS termination │ │ │ │ ┌──────────────┐ │ │ - Certificate management │ │ │ │ │ │ HTTPS │ │ - Proxies to localhost │ │ │ │ │ MacBook │────────▶│ └──────────────┬──────────────┘ │ │ │ │ │ │ │ HTTP │ │ │ └──────────────┘ │ ▼ │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ Your App (port 3004) │ │ │ │ │ │ biodex, calorie-tracker │ │ │ │ │ └─────────────────────────────┘ │ │ │ └──────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘

The --bg Flag

The --bg flag runs the serve configuration in the background and persists it across reboots. Without it, the serve would stop when you close the terminal.

Common Commands

Command Description
tailscale serve status Show current serve configuration
tailscale serve --bg https / http://localhost:PORT Serve local app over HTTPS
tailscale serve reset Remove all serve configurations
tailscale cert DOMAIN Manually download certificate files
tailscale status Show your tailnet devices and IPs

Multiple Apps

If you have multiple apps on the same machine, you have several options:

Option 1: Path-based Routing

sudo tailscale serve --bg --https=443 /biodex http://localhost:3004
sudo tailscale serve --bg --https=443 /calories http://localhost:3000

# Access at:
# https://machine.tailnet.ts.net/biodex
# https://machine.tailnet.ts.net/calories
Caveat: Apps need to handle being served from a subpath. SvelteKit, for example, needs base configuration.

Option 2: Different Ports

sudo tailscale serve --bg --https=443 / http://localhost:3004
sudo tailscale serve --bg --https=8443 / http://localhost:3000

# Access at:
# https://machine.tailnet.ts.net/ (port 443)
# https://machine.tailnet.ts.net:8443/

Option 3: Caddy Reverse Proxy

For more complex setups, use Caddy with Tailscale certificate integration:

# /etc/caddy/Caddyfile
machine.tailnet.ts.net {
    handle /biodex/* {
        uri strip_prefix /biodex
        reverse_proxy localhost:3004
    }
    handle /calories/* {
        uri strip_prefix /calories
        reverse_proxy localhost:3000
    }

    tls {
        get_certificate tailscale
    }
}

Serve vs Funnel

Tailscale has two ways to expose services:

Feature tailscale serve tailscale funnel
Accessibility Tailnet only (private) Public internet
Who can access Only your devices Anyone with the URL
Use case Personal apps, dev servers Webhooks, sharing with others
Security Protected by Tailscale auth Exposed to internet
For personal apps: Use tailscale serve. Your services stay private and are only accessible from devices signed into your Tailscale account.

Certificate Details

Automatic Management

When using tailscale serve, certificates are managed automatically:

Manual Certificates

If you need the actual certificate files (for custom server configuration):

sudo tailscale cert your-machine.tailnet.ts.net

# Creates:
# your-machine.tailnet.ts.net.crt (certificate)
# your-machine.tailnet.ts.net.key (private key)

You can then configure your web server (nginx, Node.js, etc.) to use these files.

Why HTTPS Matters for Web Apps

Modern browsers restrict powerful APIs to "secure contexts" (HTTPS or localhost):

Feature Requires HTTPS?
WebAuthn / Passkeys Yes
Geolocation API Yes
Camera / Microphone Yes
Push Notifications Yes
Service Workers (PWA) Yes
Clipboard API Yes
Web Bluetooth Yes

This is why accessing http://amd-miniserver:3004 over plain HTTP breaks features like passkey authentication — the browser refuses to expose the WebAuthn API.

Troubleshooting

Certificate not working

# Check serve status
tailscale serve status

# Reset and try again
sudo tailscale serve reset
sudo tailscale serve --bg https / http://localhost:3004

Can't access from other device

App works on localhost but not via Tailscale