Setup Tailscale site-to-site VPN with multiple exit nodes for redundancy

Intermediate 45 min Apr 29, 2026 129 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Configure a resilient Tailscale mesh VPN with multiple exit nodes for high availability site-to-site connectivity. Set up subnet routing, automatic failover, and monitoring across distributed networks.

Prerequisites

  • Multiple Linux servers with root access
  • Tailscale account
  • Public IP addresses on exit nodes
  • Basic understanding of networking concepts

What this solves

Tailscale site-to-site VPN with multiple exit nodes provides redundant connectivity between different network segments without single points of failure. This setup automatically routes traffic through available exit nodes when primary connections fail, ensuring continuous network access for distributed teams and infrastructure.

Step-by-step configuration

Install Tailscale on all nodes

Install Tailscale on every server that will participate in the mesh network. We'll install on at least 3 nodes for proper redundancy.

curl -fsSL https://tailscale.com/install.sh | sh
curl -fsSL https://tailscale.com/install.sh | sh

Configure IP forwarding on exit nodes

Enable IP forwarding on servers that will act as exit nodes to route traffic between network segments.

echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Authenticate and start Tailscale on primary exit node

Connect the first exit node and advertise subnet routes. This node will handle traffic for the local network segment.

sudo tailscale up --advertise-routes=192.168.1.0/24 --advertise-exit-node --hostname=exit-node-1
Note: Replace 192.168.1.0/24 with your actual network subnet. The command will display an authentication URL to complete setup.

Configure secondary exit node

Set up the second exit node on a different network segment or geographic location for redundancy.

sudo tailscale up --advertise-routes=192.168.2.0/24 --advertise-exit-node --hostname=exit-node-2

Add tertiary exit node

Configure a third exit node to provide additional redundancy and load distribution.

sudo tailscale up --advertise-routes=192.168.3.0/24 --advertise-exit-node --hostname=exit-node-3

Configure client nodes

Connect client machines that will use the exit nodes for network access.

sudo tailscale up --hostname=client-node-1

Enable subnet routes in Tailscale admin

Approve advertised routes and exit nodes through the Tailscale admin console at https://login.tailscale.com/admin/machines.

tailscale status
tailscale ip -4
Note: You must manually approve subnet routes and exit node advertisements in the web console before they become active.

Configure route priorities

Set route priorities to control traffic flow and failover behavior using Tailscale ACL policies.

{
  "acls": [
    {
      "action": "accept",
      "src": ["*"],
      "dst": [":"]
    }
  ],
  "autoApprovers": {
    "routes": {
      "192.168.1.0/24": ["exit-node-1"],
      "192.168.2.0/24": ["exit-node-2"],
      "192.168.3.0/24": ["exit-node-3"]
    },
    "exitNode": ["exit-node-1", "exit-node-2", "exit-node-3"]
  }
}

Configure automatic failover

Create a health check script that monitors exit node availability and switches routes automatically.

#!/bin/bash

PRIMARY_EXIT="100.64.1.10"
SECONDARY_EXIT="100.64.1.11"
TERTIARY_EXIT="100.64.1.12"

check_exit_node() {
    local exit_ip="$1"
    ping -c 3 -W 5 "$exit_ip" > /dev/null 2>&1
    return $?
}

switch_exit_node() {
    local new_exit="$1"
    sudo tailscale set --exit-node="$new_exit"
    logger "Tailscale: Switched to exit node $new_exit"
}

if check_exit_node "$PRIMARY_EXIT"; then
    switch_exit_node "$PRIMARY_EXIT"
elif check_exit_node "$SECONDARY_EXIT"; then
    switch_exit_node "$SECONDARY_EXIT"
elif check_exit_node "$TERTIARY_EXIT"; then
    switch_exit_node "$TERTIARY_EXIT"
else
    logger "Tailscale: All exit nodes unreachable"
fi

Make failover script executable

Set proper permissions and create a systemd timer for automated failover checks.

sudo chmod +x /usr/local/bin/tailscale-failover.sh
sudo chown root:root /usr/local/bin/tailscale-failover.sh

Create systemd service for failover

Configure systemd to run the failover script as a service.

[Unit]
Description=Tailscale Exit Node Failover
After=tailscaled.service
Requires=tailscaled.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/tailscale-failover.sh
User=root

[Install]
WantedBy=multi-user.target

Create systemd timer for periodic checks

Set up automatic failover checks every 30 seconds to ensure rapid detection of node failures.

[Unit]
Description=Run Tailscale failover check every 30 seconds
Requires=tailscale-failover.service

[Timer]
OnBootSec=30
OnUnitActiveSec=30
Unit=tailscale-failover.service

[Install]
WantedBy=timers.target

Enable failover monitoring

Start and enable the failover timer to begin automatic monitoring and switching.

sudo systemctl daemon-reload
sudo systemctl enable --now tailscale-failover.timer
sudo systemctl status tailscale-failover.timer

Configure monitoring alerts

Set up monitoring to track exit node health and failover events using system logs.

# Log Tailscale events to separate file
if $programname == 'tailscale-failover' then /var/log/tailscale-failover.log
& stop
sudo systemctl restart rsyslog

Test failover functionality

Verify that failover works by stopping one exit node and checking if traffic switches automatically.

sudo tailscale status
sudo systemctl stop tailscaled  # On primary exit node
tail -f /var/log/tailscale-failover.log  # On client

Configure advanced routing policies

Set up load balancing

Configure multiple exit nodes to share traffic load using Tailscale's built-in load balancing features.

tailscale set --exit-node-allow-lan-access=true
tailscale set --shields-up=false

Configure subnet-specific routing

Route different subnets through specific exit nodes based on geographic or performance requirements.

#!/bin/bash

Route management subnet through primary exit

sudo ip route add 10.0.1.0/24 via 100.64.1.10

Route production subnet through secondary exit

sudo ip route add 10.0.2.0/24 via 100.64.1.11

Route development subnet through tertiary exit

sudo ip route add 10.0.3.0/24 via 100.64.1.12

Verify your setup

Check that your Tailscale mesh network is functioning correctly with multiple exit nodes.

tailscale status
tailscale netcheck
ping 100.64.1.10
ping 100.64.1.11
ping 100.64.1.12
sudo systemctl status tailscale-failover.timer
journalctl -u tailscale-failover.service -f

Monitor your mesh network

Set up comprehensive monitoring for your Tailscale deployment to track performance and availability. You can integrate with existing monitoring solutions like the Tailscale monitoring with Prometheus and Grafana setup for detailed metrics and alerting.

Create health check endpoint

Set up a simple HTTP endpoint to monitor exit node health externally.

#!/usr/bin/env python3
import subprocess
import json
from http.server import HTTPServer, BaseHTTPRequestHandler

class HealthHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        try:
            result = subprocess.run(['tailscale', 'status', '--json'], 
                                  capture_output=True, text=True)
            status = json.loads(result.stdout)
            
            if status.get('BackendState') == 'Running':
                self.send_response(200)
                self.end_headers()
                self.wfile.write(b'Tailscale healthy')
            else:
                self.send_response(503)
                self.end_headers()
                self.wfile.write(b'Tailscale unhealthy')
        except Exception as e:
            self.send_response(500)
            self.end_headers()
            self.wfile.write(f'Error: {str(e)}'.encode())

httpd = HTTPServer(('0.0.0.0', 8080), HealthHandler)
httpd.serve_forever()

Common issues

Symptom Cause Fix
Subnet routes not working Routes not approved in admin console Approve routes at https://login.tailscale.com/admin/machines
Exit node not accessible IP forwarding disabled sudo sysctl -w net.ipv4.ip_forward=1
Failover not triggering Timer service not running sudo systemctl start tailscale-failover.timer
High latency between sites Suboptimal exit node selection Manually set preferred exit node: tailscale set --exit-node=NODE_IP
Authentication failures Expired auth tokens sudo tailscale login to re-authenticate
DNS resolution issues Split DNS not configured tailscale set --accept-dns=true

Security considerations

Implement additional security measures for production Tailscale deployments to protect your mesh network.

Security reminder: Regularly rotate Tailscale auth keys and review access controls. Enable MFA for your Tailscale account and use ACL policies to restrict access between network segments.

Configure ACL policies

Implement network segmentation using Tailscale ACL policies to control traffic flow between different network zones.

{
  "groups": {
    "group:admins": ["user1@example.com"],
    "group:developers": ["user2@example.com", "user3@example.com"],
    "group:servers": ["tag:server"]
  },
  "acls": [
    {
      "action": "accept",
      "src": ["group:admins"],
      "dst": [":"]
    },
    {
      "action": "accept",
      "src": ["group:developers"],
      "dst": ["tag:server:22,80,443"]
    }
  ]
}

Next steps

Running this in production?

Need this managed? Setting up Tailscale once is straightforward. Keeping it patched, monitored, backed up and tuned across environments is the harder part. See how we run infrastructure like this for European SaaS and e-commerce teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle private cloud infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.