Skip to content

Conversation

@Antraxmin
Copy link

@Antraxmin Antraxmin commented Apr 29, 2025

Add explanation and examples for binding ports to specific network interfaces using the extended syntax. This addresses issue #22253.

Description

Added documentation for the extended port publishing syntax IP:HOST_PORT:CONTAINER_PORT, which was missing from the current documentation. This change improves the "Publishing and exposing ports" page by explaining how to bind container ports to specific network interfaces on the host machine.

The additions include:

  • Clear explanation of the extended syntax format
  • Step-by-step examples with CLI commands and expected output
  • Common use cases highlighting security benefits
  • Docker Compose examples showing practical application
  • Added relevant networking resources in the Additional Resources section

This documentation helps users understand how to restrict container access to specific network interfaces, which is especially important for securing sensitive services like databases.

Related issues or tickets

Fixes #22253

Reviews

  • Technical review
  • Editorial review
  • Product review

Add explanation and examples for binding ports to specific network interfaces using the extended syntax. This addresses issue docker#22253.
@github-actions github-actions bot added the area/get-started Relates to get started and onboarding docs label Apr 29, 2025
@netlify
Copy link

netlify bot commented Apr 29, 2025

Deploy Preview for docsdocker ready!

Name Link
🔨 Latest commit 8ad69cc
🔍 Latest deploy log https://app.netlify.com/sites/docsdocker/deploys/6810c56a2456520008b45eeb
😎 Deploy Preview https://deploy-preview-22511--docsdocker.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@robmry
Copy link
Contributor

robmry commented Apr 29, 2025

Hi @Antraxmin - thank you for working on this, it looks good.

As @akerouanton noted on the issue, a wider review of the port publishing documentation is needed. It's got quite complicated, and the documentation is incomplete and split between a few places. But, that shouldn't stop us from making this incremental improvement first.

In the meantime though ...

I think it'd be good to add a link from this new section to https://docs.docker.com/engine/network/packet-filtering-firewalls/#setting-the-default-bind-address-for-containers - it partially describes config param host_binding_ipv4 (which also works for IPv6 addresses!), and can be used to change the default from 0.0.0.0.

The "Important" note just above this new section hints at what's described in this new text, and links to another page with some of the same description - which might be confusing. Perhaps change change its last sentence to "See [Binding to specific network interfaces] below, and [learn more about published ports here]."?

@Antraxmin
Copy link
Author

Antraxmin commented Apr 29, 2025

Hi @Antraxmin - thank you for working on this, it looks good.

As @akerouanton noted on the issue, a wider review of the port publishing documentation is needed. It's got quite complicated, and the documentation is incomplete and split between a few places. But, that shouldn't stop us from making this incremental improvement first.

In the meantime though ...

I think it'd be good to add a link from this new section to https://docs.docker.com/engine/network/packet-filtering-firewalls/#setting-the-default-bind-address-for-containers - it partially describes config param host_binding_ipv4 (which also works for IPv6 addresses!), and can be used to change the default from 0.0.0.0.

The "Important" note just above this new section hints at what's described in this new text, and links to another page with some of the same description - which might be confusing. Perhaps change change its last sentence to "See [Binding to specific network interfaces] below, and [learn more about published ports here]."?

Hi @robmry , thank you for your review and suggestions!
I'm happy to make those changes:

  • Add a link to the packet filtering documentation in the "Binding to specific network interfaces" section to reference the host_binding_ipv4 configuration parameter.
  • Update the "Important" note to reference the new section and create a clearer connection between the content.

I completely understand this is just an incremental improvement while a more comprehensive review of port publishing documentation is pending. I hope this small addition helps users in the meantime.

If there's anything I misunderstood, please let me know. If there's no particular problem, I'll work on it in more detail!

@robmry
Copy link
Contributor

robmry commented Apr 29, 2025

Thank you @Antraxmin - that sounds great, much appreciated.

@Antraxmin
Copy link
Author

Antraxmin commented Apr 29, 2025

@robmry

I've updated the PR with the requested changes: 8ad69cc

  1. Updated the "Important" note to reference the new section on binding to specific network interfaces, improving the connection between related content
  2. Added information about the host_binding_ipv4 configuration parameter with a link to the documentation about setting the default bind address

These changes should help users better understand the options available for controlling which network interfaces their container ports are bound to.

Let me know if any further adjustments are needed!

Copy link
Contributor

@robmry robmry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - thank you!

@Antraxmin Antraxmin requested a review from robmry April 30, 2025 10:21
@Antraxmin
Copy link
Author

@robmry Oops, you already approved this PR, but I accidentally hit the request review button. Please ignore the second request. My mistake!

@robmry
Copy link
Contributor

robmry commented Apr 30, 2025

@robmry Oops, you already approved this PR, but I accidentally hit the request review button. Please ignore the second request. My mistake!

No worries! We'll need a review from Docker's docs team, and I think they're a bit short-handed at the moment.

@docker-robot
Copy link

docker-robot bot commented Jul 29, 2025

Thanks for the pull request. We'd like to make our product docs better, but haven’t been able to review all the suggestions.
As our docs have also diverged, we do not have the bandwidth to review and rebase old pull requests.

If the updates are still relevant, review our contribution guidelines and rebase your pull request against the latest version of the docs, then mark it as fresh with a /remove-lifecycle stale comment.
If not, this pull request will be closed in 30 days. This helps our maintainers focus on the active pull requests.

Prevent pull requests from auto-closing with a /lifecycle frozen comment.

/lifecycle stale

@robmry
Copy link
Contributor

robmry commented Jul 29, 2025

/remove-lifecycle stale

@robmry
Copy link
Contributor

robmry commented Jul 29, 2025

cc @ArthurFlag

Copy link
Contributor

@ArthurFlag ArthurFlag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, thank you!

Copy link
Member

@akerouanton akerouanton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating that guide!

Please see my comments below — we need to not conflate 'binding on a specific interface' and 'binding on a specific HostIP'.

### Binding to specific network interfaces

By default, when you publish a port, Docker binds to all network interfaces (`0.0.0.0`). However, there are scenarios where you might want to restrict access to a specific network interface or IP address. You can do this by using the extended port syntax:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In terms of BSD socket API, binding to a specific interface isn't the same as binding on a specific IP address — both can be combined. This is done via SO_BINDTODEVICE.

I think we should not conflate both here. The Engine doesn't support binding to a specific interface, but it supports binding to a specific HostIP.

#### Common use cases for IP binding

- **Security**: Binding to localhost (127.0.0.1) to prevent external access to services like databases
- **Multi-homed hosts**: Binding to specific network interfaces on servers with multiple IP addresses
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not true — and this is where the claim that it can bind to a specific interface may instill a false sense of security.

If a port is mapped to a specific IP address, and the host has multiple interfaces, that IP address will be accessible through all interfaces by default.

This can be easily tested with the following commands on a host running the Engine (or from a dind container):

$ ip netns add test
$ ip link add name veth-dockerd type veth peer name veth-test
$ ip link set veth-test netns test
$ ip addr add 10.10.0.1/24 dev veth-dockerd
$ ip link set veth-dockerd up
$ ip netns exec test ip addr add 10.10.0.2/24 dev veth-test
$ ip netns exec test ip link set veth-test up

The 'multi-homed host' here is a dind container that has its original IP address (e.g. 172.17.0.3), plus 10.10.0.1.

You can then start a container targeting a specific HostIP:

$ docker run --rm -d -p 172.17.0.3:80:80 traefik/whoami

Finally, we can test whether 172.17.0.3:80 is accessible from the 'test' netns, but first we need to add a route to that address to let it know how it can reach it:

$ ip netns exec test ip route add 172.17.0.3/32 via 10.10.0.1
$ ip netns exec test ip -brief route show
10.10.0.0/24 dev veth-test proto kernel scope link src 10.10.0.2 
172.17.0.3 via 10.10.0.1 dev veth-test 

$ ip netns exec test curl http://172.17.0.3
Hostname: 4ab70ca9633d
IP: 127.0.0.1
IP: ::1
IP: 172.18.0.2
RemoteAddr: 10.10.0.2:43822
GET / HTTP/1.1
Host: 172.17.0.3
User-Agent: curl/7.88.1
Accept: */*

If users don't want that behavior, they need to set up firewall rules. (I'm not sure if that's clearly documented though.)

However, note that this is not true for loopback addresses (i.e. 127.0.0.0/8 and ::1/128) since v28.0 (see this blog post, and this changelog entry), as these aren't supposed to be routed anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/get-started Relates to get started and onboarding docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing <IP>:<host_port>:<container_port> explaination docker-compose

4 participants