Skip to main content

Build Peronal VLAN Web Services with Tailscale, Caddy and Soft Router

· 4 min read
Ferdinand Su
PhD Student @ HIT-ICES, Founder & Manager @ HIT-ReFreSH, C# developer.

Tailscale is good enough to build a basic VLAN than connect your devices together under 100.64.0.0/10. But it's not enough for me:

  1. I have to use multiple private networks with different subnet (10.123.0.0/16, 192.168.1.0/24, etc.), and I don't want to configure every device for tailscale.
  2. I have multiple always-on devices (a cloud server, an Orange Pi,a work PC, and a home PC), where I want to deploy private services (http server, aria2, etc.)
  3. I have my own domain (namely example.com for decription), and I want to use it for HTTPS and covinence.

Introduction

My network topology is like:

![[241205-NetworkTopology.svg]] I use cloudflare to manage DNS, so I give the 100.64.0.0/10 addresses a friendly name.

Configure Tailscale

The basic installation should follow the official documentation, every always-on device should install a tailscale client. For better performance and privacy, I think private DERP server with HTTPS protected is necessary, so I deployed one for myself:

# I am using fish shell

# install Go
wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.23.4.linux-amd64.tar.gz
set -U fish_user_paths /usr/local/go/bin $fish_user_paths
go version

# install derp
go install tailscale.com/cmd/derper@latest
derper --help

Then, try to start a raw derper run by command derper -a :1212 --http-port 1212 --verify-clients --hostname=localhost. I am using force http because I will add https with caddy.

Create a systemd service for derper:

[Unit]
Description=Tailscale DERP Server
After=network.target

[Service]
ExecStart=/root/go/bin/derper -a :1212 --verify-clients
Restart=always
User=root
Group=root
LimitNOFILE=4096
Environment=DERP_LOG_LEVEL=info
WorkingDirectory=/root

[Install]
WantedBy=multi-user.target

And enable the service. Caddy configure will be updated later.

Soft Router

My orange pi is used as soft router in my tailnet.

  1. Edit sysctl.conf: set net.ipv4.ip_forward=1 and run sudo sysctl -p.
  2. Memberize your network intefaces with ifconfig > ifs.txt, I have three main interfaces:
    1. enP4p65s0 connected to 10.123.0.0/16
    2. wlx82771952b051 connected to 192.168.0.0/24
    3. tailscale0 connected to tailnet 100.64.0.0/10
  3. Configure soft routing use nftables Use these commands to configure 10.123.0.0/16 -> 192.168.0.0/24 through wlx82771952b051 to use printer
sudo nft add table ip nat
sudo nft add chain ip nat POSTROUTING { type nat hook postrouting priority 100; }
sudo nft add rule ip nat POSTROUTING ip saddr 10.123.0.0/16 ip daddr 192.168.0.0/24 oif wlx82771952b051 masquerade
sudo nft add rule ip nat POSTROUTING ip saddr 100.64.0.0/10 ip daddr 192.168.0.0/24 oif wlx82771952b051 masquerade
sudo nft add rule ip nat POSTROUTING ip saddr 100.64.0.0/10 ip daddr 10.123.0.0/16 oif enP4p65s0 masquerade
sudo nft add rule ip nat POSTROUTING ip saddr 100.64.0.0/10 ip daddr 192.168.1.0/24 oif enP4p65s0 masquerade

sudo nft add table ip filter
sudo nft add chain ip filter FORWARD { type filter hook forward priority 0; policy drop; }
sudo nft add rule ip filter FORWARD ip saddr 10.123.0.0/16 ip daddr 192.168.0.0/24 accept
sudo nft add rule ip filter FORWARD ip saddr 192.168.0.0/24 ip daddr 10.123.0.0/16 accept
sudo nft add rule ip filter FORWARD ip saddr 100.64.0.0/10 ip daddr 192.168.0.0/24 accept
sudo nft add rule ip filter FORWARD ip saddr 192.168.0.0/24 ip daddr 100.64.0.0/10 accept
sudo nft add rule ip filter FORWARD ip saddr 100.64.0.0/10 ip daddr 10.123.0.0/16 accept
sudo nft add rule ip filter FORWARD ip saddr 10.123.0.0/16 ip daddr 100.64.0.0/10 accept
sudo nft add rule ip filter FORWARD ip saddr 100.64.0.0/10 ip daddr 192.168.1.0/24 accept
sudo nft add rule ip filter FORWARD ip saddr 192.168.1.0/24 ip daddr 100.64.0.0/10 accept

sudo nft add rule ip filter FORWARD iif tailscale0 oif enP4p65s0 accept
sudo nft add rule ip filter FORWARD iif enP4p65s0 oif tailscale0 accept

sudo nft list ruleset > /etc/nftables.conf

sudo systemctl enable nftables
sudo systemctl restart nftables

Similaly configure other routes, and add them to your devices' route table, e.g., for windows (CMD):

ROUTE ADD -p 192.168.0.0 MASK 255.255.255.0 <soft-router-tail-ip>

Remeber to enable Tailscale IP forwarding according to docs here: Subnet routers · Tailscale Docs.

sudo tailscale up --advertise-routes=10.123.0.0/16,192.168.0.0/24,192.168.1.0/24 --accept-routes

Caddy

// TODO