The client says connected, the resource still refuses, and the usual next move is to switch something off. Both controls in that sentence do different jobs: the VPN builds a path for covered traffic, and a firewall decides per connection whether the traffic may pass. A working tunnel with a refusing policy looks exactly like a broken tunnel from the user's chair, so the job is to find which layer is answering. Here is the order I run, with the reading that tells you to stop.

Separate the path from the policy

Start with the shape of the failure, because it is free information. A drop produces a timeout: the client retries, nothing comes back, and the command hangs until it gives up. A rejection produces a refusal or a reset: something answered and said no. A service that is not listening refuses on the host itself, with no firewall involved at all.

Those three outcomes point at different layers. Timeout means a policy somewhere is discarding silently, or the route never leaves the machine. Refused means you reached the host and its stack or its host firewall declined. Nothing at all, with the tunnel interface up and no route to the destination, means the path is wrong and no firewall rule will fix it.

Read the path in one pass

Confirm the tunnel covers the destination before you look at a single rule. A split tunnel that only carries the office subnet will not route a request to a different range, and the failure then looks like a firewall block that is not one:

ip route get 10.20.4.15
ip -brief address show
wg show
sudo ipsec statusall

The route output names the interface the packet will leave by and the source address it will carry. If that interface is your physical NIC rather than the tunnel, the problem is routing or the tunnel's allowed ranges, and it belongs to the VPN configuration rather than to the firewall.

One VPN-specific trap deserves its own check. In WireGuard, a peer's AllowedIPs is both a route and a cryptographic filter: a packet whose source address does not match the peer's allowed set is dropped before any firewall rule is consulted. So a perfectly correct host firewall can sit behind a silent drop that looks like a policy, and the fix is a key configuration line rather than a rule.

Read the policy at the layer that answers

Once the path is right, walk the policy from the host outward and watch for the one layer whose counters move:

ss -ltn | grep ':443'
sudo nft list ruleset
sudo iptables -S INPUT
sudo ufw status verbose

The listening socket answers a different question than the rules do. If nothing is listening on the port, the connection is refused by the kernel and no inbound rule is relevant. If the socket exists and the connection times out from a remote client, a drop is happening somewhere on the path, and the rule counters tell you whether it is happening here.

Turn on logging for the profile or chain you suspect rather than guessing from the outside. A single logged drop that names the source, destination and port identifies the layer and the rule, and it also proves the packet arrived, which no amount of client-side testing can establish.

Read the gateway decision when the tunnel ends there

On a site-to-site or remote-access gateway, the VPN authenticates a user and the policy authorizes a resource, and those are separate grants. A user who is allowed into the tunnel is not automatically allowed to every internal host, and the refusal often comes from a forwarding rule while the tunnel itself is healthy. The same separation appears in IPsec, where the security policy that selects traffic is distinct from the filter that admits it, which is why the two are documented as different mechanisms in RFC 4301.

Check the return path as carefully as the outbound one. Stateful filtering needs to see the reply, so asymmetric routing through the tunnel in one direction and around it in the other produces drops that look random and reproduce only from some clients. If traffic reaches the gateway and stops, read the forwarding rule and the return route together before you widen anything.

The gateway is also where a NAT or masquerade rule can hide the real source. If internal hosts see the gateway address instead of the client, their host firewall rules that match the client pool will never match, and the fix belongs on the gateway rather than on each server.

Change the narrowest layer, then verify

Resist the broad repair. Disabling the host firewall, adding an allow-any rule, or forcing every interface into a trusted profile each removes the control that was doing its job, and the change outlives the incident. A rule scoped to the source range and the port in question is easier to review, easier to remove, and leaves the rest of the machine's policy intact.

Verify with the same test that failed, from the same client, and then once more after a reconnect, because a rule that matches before the tunnel renegotiates can stop matching after it:

nc -vz 10.20.4.15 443
curl -v --max-time 5 https://10.20.4.15/

Before you close it out:

  • The route to the destination leaves by the tunnel interface, and the source address matches what the policy expects.
  • Something listens on the port, and the refusal or timeout is attributed to a named rule rather than assumed.
  • The gateway forwards in both directions, and the destination sees the source your rules were written for.
  • No control was disabled to make the test pass, and the change you made names one source range and one port.

সম্পৰ্কিত প্ৰবন্ধ