Connection to home

TL;DR

Heading abroad, the author wanted full remote access to his home network: wake his desktop from sleep, SSH into it, and route traffic through his home internet to dodge geoblocking and VPN captchas. After weighing several options, Tailscale came out on top. The setup runs on a Raspberry Pi as both subnet router and exit node, with Wake-on-LAN wired into Apple Home via Homebridge so the desktop can be powered on (and off) from anywhere with a single tap.

During my upcoming travels and for travel in the future, there are several home network related things that I want to achieve.

I want to be able to connect to my devices at home. I never know when it could come in handy. There are so many connected devices these days. Most importantly, I want to be able to reach my desktop remotely.

I would also like to be able to use my home internet as a VPN.

Why?

My desktop is a pretty good machine. Offloading heavy work, which I might run into in my future endeavors, to another machine is a blessing. This way I can save my MacBook's battery or continue working without impacting performance. So I want an easy way to:

  • Turn on my desktop remotely
  • SSH into it
  • Turn off the machine again

Besides that, being able to use my home internet connection from abroad as a VPN is super convenient. Using a classic VPN can be nice. But it also comes with some downsides. These days lots of services have VPN blocking lists. You get hit with a lot of captchas. But most of all: some geoblocked content simply doesn't unlock with a classic VPN. But it does if you are simply using your home internet connection!

A third reason is: it's cool.

Wake-on-LAN

First, I wanted to enable Wake-on-LAN on my desktop. This way I can turn it on remotely from anywhere. To make this even more useful, I opted to add a plugin on my Homebridge, which makes it possible to control my desktop from the Apple Home app!

To start off, I needed to enable Power On By PCI-E in my BIOS. Note that this can have a different name depending on your motherboard.

Then I went to my network settings on my Budgie and configured Wake-on-LAN. No need for fancy-schmancy command line tools here.

Then it was time for the real magic: being able to control this by a simple click in my Home app!

I installed the homebridge-wol plugin in my existing Homebridge and I configured the MAC of the desktop in the Wake configuration, added a ping command to the local IP (I "hardcoded" an IP for my desktop in a range that my router that does the DHCP leaves free) and tried it out. And it worked from the first attempt. Awesome!

Weigh options for VPN and SSH

Now that I could turn my desktop on remotely, the next step would be being able to connect to it from anywhere in the world and find a solution for the VPN requirement.

I did what I usually do these days when I need to figure something out I don't know much about: I sparred with Gemini. We quickly came to a few candidates: OpenVPN or WireGuard or maybe PiVPN on my Raspberry Pi. I also checked if I could use a solution provided by Ubiquiti, since my home network uses Unifi hardware. But sadly, the latter was not possible, since it requires a Unifi Gateway, which I don't have in my current setup. As an alternative Gemini suggested Tailscale. At that point I had never heard of Tailscale before and I parked this idea for a few days to think it over.

Decision: Tailscale

Then I ended up in a conversation with a colleague who told me he uses Tailscale and we got talking about what I was trying to do. He vouched for it and told me it was fantastic, so I decided to give it a try. And boy was he right!

The best thing about Tailscale is that it brings a lot on the table: connecting devices via a Tailscale network, home VPN via an exit node, exposing subnets from your local network inside the Tailscale network (so you can even access devices that don't have Tailscale installed, or can't install it) and a safe way to SSH into machines in the network without having to open up ports on the internet or even use passwords or SSH keys. Tailscale handles it all. And with ease.

Implementation

To start off, I created an account on Tailscale.com using my Gmail account.

Create the network

The first step in the process was to install Tailscale on the Raspberry Pi, which already acts as the Unifi controller and the Homekit hub. This was as easy as SSH'ing into the RPi and installing Tailscale via: curl -fsSL https://tailscale.com/install.sh | sh Then I had to run: tailscale up, which gave me a URL I needed to visit on my computer. After visiting, the RPi was added to my Tailscale network!

Next I installed Tailscale on my MacBook: I downloaded the standalone app on the Tailscale website and installed it on my computer. I had to enable a few permissions, but once that was done, I could register my device by clicking a button, which opened my browser automatically and I could simply add it to my Network. At first I had tried to install Tailscale via Homebrew, but I ran into issues trying to get the exit node working as expected. After some sparring with Gemini, we came to the conclusion that the standalone app is a better fit for a MacBook. This was my initial install: brew install tailscale, and I enabled it via sudo brew services start tailscale: the sudo is important to make it work correctly. Next it was like on the RPi:tailscale up, copy and paste the URL in my browser and the MacBook was added to my Tailscale network.

Then I installed the Tailscale app on my iPhone. This was pretty straightforward, and after logging in with my Gmail account again, I was able to connect to my Tailscale network.

Last up was the desktop: to install Tailscale, I ran curl -fsSL https://tailscale.com/install.sh | sh. Since I want to be able to SSH into my desktop via Tailscale I had to run sudo tailscale up --ssh to enable SSH access within the Tailscale network. See the Tailscale documentation for more info. Once again, running this tailscale up command gives an URL to visit in a browser to authenticate against my Tailscale network. To make sure Tailscale will run on startup, I made sure it was in my systemctl: sudo systemctl enable --now tailscaled Since we don't want to get blocked by the firewall, it's best to make sure port 22 is open: sudo ufw allow in on tailscale0 to any port 22. Check if the firewall is enabled to begin with via sudo ufw status and if it is inactive activate it via sudo ufw enable.

SSH into the desktop

With the network setup and Tailscale installed on all devices, it's time to SSH into the desktop. The beauty of Tailscale is that when you start it with the --ssh flag, it will automatically handle incoming SSH traffic and make it work. There is no need to install any SSH server on the desktop. However, Tailscale does have a default Access Control List for SSH that requires an extra "check" (a re-authentication with your Tailscale login provider) to be able to connect. If you want to be able to SSH into the desktop without this check (you can't re-authenticate from a headless device for example), you can disable it by changing the SSH action in the Tailscale ACL to "accept" instead of "check".

Configure the RPi as subnet router

This is the "magic" step. Configuring the RPi as a subnet router in Tailscale, allows me to reach all devices on my home network, even if they don't have Tailscale installed.

First, I had to enable IP forwarding:

  • 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

Then I had to advertise my home network via Tailscale: sudo tailscale set --advertise-routes=192.168.0.0/24

And lastly, I had to approve this route via the route settings of the RPi in the Tailscale Admin Console.

Configure the RPi as exit node

One of the goals is to route traffic through my home internet, making it look like I'm browsing from home. To achieve that, I need to configure the RPi as an exit node.

To do so, I need to restart Tailscale on the RPi with the advertise-exit-node flag. Note: since I already configured the subnet route, during restart I need to add the sub-route as well. So the command is: sudo tailscale up --advertise-exit-node --advertise-routes=192.168.0.0/24

To finish up, I need to approve this exit node the same way I did the subnet route: via the Tailscale Admin Console.

Test

To test the exit node:

  1. Disconnect from home Wi-Fi on iPhone.
  2. Check IP address via whatismyip.net.
  3. Open Tailscale on iPhone.
  4. Choose the RPi as exit node and enable it.
  5. Check IP address via whatismyip.net -> This now shows the home IP address again!

Sleep-on-LAN

Now that we can remotely start the desktop and connect to it via SSH, there is one useful piece missing: shutting it down again without having to manually SSH into it.

The Homebridge WOL plugin has support for a shutdown command. So we can SSH into the desktop and shut it down. However, since shutdown by default requires sudo and a password, we need to configure the desktop to allow that command without a password:

  1. Open a terminal
  2. Run: sudo visudo
  3. Scroll to the very bottom of the file and add this line (replace your_username with your actual Ubuntu username): your_username ALL=(ALL) NOPASSWD: /usr/sbin/poweroff, /usr/sbin/reboot
  4. Save and exit (Ctrl+O, Enter, Ctrl+X)

Note: since I'm running my Homebridge in a Docker container, which is already using network_mode: host, I still had to add some volumes to make sure Homebridge can access Tailscale in the container. To be fair I'm not entirely sure if this step was needed. I had a hard time getting this working and was trying to use tailscale ssh at first, but ended up using ssh instead. I never bothered trying to remove this afterwards.

  • - /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock
  • - /usr/bin/tailscale:/usr/bin/tailscale:ro

Homebridge still needs an SSH client, which it won't have by default in my Docker container. To fix that, I added this script to my startup script of Homebridge: apk update && apk add openssh-client.

Now we can configure the shutdown command: ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null your_username@desktop-name "sudo poweroff"