Docker Networking Question - Outbound UDP Messages not using the Port defined by the UDP Port Rule with Bridge Networking

The following forum post generally describes my same issue:

My Docker container runs a data collector that sends encrypted UDP messages to external/physical network devices. The proprietary encryption mechanism uses the sending port number (with other keys) to encrypt the message. This means that the UDP port number for the message being sent to the external devices cannot change in order for the message to be properly received and replied to. However, even with using the “-p 5500:5500/udp” on the command line or “ports: 5500:5500/udp” in the docker compose file, UDP messages sent by my data collector using port 5500 will leave the Docker host using some random UDP port number with Bridge networking. Note – the random port number used by the Docker host will remain the same for the life of my running container.

For Bridge networking, how can I make the “ports: 5500:5500/udp” rule work for both Outbound and Inbound UDP messages?

I have confirmed this behavior using the latest Docker Desktop (version 4.37.1, Engine: 27.4.0, Compose: v2.31.0-desktop.2) installed on Windows 11 and Ubuntu 24.04. My container is also based on “ubuntu:latest”.

“netstat -tulnp” and “lsof -i -P -n” both show that my data collector is definitely using UDP port 5500.

I’m trying to avoid Host networking, but is that my only option for avoiding UDP port number translation for outbound UDP messages from my data collector container?

This has nothing to do with Docker. This is how network works. The port mapping is for the inbound traffic. I’m not aware of any way specifying the port for outbound traffic. And by the port for the outbound traffic I assume you mean the UDP “source port”, Even a simple HTTP request in a webbrowser works this way. In case of an HTTP request the inbound port is usually 80 or 443 while a random port for the response is opened on the client side. It is always different for each connection. HTTP is based on TCP, but UDP is similar. I’m not a network expert to give a lecture about networking, but you can read about UDP here for example:

Or even on Wikipedia

Source Port: 16 bits
This field identifies the sender’s port, when used, and should be assumed to be the port to reply to if needed. If the source host is the client, the port number is likely to be an ephemeral port. If the source host is the server, the port number is likely to be a well-known port number from 0 to 1023.[6]

So this is another level and Docker will not help you with this. If you really have Docker Desktop as in the linked topic, that means you also have a virtual machine. So you would expect the physical host to know about all the requests inside the container in the VM when all processes would have their own source port assigned by the OS which you could not just redirect through a single source port on the host. Especially not on the same port as the port for the incomming requests. You could also have a process for which you did not set a port mapping, but it still can send requests to the outside world.

I don’t know about tha, but this seems to be something special and you should probably ask someone who understands that encryption mechanism and what you could do in any case, not just in case of using Docker.

Or maybe I just misunderstood something and your issue is completely different. Then at least I read a little about networking again and feel free to tell my I’m talking nonsense :slight_smile:

The data collector works perfectly running natively on Linux or Windows, where the UDP messages are sent from and received by UDP port 5500, or whatever port I designate and is free. UDP ports for user programs start at 5001. The issue I’m having is definitely due to the NAT behavior of Bridge networking.

You tried host network and that worked?

If it did, then yes, that is the only option. There is no way to configure other ports except for the incomming traffic as far as I know.

With Docker Desktop for Windows there is no way around the NAT:

It might work with Docker-CE in a WSL2 distribution, if networkingMode=mirrored is configured in .wslconfig in the user profile folder. Note: wsl2 networkingMode=mirrored is not the same as Docker Desktop’s host networking.

Update:
I should have mentioned two things:

  • with wsl2 mirrored mode the wsl distribution uses the same ip as the host
  • the container needs to be started with --network host, so you get rid of the NAT.

This way, the container should behave like it’s running natively on Linux, or your windows host.