Tailscale Integration

Tailscale gives you a private network without port forwarding, VPN gateways, or firewall rules. Every device on your tailnet can reach every other device by name, with encrypted WireGuard tunnels negotiated automatically.

Elide has deep Tailscale integration. You can bind to your Tailscale IP, get a Tailscale-issued TLS certificate, expose your server to the public internet via Funnel, authenticate requests by Tailscale identity, or run as a standalone Tailscale node with no daemon installed. This is not a bolt-on -- Tailscale networking is a first-class path through the runtime.

Quick start

The simplest path: serve your app on your tailnet with automatic TLS.

bash
 elide orb --config server.pkl --tailscale

Elide detects your node's Tailscale IP and DNS name, provisions a TLS certificate from the Tailscale CA, binds to port 443 on the Tailscale IP, and registers MagicDNS for all tailnet peers. The output tells you where to find it:

Serving on https://my-laptop.tail1234.ts.net (tailnet IP 100.64.0.42)
MagicDNS registered: 5 peers in tailnet 'tail1234.ts.net'

Any device on your tailnet can now reach your server at https://my-laptop.tail1234.ts.net with a browser-trusted certificate. No certificate setup, no DNS configuration, no firewall changes.

Daemon mode vs. standalone mode

Elide supports two fundamentally different ways of connecting to a Tailscale network. Understanding when to use each one will save you time.

Daemon mode (--tailscale)

Daemon mode talks to the local tailscaled daemon over its Unix domain socket. This is the mode you want when Tailscale is already installed on the machine. It gives you the full feature set: browser-trusted TLS certificates from the Tailscale CA, Funnel for public exposure, and whois-based identity authentication.

Prerequisites: tailscaled running, machine enrolled in a tailnet (tailscale up).
bash
 elide orb --config server.pkl --tailscale

Standalone mode (--tailscale-direct)

Standalone mode embeds the TS2021 control plane client directly in the Elide binary. No daemon, no sidecar, no system-wide installation. Elide authenticates with a pre-auth key, polls the network map, discovers peers, registers MagicDNS entries, and spawns a userspace WireGuard data plane via boringtun.

Prerequisites: A pre-auth key from the Tailscale admin console. Nothing else.
bash
 elide orb --config server.pkl --tailscale-direct --tailscale-auth-key tskey-auth-...

When to use which

FeatureDaemon modeStandalone mode
Tailscale IP assignmentYesYes
MagicDNS for peer namesYesYes
Network map pollingYesYes
WireGuard data planeKernelUserspace (boringtun)
DISCO peer discovery + STUNVia tailscaledBuilt-in
Browser-trusted TLS (Tailscale CA)YesNo (use —self-signed or —auto-tls)
Tailscale FunnelYesNo
Whois peer identificationYesNot yet
TUN device (system-wide tunnel)N/AYes (elide tun up or orb —tun)
ACL packet filteringHandled by tailscaledParsed from netmap (not yet applied)
Use daemon mode when Tailscale is installed and you want the full feature set -- especially Funnel and trusted TLS certificates. Use standalone mode for containers, serverless, edge deployments, CI/CD, or any environment where installing a daemon is impractical. A single binary joins the tailnet with just a pre-auth key.

Generating a pre-auth key

Create one in the Tailscale admin console or via the API:

bash
# Reusable, ephemeral, tagged key (recommended for automation)
 tailscale api keys create --reusable --ephemeral --tags tag:elide-server

Pass it via --tailscale-auth-key (on orb) or --auth-key (on tun up), or set the TAILSCALE_AUTH_KEY environment variable.

Tailscale Funnel

Funnel exposes your server to the entire internet -- not just your tailnet -- through Tailscale's relay infrastructure. Anyone with the URL can reach your server at https://your-node.tail1234.ts.net.

bash
 elide orb --config server.pkl --funnel

The --funnel flag implies --tailscale. When Funnel is active, Elide configures the Tailscale serve config via the local API to route incoming HTTPS traffic to the local server. The configuration is cleaned up automatically on shutdown.

Funnel requires that your Tailscale ACL policy allows Funnel for the node. See the Tailscale Funnel docs for ACL setup. Funnel is only available in daemon mode.

When Funnel is active, whois identity authentication is disabled -- public internet traffic does not carry Tailscale identity.

MagicDNS

When any Tailscale mode is active, Elide builds a DNS resolver from the Tailscale peer table and registers it as the process-wide resolver. All DNS lookups within Elide -- HTTP client requests, TLS connections, STUN, DERP -- can resolve tailnet names without going through getaddrinfo or system DNS.

The resolution order is straightforward:

1. If the hostname matches a known tailnet peer (e.g., other-node.tail1234.ts.net), resolve it directly from the cached peer table. 2. Otherwise, fall back to system DNS. 3. IP literals bypass DNS entirely.

The resolver is thread-safe and registered once at startup. In standalone mode, the peer table refreshes on every network map poll (background thread), so new peers appear within seconds of joining the tailnet.

TLS certificates

How Elide handles TLS depends on the Tailscale mode:

Daemon mode provisions browser-trusted certificates from the Tailscale CA (backed by Let's Encrypt). These work in every browser and every HTTP client with no extra configuration. This is the zero-friction path to real HTTPS on your tailnet. Standalone mode cannot obtain certificates from the Tailscale CA. Use --self-signed to generate an ephemeral TLS certificate for the tailnet domain:
bash
 elide orb --config server.pkl --tailscale-direct --tailscale-auth-key tskey-auth-...

The self-signed cert uses ECDSA P-256 with 365-day validity, includes the tailnet domain and all Tailscale IPs as Subject Alternative Names, and is cached to disk (regenerated when older than 30 days). It will trigger browser warnings but is fine for development and internal services.

Identity-based authentication

Daemon mode includes a whois authentication middleware that identifies the user and device behind every incoming request. For each request from a Tailscale IP, Elide resolves:
FieldDescriptionExample
login_nameThe user's login (typically an email)alice@example.com
display_nameHuman-readable nameAlice
node_hostnameShort hostname of the originating devicealice-laptop
node_dns_nameFully-qualified tailnet DNS namealice-laptop.tail1234.ts.net
tagsACL tags applied to the originating node["tag:server", "tag:prod"]
osOperating system of the originating nodelinux
user_idNumeric user ID (if available)123
Whois lookups are cached per source IP with a 60-second TTL. Identity headers are injected into each request when inject_headers is enabled (the default for --tailscale).

Access control policies

Elide supports per-route access control policies evaluated against the resolved Tailscale identity. Policies use a deny-first model:

1. All deny rules are checked first. If any deny rule matches, the request is rejected. 2. If no deny rule matches, the first matching allow rule grants access. 3. If no rules match at all, the request is denied (closed by default).
RuleDescription
AllowAllUnconditionally allow all authenticated tailnet users
DenyAllUnconditionally deny
AllowUsers(["alice@example.com"])Allow specific users by login name
DenyUsers(["blocked@example.com"])Deny specific users by login name
AllowTags(["tag:web"])Allow nodes carrying specific ACL tags
DenyTags(["tag:quarantine"])Deny nodes carrying specific ACL tags
Deny rules always take precedence. A policy with both AllowAll and DenyTags(["tag:quarantine"]) will allow everyone except quarantined nodes. Tag matching is exact -- tag:web-staging does not match tag:web.

DERP relay

DERP (Designated Encrypted Relay for Packets) relays traffic when direct peer-to-peer WireGuard connections are not possible due to NAT. Elide can run a DERP relay in two ways.

Alongside your server:
bash
 elide orb --config server.pkl --derp
 elide orb --config server.pkl --derp --derp-port 4000

The relay runs independently of the HTTP server. Default port is 3340.

As a standalone relay:
bash
 elide tun derp
 elide tun derp --port 4000 --host 0.0.0.0
 elide tun derp --mesh-with relay2.example.com,relay3.example.com
 elide tun derp --tls-cert /path/to/cert.pem --tls-key /path/to/key.pem

The standalone relay supports multi-region mesh, TLS, and STUN.

WireGuard tunnel (elide tun)

The tun command provides system-wide WireGuard tunneling. This creates a real TUN device and routes traffic through the tailnet.

elide tun requires root or CAP_NET_ADMIN for TUN device creation. Linux and macOS only.

Bringing up a tunnel

bash
 elide tun up --auth-key tskey-auth-...

This authenticates with Tailscale, fetches the network map, installs MagicDNS, creates a TUN device (elide0 by default), adds routes for all peer AllowedIPs, spawns the WireGuard data plane, starts background control polling, and blocks until SIGINT/SIGTERM.

Exit node support:
bash
# Advertise this node as an exit node
 elide tun up --auth-key tskey-auth-... --exit -node

# Route all traffic through a specific peer
 elide tun up --auth-key tskey-auth-... --use-exit -node alice-laptop
Subnet routing:
bash
 elide tun up --auth-key tskey-auth-... --advertise-routes 10.0.0.0/24,192.168.1.0/24 --accept-routes

Checking tunnel status

bash
 elide tun status
 elide tun status --peers --routes
 elide tun status --json

CLI reference

Flags on elide serve

FlagDefaultDescription
—tailscalefalseBind to Tailscale IP, provision TLS, register MagicDNS. Requires tailscaled.
—funnelfalseExpose via Tailscale Funnel. Implies —tailscale.
—tailscale-directfalseStandalone Tailscale node (no daemon). Requires —tailscale-auth-key.
—tailscale-auth-key nonePre-auth key for standalone mode. Also reads TAILSCALE_AUTH_KEY env var.
—self-signedfalseGenerate self-signed TLS for the tailnet domain. ECDSA P-256, 365-day validity, cached.
—derpfalseStart a DERP relay alongside the HTTP server.
—derp-port 3340Port for the DERP relay.

Flags on elide orb

FlagDefaultDescription
—tailscalefalseBind to Tailscale IP, provision TLS, enable identity auth. Unix only.
—funnelfalseExpose via Funnel. Unix only. Disables whois auth.
—tailscale-directfalseStandalone Tailscale node. Requires —tailscale-auth-key.
—tailscale-auth-key nonePre-auth key for standalone mode.
—tunfalseCreate a TUN device for system-wide routing (with —tailscale-direct).
—derpfalseStart a DERP relay alongside the server.
—derp-port 3340DERP relay port.

Flags on elide tun up

FlagDefaultDescription
—auth-key requiredPre-authentication key for Tailscale.
—control-url Tailscale productionCustom control server URL.
—dev elide0TUN device name.
—mtu 1280MTU for the TUN interface.
—accept-routesfalseAccept subnet routes from peers.
—exit-nodefalseAdvertise as exit node.
—use-exit-node noneRoute all traffic through a specific peer.
—advertise-routes noneAdvertise subnets (comma-separated CIDRs).
—self-signedfalseGenerate self-signed TLS certificate.
—serve noneAlso start an HTTP server on the tunnel.
—jsonfalseOutput in JSON format.

Troubleshooting

"Cannot connect to tailscaled"

Daemon mode requires the tailscaled daemon to be running. Verify with:

bash
 tailscale status

If it is not running, start it (sudo tailscaled or via your init system) and ensure the machine is enrolled (tailscale up).

On macOS, if you installed Tailscale from the App Store, the daemon runs as part of the app. Make sure the Tailscale app is open.

"Pre-auth key rejected" in standalone mode

Pre-auth keys expire. Check the key's status in the Tailscale admin console. If the key is single-use and was already consumed, create a new one. For automation, use reusable ephemeral keys.

Funnel not working

Funnel requires explicit ACL policy approval. In your Tailscale ACL policy, ensure the node (or its tags) is allowed to use Funnel. See the Tailscale Funnel docs for the exact ACL syntax.

Also confirm you are in daemon mode. Funnel is not available in standalone mode.

Self-signed certificate warnings

Expected behavior in standalone mode. The self-signed cert is valid and encrypted, but not issued by a trusted CA. For browser access, click through the warning. For programmatic access, pass your HTTP client's equivalent of --insecure or add the cert to your trust store.

If you need trusted certificates, use daemon mode -- the Tailscale CA issues Let's Encrypt-backed certs automatically.

MagicDNS names not resolving

MagicDNS is registered at Elide startup. If a peer joined the tailnet after Elide started, the name may not be in the resolver yet. In standalone mode, the peer table refreshes on every map poll (roughly every 30 seconds). In daemon mode, the peer table comes from tailscaled and updates are immediate.

If names still do not resolve, check that MagicDNS is enabled in your Tailscale admin console DNS settings.

---

Examples

Serve on your tailnet (daemon)

bash
 elide orb --config server.pkl --tailscale

Expose to the public internet via Funnel

bash
 elide orb --config server.pkl --funnel

Standalone node with self-signed TLS

bash
 elide orb --config server.pkl --tailscale-direct --tailscale-auth-key tskey-auth-... --self-signed

Standalone node in a container

dockerfile
FROM ghcr.io/elide-dev/elide:latest
COPY ./dist /app
CMD ["elide", "orb", "--config", "/app/server.pkl", "--tailscale-direct", "--tailscale-auth-key", "${TAILSCALE_AUTH_KEY}", "--no-tui"]

System-wide WireGuard tunnel

bash
 elide tun up --auth-key tskey-auth-... --accept-routes

Tailnet server with DERP relay

bash
 elide orb --config server.pkl --tailscale --derp

Standalone DERP relay

bash
 elide tun derp --port 4000 --host 0.0.0.0

---

See also

  • elide serve -- Full HTTP server documentation: TLS, static files, reverse proxy, middleware
  • CLI Reference -- Complete reference for all Elide commands and global options