This document describes the Tailscale VPN setup between the proxy server and the client server, using Headscale as a self-hosted coordination server.
Tailscale provides a secure, encrypted mesh network between the proxy server and the client server. It uses WireGuard under the hood but abstracts away all the complexity of key management, NAT traversal, and peer configuration. Unlike a manual WireGuard setup, Tailscale requires no open inbound ports on the client server and handles connection establishment automatically.
Headscale is used as a self-hosted, open-source alternative to Tailscale's coordination server, keeping the entire infrastructure under your control.
- No manual key management: Tailscale handles key generation, rotation, and distribution automatically
- NAT traversal: Works behind any NAT without opening inbound ports on the client server
- No endpoint configuration: Peers discover each other through the coordination server
- Automatic reconnection: Handles network changes, IP changes, and temporary disconnections
- Self-hosted with Headscale: Full control over the coordination server, no dependency on Tailscale's cloud
- A Headscale instance running and accessible (e.g.,
https://hs.example.com:41824) - A user created in Headscale for node registration
curl -fsSL https://tailscale.com/install.sh | shsudo tailscale up --login-server https://hs.example.com:41824This will output a registration URL or a node key. Register the node from the Headscale server:
headscale nodes register --key <node-key> --user <username>After registration, verify that both nodes are connected:
# On the Headscale server
headscale nodes listBoth the proxy server and the client server should appear as online with their assigned Tailscale IPs (from the 100.64.0.0/10 range).
From the proxy server:
ping <client-tailscale-ip>From the client server:
ping <proxy-tailscale-ip>After registration, Headscale assigns each node an IP address from the CGNAT range. Note these IPs as they will be used in the Haraka, Caddy, and firewall configurations:
| Server | Role |
|---|---|
| Proxy server | Internet-facing mail relay |
| Client server (Mailcow) | Internal mail server |
Run tailscale ip -4 on each server to retrieve its assigned IP.
If the client server runs inside an LXC container (e.g., on Proxmox), you need to enable the TUN device for Tailscale to work:
- Add the following to the container configuration (e.g.,
/etc/pve/nodes/<node>/lxc/<id>.conf):
features: nesting=1,keyctl=1
lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file
- Restart the container for the changes to take effect.
Tailscale installs as a systemd service (tailscaled.service) and starts automatically on boot. No additional configuration is needed for persistence.
# Verify the service is enabled
sudo systemctl is-enabled tailscaled
# Check status
sudo systemctl status tailscaledYou are at Step 3 of 7 in the setup process
Now that you have configured the secure tunnel between your servers, proceed to:
Step 4: Set up Mailcow on the client server
Future steps: 5. Configure DNS records 6. Set up Haraka mail server 7. Configure Caddy web server