Skip to content

Networking and DNS

Bart Reardon edited this page Aug 9, 2026 · 3 revisions

Networking and DNS

Networks

Networks ▸ + creates a NAT or host-only network, optionally with a CIDR you choose. Each stack gets its own, named <stack>-net and labelled with the stack, which is how the list groups them. The built-in default network can't be deleted.

Containers on the same network reach each other directly by address. A container's address is shown in its detail pane and in the lists.

Published ports

A published port maps a port on your Mac to one in the container:

8080:80            host 8080 → container 80
8443:443/tcp       with an explicit protocol
127.0.0.1:8080:80  bound to a specific host address

Published ports are how you reach a container from your browser, and — unlike container addresses — localhost:8080 doesn't change when things restart. That makes it the right thing to put in any configuration a service records about itself.

On macOS 27 beta published ports currently accept a connection and then reset it, so localhost:<port> doesn't reach the container while its own address still works. This is apple/container#2029, upstream, and not worked around here. See Troubleshooting.

Why containers can't reach each other by name

This is the design constraint behind a lot of the app, so it's worth stating plainly.

A container's own resolver is its network gateway, and that gateway doesn't answer for container names — it forwards to upstream DNS. So from inside a container, getent hosts my-database fails, and a compose file that has services talking to each other by name won't work as written.

ContainerManager handles it by substituting real addresses when each container is created, and re-substituting them when a stack starts and addresses have changed. See how services find each other.

Local DNS

container can make containers reachable from your Mac by name — my-app.test in a browser instead of an address that changes. Settings ▸ Local DNS sets it up.

This is host-to-container only. It does not change how containers reach each other, and it isn't a fix for the section above.

What it does

Two separate things have to line up, which is why it's easy to end up half configured:

  1. A resolver entry at /etc/resolver/<domain>, so macOS routes those queries to the container service. Created with sudo container system dns create <domain>, and needs your administrator password.
  2. A default domain in ~/.config/container/config.toml, which is what makes the service give each new container a name to register. No password needed, but the service only reads that file at startup.

Settings reports which halves are in place and completes whichever is missing, then restarts the services. Following Apple's tutorial gets you the first half only — a domain exists but nothing resolves — and that state is called out by name rather than shown as "off".

Two caveats

  • Existing containers don't get a name. The name is assigned when a container is created, so anything already running has to be re-created before its-name.test resolves.
  • Restarting stops everything. Setting up restarts the services, which stops every running container and machine.

Turning it off

Turn Off clears the default domain and restarts. The /etc/resolver entry is left in place — it's inert without a default domain, and removing it would ask for your password again for no visible gain. To remove it anyway:

sudo container system dns delete test

Reaching your Mac from a container

The reverse direction — a container calling a service running on your Mac — needs a different mechanism, and isn't set up by this app:

sudo container system dns create host.container.internal --localhost 203.0.113.113

Note the upstream warnings: a localhost domain disables Private Relay, and the packet filter rule doesn't survive a restart. See Apple's how-to.

Clone this wiki locally