A VPN that connects but reaches nothing is usually described as a firewall problem, and the fix people reach for is putting the tunnel interface into a trusted zone. That works, in the sense that traffic starts flowing, and it also admits far more than the intended service. The two policies involved are different: one admits the outer transport to a listening socket, and the other authorizes decrypted traffic to reach a specific resource. Treating them as one setting is what turns a narrow allowance into a wide one. The two are decided in different places, which is why the mistake is so easy to make.

Two policies, one tunnel

The outer policy answers a simple question: may a packet from this source reach UDP 1194 on this host? The inner policy answers a different one: may the authenticated client behind that tunnel reach this destination, by this protocol, on this port? The first is about a socket, the second is about a path, and firewalld models them with different objects because they are decided at different points. One is a property of a socket on this host, the other of a path through it.

The practical consequence is that a working tunnel tells you nothing about the second policy, and a correct second policy does not make the first one unnecessary.

Admit the actual outer listener

Start by inspecting what is already assigned rather than assuming. Read the active zones, list the zone that actually carries ingress, and check the installed service definition, because a service name describes a set of ports and says nothing about whether this server's listener matches it.

firewall-cmd --get-active-zones
firewall-cmd --zone=public --list-all
firewall-cmd --info-service=openvpn

If the listener is genuinely UDP 1194 on that zone, open that port and transport specifically, then persist the same specific rule once you have tested it. Check source-based assignments too, since a zone bound to a source range can capture the traffic before the interface zone ever sees it.

Authorize the decrypted destination separately

A connection to a service running on the VPN server itself is local-input policy. A connection forwarded to another host on the LAN needs forwarding policy, forwarding enabled in the kernel, and a reply route, which are three separate requirements that people commonly collapse into one. Modern firewalld policy objects describe directed traffic between an ingress zone and an egress zone, and that is the right place to express which VPN sources may reach which private services.

Define the permitted sources explicitly and let everything else fall through to a denial. An allowance for the outer service is not that policy, no matter how the zone layout looks.

Why trusting the interface is the wrong shortcut

Putting the tunnel interface into a zone whose target accepts everything admits all decrypted traffic to every service the host exposes, including ones you have not reviewed. Retargeting the trusted zone to be restrictive on a live machine is worse, because other interfaces and source ranges may already depend on its meaning and will change behaviour when you edit it. If you need a narrow policy, create one; do not repurpose a shared zone.

Also keep the tunnel's zone assignment stable through whatever component owns that configuration. Losing the assignment on restart produces a failure that looks like a firewall rule problem and is really a persistence problem.

Verify three things, including one denial

Test the outer connection from outside, test one authorized inner service from a connected client, and test one service that should remain unreachable. The third test is the one that distinguishes a policy from a side effect, and it is the one people skip because everything appears to work. If the denied service answers, you have admitted a zone rather than a service.

Record the zone, port, transport and policy object in the server's notes. The next change to this host will otherwise start from the same guess.

Tënë sô zo