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

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.


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:


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:

Address =
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
PublicKey = pubkey
AllowedIPs =


Address =
PrivateKey = privkey
PublicKey = pubkey
Endpoint =
AllowedIPs =, ::/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 to

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 to as well. (Don’t forget to restart/reload WireGuard so it picks up on the new config).

Best of luck,

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 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 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 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.


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, 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 . 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 and also listening on port 51910.” That would make me think your server is at . So, I am wondering what address of mine I need to substitute in for that that you have entered at that point. I am stuck in this WireGuard installation until I can settle that issue.

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

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

You can leave the number as 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.



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