Skip to main content

Setup Split DNS and Reverse Proxy for Tailscale

·3 mins

Tailscale is super easy to use and configure. It’s based on WireGuard. You can read about it here.

By default, all devices inside your tailnet will receive a domain name via MagicDNS. Here’s my list of active machines:

MacBook-Pro:~ kavish$ tailscale status --peers
100.124.220.115 macbook              kavishgr@    macOS   -
100.79.20.48    ubuntu               kavishgr@    linux   -

Only devices on which tailscale is installed, will receive DNS. To be able to access devices on which tailscale can’t be installed(or you don’t want to for some reason), you need to deploy a subnet router. You can read about subnet routers here.

Connect as a Subnet Router #

I’ll be using a Ubuntu machine as a tailscale subnet router. It will route traffics to my docker containers on the 192.168.200.0/24 subnet(custom bridge docker network).

Connecting ubuntu to Tailscale as a subnet router and advertising the route:

sudo tailscale up --advertise-routes=192.168.200.0/24 --auth-key="file:tskey" --accept-routes

I have saved my authentication key in a file called 'tskey' for non-interactive login authentication. On a minimal server, logging in via a browser is not possible. This is also the authentication method you will use inside containers if you want them to be part of your tailnet as active machines, although I personally would not recommend it. A subnet router is the preferred method in this case, unless you’ll short lived container.

Enable IP Forwarding #

Enable IP Forwarding:

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

The route should be ready to be enabled my now. Go to the Tailscale admin console in your browser, click on the machine acting as a subnet router and approve the route.

All your tailscale devices will automatically pick up the route except Linux Clients. Re-authenticate your Linux devices with the --accept-routes flag to discover your new route. The flag was also executed for subnet machine above. It’s required for all tailscale Linux Clients.

There’s also an autoApprovers ACL to allow users to enable a subnet route on the CLI without enabling it in the browser console. I’m not really sure if Linux clients will accept it by default though. I haven’t tried it yet.

Setup Split DNS and Reverse Proxy #

Next I’ll be setting up AdGuard as my split DNS server for *.home.local domains, and Nginx Reverse Proxy Manager(NPM) as my reverse proxy in Docker Compose:

version: '3.9'
services:
  tsapache:
    image: httpd:alpine3.16  
    volumes:
      - ./tsapache:/usr/local/apache2/htdocs
    networks:
      tailscale:
        ipv4_address: 192.168.200.5
  tsnginx:
    image: nginx:stable-alpine
    volumes:
      - ./tsnginx:/usr/share/nginx/html
    networks:
      tailscale:
        ipv4_address: 192.168.200.4
  nginx-proxy-manager:
    image: jc21/nginx-proxy-manager
    volumes:
      - ./nginx-proxy-manager/data:/data
    networks:
      tailscale:
        ipv4_address: 192.168.200.3
  adguardhome:
    image: adguard/adguardhome
    volumes:
      - ./adguard/work:/opt/adguardhome/work
      - ./adguard/conf:/opt/adguardhome/conf
    networks:
      tailscale:
        ipv4_address: 192.168.200.2

networks:
  tailscale:
    external: true

Browse to 192.168.200.2(AdGuard) and write a DNS rule that will point all *.home.local domains to 192.168.200.3(NPM). tsapache and tsnginx are dummy web servers.

Add NPM host rules #

In NPM, I wrote 4 Proxy Hosts rules:

adguard.home.local -> http://192.168.200.2:80
apacheweb.home.local -> http://192.168.200.5:80
nginxweb.home.local -> http://192.168.200.4:80
nginxproxy.home.local -> http://192.168.200.3:81

In Tailscale’s admin console, go the DNS page, and add the IP of Adguard 192.168.200.2 as split DNS for home.local(without the wildcard '*').

Access my containers via DNS #

Now I can access my containers via DNS:

MacBook-Pro:~ kavish$ curl apacheweb.home.local
<h1>TSAPACHE</h1>
MacBook-Pro:~ kavish$ 
MacBook-Pro:~ kavish$ curl nginxweb.home.local
<h1>TSNGINX</h1>

To access Adguard and NPM, I can simply browse to adguard.home.local or nginxproxy.home.local. That’s pretty cool. Tailscale took care of everything. I didn’t have to modify my firewall or network ports.

"Start children off on the way they should go, and even when they are old they will not turn from it." - Proverbs 22:6