In Docker, containers can typically access each other by their container names (relying on Docker's built-in DNS at 127.0.0.11
). However, the host machine cannot resolve container names by default.
This tool —— the Docker DNS Forwarder , solves this problem: it allows the host to access container services directly using domain names in the format container-name.custom-suffix
, no port mapping required, no hosts file modification needed.
By intercepting domain names that end with a custom suffix (e.g., .docker
) and forwarding them to Docker’s built-in DNS server, the host can access containers seamlessly.
Example:
curl http://myapp.docker:8080
The default suffix can be modified via command-line arguments or environment variables.
- Domains matching
.docker
→ Forwarded to Docker’s built-in DNS (127.0.0.11
) for container IP resolution. - All other domains → Return
REFUSED
, so the host automatically uses public DNS (no impact on normal internet access).
The default forwarding address can be modified via command-line arguments or environment variables.
A default domain gateway.docker
is provided, which automatically resolves to the host machine’s IP.
The default gateway name can be modified via command-line arguments or environment variables.
Built on the ldns
library and UDP protocol, it runs with minimal CPU and memory usage.
Docker’s built-in DNS forwards non-container-name domains to the host’s DNS service. This means you can also use domains like gateway.docker
inside Docker containers:
Docker forwards the request to the host’s configured DNS server (i.e., this forwarder). The forwarder strips the .docker
suffix to form a valid container name, then uses Docker’s built-in DNS to resolve the IP and return the result.
-
Docker’s default bridge network (docker0) does not support inter-container access via container names (only via IP).
Use a custom network (created with
docker network create
) to enable normal container name resolution.
For details on Docker custom networks, refer to the official Docker documentation. -
Domain name queries are case-insensitive.
graph TD
A[Host Initiates DNS Query] --> B{Does the domain end with .docker?}
B -->|Yes| C[Strip .docker suffix → Forward to 127.0.0.11]
C --> D[Return Container IP to Host]
B -->|No| E[Return REFUSED]
E --> F[Host Attempts Public DNS Resolution]
Solution | Base Image | Core Features | Image Size | Build Script |
---|---|---|---|---|
static |
scratch (empty) |
Contains only static binaries (no redundant system components) | Binary < 1.5MB | build-static.sh |
alpine |
alpine:3.22 |
Lightweight Linux distro + runtime libraries + binaries | Binary ≈ 40kB + Image ≈ 9MB | build-alpine.sh |
- Download or clone the repository.
- Run the build script:
build-alpine.sh
orbuild-static.sh
. - Run the startup script
docker-run.sh
and follow the prompts to complete initialization and deployment.
-
Build the image and run the container:
# Clone the source code git clone https://github.com/bytesharky/docker-dns # Domestic mirror (China): # git clone https://gitee.com/bytesharky/docker-dns cd docker-dns docker build -t docker-dns:static . # Start the container # Mount timezone data (optional: for local time in logs) # Set log level (optional: default is INFO) docker run -d \ -e LOG_LEVEL=INFO \ -e TZ=/zoneinfo/Asia/Shanghai \ -v /usr/share/zoneinfo:/zoneinfo:ro \ --network docker-net \ --name docker-dns-a \ -p 53:53/udp \ --restart always \ docker-dns:static
-
Configure Host DNS
Edit/etc/resolv.conf
and set127.0.0.1
as the top DNS server:nameserver 127.0.0.1 # Local forwarder nameserver 223.5.5.5 # Public DNS 1 nameserver 8.8.8.8 # Public DNS 2
(Optional) Prevent the file from being overwritten by the system:
sudo chattr +i /etc/resolv.conf
-
Pull the prebuilt image:
docker pull ccr.ccs.tencentyun.com/sharky/docker-dns:static docker tag ccr.ccs.tencentyun.com/sharky/docker-dns:static docker-dns:static # Start the container # Mount timezone data (optional: for local time in logs) # Set log level (optional: default is INFO) docker run -d \ -e LOG_LEVEL=INFO \ -e TZ=/zoneinfo/Asia/Shanghai \ -v /usr/share/zoneinfo:/zoneinfo:ro \ --network docker-net \ --name docker-dns \ -p 53:53/udp \ --restart always \ docker-dns:static
-
Configure Host DNS
Refer to Step 2 in Method 2.
ping -c 3 docker-dns.docker
Expected output (IP = container’s internal network address):
PING docker-dns.docker (172.18.0.6): 56 data bytes
64 bytes from 172.18.0.6: icmp_seq=1 ttl=64 time=0.05 ms
ping -c 3 github.com
Expected output (public IP):
PING github.com (140.82.112.4): 56 data bytes
64 bytes from 140.82.112.4: icmp_seq=1 ttl=51 time=10.2 ms
Control the program’s output by setting the LOG_LEVEL
environment variable (default: INFO
).
Supported levels: DEBUG
, INFO
, WARN
, ERROR
, FATAL
Number | Log Level | Core Meaning | Severity Level |
---|---|---|---|
0 | DEBUG | Debug level: Prints detailed runtime info for development/testing (aids in code debugging) | Lowest (only for dev environments) |
1 | INFO | Info level: Records key statuses of normal system operation | Low (safe for production; logs normal events) |
2 | WARN | Warning level: Records non-fatal exceptions or potential risks (system continues running) | Medium (monitor; may predict future issues) |
3 | ERROR | Error level: Records fatal exceptions (single DNS resolution fails, but system remains functional) | High (investigate promptly to avoid scope expansion) |
4 | FATAL | Fatal level: Records critical errors that render the system completely inoperable | Highest (system unavailable; urgent fix required) |
The Docker DNS Forwarder acts as a "bridge" between the host machine and Docker’s built-in DNS. Its key advantages:
- 🟢 Host resolves
.docker
domains seamlessly - 🟢 No impact on normal internet DNS resolution
- 🟢 Simple deployment + minimal resource usage
Development/testing environments, or scenarios where the host needs direct access to containers via container names.
Use with caution in production environments — fixed IP addresses are recommended instead.
Short Opt | Long Option | Env Variable | Description | Default Value |
---|---|---|---|---|
-L |
--log-level |
LOG_LEVEL |
Sets log verbosity (controls detail of output) | INFO |
-G |
--gateway |
GATEWAY_NAME |
Sets gateway name (inside Docker, the gateway is the host; allows resolving the host IP via gateway-name.suffix ) |
gateway |
-S |
--suffix |
SUFFIX_DOMAIN |
Sets the domain suffix for forwarded DNS queries | .docker |
-C |
--container |
CONTAINER_NAME |
Sets container name (used to send a test container-name.suffix resolution request to the forwarder on startup) |
docker-dns |
-D |
--dns-server |
FORWARD_DNS |
Sets the target DNS server for forwarded queries (default: Docker’s built-in DNS) | 127.0.0.11 |
-P |
--port |
LISTEN_PORT |
Sets the port the service listens on | 53 |
-K |
--keep-suffix |
KEEP_SUFFIX |
Controls whether to retain the suffix when forwarding DNS queries (strip suffix when forwarding to 127.0.0.11 ) |
Disabled |
-M |
--max-hops |
MAX_HOPS |
Sets maximum hop count for DNS queries (prevents looped queries) | 3 |
-W |
--workers |
NUM_WORKERS |
Sets the number of worker threads for the service | 4 |
-f |
--foreground |
- | Runs the service in foreground mode (does not daemonize) | Disabled (daemon by default) |
-h |
--help |
- | Shows this help message (lists options + descriptions) and exits | - |
root@VM-4-2-debian:~# ./docker-dns/docker-dns -h
Usage: ./docker-dns [OPTIONS]
Options:
-L, --log-level Set log level (DEBUG, default: INFO, WARN, ERROR, FATAL)
-G, --gateway Set gateway name (default: gateway)
-S, --suffix Set suffix name (default: .docker)
-C, --container Set container name (default: docker-dns)
-D, --dns-server Set forward DNS server (default: 127.0.0.11)
-P, --port Set listening port (default: 53)
-K, --keep-suffix keep suffix forward dns query (default: strip)
-M, --max-hops Set maximum hop count (default: 3)
-W, --workers Set number of worker threads (default: 4)
-f, --foreground Run in foreground mode (do not daemonize)
-h, --help Show this help message and exit
Environment variable:
Command-line arguments take precedence over environment variables.
--log-level => LOG_LEVEL
--gateway => GATEWAY_NAME
--suffix => SUFFIX_DOMAIN
--container => CONTAINER_NAME
--dns-server => FORWARD_DNS
--port => LISTEN_PORT
--keep-suffix => KEEP_SUFFIX
--max-hops => MAX_HOPS
--workers => NUM_WORKERS