Skip to content

Tailscale Subnet Router — Proxmox LXC

A dedicated unprivileged LXC container that acts as a Tailscale subnet router, advertising your home LAN (192.168.0.0/24) to your tailnet. This allows remote access to every device on the LAN — including the Proxmox host and its web UI — without installing Tailscale on the hypervisor itself.

This container is a high-value target

The subnet router is the single container that, if compromised, gives an attacker routed access to your entire home LAN over Tailscale. Treat it accordingly:

  • Keep it minimal: no extra packages, no services beyond Tailscale
  • Keep it updated: apt upgrade regularly
  • SSH key auth only, root login disabled
  • Static IP outside your DHCP pool so its address never changes unexpectedly
  • No inbound ports open from the LAN side — Tailscale initiates outbound connections only

1. Download a Container Template

In the Proxmox web UI:

  1. Click your local storageCT TemplatesTemplates
  2. Download Debian 12

2. Create the LXC

In the Proxmox web UI click Create CT:

General - CT ID: e.g. 100 - Hostname: tailscale-router - Leave Unprivileged container checked - Set a root password

Template - Select the Debian 12 template

Disks - Disk size: 2 GB

CPU - Cores: 1

Memory - Memory: 256 MB - Swap: 256 MB

Network - Bridge: vmbr0 - IPv4: Static - IPv4/CIDR: e.g. 192.168.0.2/24 (choose an IP outside your DHCP pool) - Gateway: your router IP, e.g. 192.168.0.1

DNS - Leave as-is or set to your router IP

Why a static IP?

A static IP assigned in the container itself (not a DHCP reservation) ensures the subnet router's LAN address never changes, even across reboots or DHCP server restarts. This matters because if the container's IP shifts, the Tailscale subnet advertisement still points at the old address until manually corrected.

Click Finish — do not check "Start after created" yet.


3. Add TUN Device Access (Unprivileged LXC)

On the Proxmox host shell, verify the TUN device exists:

ls -la /dev/net/tun

If it shows crw-rw-rw- you're good. If not, create it:

mkdir -p /dev/net
mknod /dev/net/tun c 10 200
chmod 0666 /dev/net/tun

Edit the LXC config (replace 100 with your CT ID):

nano /etc/pve/lxc/100.conf

Add at the bottom:

lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file

Save and exit, then start the LXC.


4. Update and Install Prerequisites

Open the LXC console in Proxmox or SSH in as root:

apt update && apt upgrade -y
apt install -y curl sudo

5. Create a Sudo User

useradd -m -s /bin/bash jake
passwd jake
usermod -aG sudo jake

Set up the SSH key directory:

mkdir -p /home/jake/.ssh
chmod 700 /home/jake/.ssh
touch /home/jake/.ssh/authorized_keys
chmod 600 /home/jake/.ssh/authorized_keys
chown -R jake:jake /home/jake/.ssh

6. Upload Your SSH Public Key

From your local machine:

ssh-copy-id jake@192.168.0.2

Or paste your public key manually:

nano /home/jake/.ssh/authorized_keys

Verify SSH access works before continuing:

ssh jake@192.168.0.2
sudo whoami  # should return: root

7. Disable Root SSH Login

Do this after confirming jake can SSH in and sudo successfully

If you lock out root before verifying key-based access works, you can end up locked out of the container entirely. Confirm in a second terminal first.

sudo nano /etc/ssh/sshd_config

Find or add (use Ctrl+W to search):

PermitRootLogin no

Restart SSH:

sudo systemctl restart sshd

Disabling root login means an attacker who obtains the root password (e.g. from the Proxmox console) still can't SSH in remotely. Combined with key-only auth (PasswordAuthentication no is also worth adding), SSH access requires possession of your private key.


8. Install Tailscale

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

Enable IP forwarding — required for the container to route packets on behalf of tailnet clients:

echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.d/99-tailscale.conf
sysctl -p /etc/sysctl.d/99-tailscale.conf

9. Start Tailscale as Subnet Router

sudo tailscale up --operator=jake --advertise-routes=192.168.0.0/24 --accept-dns=false

Replace 192.168.0.0/24 with your actual LAN subnet if different.

--operator=jake allows jake to run tailscale CLI commands without sudo. The tailscaled daemon itself still runs as root.

--accept-dns=false prevents Tailscale from overriding the container's DNS with MagicDNS — this container doesn't need MagicDNS and accepting it can interfere with its role as a router.

This will print an authentication URL — open it in a browser to authorize the machine in your Tailscale account.


10. Approve the Subnet Route

In the Tailscale admin console at login.tailscale.com/admin/machines:

  1. Find tailscale-router
  2. Click the three-dot menuEdit route settings
  3. Enable 192.168.0.0/24

Why manual approval?

Tailscale requires an admin to explicitly approve advertised subnet routes in the console. This is a deliberate security control — a compromised node can't unilaterally gain routed access to your network just by advertising a route.


11. Test Remote Access

From a device on an external network with Tailscale running:

Ping the Proxmox host:

ping 192.168.0.x  # your Proxmox host's LAN IP

Open the Proxmox web UI:

https://192.168.0.x:8006

If both work, your subnet router is functioning correctly and your full home LAN is accessible over Tailscale.


Notes

  • Proxmox host static IP: The Proxmox host has a static IP set at the OS level (/etc/network/interfaces) — it is not a DHCP client, which is why it doesn't appear in your router's DHCP reservation list. This is fine and more reliable than a DHCP reservation.

  • Routing conflict: If a remote network you connect from also uses 192.168.0.x, there will be a routing conflict and LAN access over the subnet router will break silently. In that case, consider also installing Tailscale on the Proxmox host itself so you can reach it via its stable 100.x.x.x Tailscale IP regardless of the remote network.

  • Scope creep: Resist the temptation to run additional services on this container. Its sole job is to route traffic — every additional package or service is an additional attack surface on the container that has LAN-wide reach.