Docker Compose Ports Generator
Build a valid ports: block in both short and long syntax, and catch the unquoted-port mistake that quietly breaks YAML before it ships.
Port mappings
Short syntax
Long syntax
How to use this tool
- Add a row per port mapping: an optional host IP, the host port (or a range), the container port (or a matching range), and the protocol.
- Leave host port blank to publish the container port without pinning a specific host port — Docker assigns an ephemeral one.
- A host port range mapped to a single container port is valid — Docker picks the first free port in that range. A container port range needs a host range of the exact same length.
- Copy whichever syntax your compose file uses. Both are always quoted here, because unquoted colon-separated ports are the single most common way a compose file’s ports silently corrupt on parse.
- Watch the yellow warning — it flags any row where the host:container mapping happens to match YAML’s sexagesimal number pattern, the exact shape that bites people using low ports like 22 or 53.
Docker Compose’s ports: key has two equivalent forms. Short syntax is the familiar HOST:CONTAINER string, optionally prefixed with a host IP and suffixed with a protocol: "127.0.0.1:8080:80". Long syntax spells the same mapping out as an object with target (the container port), published (the host port), protocol and host_ip keys. Long syntax exists mainly because it is easier to template and validate in tools that generate compose files programmatically; for a file you write by hand, short syntax is almost always clearer.
Quoting the short-syntax value is not optional, even though Compose examples in the wild frequently skip it. YAML is a superset of several older typing conventions, and one of them — inherited from YAML 1.1 — is a sexagesimal (base-60) number format: a colon-separated string like 1:30 can be read as sixty times one, plus thirty. An unquoted port mapping where every segment after the first colon happens to be a number from 0 to 59 gets silently parsed as an integer instead of the string you meant. "2222:22" is exactly this shape — a common SSH-forwarding mapping — and so is anything ending in a low port like DNS’s 53 or SMTP’s 25.
The reason this trap is so easy to miss in testing is that it only fires for specific values. 8080:80 is safe unquoted, because 80 does not match the sexagesimal digit pattern (a valid base-60 digit is at most two characters with the first in the 0-5 range). Swap the container port for anything under 60 and the same-looking line starts parsing as a number. That inconsistency is precisely why Docker’s own documentation recommends quoting every port mapping unconditionally, rather than trying to remember which specific values are affected.
A parallel, more basic mistake is forgetting the list dash. ports: expects a YAML sequence, so every entry needs a leading -. Indent 8080:80 directly under ports: without that dash and YAML reads it as a nested mapping — key 8080, value 80 — under the ports key, which fails Compose’s schema validation immediately rather than silently misbehaving. It is a different failure mode from the quoting trap but the same root cause: colons are structurally significant in YAML, so a value that itself contains one always needs either quoting, list context, or both.
Port ranges add one more rule worth knowing: a host range can map to a single container port (Docker publishes the container on the first free port in that range), and a host range can map to a same-length container range one-to-one, but a container range can never collapse onto a single host port — there would be no way to route multiple container ports through one host port.
Frequently asked questions
Why do I need to quote “8080:80” in a compose file?
Because YAML’s older typing rules can interpret a colon-separated numeric string as a sexagesimal (base-60) integer instead of leaving it as text. It only actually happens for specific low values, but quoting every port mapping unconditionally is the only way to be sure your file behaves the same regardless of which ports you pick later.
Which port numbers actually trigger the YAML number bug?
Any mapping where every segment after the first colon is a plain 1-2 digit number from 0 to 59 — so 2222:22 (SSH) and 1053:53 (DNS) are at risk, while 8080:80 is not, since 80 falls outside that range. This tool’s warning flags the exact rows where it would matter.
What is the difference between short and long syntax?
They describe the same mapping. Short syntax is a compact [host_ip:]host:container[/protocol] string; long syntax spells out target, published, protocol and host_ip as separate YAML keys. Long syntax is more verbose but easier to generate or template programmatically.
Can I map a range of host ports to one container port?
Yes — "8000-9000:80" is valid, and Docker publishes the container on the first free port it finds in that range. The reverse, many container ports onto one host port, is not possible and this tool rejects it.
Do I need to specify a host port at all?
No. Listing just the container port, like "80", publishes it on a random ephemeral host port that Docker chooses. That is intentional for cases where the exact host port does not matter and something else — a reverse proxy, service discovery — is finding it dynamically.