A VPN service is reachable from wherever its socket is bound and its firewall allows. Those are two separate decisions, and people usually make only one of them. Reading the actual listener takes ten seconds and settles a question that guessing cannot. Start there, then change one control at a time.

Everything below assumes you can run commands on the host with root or sudo.

Read the sockets before you change anything

On Linux, ss -lunp lists UDP listeners with their local address, port and process, and ss -ltnp does the same for TCP. Look for the VPN's port and read the address column carefully. 0.0.0.0:51820 and [::]:51820 mean every interface, while 10.0.0.5:51820 means one address on one interface. The ss manual documents the columns if the output is unfamiliar. If the process name is missing, run the same command with sudo, because the owner column needs privilege.

Write the address down. It is the fact the rest of this runbook depends on.

Bind to an address, not to a wish

OpenVPN's local directive binds the listener to a specific address, and that is the supported way to scope it at the process level. Not every implementation offers an equivalent, and a protocol with no bind option cannot be narrowed this way. If yours has none, the firewall is your only control, and the deployment notes should say so plainly. On a host with several addresses, bind to the one facing the tunnel; binding to an address that floats is usually a mistake.

A service that has to survive an address change needs a plan for the stale binding, not just a configuration line.

Check the address family separately

IPv4 and IPv6 are separate sockets. A process bound to 0.0.0.0 may still accept IPv6 through a dual-stack socket, or may not, depending on the socket option and the platform default. Reading only the IPv4 line has fooled more than one deployment review. List both families before you conclude the listener is narrow.

If IPv6 is not part of the design, disabling it at the socket level is cleaner than hoping the firewall covers it. That is a policy decision, so record it with the rest of the interface choices.

Layer the firewall on top of the binding

A narrow bind does not replace a firewall rule, and a firewall rule does not narrow a wildcard bind. Use both: bind where the implementation supports it, then permit the port only from the sources that should reach it. Cloud security groups sit in front of the host firewall, so check both when the path crosses a VPC boundary. The effective rule is the intersection of the two, and each layer can only subtract reachability.

Test from an allowed source and from a deliberately excluded one. A connection from localhost proves nothing about the public boundary.

Record what you chose

Write down the bound address, the interface that owns it, the firewall rule and its purpose. A replacement NIC or a reassigned cloud address can change exposure without anyone editing the profile. Date the note, because cloud addresses move between reviews more often than people expect.

That note is what makes the next review a comparison instead of an archaeology project.

Allakkat attuumassuteqartut