HOST:CONTAINER/udp. This covers services such as a DNS server or a STUN endpoint. It is the first slice of ADR 049: UDP publishing only.
What it does
- Publishes the UDP port straight on the host. UDP does not go through the HTTP reverse proxy, which cannot carry it.
- Accepts the short form (
"53:53/udp") and the long form (target,published,protocol: udp). - Treats TCP and UDP on the same number as two separate ports.
53:53/tcpand53:53/udpcan both be declared. - Shows each published port as
53/udp(or53/tcp). The API returns it underpublished_portson the app and on each compose deployservices[]entry:
published_ports shape.
What it does not do
- It works on the control plane’s own node only. A service placed on a remote node is refused with
published_port_remote_node. - It gives no reachability probe. A UDP port only reports whether it is bound.
- It does not add capabilities, sysctls or host networking (see Not yet).
Safety
- The port binds to the service’s bind address, which is private by default, like a TCP host port. Making it public follows the same exposure rules as a TCP host port, see App ports and exposure.
- The host or cloud firewall must still allow the port from the clients you want. Publishing does not open it for you.
- A public UDP service is easy to abuse. An open DNS resolver can be used for amplification, so keep it private unless you mean to serve the internet.
- Exposure findings already list UDP ports from Docker.
- The interaction with the Docker
DOCKER-USERfirewall chain has not been tested on a real server yet. Do not rely on aDOCKER-USERrule to restrict a UDP port until it is. - The host firewall view (
GET /api/v1/firewall/host, see Host firewall) lists each published UDP port with its app, bind address and whether ufw allows it. - A deploy is refused when another process on the server already binds the UDP port on a clashing address. systemd-resolved on 127.0.0.53:53 does not clash with the private default (127.0.0.1), but it does clash with a public bind. If the socket table cannot be read (not Linux), the check is skipped and Docker reports the bind failure.
Errors
A running deploy that hits the remote node case reports the reconcile reason
PublishedPortsRemoteNode.
Example: UDP echo test
nc -e serves only one client per container start, so a second test would hang.
Example: DNS-style service
dig @<server-ip> -p 5354 app.test, which answers 10.0.0.5. Host port 5354 avoids a clash with a resolver already on port 53 and with mDNS on 5353. --interface=eth0 makes dnsmasq answer queries that arrive through the port forward; without it dnsmasq drops them as non-local. The container installs dnsmasq at start, so it needs outbound network access.
Not yet
These are not built, so compose files that use them are still rejected:cap_add(for exampleNET_ADMIN)sysctlsnetwork_mode: host