How to Configure DNS to Access Host Services from a Container
Apple Container provides an embedded DNS server that maps custom domain names to host IP addresses, allowing containers to resolve and connect to services running on the host via friendly DNS names.
The apple/container repository includes a built-in DNS resolution system that bridges the networking gap between macOS hosts and Linux containers. By configuring a custom DNS domain that points to a specific host IP address, you can access host-bound services from inside containers without hardcoding IP addresses or exposing ports externally.
How the DNS Resolution System Works
The container runtime runs an embedded DNS server that intercepts DNS queries from containers and resolves custom domains to host-local IP addresses. When you register a domain using the CLI, the system writes a resolver file to /etc/resolver on macOS and updates an in-memory lookup table.
According to the source code in Sources/APIServer/LocalhostDNSHandler.swift, the LocalhostDNSHandler class monitors the resolver directory using a DirectoryWatcher. When files change, it parses lines matching localhostOptionsRegex to build a [DNSName: IPv4Address] dictionary. This dictionary is used to answer DNS queries for custom domains, returning the mapped IP address to the requesting container.
The default domain suffix is controlled by DNSConfig.defaultDomain in Sources/ContainerPersistence/ContainerSystemConfig.swift, which automatically appends the local search domain to container resolver configurations.
Step-by-Step DNS Configuration
Select a Safe IPv4 Address Range
Choose an IP address that will not conflict with real networks. Apple recommends using documentation blocks such as 203.0.113.0/24 (TEST-NET-3) or private ranges like 172.16.0.0/12. Avoid using 127.0.0.1 directly, as this can cause routing issues within the container network namespace.
Register the DNS Domain
Use the container system dns create command to map your chosen IP to a hostname:
sudo container system dns create <domain-name> --localhost <ipv4-address>
This command creates a resolver file under /etc/resolver on macOS and registers the mapping with the container's DNS server. The LocalhostDNSHandler immediately updates its internal routing table to answer queries for the new domain.
Verify Container Resolution
Test the configuration by running a container that attempts to resolve the custom domain:
container run -it --rm alpine/curl curl http://<domain-name>:<port>
The container forwards DNS requests to the host's DNS server, which returns the configured IPv4 address. The request is then routed to the host service listening on that address.
Complete Working Example
The following example demonstrates mapping a custom domain to a documentation-range IP address and accessing a Python HTTP server from within a container:
# Choose a non-conflicting IP from the documentation range
IP=203.0.113.113
DOMAIN=host.container.internal
# Register the domain with the container DNS service
sudo container system dns create ${DOMAIN} --localhost ${IP}
# Start a simple HTTP server on the host (binding to localhost)
mkdir -p /tmp/test && cd /tmp/test && echo "hello" > index.html
python3 -m http.server 8000 --bind 127.0.0.1
# From a container, fetch the page using the DNS name
container run -it --rm alpine/curl curl http://${DOMAIN}:8000
# Output: hello
To remove the DNS mapping when finished:
sudo container system dns delete ${DOMAIN}
Key Implementation Files
The DNS functionality is implemented across several core components:
Sources/APIServer/LocalhostDNSHandler.swift– Watches resolver files and answers DNS queries for locally created domains using theDirectoryWatcherand regex parsing.Sources/ContainerPersistence/ContainerSystemConfig.swift– DefinesDNSConfigand stores thedefaultDomainused for automatic search domain configuration./etc/resolver– The macOS directory where the CLI writes resolver files for system-wide DNS resolution.
Summary
- Apple Container uses an embedded DNS server (
LocalhostDNSHandler) to resolve custom domains to host IP addresses. - Use safe IP ranges like
203.0.113.0/24to avoid network conflicts when mapping host services. - Register domains with
sudo container system dns create <domain> --localhost <ip>to write resolver files and update the DNS table. - Containers automatically inherit the local search domain from
DNSConfig.defaultDomain, enabling immediate resolution without restarting the runtime. - Resolution is dynamic – the
DirectoryWatcherdetects changes to/etc/resolverfiles and updates the in-memory DNS table without requiring service restarts.
Frequently Asked Questions
What IP addresses are safe to use for host DNS mapping?
Use documentation-range addresses like 203.0.113.0/24 (TEST-NET-3) or private network ranges such as 172.16.0.0/12. These ranges are guaranteed not to conflict with public internet addresses and are specifically reserved for testing and documentation purposes.
How does the container DNS server know when I add a new domain?
The LocalhostDNSHandler in Sources/APIServer/LocalhostDNSHandler.swift uses a DirectoryWatcher to monitor /etc/resolver for changes. When you run container system dns create, the CLI writes a new resolver file, triggering the handler to parse the file and update its in-memory [DNSName: IPv4Address] dictionary used for query responses.
Where is the DNS configuration stored on macOS?
The container system dns create command writes resolver configuration files to /etc/resolver. macOS uses this directory to determine which DNS server should handle queries for specific domains. The container runtime reads these files to build its internal routing table.
Can I delete a DNS mapping after creating it?
Yes. Use sudo container system dns delete <domain-name> to remove the resolver file and unregister the mapping from the embedded DNS server. The DirectoryWatcher detects the file deletion and immediately removes the entry from the in-memory lookup table, preventing further resolution of that domain.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →