Get started - it's free!
Log in
© 2025

Site-to-site networking

Site-to-site networking (also known as layer 3 (L3) routing) creates a bridge between two or more distinct networks, letting devices in different subnets communicate with each other without a direct connection. You can create a site-to-site connection using Tailscale subnet routers, which lets you connect entire networks (such as different physical locations or cloud environments) together securely through your Tailscale network (known as a tailnet). Example use cases include connecting branch offices to a central office or connecting cloud environments to on-premises networks.

Using Tailscale to create a site-to-site connection is a powerful alternative to traditional methods of connecting networks, such as VPNs or multi-protocol label switching (MPLS), which often require complex configuration and management. It lets you leverage Tailscale's encrypted connections to securely connect networks without complicated configurations or management overhead.

Requirements and limitations

The subnets and subnet router devices within a tailnet must meet the following requirements for site-to-site networking to work:

  • The subnets must not have overlapping CIDR ranges.
  • The subnets must not use 4via6 subnet routing.
  • Both subnet routers must use a Linux-based operating system.

Create a site-to-site connection

Creating a site-to-site connection involves configuring a device in each subnet to act as a subnet router, approving the subnet routers from the Machines of the admin console, updating the tailnet access control policies, and configuring the devices in each subnet to use the designated subnet router for the correct routes.

Step 1: Select a subnet router

The first step is to select a device within the subnet to act as the designated subnet router. This device must use a Linux-based operating system.

Step 2: Configure the subnet router

After selecting a device in the subnet to function as the subnet router, you must configure it to act as a subnet router. Configuring the subnet router involves installing the Tailscale client, enabling IP address forwarding, starting the Tailscale client with the correct configuration options, and configuring the device's iptables settings.

IP address forwarding

If your Linux system has a /etc/sysctl.d directory, use:

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

Otherwise, use:

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 /etc/sysctl.conf

Subnet router configuration options

Configuring a device as a subnet router involves specifying the subnet routes to advertise, disabling source network address translation (SNAT), and enabling the device to accept routes. You can use the tailscale up or tailscale set CLI commands to set these configuration options.

Configuration optionCLI flagDescription
Advertise subnet routes--advertise-routes=<CIDR>The --advertise-routes flag specifies a CIDR range of the IP addresses to be exposed to the tailnet. Access to those addresses is controlled by Tailscale access control policies.
Disable source network address translation (SNAT)--snat-subnet-routes=false (Linux only)The --snat-subnet-routes=false flag disables source NAT (SNAT). By default, a device behind a subnet router sees traffic as originating from the subnet router. This reduces routing complexity but prevents traversing multiple networks. By disabling source NAT, the end device sees the IP address of the originating device as the source, which might be a Tailscale IP address or an address behind another subnet router.
Accept routes--accept-routesThe --accept-routes flag accepts the advertised routes of all other subnet routers in the tailnet.

When setting up subnet routers for high availability (HA), be careful with the --accept-routes flag. If you turn on --accept-routes for subnet routers that share the same routes in the same region, the standby router will accept its own advertised routes from the primary router.

This leads to an inefficient routing path. The standby router will send traffic for its directly connected subnet through the primary router instead. For example, if both subnet routers advertise and accept the same route, such as 192.168.1.0/24, the standby router will send all 192.168.1.0/24 traffic through the primary router, even though it is directly connected to that network.

For most HA subnet router setups, use the --advertise-routes flag alone. Avoid using --accept-routes unless you specifically need that routing behavior.

Clamp the MSS to the MTU

You should also clamp the maximum segment size (MSS) to the maximum transmission unit (MTU). You can do this using iptables. The following command updates the Tailscale network interface (tailscale0) to clamp MSS to MTU.

iptables -t mangle -A FORWARD -o tailscale0 -p tcp -m tcp \
--tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

Step 3: Approve the subnet router

After selecting and configuring the subnet router, you must approve it from the Machines page of the admin console. If you used an auto approver policy in the tailnet policy file for the device, you don't need to approve the subnet router manually.

  1. Open the Machines page of the admin console.
  2. Locate the subnet router devices by locating the Subnets badge or using the property:subnet filter.
  3. For each subnet router:
    1. Select the ellipsis icon menu > Edit route settings.
    2. Approve the device.

You might prefer to disable key expiry on your subnet routers to avoid having to periodically reauthenticate. If you are using tags, key expiry is disabled by default.

Step 4: Update tailnet access control policies

You must update the access control policies for your tailnet to allow communication between the subnets by creating access rules (grants) to permit the subnets to connect.

You can do this from the Access controls page of the admin console using either the visual editor or the JSON editor.

The following examples permit all traffic between the subnets.

JSON editor

To use the JSON editor to create access rules between the subnets, you must create two access rules: one for each direction of traffic between the subnets.

  1. Open the Access controls page of the admin console.
  2. Select the JSON editor tab to update the tailnet policy file using JSON.
  3. Locate the grants section of the policy file.
  4. Add two access rules to the grants section of the policy file: one for each direction of traffic between the subnets.

The end result should look similar to the following example, which permits all traffic between two subnets. Replace <first-subnet-CIDR> and <second-subnet-CIDR> with the actual CIDR ranges of the subnets.

{
 "grants": [
   {
     "src": [ <first-subnet-CIDR> ],
     "dst": [ <second-subnet-CIDR> ],
     "ip": ["*"]
   },
   {
     "src": [ <second-subnet-CIDR> ],
     "dst": [ <first-subnet-CIDR> ],
     "ip": ["*"]
   }
 ]
}

Visual editor

To use the visual editor to create access rules between the subnets, you must create two access rules: one for each direction of traffic between the subnets.

  1. Create an access rule to allow traffic from the first subnet to the second subnet:
    1. Open the Access controls page of the admin console.
    2. Select the Visual editor tab.
    3. Select Add rule.
    4. In the Source field, enter the CIDR range of the first subnet.
    5. In the Destination field, enter the CIDR range of the second subnet.
    6. In the Port and protocol field, select All ports and protocols.
    7. (Optional) Add a descriptive note to the access rule to help you identify it later.
    8. Select Save grant.
  2. Create an access rule to allow traffic from the second subnet to the first subnet:
    1. Open the Access controls page of the admin console.
    2. Select the Visual editor tab.
    3. Select Add rule.
    4. In the Source field, enter the CIDR range of the second subnet.
    5. In the Destination field, enter the CIDR range of the first subnet.
    6. In the Port and protocol field, select All ports and protocols.
    7. (Optional) Add a descriptive note to the access rule to help you identify it later.
    8. Select Save grant.

This creates two access rules using the grants syntax. They apply immediately as soon as you save them.

Step 5: Configure the other subnet devices

After configuring and approving the subnet router, make sure the devices in the subnet use the designated subnet router for the correct routes. The best way to configure the devices in the subnet depends on your infrastructure. For example, if the subnet devices already use the subnet router as the default gateway, you don't need to configure them because they will automatically use the subnet router for all traffic (unless a more specific route applies). If the subnet devices don't use the subnet router as the default gateway, you must configure them to use the subnet router for the correct routes.

For example, on Linux devices, you can use the ip route command. You don't need to configure the subnet devices if the subnet router you selected for the subnet is already the default gateway for the subnet.

ip route add <first-subnet-CIDR> via <first-subnet-router-IP-address>
ip route add <second-subnet-CIDR> via <second-subnet-router-IP-address>

The ip route commands do not persist after rebooting. You must run them again after each reboot. Depending on your setup, you can make the route settings persistent by adding them to your network manager or netplan configuration. Alternatively, you can manage route settings with a DHCP server on your network.

If the subnet is in a cloud environment, such as AWS, you can usually update the cloud provider's routing tables instead of configuring each device directly.

Example scenario

The following sections demonstrate using two subnet routers to connect two subnets within a tailnet. The following table documents the example subnets and subnet routers.

Subnet nameSubnet CIDR rangeSubnet router IP address
Subnet A192.0.2.0/24192.0.2.2 (subnet router A)
Subnet B172.16.100.0/24172.16.100.2 (subnet router A)

To create a site-to-site connection between subnet A and subnet B, follow these steps:

  1. Configure both subnet routers (subnet A at 192.0.2.2 and subnet B at 172.16.100.2):

    1. Install the Tailscale client on each subnet router.

    2. Enable IP forwarding.

    3. Configure the Tailscale client.

      For the 192.0.2.2 subnet router, use 192.0.2.0/24:

      tailscale up --advertise-routes=192.0.2.0/24 --snat-subnet-routes=false --accept-routes
      

      For the 172.16.100.2 subnet router, use 172.16.100.0/24:

      tailscale up --advertise-routes=172.16.100.0/24 --snat-subnet-routes=false --accept-routes
      

      The --snat-subnet-routes flag only works if the operating system is Linux.

    4. Configure iptables to clamp the MSS to the MTU.

  2. Approve the subnet routes.

  3. Configure the subnet devices by running the following commands on each device in the subnet (except the subnet router):

    1. For each device in the 192.0.2.0/24 subnet (except the subnet router), run the following commands:

      ip route add 100.64.0.0/10 via 192.0.2.2
      ip route add 172.16.100.0/24 via 192.0.2.2
      
    2. For each device in the 172.16.100.0/24 subnet (except the subnet router), run the following commands:

      ip route add 100.64.0.0/10 via 172.16.100.2
      ip route add 192.0.2.0/24 via 172.16.100.2
      
  4. Update the tailnet access control policies to allow communication between the subnets. In the following example, the tailnet policy file permits all traffic between the subnets using grants:

    {
       "grants": [
          {
             "src": ["100.64.0.0/10"], // CIDR range of subnet A
             "dst": ["192.0.2.0/24"], // CIDR range of subnet B
             "ip": ["*"]
          },
          {
             "src": ["192.0.2.0/24"], // CIDR range of subnet B
             "dst": ["100.64.0.0/10"], // CIDR range of subnet A
             "ip": ["*"]
          }
       ]
    }
    
  5. Test the connectivity between subnet A and subnet B:

    Now a device in subnet A can connect to a device in subnet B (and vice versa) without either needing to install the Tailscale client. You can test the connection by running the ping command from a subnet A device to a subnet B device. For example, ping 172.16.100.3 from 198.0.2.3:

    ping 172.16.100.3
    
    PING 172.16.100.3 (172.16.100.3) 56(84) bytes of data.
    64 bytes from 172.16.100.3: icmp_seq=1 ttl=64 time=9.34 ms
    64 bytes from 172.16.100.3: icmp_seq=2 ttl=64 time=3.85 ms
    

Last updated Oct 30, 2025