Access your home network using WireGuard
Table Of Contents
Setting up a secure WireGuard VPN to access your home network
About two years ago, I published this blog about using Algo to access a local network. It remains my most visited post (not that it's wildly popular), but I actually stopped using it very shortly after and switched to this new method.
There were a couple of reasons. First, Algo is meant for a server that is only used as a VPN. It configures iptables rules and changes other settings that can conflict with additional services on the same server. Second, having the WireGuard server on your home network was problematic for people who didn't have a public IP address or had a router that they couldn't configure.
So I ditched Algo and rethought the best way to get to my home network from wherever I am. I've been using this for the past year, and it's not perfect, but it is easier to set up and doesn't rely on port forwarding or having a public IP address at your house.
As a general overview, two servers make up the routing and forwarding part of the network. The public server is a VPS. I use the $5/month server from Linode (here's an affiliate link to use); other server providers are available. The gateway client is a Raspberry Pi, but you can use any Linux server that supports WireGuard.
Setting up the server
We'll configure the server first. Note that I'm assuming you're using systemd (sorry Gentoo and Alpine users). If you're using Ubuntu, install
wireguard-tools. Other distros might have different names; make sure you install the package that has
wg-quick in it.
Once you install it, find or create a folder to put the configuration files. I use
/etc/wireguard/ since that's where the systemd target looks for the main conf file. In that folder, generate the private and public keys for the server and each client you'll connect by doing
wg genkey | tee client.key | wg pubkey > client.pub, replacing
client with the computer's name you're creating the key for. As an example, I created these keys:
wg genkey | tee server.key | wg pubkey > server.pub wg genkey | tee gateway.key | wg pubkey > gateway.pub wg genkey | tee iphone.key | wg pubkey > iphone.pub wg genkey | tee macbook.key | wg pubkey > macbook.pub
I'll be referencing the names of these files throughout, so I would suggest naming the
gateway like I did.
Once those are done, you'll need to create a configuration file. The files are different for the server and client; we'll start with the server configuration file. Conventionally, this is called
wg0.conf. Once we start it with systemd,
wg0 will be the name of the network interface. Here's my (redacted)
wg0.conf with comments:
# Server [Interface] # Put the contents of server.key here PrivateKey = [redacted] # Create the IP address in a subnet different from your home network subnet # this should be a good value for most people. If you want a larger or smaller subnet, change /24 accordingly. Address = 10.200.0.1/24 # Port that the server listens on. You can change it; make sure to change it in each client config once we make them ListenPort = 51820 # Gateway [Peer] # Put the contents of gateway.pub here PublicKey = [redacted] # AllowedIPs in the server config lists the IPs that the server routes to the client. # The first address is the address that the client will have. # since this is our gateway to our home network, we want to route the home network subnet to it. # Replace 192.168.0.0/24 with your actual home network subnet AllowedIPs = 10.200.0.2/32,192.168.0.0/24 PersistentKeepalive = 25 # mac [Peer] # Put the contents of mac.pub here PublicKey = [redacted] # Since this is a normal client, we only need to add the IP address that it will use. AllowedIPs = 10.200.0.3/32 PersistentKeepalive = 25 ## Copy/paste the mac section for each client, replacing the PublicKey and incrementing the value of AllowedIPs each time.
Once you have all the clients'
[Peer] sections added, save the
wg0.conf file, and run
systemctl start email@example.com (you'll need sudo if you aren't root). Then run
ip a or the equivalent for your distro, and you should see a
wg0 interface with the IP address you put in the config. Here's my output:
5: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000 link/none inet 10.200.0.1/24 scope global wg0 valid_lft forever preferred_lft forever
Next, make sure that the server allows IP forwarding. Open
/etc/sysctl.conf and find the line that has
net.ipv4.ip_forward. Uncomment it and set it to
1. Then run
sysctl -w net.ipv4.ip_forward=1 to make it take effect without rebooting.
Finally, add an
iptables rule to forward the traffic to the gateway:
iptables -t nat -A POSTROUTING -s 10.200.0.0/24 -o eth0 -j MASQUERADE.
eth0 is the name of the main interface. Replace it if yours is different, and replace the subnet if you changed it from my example conf.
There's not a way to test it until we set up the gateway client. So let's do that.
Setting up the gateway client
wireguard-tools like on the server. Then create the configuration file at
/etc/wireguard/wg0.conf. Here's my file:
[Interface] # Put the first address that is in the AllowedIPs value on the gateway section of the server conf file Address = 10.200.0.2/32 # Put the contents of gateway.key here PrivateKey = [redacted] [Peer] # Replace 126.96.36.199:51820 with the IP and port of your server Endpoint = 188.8.131.52:51820 # Put the contents of server.pub here PublicKey = [redacted] # This should be the same subnet as the Address of the server configuration file AllowedIPs = 10.200.0.0/24 PersistentKeepalive = 25
Save it, and then run
systemctl start firstname.lastname@example.org. Then run
ip a to check, you should see a
wg0 interface with the correct address, for example:
8: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000 link/none inet 10.200.0.2/32 scope global wg0 valid_lft forever preferred_lft forever
net.ipv4.ip_forward value the same way you did on the server, and then add the iptables rule, which is slightly different:
iptables -t nat -A POSTROUTING -s 10.200.0.0/24 -j MASQUERADE.
We can now test it. You should be able to
ping the server IP from the client and vice versa, and get a response. If you don't get a response, check
/var/log/kern.log for errors, and make sure that you copy/pasted the private and public keys correctly.
Now on the server, ping an IP address on your local network (not the gateway client IP). You should get a response from that same IP address. If you didn't, make sure that the subnet and network interface name of the iptables rules are correct, and that you ran
sysctl -w net.ipv4.ip_forward=1 on both the server and the client.
Once you've successfully got those two set up, you can make the configuration files for the other clients you'll be connecting with. I save each file in the same directory that I created the public/private keys for each. Here's a sample file for my Macbook:
[Interface] # Name = mac # The IP from the AllowedIP of the mac section in the server configuration file Address = 10.200.0.3/32 # Put the contents of mac.key here PrivateKey = [redacted] [Peer] # IP and port of the server Endpoint = 184.108.40.206:51820 # Put the contents of server.pub here PublicKey = [redacted] # The first value is the same as the AllowedIPs value of the mac section of the server config # The second value is the subnet of your home network. AllowedIPs = 10.200.0.0/24,192.168.0.0/24 PersistentKeepalive = 25
Now, this configuration will only send traffic to IP addresses in those subnets through WireGuard. This is useful if, for instance, you're at work and need to access internal servers. If you want all your traffic going through WireGuard, like when you're on public wifi, change
0.0.0.0/0. You can import multiple configuration files, so I have one with only the home subnets, and the other with all traffic, and switch between them depending on where I am.
Connecting the other clients
If you're using a laptop/desktop, just copy/paste the configuration file to that computer and import it into the WireGuard client. For phones, you can import via QR code. Install the
qrencode package (other distros might have a different name), and then run
qrencode -t ansiutf8 < /etc/wireguard/iphone.conf, changing
iphone.conf to the name of the config for that client. Then you can scan it with your phone, and it will import it.
As I said in the intro, this isn't perfect. There are two downsides to this setup. The first is that you need to remember to not have the WireGuard client running on your phone/tablet/laptop when you're at home; otherwise all the traffic will be going through the server and back and will be slower than normal. Second, if you're at work and your home and work subnets overlap, then you won't be able to access both of them. The easiest fix is to change your home network's subnet (and update the configuration files accordingly).
Extra step: DNS
Because you're able to access your home network from wherever, if you have a network-level adblocking setup, like AdGuard Home or Pihole, you can force WireGuard to use that as the DNS server. In each client config, underneath the
Address line, add this line:
DNS = 192.168.1.1
Change the IP address to the IP of your DNS server. Now you have the benefits of network-level adblocking even when you're not at home!