Homelab VPN Exit Node with Tailscale
Aug 30, 2022
4 minute read

    While at DEFCON30 this year, I used my PIA vpn subscription. A lot. It would have been great to be able to click a button and connect back to my house to gain access to some services, and also use that as a secure tunnel to the open internet. Well I think I’ve finally got a great solution going using Tailscale.

    Tailscale is a VPN service that makes the devices and applications you own accessible anywhere in the world, securely and effortlessly. It enables encrypted point-to-point connections using the open source WireGuard protocol, which means only devices on your private network can communicate with each other.

    There’s been some shifts happening in the VPN space over the last few years. Wireguard is starting to take over as the new VPN service, offering a lightweight alternative to OpenVPN and other solutions. Tailscale is a service that’s also come out recently that builds an overlay mesh network using Wireguard. Oh, and they have a Personal tier, offering 1 user and 20 devices!

    By default, Tailscale acts as a point to point mesh network, allowing you to connect from computer A to computer B. If you want to route all your traffic through computer B, then Computer B needs to be what they call an Exit Node.

    Getting this working required the following:

    1. Spin up a linux VM with tun/tap device access and ip forwarding.
    2. Run the Tailscale cli installer.
    3. Advertise a tailscale exit node
    4. Approve the exit node request in the Tailscale web interface.

    That was it! The hardest part was getting the LXC container to play nice. Not bad for less than an hours worth of work.

    VM Provisoning

    I decided to use a Linux LXC container via my Proxmox cluster as the Tailscale node. I’ve been using CTs more and more recently, and like how lightweight they are. However, this was the first time I ever had an issue with one.

    Note: LXC containers are different from containers used with Docker/podman. Reddit Homelabe: Proxmox: LXC vs Docker has a good summary.

    When I went to run tailscale up it would fail with an unnamed error code.

    tun/tap devices

    If you’re running the Tailscale node in an LXC container, be sure to RTFM. See Tailscale: Tailscale in LXC containers. If you’re setting up using a regular VM, you can probably skip this section.

    Running tailscale up resulted in an error, but the command didn’t say what the error was. I had to check out journalctl for more info.

    $ journalctl -xe
    ...
    Aug 31 03:48:32 tailscale tailscaled[1994]: logpolicy: using $STATE_DIRECTORY, "/var/lib/tailscale"
    Aug 31 03:48:32 tailscale tailscaled[1994]: wgengine.NewUserspaceEngine(tun "tailscale0") ...
    Aug 31 03:48:32 tailscale tailscaled[1994]: Linux kernel version: 5.15.39-1-pve
    Aug 31 03:48:32 tailscale tailscaled[1994]: is CONFIG_TUN enabled in your kernel? `modprobe tun` failed with: modprobe: FATAL: Module tun not found in directory /lib/modules/5.15.39-1-pve
    Aug 31 03:48:32 tailscale tailscaled[1994]: tun module not loaded nor found on disk
    Aug 31 03:48:32 tailscale tailscaled[1994]: wgengine.NewUserspaceEngine(tun "tailscale0") error: tstun.New("tailscale0"): CreateTUN("tailscale0") failed; /dev/net/tun does not exist
    Aug 31 03:48:32 tailscale tailscaled[1994]: flushing log.
    Aug 31 03:48:32 tailscale tailscaled[1994]: logger closing down
    Aug 31 03:48:32 tailscale tailscaled[1994]: createEngine: tstun.New("tailscale0"): CreateTUN("tailscale0") failed; /dev/net/tun does not exist
    Aug 31 03:48:32 tailscale systemd[1]: tailscaled.service: Main process exited, code=exited, status=1/FAILURE
    ...
    

    The line that caught my attention was: ... is CONFIG_TUN enabled in your kernel? modprobe tun failed with: modprobe: FATAL: Module tun not found in directory /lib/modules/5.15.39-1-pve.

    After googling around a bit, it turns out LXC containers do not by default have permissions to be able to setup TUN/TAP devices. These are needed by Tailscale in order to setup the Wireguard connections. Fortunately, someone on the Proxmox forums had a solution:

    How to enable tun/tap in a LXC container? | Proxmox Support Forum

    It wasn’t until writing this post that I found the doc in the Tailscale KB about this issue.

    The fix: ssh into your proxmox instance (not the container itself) and enable additional permissions for the container.

    $ ssh proxmox
    
    # edit your LXC CT config file
    $ vim /etc/pve/lxc/XXX.conf
    
    # add the following 2 lines to your file
    lxc.cgroup.devices.allow: c 10:200 rwm
    lxc.mount.entry: /dev/net dev/net none bind,create=dir
    

    Enable IP Forwarding in the tailscale container

    Since what we want is an exit node, we need to enable IP forwarding for this VM host. This is pulled straight from the tailscale exit node docs:

    $ 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
    

    Advertise as an Exit Node

    $ tailscale up --advertise-exit-node
    

    Finally, you need enable this node as an exit node via the tailscale web UI.

    That was basically it. I have the tailscale client installed on my laptops, and they’re able to connect to this machine and use it as an exit node. Pretty slick!