Allow the VPN port in the cloud policy and the handshake can still die on the instance: the guest runs its own filter and its own listener binding, and either can discard what the cloud approved. The reverse happens too, when a host rule permits the port and an upstream policy drops it first. Two owners, two rule sets, one packet path. Walk it in order instead of guessing at the most suspicious layer.

Start at the edge and walk inward

The order is fixed: public endpoint, resource interface, attached cloud policy, guest address, process listener, local input rules. Each stage passes the packet or ends the investigation, which is why starting at the guest wastes the most time.

Forwarded client traffic is a separate stage, inspected after the tunnel is decapsulated. The cloud layer only sees the outer tunnel, so it can approve a connection and still have nothing to do with an inner service request. A tunnel that connects but cannot reach an internal host usually points at forwarding, not a closed port.

Read the cloud policy before touching the guest

Confirm the inbound rule for the VPN port, its protocol, and the source scope that matches your test client. Check the subnet access control list too: a second filter with its own rules and defaults. Both must allow the flow before a packet reaches the instance. An allow in one and a deny in the other is the usual shape of this bug.

Narrow the scope until it means something. Opening the VPN port to the whole internet is easy to prove and hard to defend, while a rule pinned to one address breaks when your test client moves networks. Note the rule identifier and the policy owner, so the next change is traceable to a person.

Confirm the listener, then the input chain

On the instance, check that the VPN process is bound to the address and port you expect, for example with ss -lntp 'sport = :1194'. A daemon bound only to 127.0.0.1 accepts local clients and nothing through the tunnel, which looks exactly like a filtered port from outside.

Then read the local rules in the syntax you would use to change them, such as iptables -S INPUT or nft list chain inet filter input. A rule written to a file but never loaded, or a default drop with no matching accept, discards packets silently. For a forwarding gateway, check the forwarding and reverse-path settings too. They decide what happens to packets routed through the instance rather than addressed to it.

Stateful in one layer, stateless in the next

Security groups remember the flows they permitted and let the responses back in. Subnet access control lists and many host firewalls keep no such state, so a rule that only covers the outbound direction passes the request and drops the reply. Never carry a return-traffic assumption between layers without reading the second layer's rule.

Counters settle it faster than reading every rule in the account. A counter that climbs means the packet arrived and was dropped there, while one frozen at zero means it never got that far; iptables -vnL INPUT and nft list ruleset show those counts when the rules were loaded with counters.

Test with a fresh session, not a live one

Leave the source network and the test profile alone as you compare views, and open a new connection after each change. Reaching the web console on 443 says nothing about whether the VPN daemon is bound to 1194, so test the port you need. An existing session is the worst witness here. It keeps working while every new login is rejected.

Before editing a remote policy, have a way back in that does not depend on the path you are changing. Then open a second administration session alongside the VPN test: one established earlier can outlive the rule that blocks new ones. Record both policy owners so no rebuild restores half the path; if both layers agree and the tunnel still fails, capture at the guest interface and check the address and port the client really uses.

Ũhoro ũhĩtĩte