Troubleshooting WireGuard with Tcpdump

When a WireGuard connection isn’t working, it’s usually one of four things: a WireGuard configuration problem, a firewall problem, a routing problem, or a DNS problem. The tcpdump utility can help you quickly diagnose what kind of problem it is, by identifying where packets are going awry.

For example, say we’re trying to set up a point-to-site WireGuard network, like the one shown by the Point-to-Site WireGuard Configuration guide. In this scenario, we’re trying to access Endpoint B through a WireGuard tunnel from Endpoint A to Host β. We can use tcpdump to identify if packets are being dropped or misdirected at the following points (labeled A1-A6 on Endpoint A, and B1-B8 on Host β):

WireGuard Point-to-Site Connection Between Endpoints A and Host β

In this scenario, Endpoint A has a WireGuard interface wg0, with an IP address of 10.0.0.1, that we want to connect to the wg0 WireGuard interface on Host β, with an IP address of 10.0.0.2. Endpoint A is connected to the Site A LAN (Local Area Network) through its WiFi interface wlan0, with an IP address of 192.168.1.11; and there’s a NAT (Network Address Translation) router with a public IP address of 198.51.100.1 between it and the Internet.

Host β has a WAN (Wide Area Network) interface of eth0, with a public IP address of 203.0.113.2, connected to the Internet. It’s connected to the Site B LAN through a second network interface, eth1, with an IP address of 192.168.200.2. Endpoint B has an IP address of 192.168.200.22 in the Site B LAN; and it’s running a webserver on TCP port 80 that we want to connect to from Endpoint A.

Running Tcpdump

On Endpoint A, run the following command, using the host’s own WireGuard listen port 51821, and the IP address of a host you want Endpoint A to be able to contact via WireGuard — in this example, Endpoint B, with an IP address of 192.168.200.22:

$ sudo tcpdump -niany udp port 51821 or host 192.168.200.22

On Host β, run the following command, this time using Host β’s own WireGuard listen port 51822, and the same IP address:

$ sudo tcpdump -niany udp port 51822 or host 192.168.200.22

While both tcpdump commands are running, open up another terminal on Endpoint A, and attempt to connect from Endpoint A to Endpoint B, using Endpoint B’s IP address:

$ curl 192.168.200.22
Tip

When troubleshooting WireGuard like this, make sure to use always use IP addresses instead of DNS names for any hosts running WireGuard (eg Endpoint A and Host β), and any hosts that you’re trying to access through WireGuard (eg Endpoint B). Using DNS names will only add a confounding factor to your troubleshooting efforts.

First test out everything without DNS names; if it all works as expected, but stops working when you try to access a host by its DNS name instead of IP address, you’ve eliminated all other types of problems, so now you know that you “just” have a DNS problem. In that case, see the Troubleshooting WireGuard DNS Issues article for help.

Tip

When troubleshooting WireGuard like this, don’t use ping (unless it is actually in fact the network service you’re trying to troubleshoot) — instead, test using the network service that you actually want to access directly. For example, if you want to access a webserver, use curl (or a web browser); if you want to access a mailserver, use sendmail (or your regular mail client); etc.

Like DNS, ping will just add another confounding factor to your troubleshooting efforts: Firewalls between Endpoint A, Host β, and Endpoint B (or the firewalls on those hosts themselves) may block ping packets, but allow through connections to the actual network service you’re trying to access — or vice versa: they may allow ping, but block the network service you actually want to access.

When everything is working correctly with the WireGuard connection between Endpoint A and Host β, you’d expect to see the following output from tcpdump on Endpoint A (except for the labels in bold, which we’ve added to mark each key point):

    $ sudo tcpdump -niany udp port 51821 or host 192.168.200.22
    tcpdump: data link type LINUX_SLL2
    tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
    listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
A1. 19:47:20.751416 wg0   Out IP 10.0.0.1.45734 > 192.168.200.22.80: Flags [S], seq 1045811890, win 62167, options [mss 1380,sackOK,TS val 133588375 ecr 0,nop,wscale 6], length 0
A2. 19:47:20.751785 wlan0 Out IP 192.168.1.11.51821 > 203.0.113.2.51822: UDP, length 148
A3. 19:47:20.753212 wlan0 In  IP 203.0.113.2.51822 > 192.168.1.11.51821: UDP, length 92
A4. 19:47:20.753591 wlan0 Out IP 192.168.1.11.51821 > 203.0.113.2.51822: UDP, length 96
A5. 19:47:20.754497 wlan0 In  IP 203.0.113.2.51822 > 192.168.1.11.51821: UDP, length 96
A6. 19:47:20.754516 wg0   In  IP 192.168.200.22.80 > 10.0.0.1.45734: Flags [S.], seq 2143248836, ack 1045811891, win 62643, options [mss 1460,sackOK,TS val 659394353 ecr 133588375,nop,wscale 6], length 0
    19:47:20.754534 wg0   Out IP 10.0.0.1.45734 > 192.168.200.22.80: Flags [.], ack 1, win 972, options [nop,nop,TS val 133588379 ecr 659394353], length 0
    19:47:20.754549 wlan0 Out IP 192.168.1.11.51821 > 203.0.113.2.51822: UDP, length 96
    19:47:20.754587 wg0   Out IP 10.0.0.1.45734 > 192.168.200.22.80: Flags [P.], seq 1:79, ack 1, win 972, options [nop,nop,TS val 133588379 ecr 659394353], length 78: HTTP: GET / HTTP/1.1
    19:47:20.754630 wlan0 Out IP 192.168.1.11.51821 > 203.0.113.2.51822: UDP, length 176
    19:47:20.755411 wlan0 In  IP 203.0.113.2.51822 > 192.168.1.11.51821: UDP, length 96
    19:47:20.755420 wg0   In  IP 192.168.200.22.80 > 10.0.0.1.45734: Flags [.], ack 79, win 978, options [nop,nop,TS val 659394354 ecr 133588379], length 0
    19:47:20.756127 wlan0 In  IP 203.0.113.2.51822 > 192.168.1.11.51821: UDP, length 240
    19:47:20.756144 wg0   In  IP 192.168.200.22.80 > 10.0.0.1.45734: Flags [P.], seq 1:156, ack 79, win 978, options [nop,nop,TS val 659394355 ecr 133588379], length 155: HTTP: HTTP/1.0 200 OK
    19:47:20.756152 wg0   Out IP 10.0.0.1.45734 > 192.168.200.22.80: Flags [.], ack 156, win 970, options [nop,nop,TS val 133588380 ecr 659394355], length 0
    19:47:20.756160 wlan0 In  IP 203.0.113.2.51822 > 192.168.1.11.51821: UDP, length 384
    19:47:20.756170 wg0   In  IP 192.168.200.22.80 > 10.0.0.1.45734: Flags [FP.], seq 156:453, ack 79, win 978, options [nop,nop,TS val 659394355 ecr 133588379], length 297: HTTP
    19:47:20.756179 wlan0 Out IP 192.168.1.11.51821 > 203.0.113.2.51822: UDP, length 96
    19:47:20.756252 wg0   Out IP 10.0.0.1.45734 > 192.168.200.22.80: Flags [F.], seq 79, ack 454, win 966, options [nop,nop,TS val 133588380 ecr 659394355], length 0
    19:47:20.756278 wlan0 Out IP 192.168.1.11.51821 > 203.0.113.2.51822: UDP, length 96
    19:47:20.757068 wlan0 In  IP 203.0.113.2.51822 > 192.168.1.11.51821: UDP, length 96
    19:47:20.757099 wg0   In  IP 192.168.200.22.80 > 10.0.0.1.45734: Flags [.], ack 80, win 978, options [nop,nop,TS val 659394356 ecr 133588380], length 0
    19:47:30.984489 wlan0 Out IP 192.168.1.11.51821 > 203.0.113.2.51822: UDP, length 32

And you’d see the following output from tcpdump on Host β:

    $ sudo tcpdump -niany udp port 51822 or host 192.168.200.22
    tcpdump: data link type LINUX_SLL2
    tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
    listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
B1. 19:47:20.752059 eth0  In  IP 198.51.100.1.51821 > 203.0.113.2.51822: UDP, length 148
B2. 19:47:20.752802 eth0  Out IP 203.0.113.2.51822 > 198.51.100.1.51821: UDP, length 92
B3. 19:47:20.753831 eth0  In  IP 198.51.100.1.51821 > 203.0.113.2.51822: UDP, length 96
B4. 19:47:20.753857 wg0   In  IP 10.0.0.1.45734 > 192.168.200.22.80: Flags [S], seq 1045811890, win 62167, options [mss 1380,sackOK,TS val 133588375 ecr 0,nop,wscale 6], length 0
B5. 19:47:20.753880 eth1  Out IP 192.168.200.2.45734 > 192.168.200.22.80: Flags [S], seq 1045811890, win 62167, options [mss 1380,sackOK,TS val 133588375 ecr 0,nop,wscale 6], length 0
B6. 19:47:20.754071 eth1  In  IP 192.168.200.22.80 > 192.168.200.2.45734: Flags [S.], seq 2143248836, ack 1045811891, win 62643, options [mss 1460,sackOK,TS val 659394353 ecr 133588375,nop,wscale 6], length 0
B7. 19:47:20.754079 wg0   Out IP 192.168.200.22.80 > 10.0.0.1.45734: Flags [S.], seq 2143248836, ack 1045811891, win 62643, options [mss 1460,sackOK,TS val 659394353 ecr 133588375,nop,wscale 6], length 0
B8. 19:47:20.754110 eth0  Out IP 203.0.113.2.51822 > 198.51.100.1.51821: UDP, length 96
    19:47:20.754786 eth0  In  IP 198.51.100.1.51821 > 203.0.113.2.51822: UDP, length 96
    19:47:20.754797 wg0   In  IP 10.0.0.1.45734 > 192.168.200.22.80: Flags [.], ack 1, win 972, options [nop,nop,TS val 133588379 ecr 659394353], length 0
    19:47:20.754806 eth1  Out IP 192.168.200.2.45734 > 192.168.200.22.80: Flags [.], ack 1, win 972, options [nop,nop,TS val 133588379 ecr 659394353], length 0
    19:47:20.754863 eth0  In  IP 198.51.100.1.51821 > 203.0.113.2.51822: UDP, length 176
    19:47:20.754881 wg0   In  IP 10.0.0.1.45734 > 192.168.200.22.80: Flags [P.], seq 1:79, ack 1, win 972, options [nop,nop,TS val 133588379 ecr 659394353], length 78: HTTP: GET / HTTP/1.1
    19:47:20.754886 eth1  Out IP 192.168.200.2.45734 > 192.168.200.22.80: Flags [P.], seq 1:79, ack 1, win 972, options [nop,nop,TS val 133588379 ecr 659394353], length 78: HTTP: GET / HTTP/1.1
    19:47:20.754996 eth1  In  IP 192.168.200.22.80 > 192.168.200.2.45734: Flags [.], ack 79, win 978, options [nop,nop,TS val 659394354 ecr 133588379], length 0
    19:47:20.754999 wg0   Out IP 192.168.200.22.80 > 10.0.0.1.45734: Flags [.], ack 79, win 978, options [nop,nop,TS val 659394354 ecr 133588379], length 0
    19:47:20.755020 eth0  Out IP 203.0.113.2.51822 > 198.51.100.1.51821: UDP, length 96
    19:47:20.755719 eth0  In  IP 192.168.200.22.80 > 192.168.200.2: Flags [P.], seq 1:156, ack 79, win 978, options [nop,nop,TS val 659394355 ecr 133588379], length 155: HTTP: HTTP/1.0 200 OK
    19:47:20.755722 wg0   Out IP 192.168.200.22.80 > 10.0.0.1.45734: Flags [P.], seq 1:156, ack 79, win 978, options [nop,nop,TS val 659394355 ecr 133588379], length 155: HTTP: HTTP/1.0 200 OK
    19:47:20.755743 eth0  Out IP 203.0.113.2.51822 > 198.51.100.1.51821: UDP, length 240
    19:47:20.755750 eth1  In  IP 192.168.200.22.80 > 192.168.200.2.45734: Flags [FP.], seq 156:453, ack 79, win 978, options [nop,nop,TS val 659394355 ecr 133588379], length 297: HTTP
    19:47:20.755756 wg0   Out IP 192.168.200.22.80 > 10.0.0.1.45734: Flags [FP.], seq 156:453, ack 79, win 978, options [nop,nop,TS val 659394355 ecr 133588379], length 297: HTTP
    19:47:20.755773 eth0  Out IP 203.0.113.2.51822 > 198.51.100.1.51821: UDP, length 384
    19:47:20.756453 eth0  In  IP 198.51.100.1.51821 > 203.0.113.2.51822: UDP, length 96
    19:47:20.756461 wg0   In  IP 10.0.0.1.45734 > 192.168.200.22.80: Flags [.], ack 156, win 970, options [nop,nop,TS val 133588380 ecr 659394355], length 0
    19:47:20.756465 eth1  Out IP 192.168.200.2.45734 > 192.168.200.22.80: Flags [.], ack 156, win 970, options [nop,nop,TS val 133588380 ecr 659394355], length 0
    19:47:20.756519 eth0  In  IP 198.51.100.1.51821 > 203.0.113.2.51822: UDP, length 96
    19:47:20.756535 wg0   In  IP 10.0.0.1.45734 > 192.168.200.22.80: Flags [F.], seq 79, ack 454, win 966, options [nop,nop,TS val 133588380 ecr 659394355], length 0
    19:47:20.756539 eth1  Out IP 192.168.200.2.45734 > 192.168.200.22.80: Flags [F.], seq 79, ack 454, win 966, options [nop,nop,TS val 133588380 ecr 659394355], length 0
    19:47:20.756656 eth1  In  IP 192.168.200.22.80 > 192.168.200.2.45734: Flags [.], ack 80, win 978, options [nop,nop,TS val 659394356 ecr 133588380], length 0
    19:47:20.756659 wg0   Out IP 192.168.200.22.80 > 10.0.0.1.45734: Flags [.], ack 80, win 978, options [nop,nop,TS val 659394356 ecr 133588380], length 0
    19:47:20.756676 eth0  Out IP 203.0.113.2.51822 > 198.51.100.1.51821: UDP, length 96
    19:47:30.984753 eth0  In  IP 198.51.100.1.51821 > 203.0.113.2.51822: UDP, length 32

A1. On initiating host, before packet is encrypted

The first entry you should see from tcpdump on Endpoint A is the following:

19:47:20.751416 wg0   Out IP 10.0.0.1.45734 > 192.168.200.22.80: Flags [S], seq 1045811890, win 62167, options [mss 1380,sackOK,TS val 133588375 ecr 0,nop,wscale 6], length 0

This entry indicates that Endpoint A is attempting to initiate a TCP connection from its WireGuard address of 10.0.0.1 to port 80 of Endpoint B’s IP address, 192.168.200.22, which will go out Endpoint A’s wg0 interface.

Problem signs:

No tcpdump entry

If you see nothing from tcpdump on Endpoint A, you have a routing problem: Endpoint A doesn’t have a usable route for Endpoint B’s IP address of 192.168.200.22. First run the wg command on Endpoint A to double-check that its WireGuard interface is up, and that 192.168.200.22 is included its AllowedIPs address ranges; then try running the ip route and ip rule commands on Endpoint A to debug its routes and policy-routing rules.

Wrong interface name

If you see an interface name other than wg0 in this entry, you have a routing problem: Endpoint A isn’t routing Endpoint B’s IP address of 192.168.200.22 to WireGuard. First run the wg command on Endpoint A to double-check that its WireGuard interface is up, and that 192.168.200.22 is included its AllowedIPs address ranges; then try running the ip route and ip rule commands on Endpoint A to debug its routes and policy-routing rules.

A2. On initiating host, sending WireGuard handshake

The second entry you should see from tcpdump on Endpoint A is the following:

19:47:20.751785 wlan0 Out IP 192.168.1.11.51821 > 203.0.113.2.51822: UDP, length 148

This entry indicates that Endpoint A is attempting to send a UDP packet from its LAN address of 192.168.1.11 to Host β’s public address of 203.0.113.2 at Host β’s WireGuard listen port of 51822. The packet will go out Endpoint A’s own WireGuard port of 51821, using its wireless network interface wlan0.

This is the WireGuard handshake initiation packet. However, if Endpoint A and Host β have already successfully completed a handshake in the last 2 minutes, you won’t see this entry (or B1 or B2 or A3) — you’ll instead see A4.

Problem signs:

No tcpdump entry

First double-check the A1 entry for problems; if it looks good, but Endpoint A and Host β haven’t yet successfully completed a handshake, and you don’t see this entry, you may have a WireGuard configuration problem: Run the wg command on Endpoint A to check that you have an Endpoint set for Host β (and that it is Host β’s correct public IP address and WireGuard listen port: 203.0.113.2:51822 in this example).

Otherwise if you don’t see this tcpdump entry, you may have a routing problem: Endpoint A may not have a usable route for Host β’s IP address of 203.0.113.2. Try running the ip route and ip rule commands on Endpoint A to debug its routes and policy-routing rules.

Wrong destination address or port

If you see a destination IP address other than Host β’s public address of 203.0.113.2, or a destination port other than Host β’s WireGuard listen port of 51822, you have a WireGuard configuration problem: Correct the Endpoint setting for Host β in Endpoint A’s WireGuard config file, and restart the WireGuard interface.

Tip

One side of every WireGuard connection must have a publicly-accessible IP address and WireGuard listen port, and the other side must be pre-configured with that address and port as its Endpoint setting. In this example, Host β has a publicly-accessible IP address and WireGuard listen port, and Endpoint A does not, so Endpoint A must be pre-configured with Host β’s address and port.

If Endpoint A had a publicly-accessible IP address and WireGuard listen port, and Host β did not, Host β would have to be pre-configured with Endpoint A’s address and port — and Host β would also have to be configured with PersistentKeepalive setting, to proactively initiate a WireGuard connection with Endpoint A and keep it alive (ensuring that Endpoint A is dynamically set with a usable endpoint for Host β).

Wrong length

If this packet’s data length is not exactly 148 bytes, it’s not a WireGuard handshake initiation packet. Most likely, a WireGuard handshake between Endpoint A and Host β has already occurred in last 2 minutes, and this is actually an encrypted WireGuard data packet — the A4 tcpdump entry.

Repeated entries

If you see the exact same A2 entry repeated about 20 times in a row, spaced 5 seconds apart, first check the B1 and B2 tcpdump entries on Host β. If they are both present and look good, follow the advice under the “No tcpdump entry” heading for the A3 entry.

B1. On receiving host, receiving WireGuard handshake

The first entry you should see from tcpdump on Host β is the following:

19:47:20.752059 eth0  In  IP 198.51.100.1.51821 > 203.0.113.2.51822: UDP, length 148

This entry indicates that Host β has received a UDP packet sent from Endpoint A’s public address of 198.51.100.1 (technically the WAN address of the NAT router in front of Endpoint A) to Host β’s WAN address of 203.0.113.2 and WireGuard listen port of 51822 on Host β’s eth0 interface.

This is the WireGuard handshake initiation packet. If Endpoint A and Host β have already successfully completed a handshake in the last 2 minutes, you won’t see this entry (or A2 or B2 or A3) — instead you’ll see B3.

Problem signs:

No tcpdump entry

First double-check the A2 entry on Endpoint A for problems; if it looks good, but Endpoint A and Host β haven’t yet successfully completed a handshake, and you don’t see this entry, you either have a firewall problem or a routing problem in the networks between Endpoint A and Host β: Try checking any firewalls or routers in front of Host β to which you have access. Make sure any such firewalls allow forwarding new connections at least to Host β’s UDP port 51822 and public IP address of 203.0.113.2 from Endpoint A’s public IP address of 198.51.100.1.

If it’s not a firewall or routing problem between networks, it could possibly be a routing problem on Host β: Try running the ip route get 198.51.100.1 command on Host β to ensure that a) it has a route to Endpoint A, and b) this route goes out Host β’s WAN network interface, eth0.

Wrong length

If this packet’s data length is not exactly 148 bytes, it’s not a WireGuard handshake initiation packet. Most likely, a WireGuard handshake between Endpoint A and Host β has already occurred in last 2 minutes, and this is actually an encrypted WireGuard data packet — the B3 tcpdump entry.

B2. On receiving host, sending WireGuard handshake reply

The second entry you should see from tcpdump on Host β is the following:

19:47:20.752802 eth0  Out IP 203.0.113.2.51822 > 198.51.100.1.51821: UDP, length 92

This entry indicates that Host β is attempting to send a UDP packet from its WAN address of 203.0.113.2 and WireGuard listen port of 51822. This packet will be sent to the exact same source address and port from which B1 was received, regardless of any Endpoint setting for Endpoint A in Host β’s WireGuard config.

This is the WireGuard handshake response packet. If Endpoint A and Host β have already successfully completed a handshake in the last 2 minutes, you won’t see this entry (or A2 or B1 or A3).

Problem signs:

No tcpdump entry

If Endpoint A and Host β haven’t yet successfully completed a handshake, and you don’t see this entry, you either have a WireGuard configuration problem, or a firewall problem on Host β: First, run the wg command on Host β to check that you have a peer configured for Endpoint A.

If you have a peer configured on Host β for Endpoint A, also run the wg command on Endpoint A to compare the keys shown it its output to that of Host β. The public key listed for the interface in the output on Endpoint A should match the peer for Endpoint A listed in the output on Host β; and vice versa. If correctly configured, you should see a match like the following:

justin@endpoint-a:~$ sudo wg
interface: wg0
  public key: /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU=
  private key: (hidden)
  listening port: 51821

peer: fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
  endpoint: 203.0.113.2:51822
  allowed ips: 192.168.200.0/24
  transfer: 0 B received, 148 B sent
justin@host-b:~$ sudo wg
interface: wg0
  public key: fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
  private key: (hidden)
  listening port: 51822

peer: /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU=
  allowed ips: 10.0.0.1/32

Also, if you’re using a preshared key for this WireGuard connection, check the WireGuard config file on both Endpoint A and Host β to verify that the PresharedKey setting for the corresponding peer is identical in both config files.

If the WireGuard keys match, try running the iptables-save and nft list ruleset commands on Host β to debug problems with its own host-based firewall. Make sure Host β’s own firewall allows inbound access for new connections to its eth0 interface, at least for its UDP port 51822, from Endpoint A’s public IP address of 198.51.100.1.

Wrong interface name

If you see an interface name other than eth0 in this tcpdump entry (ie a different interface than the B1 entry), you may have a routing problem: Host β isn’t routing Endpoint A’s public IP address of 198.51.100.1 out the same interface from which Endpoint A’s packets are coming in. Unless this is an deliberate routing choice you have made, try running the ip route and ip rule commands on Host β to debug its routes and policy-routing rules.

Wrong length

If this packet’s data length is not exactly 92 bytes, it’s not a WireGuard handshake response packet. Most likely, a WireGuard handshake between Endpoint A and Host β has already occurred in last 2 minutes, and this is some other packet. If this entry matches the example above perfectly except for the data length, then it is actually an encrypted WireGuard data packet being sent from Host β to Endpoint A — the B8 tcpdump entry.

A3. On initiating host, receiving WireGuard handshake reply

The third entry you should see from tcpdump on Endpoint A is the following:

19:47:20.753212 wlan0 In  IP 203.0.113.2.51822 > 192.168.1.11.51821: UDP, length 92

This entry indicates that Endpoint A has received a UDP packet sent from Host β’s address of 203.0.113.2 to its WireGuard listen port of 51821 on its wlan0 interface.

This is the WireGuard handshake response packet. If Endpoint A and Host β have already successfully completed a handshake in the last 2 minutes, you won’t see this entry (or A2 or B1 or B2).

Problem signs:

No tcpdump entry

First double-check the B2 entry on Host β for problems; if it looks good, but Endpoint A and Host β haven’t yet successfully completed a handshake, and you don’t see this entry, you either have a firewall problem or a routing problem in the networks between Host β and Endpoint A: Try checking any firewalls or routers in front of Endpoint A to which you have access. Make sure any such firewalls allow forwarding established connections at least to Endpoint A’s UDP port 51821 and public IP address of 198.51.100.1 (or LAN address of 192.168.1.11 for the path between Endpoint A and its NAT router) from Host β’s public IP address of 203.0.113.2.

Wrong length

If this packet’s data length is not exactly 92 bytes, it’s not a WireGuard handshake response packet. Most likely, a WireGuard handshake between Endpoint A and Host β has already occurred in last 2 minutes, and this is actually an encrypted WireGuard data packet — the A5 tcpdump entry.

Repeated entries

If you see the exact same A2 and A3 entries repeated one after the other about 20 times, you have a firewall problem on Endpoint A: Try running the iptables-save and nft list ruleset commands on Endpoint A to debug problems with its own host-based firewall. Make sure Endpoint A’s own firewall allows inbound access for established connections to its wlan0 interface, at least for its UDP port 51821, from Host β’s public IP address of 203.0.113.2.

A4. On initiating host, sending encrypted packet

The fourth entry you should see from tcpdump on Endpoint A is the following:

19:47:20.753591 wlan0 Out IP 192.168.1.11.51821 > 203.0.113.2.51822: UDP, length 96

This entry indicates that Endpoint A is attempting to send its first encrypted WireGuard data packet from its LAN address of 192.168.1.11 to Host β’s public address of 203.0.113.2 at Host β’s WireGuard listen port of 51822. The packet will go out Endpoint A’s own WireGuard port of 51821, using its wireless network interface wlan0.

The data payload of this packet is the original TCP packet from the A1 entry, encrypted and wrapped as a UDP packet. If you see an entry for this packet (and the packet length is not 148), the WireGuard handshake between Endpoint A and Host β has completed successfully.

Problem signs:

No tcpdump entry

First double-check the B2 entry on Host β for problems; if it looks good, but Endpoint A and Host β haven’t yet successfully completed a handshake, and you don’t see this entry, you have a firewall problem on Endpoint A: Try running the iptables-save and nft list ruleset commands on Endpoint A to debug problems with its own host-based firewall. Make sure Endpoint A’s own firewall allows inbound access for established connections to its wlan0 interface, at least for its UDP port 51821, from Host β’s public IP address of 203.0.113.2.

Wrong length

This packet’s data length will vary based on the underlying data it’s encrypting, but if its length is exactly 148 bytes, it’s probably actually a WireGuard handshake attempt, and this is actually another A2 entry. If WireGuard on Endpoint A does not receive a successful handshake response, you will see about 20 A2 entries, spaced 5 seconds apart, as WireGuard tries again and again to initiate a handshake with Host β. If you see these entries interspersed with corresponding A3 entries, you have a firewall problem on Endpoint A (see above). If don’t see any A3 entries, you have a firewall or routing problem between Host β and Endpoint A (see A3).

B3. On receiving host, receiving encrypted packet

The third entry you should see from tcpdump on Host β is the following:

19:47:20.753831 eth0  In  IP 198.51.100.1.51821 > 203.0.113.2.51822: UDP, length 96

This entry indicates that Host β has received its first encrypted WireGuard data packet sent from Endpoint A’s public address of 198.51.100.1 to Host β’s WAN address of 203.0.113.2 and WireGuard listen port of 51822 on Host β’s eth0 interface.

The data payload of this packet is the original TCP packet from the A1 entry, encrypted and wrapped as a UDP packet. If you see the A4 entry sent on Endpoint A (and its packet length is not 148), you should always see this corresponding entry received.

Problem signs:

Wrong length

This packet’s data length will vary based on the underlying data it’s encrypting, but if its length is exactly 148 bytes, it’s probably actually a WireGuard handshake attempt, and this is actually another B1 entry. If WireGuard on Endpoint A does not receive a successful handshake response, you may see about 20 B1 entries, spaced 5 seconds apart, as WireGuard tries again and again to initiate a handshake with Host β. If you see these entries interspersed with corresponding B2 entries, you likely have a firewall or routing problem between Host β and Endpoint A (see A3). If you don’t see any B2 entries, you likely have a firewall or WireGuard configuration problem on Host β (see B1).

B4. On receiving host, after packet is decrypted

The fourth entry you should see from tcpdump on Host β is the following:

19:47:20.753857 wg0   In  IP 10.0.0.1.45734 > 192.168.200.22.80: Flags [S], seq 1045811890, win 62167, options [mss 1380,sackOK,TS val 133588375 ecr 0,nop,wscale 6], length 0

This entry should mirror the original A1 entry from Endpoint A, indicating that Host β has received its first data packet through its WireGuard tunnel, and decrypted it successfully. It should show a TCP packet incoming through Host β’s wg0 interface, from Endpoint A’s WireGuard address of 10.0.0.1, with a destination of Endpoint B’s LAN address of 192.168.200.22, on port 80.

Problem signs:

No tcpdump entry

If you see the B3 entry, but not this entry, you have a WireGuard configuration problem: Run the wg command on Host β to check that its AllowedIPs setting for Endpoint A includes Endpoint A’s WireGuard address of 10.0.0.1.

B5. On receiving host, forwarding packet

The fifth entry you should see from tcpdump on Host β is the following:

19:47:20.753880 eth1  Out IP 192.168.200.2.45734 > 192.168.200.22.80: Flags [S], seq 1045811890, win 62167, options [mss 1380,sackOK,TS val 133588375 ecr 0,nop,wscale 6], length 0

It should show essentially the same packet details as the B4 entry, but this entry should show the packet going out Host β’s LAN network interface eth1; and if you’re using NAT on Host β to masquerade connections from Endpoint A with Host β’s own LAN address, as we are in this example, the packet’s source IP address should be Host β’s LAN address of 192.168.200.2 (instead of Endpoint A’s WireGuard address of 10.0.0.1).

Note

In a WireGuard Hub-and-Spoke Configuration, where Endpoint A is using Host β as a central hub to forward connections to other endpoints also using WireGuard, this entry should show the packet leaving out its WireGuard interface wg0, instead of eth1. Also, you usually wouldn’t be using NAT in that scenario, so the packet’s source IP address should remain 10.0.0.1.

Note

In a WireGuard Point-to-Point Configuration, where Endpoint A is simply trying to connect to a network service on Host β itself, instead of using Host β to forward its connections on to other hosts, you won’t see this entry, or B6 — the next entry you see on Host β should be B7.

Problem signs:

No tcpdump entry

If you see the B4 entry, but not this entry, you either have a firewall problem or a routing problem on Host β. First run the sysctl net.ipv4.conf.all.forwarding command on Host β to check that you’re allowing any IPv4 packet forwarding at all (the output should have a value of 1, indicating that forwarding is allowed).

If packet forwarding is allowed, try running the iptables-save and nft list ruleset commands on Host β to debug problems with its firewall (the output should show that it allows at minimum the forwarding of new connections to TCP port 80 of Endpoint B’s LAN address of 192.168.200.22, using Host β’s LAN interface eth1, from Endpoint A’s WireGuard address of 10.0.0.1, using Host β WireGuard interface wg0).

Tip

Consult the “Configure Firewall on Host β” section of the Point-to-Site WireGuard Configuration guide, or the “Point to Site” section of the How to Use WireGuard with Nftables guide, for a detailed explanation of the firewall rules you should be using with this example.

If it’s not a firewall problem, try running the ip route get 192.168.200.22 command on Host β to ensure that a) it has a route to Endpoint B, and b) this route goes out Host β’s LAN network interface, eth1.

Wrong source address

If you’re expecting to use SNAT (Source Network Address Translation, aka packet masquerading) with this connection, you should see the source address change between the B4 entry and this one (in this example, we’re using SNAT to translate Endpoint A’s WireGuard address of 10.0.0.1 to Host β’s own LAN address of 192.168.200.2). If it’s not being translated to the correct address, you have a firewall problem: Try running the iptables-save and nft list ruleset commands on Host β to debug problems with its firewall rules.

Wrong destination address

If you’re expecting to use DNAT (Destination Network Address Translation, aka port forwarding) with this connection, you should see the destination address change between the B4 entry and this one (however, in this example, we’re not using DNAT, so we should see no changes). If it’s not being translated to the correct address, you have a firewall problem: Try running the iptables-save and nft list ruleset commands on Host β to debug problems with its firewall rules.

B6. On receiving host, forwarding packet reply

The sixth entry you should see from tcpdump on Host β is the following:

19:47:20.754071 eth1  In  IP 192.168.200.22.80 > 192.168.200.2.45734: Flags [S.], seq 2143248836, ack 1045811891, win 62643, options [mss 1460,sackOK,TS val 659394353 ecr 133588375,nop,wscale 6], length 0

This entry should show the reply from Endpoint B, with a new packet coming in Host β’s LAN interface eth1 from Endpoint B’s LAN IP address 192.168.200.22. If you’re using NAT on Host β to masquerade connections from Endpoint A with Host β’s own LAN address, as we are in this example, the packet’s destination IP address should be Host β’s LAN address of 192.168.200.2 — the packet’s source and destination should be reversed exactly between this entry and B5.

Note

In a WireGuard Hub-and-Spoke Configuration, where Endpoint A is using Host β as a central WireGuard hub to forward connections to other WireGuard endpoints, you should see at least two more entries on Host β between B5 and this entry, showing encrypted WireGuard packets being sent between Host β and Endpoint B.

For example, if Endpoint B was not in the Site B LAN, and instead was a remote host accessible somewhere on the Internet at 192.0.2.3, with a WireGuard listen port of 51823, you should see at least the following entries between B5 and this entry:

19:47:20.753991 eth0  Out IP 203.0.113.2.51822 > 192.0.2.3.51823: UDP, length 176
19:47:20.754002 eth0  In  IP 192.0.2.3.51823 > 203.0.113.2.51822: UDP, length 96

You may also see additional packets sent between Host β and Endpoint B for their own WireGuard handshake, if 2 minutes or more has elapsed since they last exchanged a handshake. However, if you don’t see any additional entries, it may mean the WireGuard connection between Host β and Endpoint B is itself not working — if so, you should stop and debug it separately before continuing on.

Also, with a hub-and-spoke configuration, this entry should show the packet coming in wg0 instead of eth1; and you usually wouldn’t be using NAT in a hub-and-spoke scenario, so the packet’s destination IP address should be 10.0.0.1.

Note

In a WireGuard Point-to-Point Configuration, where Endpoint A is simply trying to connect to a network service on Host β, instead of using Host β to forward its connections on to other hosts, you won’t see this entry, or B5 — the next entry you see on Host β should be B7.

Problem signs:

No tcpdump entry

First double-check the B5 entry for problems; if it looks good, you either have a firewall problem or a routing problem at the Site B LAN (or in the networks between Host β and Endpoint B, if they are not simply on the same LAN), or on Endpoint B itself.

If you are using NAT on Host β to masquerade connections from Endpoint A with Host β’s own LAN address, as we are in this example, connections from Endpoint A should appear to the Site B LAN as if they were coming from Host β’s own LAN address of 192.168.200.2. In that case, check that any firewalls between Host β and Endpoint B allow new connections to be forwarded from 192.168.200.2 to TCP port 80 of Endpoint B’s IP address 192.168.200.22; and on Endpoint B, check that its own host-based firewall allows new incoming connections on its LAN network interface from 192.168.200.2 to TCP port 80.

If, unlike this example, you’re not using NAT on Host β, connections from Endpoint A will appear to the Site B LAN as if they were coming from Endpoint A’s WireGuard address of 10.0.0.1. In that case, check that the Site B LAN is configured to route 10.0.0.1 back to Host β’s LAN address of 192.168.200.2, and that any firewalls between Host β and Endpoint B allow new connections to be forwarded from 10.0.0.1 to TCP port 80 of Endpoint B’s IP address 192.168.200.22; and on Endpoint B, check that its own host-based firewall allows new incoming connections on its LAN network interface from 10.0.0.1 to TCP port 80.

B7. On receiving host, before packet reply is encrypted

The seventh entry you should see from tcpdump on Host β is the following:

19:47:20.754079 wg0   Out IP 192.168.200.22.80 > 10.0.0.1.45734: Flags [S.], seq 2143248836, ack 1045811891, win 62643, options [mss 1460,sackOK,TS val 659394353 ecr 133588375,nop,wscale 6], length 0

It should show essentially the same packet details as the B6 entry, but this entry should show the packet going out Host β’s WireGuard network interface wg0; and if you’re using NAT on Host β to masquerade connections from Endpoint A with Host β’s own LAN address, as we are in this example, the packet’s destination IP address will be changed back to Endpoint A’s WireGuard address of 10.0.0.1 (if you’re not using NAT, then the destination address would have been 10.0.0.1 in the B6 entry, as well).

Note

In a WireGuard Point-to-Point Configuration, where Endpoint A is simply trying to connect to a network service on Host β itself, instead of using Host β to forward its connections on to other hosts, you should see this entry directly after B4. If you don’t, you have a firewall problem on Host β: Try running the iptables-save and nft list ruleset commands on Host β to debug problems with its firewall (the output should show that it allows at minimum incoming connections from Endpoint A’s WireGuard address of 10.0.0.1, using Host β’s WireGuard interface wg0, to TCP port 80 or whatever network service to which Endpoint A is trying to connect).

Problem signs:

No tcpdump entry

If you see the B6 entry, but not this entry, you have a firewall problem on Host β. Try running the iptables-save and nft list ruleset commands on Host β to debug problems with its firewall (the output should show that it allows at minimum the forwarding of established connections to Endpoint A’s WireGuard address of 10.0.0.1, using Host β’s WireGuard interface wg0, from Endpoint B’s LAN address of 192.168.200.22, using Host β’s LAN interface eth1).

Wrong interface name

If you see an interface name other than wg0 in this entry, you have a routing problem: Host β isn’t routing Endpoint A’s WireGuard address of 10.0.0.1 to WireGuard. Try running the ip route and ip rule commands on Host β to debug its routes and policy-routing rules.

B8. On receiving host, sending encrypted packet reply

The eighth entry you should see from tcpdump on Host β is the following:

19:47:20.754110 eth0  Out IP 203.0.113.2.51822 > 198.51.100.1.51821: UDP, length 96

This entry shows Host β sending an encrypted WireGuard data packet out its WAN network interface eth0 from its public IP address 203.0.113.2 back to Endpoint A’s public IP address 198.51.100.1. The data payload of this packet is the TCP packet from the B7 entry, encrypted and wrapped as a UDP packet.

If this entry doesn’t match what you’re seeing, go back and double-check previous entries — there should be a tell-tale sign of the problem in an earlier entry.

A5. On initiating host, receiving encrypted packet reply

The fifth entry you should see from tcpdump on Endpoint A is the following:

19:47:20.754497 wlan0 In  IP 203.0.113.2.51822 > 192.168.1.11.51821: UDP, length 96

This entry shows Endpoint A has received an encrypted WireGuard data packet on UDP port 51821 of its wlan0 interface from Host β’s public IP address 203.0.113.2. The data payload of this packet is the TCP packet from the B7 entry, encrypted and wrapped as a UDP packet.

Problem signs:

Wrong length

This packet’s data length will vary based on the underlying data it’s encrypting, but if its length is exactly 92 bytes, it’s probably actually a WireGuard handshake response, and this is actually another A3 entry. If you see multiple handshake-initiation A2 entries interspersed with multiple handshake-response A3 entries, you have a firewall problem on Endpoint A: Try running the iptables-save and nft list ruleset commands on Endpoint A to debug problems with its own host-based firewall. Make sure Endpoint A’s own firewall allows inbound access for established connections to its wlan0 interface, at least for its UDP port 51821, from Host β’s public IP address of 203.0.113.2.

A6. On initiating host, after packet is decrypted

The sixth entry you should see from tcpdump on Endpoint A is the following:

19:47:20.754516 wg0   In  IP 192.168.200.22.80 > 10.0.0.1.45734: Flags [S.], seq 2143248836, ack 1045811891, win 62643, options [mss 1460,sackOK,TS val 659394353 ecr 133588375,nop,wscale 6], length 0

This entry should mirror the B7 entry from Host β, indicating that Endpoint A has received its first data packet response through its WireGuard tunnel, and has decrypted it successfully. The entry should show a TCP packet incoming through Endpoint A’s wg0 interface, from port 80 of Endpoint B’s LAN address of 192.168.200.22, with a destination of Endpoint A’s WireGuard address of 10.0.0.1.

Problem signs:

Repeated entries

If you see the same exact A5 and A6 entries repeated several times (and no other entries besides keepalive entries), you have a firewall problem on Endpoint A: Try running the iptables-save and nft list ruleset commands on Endpoint A to debug problems with its firewall (the output should show that it allows at minimum established connections incoming to Endpoint A’s WireGuard interface wg0 from Endpoint B’s LAN address of 192.168.200.22).

Application receives nothing

If this tcpdump entry looks good, but the underlying application (eg curl) does not report receiving anything, you have a firewall problem on Endpoint A: Try running the iptables-save and nft list ruleset commands on Endpoint A to debug problems with its firewall (the output should show that it allows at minimum established connections incoming to Endpoint A’s WireGuard interface wg0 from Endpoint B’s LAN address of 192.168.200.22).

Keepalive packets

The rest of the entries in the example tcpdump output either show additional UDP WireGuard data packets being sent back and forth between Endpoint A and Host β, or show the underlying TCP packets that are being tunneled through WireGuard. You’ll see lots of this traffic once your WireGuard connection is up and working.

The lone exceptions to this are the last entries shown for Endpoint A and Host β: they are small “keepalive” packets that you may see when the WireGuard connection is otherwise inactive.

In the Endpoint A tcpdump output, the last entry is the following:

19:47:30.984489 wlan0 Out IP 192.168.1.11.51821 > 203.0.113.2.51822: UDP, length 32

And in the Host β tcpdump output, the last entry is the following:

19:47:30.984753 eth0  In  IP 198.51.100.1.51821 > 203.0.113.2.51822: UDP, length 32

These packets are recognizable because they’re UDP packets of length 32, sent between the two WireGuard listen ports of 51821 and 51822.

You’ll see these packets only if the WireGuard handshake has previously been completed successfully. WireGuard will send a keepalive automatically a few seconds after any burst of traffic from one side or the other, to try to keep the connection open through stateful firewalls in case the other side still has some packets left it wants to send.

Also, if you configure the PersistentKeepalive setting for a peer, WireGuard will repeatedly send a keepalive packet from the configured side of the connection every X seconds after the last data (or keepalive) packet was previously sent (where X is the value of the PersistentKeepalive setting) — keeping the connection open indefinitely.