How To Set Up a WireGuard VPN Server on Ubuntu Linux

A VPN is an essential feature of any homelab as it allows you to access your network remotely for both emergency maintenance and routine use. Arguably, the best-in-class VPN service is WireGuard, which I now use exclusively for reasons that will be outlined below.


This is a companion discussion topic for the original entry at https://engineerworkshop.com/blog/how-to-set-up-a-wireguard-vpn-server-on-ubuntu-linux/

Thanks for writing this. I did want to check a couple of things though. First, port 51910 is supposed to be 51900 right? It’s different in a couple places so I think that’s a typo.

Beyond that, I am using an Ubuntu server behind pfSnse as well. I believe I have to put a static route with a gateway to the PF sense for the range of the VPN clients to allow the return traffic to them correct? I believe there may also be a rule setting about bypassing firewall rules for traffic on the same interface that has to be adjusted as well. Does that sound right?

You are correct; that was a typo. I’ve set up WireGuard so many times on so many different ports to keep the instances separated, I mixed them up. (And I thought I had even explicitly checked to make sure I hadn’t!)

No static route/gateway necessary. Your thoughts are good though.

The reason it isn’t necessary is because of our rule in PostUp, specifically this part: iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE

Masquerading with a postrouting chain allows us to mask requests as they exit the firewall with the IP address of the firewall’s device (in my example, ens18); i.e. the IP address of my WireGuard VPN server on its “real” LAN, not the tunnel’s IP address. Therefore, pfSense never sees our WireGuard tunnel IP addresses and no static route/gateway set up is necessary.

-TorqueWrench

Thanks for confirming, and for the info on the MASQUERADE. So I removed the static route, but I’m afraid it’s still not working. Any ideas on how I can troubleshoot this? Neither the Android client, nor the server, seems to offer nearly as much by way of info as I’m used to seeing.

Hi BurntOC,

I’m happy to troubleshoot with you. Just to clarify, by “it’s still not working”, are you seeing any real data transfer (as defined by both sent and received traffic)?

Post your server and client configs (with private keys removed). Also, double check your keys to make sure you have the right ones plugged in.

Other ideas:

-TorqueWrench

Thank you for the offer! So last night i’d posted on this, including the conf files, to r/Wireguard here:


I’m happy to repost here if that’s more helpful, and in any case I figure when I get this resolved I’ll give your site a shout out there.

I’m pretty sure the keys are good but I’ll double check that tonight. When I’m testing, I’ve been predominately trying from the cell network, with only occasional fallback attempts internally while on Wifi. The behavior so far has been the same - I see a little data in Tx, but I’m not receiving anything. I’ll also take a look at the loopback item and the thread you posted tonight and see if there’s any other insights there.

Also, to your earlier comment about not needing the static route due to MASQUERADE. Are there advantages to using MASQUERADE and eliminating the static route vs keeping the static route and eliminating the MASQUERADE setting?

1 Like

Yeah, if you’re just seeing tx and not rx, you don’t have a connection. Just adding your config in here for future reference:

Server wg.0 config:

[Interface]
Address = 10.30.42.1/24
SaveConfig = true
PrivateKey = privkey
ListenPort = 51900
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
PublicKey = pubkey
AllowedIPs = 10.30.42.0/24

wg0-client.conf

[Interface]
Address = 10.30.42.10/24
PrivateKey = privkey
DNS = 1.1.1.1
[Peer]
PublicKey = pubkey
Endpoint = vpn.mydomain.me:51900
AllowedIPs = 0.0.0.0/0, ::/0

The only thing that really jumps out at me is the interface address in wg0-client.conf. Since we’re using this with a single peer, humor me and try changing the address so that only a single IP address is given: i.e. change 10.30.42.10/24 to 10.30.42.10/32.

While you’re at it, let’s simplify things a bit and do the same for your server’s wg0.conf and change AllowedIPs under [Peer] from 10.30.42.0/24 to 10.30.42.10/32 as well. (Don’t forget to restart/reload WireGuard so it picks up on the new config).

Best of luck,
TorqueWrench

Sorry for the delayed follow up - I didn’t see a notification you’d responded. So I made those changes you mentioned and that’s where I am now and it hasn’t fixed it. I can confirm that from my cell phone I can ping 10.30.42.1 and wg shows the handshake. I still can’t get to anything beyond the VPN server, though. I’d been given advice to remove the iptables postrouting MASQUERADE lines or static routes so I’d think it was a problem with the responses, but I don’t see any requests from the VPN server at 192.168.120.71 or the VPN 10.x range to the firewall,…

UPDATE - Yep, it was as I suspected. I went back in and put the iptables lines back in and it’s working. I did, FWIW, use the lines from another site but they look pretty similar except yours uses %i instead of the wireguard interface name. I’m not sure if that’s contributing to the issue, but that means this is what I used instead:

PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0  -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

Actually, I believe the other guide also included installing wireguard-tools, and also a package, something like resolvconf, that may have been the key as well. Sorry I don’t have that definitively, but I am so glad it works. Thanks for the help!

Glad to hear you got it working! (And thank you even more on taking the time to follow-up so we can hopefully make this easier for others to install).

I have two thoughts on why the config might not have worked for you. If you could answer these questions for me so I can decide if I need to make adjustments to the configuration to help others, I would appreciate it:

  1. What Linux distribution (and version) are you running on your Wireguard server?

The %i is what is known as a “template specifier”; more specifically, the variable %i represents the instance identifier. In our case, in the PostUp/PostDown configuration %i represents the WireGuard interface name, wg0. Since this is systemd, if your Linux distribution doesn’t use systemd, I would not expect this to work.

  1. Are you using IPv6 (either internally in your home network or provided by your ISP)?

The easiest way to test if you’re not sure is to use http://test-ipv6.com/ and let me know what you see there. (Visited with the WireGuard connection enabled).

Additionally, running ifconfig and pulling the line with the inet6 addr would also be extremely helpful. I’m especially interested in the Scope that appears in that line (particularly if it says Scope:Site which indicates an IPv6 routed address.

Since I am currently only using IPv4, and I only post material that I have been able to test myself, my configuration only provides for IPv4 in iptables.

The wireguard-tools package should have been pulled in with the rest when you installed wireguard with sudo apt install wireguard. Since it includes both wg and wg-quick, if you didn’t have it, you would have had a heck of a time starting up Wireguard.

Thanks again for the update, and I hope to hear back from you re: the questions above.

-TorqueWrench

Happy to help! I’d actually started making changes to try to get this to work without the iptables NAT on the VPN sever as I want to be able to use firewall and DNS controls on some VPN hosts (like my kids who will also be always-on VPN). Unfortunately, while I got so far as to be able to ping not only the gateway but Internet addresses like 8.8.8.8, I can’t get DNS to work that way for some reason - no matter what I do.

In any event, I restored a backup so hopefully I can you some answers. Here we go:

  1. I am running Ubuntu 20.04 on a pi 4 for this.

  2. I’ve tried to disable IPv6 everywhere for now because I haven’t felt comfortable setting up all the rules yet. That site you linked seems to verify IPv6 is not enabled.

That’s weird regarding the tools. I’d also flushed the iptables with iptables -F and rebooted, so maybe I didn’t read the message right and it was just something like that. I’m glad it’s working, but I sure do wish I could finish getting this up without NAT’ting the VPN clients to the VPN server interface

HI, I’m about half-way through the tutorial and have all of the keys generated and the wg0.conf created. The one thing I am a bit lost on is the address you are showing for the {Interface] setting in the conf file.

In the WireGuard config file (wg0.conf), Under the heading of [Interface], you have entered 10.253.4.1/24 . I would assume that you have entered the IP address for your server’s NIC which is ens18, but you mention in the paragraph just before the Prerequisites section of the article this, “forwards it on to the Ubuntu server, which is connected to the router on ens18 with IP address 10.0.20.129 and also listening on port 51910.” That would make me think your server is at 10.0.20.129 . So, I am wondering what address of mine I need to substitute in for that 10.253.4.1/24 that you have entered at that point. I am stuck in this WireGuard installation until I can settle that issue.

Is 10.253.4.1/24 an address you assigned to the Wire Guard server application?

That’s correct. My server’s IP address (on ens18) is 10.0.20.129.

You can leave the number as 10.253.4.1/24. Any line where you see 10.253.4.X/yy you can leave as is in both your server and client config. There’s no need to change either on a simple install.

The reason is that you’re essentially creating a network device with these commands and, as a result, you get to assign the IP addresses you want those interfaces to use.

Correct.

-TorqueWrench

Thank you, TorqueWrench! You confirmed what I thought after I re-read the tutorial several more times. I’ve installed the official WireGuard Android Client and will be testing it out. I’ll let you know the results as soon as I can get through all of this. Thanks, again!

1 Like

Using a VM lab I followed this article successfully and I have a windows client VM connected to a ubuntu desktop VPN server VM. Eventually my end goal is ubuntu server/desktop running on a Raspberry Pi 4 and windows/mac clients accessing from outside the home network. And a secondary goal is to have a 2nd raspberry PI 4 set up as a site-to-site VPN and as a wireless access point so that any devices connecting to it as the wireless are automatically connected to my home network.

However, back to my simpler step 1, I don’t know what to do next. On my windows client I do see Rx/Tx values greater than 0 and the activated light is green and on my ubuntu desktop I do see Rx/Tx values greater than 0 with wg show but that’s all I can do. What else do I need to make this VPN tunnel useful?

For example, if my ubuntu server is 10.253.4.1 and my windows client is 10.253.4.2 what do I need so that I can access resources on the home network (which is 192.168.7.x) from my client (10.253.4.2) through the tunnel? DNS? How do I configure DNS (and where)? If I have a windows machine on my home network at 192.168.7.95 how can I RDP from my remote windows client across the VPN? (again its on 10.253.4.2 and I don’t know conceptually or installed service wise what I’m missing to make this all work) Or in simpler terms, how do I browse my 192.168.7.x home network when I’m remote and only able to connect via the 10.253.4.x VPN?

In a possibly related observation, from inside my home network I also can’t see my ubuntu server by name, I can only SSH/RDP by IP. Maybe this is part of my problem? – what do I need so that my ubuntu machines/VMs can be found via name like my windows machines can?

Thanks for the help!

1 Like

Hi @mark.d.harris,

Brace yourself for my barrage of questions/comments below! :wink:

That’s great news. If you are receiving data then your WireGuard tunnel is working.

Are you saying that you can’t do anything else? I.e. Can you browse a web page? Are you able to ping other devices on your local network? (Note that if you’re trying to ping a Windows machine, by default they don’t respond to pings/ICMP requests).

You should be able to use Windows RDP as usual. Some of your other statements are making me think that you think you might have a DNS issue in which case instead of using your Windows PC’s hostname, you should be able to do connect by putting in that PC’s IP address into Windows RDP instead.

Just to confirm, are you saying that you can’t access any other devices on your local network when connected to WireGuard? Are you able to ping them? If you aren’t able to ping them by hostname, are you able to at least ping them by IP address?

All of this is sounding like you’re “locked inside” the WireGuard server and your connection can’t leave it since 1) you’ve confirmed that you can connect to the WireGuard server and it’s a real connection by receiving data but 2) can’t seem to access outside resources. If that’s the case, did you enable IP forwarding on your WireGuard server?

-TorqueWrench

Thank you so much for your questions!.. as I studied and investigated each one I realized that the VPN tunnel is actually working just fine. The name resolution does not work and that is why I was confused.

It seems strange to me, but yes, from my remote client (which is on the VPN network at 10.253.4.2) I can RDP to or find a resource on my home network like 192.168.7.95. I wouldn’t have thought that would work like that but I guess that comes from the " iptables -A FORWARD part? (is there 101 level info that explains how that iptables work as well as how to set them for wireguard? I blindly followed the setup for wg0.conf but would like to understand it better.)

So, I think the problem I have is that on the remote client, I cannot resolve names of linux or windows hosts. Even in the simpler case, on a home network where there are both linux and windows machines, how can you get name resolution to work (windows machines can find other windows machines just fine but not linux and linux can’t seem to find anything except by IP)? I know its not a VPN question since the tunnel definitely works when I use IP but I’d like to understand how to get name resolution working too.

Thank you!

1 Like

It’s technically because of the iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE piece, where ens18 is your network device on the local network.

The combination of Network Address Translation (NAT) and MASQUERADE basically allows us to run all of our traffic from the WireGuard tunnel under the “false flag” of our WireGuard server’s primary network device, ens18. As a result, to other devices on the local network, all of the traffic appears to be coming from your WireGuard server on the local network and not from a device in the WireGuard tunnel itself.

Viewed another way, that configuration allows our WireGuard server to act as a sort-of router, allowing traffic to traverse from one network (the WireGuard tunnel) to another (your local home network).

I’ve been meaning to do such an article. In the meantime, here is a good reference on NAT with Linux and iptables. It might be a little advanced, but it will get you started.

Since this isn’t necessarily specific to WireGuard, to keep everything organized and easier to find, would you mind posting this as a separate discussion in the Networking forum? Thanks!

-TorqueWrench

Trying to access my home network over the VPN from an actually remote (non-test) location turned out to be somewhat disappointing. I am able to get an active client and see data transferring in both directions but the only thing that seems to be reasonably working now is seeing the internet from my home network’s IP while remote. That’s good but I do not seem to be able to actually access my home network resources like I thought I could before. (even by IP which I know from my eero phone app). Plus, I put docker on the same PI and am running a test nginx container and am not even able to see that by attempting to browse to the IP of the PI on port 80 (which definitely worked when local)

I’ve also noticed excessively high latency in what is probably DNS resolution of internet resources through the tunnel. It works eventually but a lot of attempts are timing out more often than being successful.

Does any of these symptoms suggest what I might have misconfigured? Also, do you have suggestions for how to work with multiple VPNs? (work requires a VPN client, now I have a home one, etc. - can they be made to work together? if so how does the traffic flow?)

Thanks for any suggestions!
Mark