A reader (Raf Czlonka) wrote in with some feedback on my OpenBSD and TailScale post and also suggested maybe I expand the post a bit on what TailScale is for those who don’t know. A good suggestion, I hadn’t thought people might not know what TailScale is.
There’s no real point in me explaining TailScale as there’s this amazing official blog post that explains it all. If you are curious as to how TailScale works there’s no better place to start. I will, however, try and give a big picture of what it is though coz I like trying to explain things.
Since this started with an OpenBSD post let’s start with 3 OpenBSD servers. They are actually all on the same network but assume they are actually in 3 different locations and I want to connect them all together via WireGuard.
On each of these servers I’d do the following to create a WireGuard interface:
1 2 3 4 5 6 7 8 |
# create a private key openssl rand -base64 32 > $HOME/wg0.key # create the WireGuard interface listening on port 3000, with this private key doas ifconfig wg0 create wgport 3000 wgkey `cat $HOME/wg0.key` # assign an IP to this interface doas ifconfig wg0 192.168.200.1 netmask 255.255.255.0 |
At this point I can type doas ifconfig wg0
to see that the interface is up and running and note its public key.
Here’s all the info:
Hostname | Real IP address | Tunnel IP address | Public Key |
obsd01 | 192.168.17.114 | 192.168.200.1 | Pkh6nXWshcIlYggYWhMTOodqoiFtqUiG17F4veRTJBk= |
obsd02 | 192.168.17.115 | 192.168.200.2 | wPRLv5NTZkPM50gsAExqgxq9szFdfwKuedADIQ+rdCo= |
obsd03 | 192.168.17.116 | 192.168.200.3 | Qm8t8/pp6pPJCVRl20J7y6TI0c94cAw0rZeCO8BsDBY= |
In reality the Real IP addresses would be on separate networks, with some of them being private others being public. That would complicate things so this is something I am intentionally keeping easy.
What I have to do now is add the public keys of obsd02 & obsd03 to obsd01, along with their tunnel IPs; and repeat and rinse the same on obsd02 and obsd03. I could do this via the doas ifconfig wg0 wgpeer
command but I know I’ll want to persist all this info eventually so let’s just put it all in a config file on each host (including the private key info from above).
Thus on obsd01 I create /etc/hostname.wg0
with the following:
1 2 3 4 5 6 7 8 9 10 |
# private key I generated initially wgkey qfSureF6SGQUL0ukInNvlzg2POe/P+mitLMwZ6t+yPw= wgport 3000 # each of my peers wgpeer wPRLv5NTZkPM50gsAExqgxq9szFdfwKuedADIQ+rdCo= wgaip 192.168.200.2/32 wgendpoint 192.168.17.115 3000 wgpeer Qm8t8/pp6pPJCVRl20J7y6TI0c94cAw0rZeCO8BsDBY= wgaip 192.168.200.3/32 wgendpoint 192.168.17.116 3000 inet 192.168.200.1/24 up |
This defines the interface with its private key and IP; and adds each of the peers with their real IP & port, and associates their tunnel IP with the peer.
Similarly on obsd02 & obsd03:
1 2 3 4 5 6 7 8 9 10 |
# private key I generated initially wgkey 9G/QM00nM1O3h+wRS6tWjcVwrmFWsmIv7xObPogrV74= wgport 3000 # each of my peers wgpeer Pkh6nXWshcIlYggYWhMTOodqoiFtqUiG17F4veRTJBk= wgaip 192.168.200.1/32 192.168.17.114 3000 wgpeer Qm8t8/pp6pPJCVRl20J7y6TI0c94cAw0rZeCO8BsDBY= wgaip 192.168.200.3/32 192.168.17.116 3000 inet 192.168.200.2/24 up |
1 2 3 4 5 6 7 8 9 10 |
# private key I generated initially wgkey jnGcR/aYTrB+zizwdjDCd4J39EdaZI3vVDszV/yxDBk= wgport 3000 # each of my peers wgpeer Pkh6nXWshcIlYggYWhMTOodqoiFtqUiG17F4veRTJBk= wgaip 192.168.200.1/32 192.168.17.114 3000 wgpeer wPRLv5NTZkPM50gsAExqgxq9szFdfwKuedADIQ+rdCo= wgaip 192.168.200.2/32 192.168.17.115 3000 inet 192.168.200.3/24 up |
That’s all! Now I can ping each of the 192.168.200.x IPs from each other. I have all 3 hosts connected in a WireGuard network.
This isn’t too difficult to do in the example above because I kept the network simple. If some of these were public and some were private network machines it would complicate things a bit. For instance I won’t be able to hook up two machines that are both behind private networks without doing extra tricks like finding their respective public IPs. Similarly I’d have to open up firewall ports, and also allowing incoming traffic if the public IP machine had a firewall.
Further each time I add a new peer I’d have to add it to each of the other hosts, and add all of them to this new peer. Not too bad when it’s only 3 hosts but it’s nothing something I am going to do willy nilly when I have say 6-7 hosts. It’s doable, but I am going to go “eugh!” in my head or look at automating this somehow.
This is where TailScale comes in. With TailScale all you do is sign up for an account (currently uses Google & Microsoft accounts), then you install the client on each of your machines; and the client takes care of creating the public/ private keys, assigning each of the endpoints a private IP (from a Carrier Grade NAT pool), figuring out the public IPs of private machines, doing some tricks to bypass the firewall, and taking care of passing on the public key of each node to every other node in your list of nodes without you having to do anything. It sounds simple when I type it out here, but there’s a lot of behind the scenes stuff and that’s where the blog post I referred to is a must-read.
I’ve only used TailScale as a free tier user as I just have a handful of machines and what I chiefly use it for is SSHing from my iPhone when outside home to any of my devices at home as they are all on the TailScale mesh network; but if you sign up for one of the Enterprise plans you get more features.