VPN port requirements: three lines to write before comparing
Work out which port question you actually have: outbound destination, inbound publishing, or the tunnel's own transport. Then ask a provider only that.
Port lists for VPN services get copied between comparison pages without the detail that decides whether they matter: who starts the connection. A rule that permits outbound TCP 443 says nothing about whether another host can reach a listener on your machine. Write three separate requirements before you compare a single plan, and mark which ones your task actually needs. Most comparisons collapse into one short question once that sheet exists.
Split the requirement before you read any port list
Three lines cover almost every case: reaching a destination beyond the tunnel, publishing something so others can connect in, and carrying the tunnel itself. Each line fails for a different reason, and a provider policy that satisfies one can leave the other two untouched. Sorting your task into the right line takes five minutes and saves an argument later.
| Line | Who starts it | What can block it | Question for the provider |
|---|---|---|---|
| Outbound destination | Your application | Egress filter on the exit node | Is this protocol and port allowed to that destination? |
| Inbound publishing | A remote peer | No mapping, no public address, short lifetime | Which protocol, which external port, and how long does the mapping last? |
| Tunnel transport | Your client to the gateway | The access network drops that protocol | Does the client offer a fallback the local network permits? |
Marketing statements blur the three lines on purpose. A P2P allowance describes a destination policy, a dedicated address describes an address, and a claim of no port restrictions usually means the plan does not enumerate them. None of those phrases answers the others.
Pick one concrete flow and write it as a sentence: initiator, transport, port, address family, direction. A nightly backup client uploading to a remote host is outbound only. A game server on your desk that friends join is inbound. Running both through one tunnel means the sheet needs both lines, not a compromise between them.
Outbound access fails on destination policy, not on the tunnel
Outbound traffic through a translating gateway creates state. The first packet from an internal address and port builds a translation entry, and replies match it, which is the mapping behaviour described in RFC 3022. That mechanism is why a browser tab usually works without any port request at all.
Two things still break it. The exit node may filter destinations or port numbers it considers abusable, and the application may be listening on a port that the exit policy never expected. Ask about the destination pair rather than about inbound rules, and expect different answers for TCP and UDP.
Measure before you argue. Run these on the machine that will sit behind the tunnel, once with the tunnel down and once with it up:
ss -lntup | sort
nc -vz -w 3 203.0.113.10 443
curl -sS -o /dev/null -w '%{http_code}\n' --max-time 5 https://example.com
Same commands, same destination, two tunnel states, gives an operator a before-and-after they can act on. Replace the documentation address with the host you actually need; what matters is that the comparison repeats, not that any number looks impressive.
Inbound publishing needs a mapping, an address and a lifetime
Nothing outside can start a connection to your listener unless something on the public side knows where to deliver it. A static port reservation held by the operator, a client-requested mapping through UPnP, NAT-PMP or PCP, and a routed public address are three different products with three different limits.
Ask five questions of any of them: which protocol, which external port, whether the external port may differ from the local one, which address family it covers, and how long the mapping survives a reconnect. A reservation tied to an active session disappears when that session ends, whatever the plan page says.
Confirm the local half first, because a dead listener and a blocked inbound path look identical from outside:
ss -lntup | grep -E ':(8080|51820)\b'
python3 -m http.server 8080 --bind 0.0.0.0
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080
When the local request returns 200 and a request from a network you do not control still times out, the gap sits on the public side. That is the moment to quote protocol and external port to the operator instead of describing the app by name.
The tunnel's own transport is a separate question
Carrier ports are the smallest part of the problem and the easiest to look up. Defaults differ by protocol, and what the client can negotiate matters more than any plan description.
| Client | Outer transport | Default port | When it helps |
|---|---|---|---|
| OpenVPN | UDP | 1194 | Default mode; needs outbound UDP to pass |
| OpenVPN | TCP | 443 | UDP is dropped and TCP 443 is not |
| WireGuard | UDP | 51820 | Short handshake; there is no TCP mode |
| IKEv2/IPsec | UDP | 500 and 4500 | Mobile clients; 4500 carries NAT traversal |
A network that drops outbound UDP will accept a TCP 443 tunnel and refuse a UDP one, so a fallback mode belongs on the requirement sheet. Changing the carrier does not move an application port inside the tunnel, and it does not widen a destination policy; those stay on their own lines.
Fragmentation deserves one probe while you are there, because a tunnel that connects and then stalls on large transfers usually has the wrong MTU rather than a closed port:
ping -M do -s 1400 203.0.113.10 ping -M do -s 1372 203.0.113.10
On Windows the same probe is ping -f -l 1400 203.0.113.10. Set the tunnel MTU below the largest size that passes, then retest the transfer that failed.
Verify the three lines before you pay for a plan
Put the three lines on one page and fill each cell with a measured result instead of a promise. These commands produce the local half of that page in about a minute:
ss -lntup | sort
nc -vz -w 3 203.0.113.10 443
python3 -m http.server 8080 --bind 0.0.0.0
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080
ping -M do -s 1400 203.0.113.10
Read the output as a checklist. Outbound works when the destination answers with the tunnel up. Inbound works only when a host outside your network reaches the listener on the external port. The carrier works when the handshake completes on a protocol your access network permits.
Two habits keep the sheet honest. Record the date and the client version beside each result, since provider policies and client defaults both move. Then ask for the narrowest mapping that serves the flow, because a request to open everything tends to earn a refusal or an upsell rather than a technical answer.