When I first read the original post, I felt inclined to shift the "blame" on the author, much like they shifted it on Docker, though they are aware of how this footgun can also be a benefit to some:

> It would make for a much more dramatic read if I was hit through a vulnerability in Docker instead of a footgun. By having Docker silently override the firewall, Docker has made it easier for developers who want to open up ports on their containers at the expense of security.

When I want to run my own web server on an arbitrary Linux distro inside of a container, I want to bind to 0.0.0.0:80 and 0.0.0.0:443. That's it.

When I want to run my own database on an arbitrary Linux distro inside of a container, without making it accessible externally, I want to just omit exposing ports. That's it.

I don't want to think about the firewall on the system (even what kind of a firewall it is running, if any) or configure it separately, otherwise it'd be as bind mount target directories on host system not being automatically created, making me use "mkdir -p PATH", which already adds unnecessary friction (if I want the files to be available in the host OS, as opposed to just in abstracted away Docker volumes). After all, if there were more steps, then an awkward dance would inevitably start: "Hey, we launched the container on SOME_DISTRO but we can't access the UI/API/whatever." and you'd have to write platform-specific instructions, as opposed to being able to just give a Docker Compose file or an equivalent and be done with it.

Thus, my original thoughts were along the lines of: "It's not at the expense of security, as much as it is to the benefit of your convenience without any changes to security, if you are aware of what you are doing." though that isn't charitable enough. Something like this would be more helpful instead:

# Suppose you want to let people know that your container wants to listen on the port 2000
# You can specify it in the Dockerfile, though this will be more like documentation for the container, as opposed to publishing anything
# Docs: https://docs.docker.com/engine/reference/builder/#expose
# File: Dockerfile
EXPOSE 2000/tcp
...

# If you want your port to be available locally, then Docker gives you that ability as well
# You can even change the port, for example, to 2005 on the host
# Docs: https://docs.docker.com/compose/compose-file/compose-file-v3/#ports
# File: docker-compose.yml
ports:
- "127.0.0.1:2005:2000/tcp"
...

# If you want your port to be available remotely, then you can either omit the IP address or use 0.0.0.0
# Let's take the above example and use 2005 as the exposed port again
# File docker-compose.yml
ports:
- "2005:2000/tcp"
...

# For examples of Docker CLI without Docker Compose/Swarm, have a look at the docs: https://docs.docker.com/config/containers/container-networking/
# There's also good information there about additional networking options, such as creating custom networks for limiting what can talk to what.

Actually, here's an example that anyone can run, with Docker CLI (using the httpd web server as example, same idea applies to DBs):

# Launch everything (detached, so we can use the same terminal session, remove containers once stopped)
docker run -d --rm --name "net_test_not_exposed" httpd:alpine3.17
docker run -d --rm --name "net_test_local_access" -p "127.0.0.1:2005:80/tcp" httpd:alpine3.17
docker run -d --rm --name "net_test_public_access" -p "0.0.0.0:2006:80/tcp" httpd:alpine3.17
docker run -d --rm --name "net_test_public_access_shorthand" -p "2007:80" httpd:alpine3.17

# Check that everything is running
docker ps

# Or different formatting
docker ps --format "{{.Names}} is {{.Status}} with ports {{.Ports}}"

# Then you can use a browser to check them, or do it manually, either locally or from another node (with actual IP address)
# 2005 will be available locally, whereas 2006 and 2007 will be available remotely
curl http://127.0.0.1:2005
curl http://127.0.0.1:2006
curl http://127.0.0.1:2007

# Finally, the cleanup (the --rm will get rid of the containers)
docker kill net_test_not_exposed net_test_local_access net_test_public_access net_test_public_access_shorthand

I will say that this is a good suggestion:

> Better would be for Docker to issue a warning when it detects that the most popular firewall on Linux is active and filtering traffic to a port that Docker is about to open.

However, the thing with warnings is that they're easy to miss. Either way, I've been there - when I was learning Docker a number of years back, I left its socket open and by the morning the tiny VPS was mining crypto. Good docs help, maybe exposing things publicly by default with a port binding or even using the shorthand in the first place isn't such a good idea either.