SSD Nodes Learn Hosting plans →
Guides Matt ConnorBy Matt Connor

TP-Link Router WireGuard to Your Own VPS

Use your TP-Link router's VPN Client with a WireGuard server on your own VPS. Spot CGNAT first, then build an IPv4 only config the router will import.

A TP-Link router with a WireGuard client can send your home traffic through a VPS (virtual private server) that you rent and control. The VPS runs the WireGuard server, and the router connects out to it from its Advanced > VPN Client page. This works even when your home connection has no public IP address, because the router only makes outgoing connections.

TP-Link's own guide, FAQ 3772 ("WireGuard VPN Setup Guide for TP-Link Routers | Server and Client", last updated April 17, 2026), shows how to import a config file from a VPN provider. It does not show how to build the server end yourself. This guide covers that half: an Ubuntu VPS as the server, and a router config file the TP-Link firmware will accept.

If you have never set up WireGuard before, the full guide to self-hosting a WireGuard VPN on a VPS explains each server-side setting in more depth. Here the focus is on what changes when the client is a TP-Link router.

Server mode or client mode: which one do you need?

A TP-Link router with WireGuard has two modes. In VPN Server mode (Advanced > VPN Server > WireGuard), the router is the server, and your phone or laptop connects to your home from outside. In VPN Client mode, the router connects out to a server somewhere else.

Server mode has a hard requirement. TP-Link's FAQ 2706 says: "As a server, router needs a public IP so that it can guarantee the connection remotely." Your phone must be able to send UDP (user datagram protocol) packets to the router's WAN (wide area network) address. If that address is not public, the packets never reach the router.

Client mode has no such requirement. The router opens the connection, so its WAN address can be private. That makes client mode plus a VPS the working option for two common cases: CGNAT and double NAT.

How to tell CGNAT or double NAT from a public IP

NAT (network address translation) lets many devices share one address. CGNAT (carrier-grade NAT) means your ISP (internet service provider) does this for many customers at once, so your router never gets a public address of its own. Double NAT means a second NAT device, often the ISP's modem router, sits between your TP-Link router and the internet.

Start with the WAN address the router reports. Open the router's web interface, find its Internet or WAN status, and write that address down. Then, on a computer connected to the router, run:

curl -4 https://ifconfig.co

This prints the public IPv4 address the internet sees for your connection. Now compare the two addresses. This comparison is a test you run yourself, not a TP-Link procedure.

  • The WAN address is between 100.64.0.0 and 100.127.255.255. That is CGNAT. RFC 6598 (April 2012) reserves 100.64.0.0/10 as "Shared Address Space" for carrier-grade NAT, separate from the normal private ranges. TP-Link's FAQ 785 gives the same range and says these addresses look public but are not routable on the internet.
  • The WAN address is in a private range (RFC 1918): 10.0.0.0/8, 172.16.0.0/12 or 192.168.0.0/16. Another NAT device sits in front of your router. That is double NAT.
  • The WAN address is public but differs from the curl result. Something upstream still translates your traffic, so inbound connections are unlikely to reach the router.
  • The WAN address is public and matches the curl result. Server mode is an option for you.

TP-Link's FAQ 785 says that most 4G/LTE and 5G ISPs assign private IP addresses by default, and suggests asking your ISP for a public IP. For double NAT, TP-Link's FAQ 3113 describes putting the modem router into bridge mode, so that only the TP-Link router does NAT. FAQ 3772 also notes that a TP-Link router behind a main router may need port forwarding on that main router. If none of this is possible, use client mode with a VPS. The rest of this guide does that.

Be clear about what client mode gives you. It sends traffic from your home out through the VPS. It does not, on its own, let you reach your home from outside. That is a different job, and a reverse tunnel through a VPS when you are behind CGNAT covers it.

What you need before you start

  • A TP-Link router whose web interface offers WireGuard as a VPN Type under Advanced > VPN Client. TP-Link's FAQ 3135 says: "WireGuard is supported on select TP-Link router models only." FAQ 3772 names no model list, so check your own router's menu.
  • An Ubuntu 24.04 or 26.04 VPS with a public IPv4 address and SSH (secure shell) access as a user with sudo.
  • A computer on your home network with a web browser, to upload the config file to the router.

Deco mesh systems and Omada business gear have their own WireGuard pages. This guide does not cover them.

Install WireGuard and generate keys on the VPS

WireGuard is in Ubuntu's own archive. The Ubuntu man pages show wireguard-tools 1.0.20210914 on Ubuntu 24.04 and 1.0.20250521 on Ubuntu 26.04. Both work for this setup.

sudo apt update
sudo apt install -y wireguard
apt policy wireguard-tools

apt policy shows the installed version. Next, make two key pairs: one for the VPS and one for the router. The router's client mode works by importing a finished config file, so you generate its key pair here and put its private key in that file.

sudo install -d -m 700 /etc/wireguard
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/server.key'
sudo sh -c 'wg pubkey < /etc/wireguard/server.key > /etc/wireguard/server.pub'
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/router-home.key'
sudo sh -c 'wg pubkey < /etc/wireguard/router-home.key > /etc/wireguard/router-home.pub'
sudo ls -l /etc/wireguard

The umask 077 makes each new file readable by root only. WireGuard's quickstart sets the same restrictive umask before wg genkey. In the ls output, both .key files should show -rw-------. If one shows -rw-r--r--, other users still cannot read it, because /etc/wireguard itself is root-only (mode 700), but tighten it anyway with sudo chmod 600 on that file.

Write wg0.conf with one peer per router

The server config holds the VPS's private key and one [Peer] block for each router. These commands build it without you pasting keys by hand:

SERVER_KEY=$(sudo cat /etc/wireguard/server.key)
ROUTER_PUB=$(sudo cat /etc/wireguard/router-home.pub)
sudo sh -c 'umask 077; cat > /etc/wireguard/wg0.conf' <<EOF
[Interface]
Address = 10.66.0.1/24
ListenPort = 51820
PrivateKey = ${SERVER_KEY}

[Peer]
# home TP-Link router
PublicKey = ${ROUTER_PUB}
AllowedIPs = 10.66.0.2/32
EOF
unset SERVER_KEY
sudo cat /etc/wireguard/wg0.conf

The output should show both key lines filled in. An empty PrivateKey = line means the sudo cat in the first line failed, so check that /etc/wireguard/server.key exists and run the block again.

The tunnel uses 10.66.0.0/24. The VPS is 10.66.0.1 and the router is 10.66.0.2. Pick a range that does not match your home LAN (local area network). If your home network already uses 10.66.0.x, change every 10.66.0 in this guide.

The AllowedIPs line on the server is a /32, a single address, and it works in both directions. The wg man page describes AllowedIPs as the addresses "from which incoming traffic for this peer is allowed" and "to which outgoing traffic for this peer is directed." So the VPS accepts packets from this router only when they come from 10.66.0.2, and it sends packets for 10.66.0.2 only to this router. How WireGuard's cryptokey routing works explains this table in detail.

A second router gets its own key pair, its own [Peer] block and its own address, such as 10.66.0.3/32. Separate addresses mean each address points to exactly one peer.

Turn on forwarding and NAT with ufw

The VPS has to take packets in on wg0, send them out of its public interface, and rewrite their source address so that replies come back to it. That is forwarding plus NAT. Ubuntu's WireGuard docs set net.ipv4.ip_forward = 1 for this, because without it the kernel does not pass packets from one interface to another.

Ubuntu's firewall, ufw, is disabled by default. Once enabled, its default forward policy is deny. Ubuntu's firewall guide puts the NAT rule in /etc/ufw/before.rules, and this guide does the same.

First, find the VPS's public interface. It is often not eth0:

WAN_IF=$(ip -4 route show default | awk '{print $5; exit}')
echo "$WAN_IF"

You should see a name such as eth0, ens3 or enp1s0. Keep this shell open, because the next commands use $WAN_IF.

Turn on IPv4 forwarding in two places. The file in /etc/sysctl.d/ applies at every boot. The ufw file applies when ufw starts, and the ufw man page says route rules need forwarding enabled there.

printf 'net.ipv4.ip_forward = 1\n' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system
sysctl net.ipv4.ip_forward
sudo sed -i 's|^#net/ipv4/ip_forward=1|net/ipv4/ip_forward=1|' /etc/ufw/sysctl.conf
grep '^net/ipv4/ip_forward' /etc/ufw/sysctl.conf

sysctl net.ipv4.ip_forward should print net.ipv4.ip_forward = 1. The grep should print net/ipv4/ip_forward=1. If grep prints nothing, open /etc/ufw/sysctl.conf and remove the # from that line by hand.

Now add the NAT rule at the top of before.rules. Run this block once only. A second run adds a second copy of the rule.

sudo cp /etc/ufw/before.rules /etc/ufw/before.rules.bak
{ printf '*nat\n:POSTROUTING ACCEPT [0:0]\n-A POSTROUTING -s 10.66.0.0/24 -o %s -j MASQUERADE\nCOMMIT\n\n' "$WAN_IF"; sudo cat /etc/ufw/before.rules.bak; } | sudo tee /etc/ufw/before.rules > /dev/null
sudo head -n 5 /etc/ufw/before.rules

The head output should show the *nat block with your real interface name after -o. If nothing follows -o, then $WAN_IF was empty in this shell. Restore the backup with sudo cp /etc/ufw/before.rules.bak /etc/ufw/before.rules, set WAN_IF again, and repeat the block.

Then open the ports and allow forwarding from the tunnel to the internet:

sudo ufw allow 22/tcp
sudo ufw allow 51820/udp
sudo ufw route allow in on wg0 out on "$WAN_IF"
sudo ufw enable
sudo ufw status verbose

Allow SSH before you enable ufw. The default incoming policy is deny, so enabling ufw without that rule can cut off your own session. ufw enable asks you to confirm, because it may disrupt existing SSH connections. If ufw was already active, run sudo ufw reload instead, so that it reads the new before.rules.

ufw status verbose should show deny (routed) as the default, plus a forward rule for traffic coming in on wg0. Ubuntu's firewall guide switches the whole forward policy to accept. The ufw route rule here is narrower: it lets only tunnel traffic out to the internet.

If your VPS provider has its own firewall in the control panel, open UDP 51820 there as well. It is a separate filter, and ufw cannot change it.

Start the tunnel on the VPS

sudo systemctl enable --now wg-quick@wg0
sudo wg show

wg show should list interface: wg0, listening port: 51820, and the router's peer with allowed ips: 10.66.0.2/32. There is no latest handshake line yet, because the router has not connected. enable brings the tunnel back after every reboot. If the unit fails to start, journalctl -u wg-quick@wg0 -n 50 shows the reason.

Build the router's .conf: IPv4 only, no MTU line

The firmware covered by TP-Link's FAQ 3772 does not accept every line a normal WireGuard config can hold. FAQ 3772 says: "If your configuration file includes unsupported parameters such as IPv6 addresses or MTU values (shown in Pic 2 below), edit the file and delete those parameters before saving." The example image in that FAQ lists PrivateKey, Address, DNS, PublicKey, AllowedIPs and Endpoint. The router file below uses those six fields and nothing else.

IPv6 support now depends on the model and firmware. TP-Link's release notes for Archer BE400(US) V1.6 firmware 1.2.4 Build 20260311, published June 2, 2026, add IPv6 support for VPN Server and Client. This guide still builds an IPv4-only tunnel, so keep its config IPv4-only even on firmware with IPv6 support.

Build it on the VPS:

ROUTER_KEY=$(sudo cat /etc/wireguard/router-home.key)
SERVER_PUB=$(sudo cat /etc/wireguard/server.pub)
VPS_IP=$(curl -4 -s https://ifconfig.co)
echo "$VPS_IP"
(umask 077; cat > ~/router-home.conf) <<EOF
[Interface]
PrivateKey = ${ROUTER_KEY}
Address = 10.66.0.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = ${SERVER_PUB}
Endpoint = ${VPS_IP}:51820
AllowedIPs = 0.0.0.0/0
EOF
unset ROUTER_KEY
cat ~/router-home.conf

Check that echo "$VPS_IP" printed your VPS's public IPv4 address. If it printed nothing, write the address into the Endpoint line by hand.

Each line has one job:

  • Address = 10.66.0.2/32 is the router's tunnel address. It must match the router's AllowedIPs on the VPS.
  • DNS = 1.1.1.1 is a public resolver that is reachable through the tunnel. Whether the router applies it is covered further down.
  • AllowedIPs = 0.0.0.0/0 sends all IPv4 traffic from VPN-enabled devices to the VPS. There is no ::/0, because IPv6 entries are what TP-Link tells you to delete.
  • There is no MTU line. On the VPS, the wg-quick man page says that when MTU is not specified, it "is automatically determined from the endpoint addresses or the system default route." TP-Link does not document which MTU the router uses.

Copy the file to your computer. Run this on your computer, with your own user name and VPS address:

scp youruser@203.0.113.10:router-home.conf .

Then delete the copies on the VPS:

rm ~/router-home.conf
sudo rm /etc/wireguard/router-home.key

Now the router's private key exists only in the file on your computer, and on the router after import. Delete the computer copy once the router is connected. If you ever need the file again, generate a new key pair for the router and replace its PublicKey on the VPS.

Import the file in Advanced > VPN Client

The steps below follow FAQ 3772, which uses the Archer AX55 as its example model.

  1. Log in to the router's web interface and go to Advanced > VPN Client.
  2. Enable VPN Client and click SAVE.
  3. Click Add in the upper-right of the Server List.
  4. Enter a description, for example my-vps, and choose WireGuard as the VPN Type.
  5. Click BROWSE, select router-home.conf, then click SAVE.
  6. Enable the new entry in the Server List.
  7. In the VPN Device List, add the devices that should use the tunnel and switch on their VPN Access.

Step 7 is the one people miss. TP-Link's FAQ 3135 says: "Only the devices you add to this list will use the VPN connection." Every other device keeps using your home connection directly.

If the import fails, open the file and look for any line outside the six fields above. Remove a stray MTU line, an IPv6 address in Address, or ::/0 in AllowedIPs first, because those are the parameters TP-Link names as unsupported.

Use one config per router, never shared. TP-Link says it plainly: "It's NOT suggested to use the same configuration file on multiple VPN Clients simultaneously." Two clients with the same private key are one peer to the VPS, so they take the tunnel from each other and only one works at a time. Give any other device, such as your phone or a second router, its own key pair and its own [Peer] block.

Check that traffic really leaves through the VPS

On the VPS:

sudo wg show wg0

The peer should now show latest handshake: with a time in seconds, plus a transfer: line with bytes received and sent. A peer with no handshake line means the router's packets are not arriving. Check UDP 51820 in ufw and in your provider's firewall. Then check the Endpoint address, and check that the keys are not swapped: the router's file holds the router's private key and the server's public key.

On a device you added to the VPN Device List:

curl -4 https://ifconfig.co

It should print the VPS's public IPv4 address. A device that is not on the list should still print your home address.

If the handshake works but VPN devices have no internet, forwarding or NAT is missing. Check that sysctl net.ipv4.ip_forward prints 1, then look at the packet counter on the MASQUERADE rule while a device loads a page:

sudo iptables -t nat -L POSTROUTING -n -v

A counter that stays at zero means the rule never matches. The usual reason is a wrong interface name after -o in before.rules.

If pages load but some sites hang, the cause may be the MTU. You cannot set it in the router file, but you can lower it on the VPS side. Finding the right WireGuard MTU and clamping TCP MSS shows how to test for it.

TP-Link's pages do not answer four questions about client mode. Do not guess. Each one below comes with a test you can run.

Is PersistentKeepalive honoured?

The router's own VPN Server settings have a Persistent Keepalive field, "25 seconds by default". The client-mode import steps never mention it, and PersistentKeepalive is not among the fields in TP-Link's example. The wg man page describes it as an empty packet sent "for the purpose of keeping a stateful firewall or NAT mapping valid persistently", and says it is off by default.

For this setup you do not need it. The router sends first whenever a VPN device sends traffic, so the tunnel always starts from the router's side. Keepalive matters when the VPS must start traffic toward the router, which this guide does not set up.

To test whether your firmware accepts it, add PersistentKeepalive = 25 under [Peer] in the router file and import it again. If the import fails, remove the line. If it imports, switch off VPN Access for every device, so that nothing on the LAN uses the tunnel. Then run this on the VPS twice, a minute apart:

sudo wg show wg0 transfer

If the received bytes grow a little between the two runs while no device uses the tunnel, the router is sending keepalives. If the number does not change, it is not.

Does the DNS line take effect?

TP-Link's example lists DNS as a supported field, but no TP-Link page says what the router does with it. Test it. On the VPS:

sudo apt install -y tcpdump
sudo tcpdump -ni wg0 udp port 53

Then, on a VPN-enabled device, run nslookup for a name you have not looked up before. Lines that contain > 1.1.1.1.53: mean DNS queries are going through the tunnel. No lines at all means this capture saw no matching UDP port 53 traffic on wg0; it does not establish which resolver or path the device used. Press Ctrl+C to stop tcpdump. If DNS does leak this way, fixing DNS over WireGuard covers the server-side options.

Does IPv6 bypass the tunnel?

The router file is IPv4-only. If your home connection also has IPv6, a VPN-enabled device may still send IPv6 traffic straight out over your home connection. TP-Link's VPN pages do not say whether this happens. Test it on a VPN-enabled device:

curl -4 https://ifconfig.co
curl -6 https://ifconfig.co

The first command should print the VPS address. If the second prints an IPv6 address, that address belongs to your home connection, because the tunnel carries no IPv6. That means IPv6 traffic from this device leaves outside the tunnel. If the second command fails with a connection error, it only shows that curl could not connect to that destination; it does not establish that IPv6 routing is unavailable or rule out IPv6 leaks. A server can refuse a connection even when the IPv6 route works. To stop a leak, turn off IPv6 on the device, or in the router's IPv6 settings if your firmware has that option.

Can the VPS reach your home LAN through the tunnel?

This is unknown, and this guide does not try it. TP-Link's FAQ 3637 on LAN devices that cannot be reached over VPN is written for a router acting as the VPN server, not for client mode. Also, the VPS's [Peer] block lists only 10.66.0.2/32, so the VPS would not send traffic for your home subnet to the router in any case. If reaching home is your real goal, use a setup built for it: routing a WireGuard tunnel to your home LAN, or the CGNAT reverse tunnel linked earlier.

Adding a second router

Repeat the key step with a new name, for example router-office. Append a new [Peer] block with its public key and AllowedIPs = 10.66.0.3/32, then build its file with Address = 10.66.0.3/32. Load the new peer without dropping the first router's tunnel:

sudo bash -c 'wg syncconf wg0 <(wg-quick strip wg0)'

Adding a WireGuard peer without restarting the interface explains what syncconf changes and what it leaves alone. The NAT rule already covers the whole 10.66.0.0/24, so the new router needs no firewall change.

FAQ

Yes, if your model offers WireGuard under Advanced > VPN Client. TP-Link says WireGuard is supported on select models only, so check your router's menu. Run the WireGuard server on the VPS, then import a config file that holds only the fields TP-Link's example lists: PrivateKey, Address, DNS, PublicKey, AllowedIPs and Endpoint. Finally, add the devices that should use the tunnel to the VPN Device List and switch on their VPN Access.

TP-Link's FAQ 3772 says a file with unsupported parameters, such as IPv6 addresses or MTU values, must have those lines deleted before import. Remove any MTU line, any IPv6 address from Address, and ::/0 from AllowedIPs. Keep the router's tunnel IPv4-only.

How do I know if my router is behind CGNAT?

Look at the WAN or Internet IP on the router's status page. An address between 100.64.0.0 and 100.127.255.255 is carrier-grade NAT space, reserved by RFC 6598. A WAN address in a private range, such as 192.168.x.x, means another NAT device sits in front of the router. TP-Link says a router acting as a VPN server needs a public IP, so in both cases use VPN Client mode with a VPS instead.

Can I use the same WireGuard config on my phone and my router?

No. TP-Link says: "It's NOT suggested to use the same configuration file on multiple VPN Clients simultaneously." The VPS sees both devices as one peer, so only one of them can use the tunnel at a time. Generate a separate key pair, a separate [Peer] block and a separate tunnel address for each device.

Will my devices leak IPv6 or DNS outside the tunnel?

TP-Link does not document this for client mode, so test it. On a VPN-enabled device, if curl -6 https://ifconfig.co prints an address, IPv6 traffic bypasses the IPv4-only tunnel. A connection error does not rule out IPv6 leaks. On the VPS, sudo tcpdump -ni wg0 udp port 53 shows whether DNS queries cross the tunnel while that device looks up names.

Was this article useful?

#wireguard#tp-link#router#vpn#cgnat