Why your Docker VPN port mapping never reaches OpenVPN
Host port, container port and transport are three separate decisions. Follow one UDP attempt through each boundary before touching certificates.
Your container can listen on UDP 1195 while the host publishes 1194, and that is correct as long as the mapping says so. The numbers form a translation table: the client dials the host port, Docker rewrites the destination to the container port, and OpenVPN answers on the port its own configuration names. A mismatch at any one of those links produces a silent failure that looks like a firewall. Certificates and ciphers sit downstream of this and cannot repair it.
Follow one packet from client to process before changing anything about authentication.
Three numbers, one connection
The three numbers are the remote destination the client uses, the published mapping on the host, and the listener inside the container. They do not have to be equal, but they have to chain. Equal numbers are a special case that happens to be the common one, which is why a mismatch is easy to write once and hard to see later.
Write the chain down as one line before debugging: client address and port, host mapping, container listener, transport. A defect in the chain shows up as a number that appears twice with different values.
| Location | Example |
|---|---|
| Remote client destination | Host address, UDP 1194 |
| Published mapping | Host UDP 1194 to container UDP 1195 |
| Container listener | OpenVPN on UDP 1195 |
What the short syntax actually says
In the short form the left side is the host port and the right side is the container port, and a slash suffix selects the transport. Omit the suffix and Docker treats the mapping as TCP, so a UDP listener behind a mapping without a protocol is a listener nobody can reach. That default is documented and still surprises people who matched the numbers and called it done.
The long form pins the bind address and protocol explicitly, which is worth the extra lines on anything facing a network. Read the published mapping back rather than trusting the file that produced it.
ports:
- 1194:1195/udpWhere the packet can stop
A request can be dropped before Docker, at Docker, or at the listener. Ahead of Docker there may be a cloud firewall or a router doing its own forwarding, and that device needs the host-facing port and the right transport. Inside Docker, a mapping for the wrong container port forwards to a closed socket.
Then the listener: OpenVPN's configuration names a port and protocol, and a client arriving on a different one inside the container reaches nothing. TCP testing of a UDP service proves nothing at any of these stages, so use the transport the client will use.
Bind addresses decide reachability
A published mapping bound to loopback is reachable only from the host, while one bound to all interfaces is reachable wherever the firewall allows. Those two look identical in a Compose file that omits the address, and the Docker default is the broad one.
Decide which exposure the deployment intends, then write it explicitly. An internal test that connects over loopback and a remote client that cannot connect can both be accurate descriptions of the same container.
Read the running state
Inspect the running container's effective mapping and the listener in its network namespace. A Compose file may have been edited after the container started, image metadata may declare a port without publishing it, and a second container may already hold the host port. Declaring a port in an image is not publishing it, and neither is the same as listening.
Three different states, three different commands, and only the last one involves OpenVPN.
After the mapping is right
Once the packet reaches OpenVPN, its log is the place to read about TLS and authentication. Regenerating certificates to fix a packet that never arrived is wasted work that adds a second variable. Keep the mapping note beside the client profile so the next person reads one line instead of rediscovering all three numbers. One packet capture on the host side settles which of the three links is wrong, and it costs less than a certificate regeneration.
Bridge publishing is the case described here. Host networking and routed container addresses skip the translation, so the same numbers mean something different in those designs.