The handshake completes, the client shows a recent transfer counter, and a request to a service on the same server still fails. That combination confuses people because the tunnel is demonstrably working. What has not been demonstrated is local delivery: the packet reached the host, and the host still has to accept it on the right socket and pass it to a process with permission to answer. Work through those three checkpoints in order.

Stop at the first one that does not hold, and do not add rules for the others.

The Handshake Proves Only the Tunnel

WireGuard's handshake establishes keys between peers and authorises traffic for the ranges each peer listed. It says nothing about which processes listen on the server, and nothing about whether the host firewall accepts packets addressed to one of its own addresses.

That last distinction is the one most often missed: traffic to the host itself is local input, while traffic passing through the host to somewhere else is forwarding. They are handled by different firewall chains and by different settings. Checking the wrong chain wastes an afternoon and returns counters that look innocent.

Read the Listener and the Route

On the client, confirm the server's tunnel address routes into the tunnel. On the server, confirm a socket exists on the address the client is using, and that the process behind it is the one you intended.

wg show
ip route get 10.66.0.1
ss -lntup | grep -E ':80|:443'
nft list ruleset | grep -A6 'chain input'
curl -vk --max-time 5 https://10.66.0.1/

A listener on 127.0.0.1 will never answer a request addressed to 10.66.0.1, no matter what the firewall allows. A listener on the wildcard address will, unless a rule blocks it. The socket listing therefore settles half the cases before any rule is examined. Port and address together decide whether a request can land.

Compare the address the client uses with the address the server actually owns on the tunnel interface. A stale configuration on either side produces a request that is correctly routed to a peer that has no such address.

Apply Rules for Local Input, Not Forwarding

If the packet arrives and the socket exists, the remaining boundary is the input policy. A rule that permits forwarding does not permit local delivery, and a rule scoped to one interface may not match the tunnel interface name you expect.

Test with a single permitted port to the intended service rather than opening the host. Then check the application's own authorisation: an allowlist, an account requirement or a bind to a specific hostname can reject a request the network delivered successfully.

Keep certificate checks in place. An unexpected certificate identity is information about which host answered, not an obstacle to bypass. Clicking through it hides the one clue that identifies the wrong service.

Separate Name, Size and Identity Failures

A service that works by address but fails by name is a DNS problem, and the fix belongs in the resolver configuration pushed to the client rather than in the firewall. A service that answers small requests but stalls on larger responses points at packet size and MTU, which is a different investigation entirely.

An HTTPS error naming the wrong host usually means the request reached a different service, often because a proxy or another listener owns that port. Read the certificate subject and compare it with the host you intended to reach. That comparison costs nothing and often ends the investigation.

Record which checkpoint failed: socket, input rule or application policy. That single line distinguishes a network fault from an authorisation decision. It also prevents the next person from opening ports that were never the problem.

Winndannde jowitiiɗe heen