Skip to content
DevOps AI ToolKit
Newsletter

Kali Linux on Docker · Part 10 of 16

DNS Troubleshooting From a Kali Docker Container

Difficulty: Intermediate ~16 min Part 10/16
Prerequisites: Kali Linux fundamentalsBasic Docker knowledge
Series progress10 / 16
Series curriculum (16 lessons)

When a container “cannot reach” another service, the failure is almost always name resolution, not the network wire. A Kali container is a perfect vantage point to prove which one it is: it ships with the tools to ask, step by step, “who does this name resolve to, and who is answering?” In this lesson you will read the container’s DNS configuration, resolve a lab service name two different ways, and walk a systematic path from the container all the way out to an external resolver.

Only scan, inspect, or test systems you own or have explicit permission to assess. Everything here targets your own local lab containers and benign public endpoints like example.com.

The Core Idea: Docker’s Embedded DNS

Docker runs a small DNS server inside every user-defined network. Each container on that network has its /etc/resolv.conf pointed at the special address 127.0.0.11 — Docker’s embedded DNS resolver. That resolver does two jobs:

  1. Service-name resolution. It knows the name and IP of every container and Compose service on the same user-defined network, so web resolves to that container’s address automatically.
  2. External forwarding. For anything it does not own (like example.com), it forwards the query to the host’s configured resolvers.

This behavior is not on by default everywhere. On the default bridge network (what you get with no --network flag), Docker does not provide automatic service-name resolution — containers there can only find each other by IP or the legacy --link flag. On a user-defined network (one you create with docker network create, or any network Compose creates for you), service-name DNS is automatic. That single distinction is the root cause of a large share of “it can’t resolve the other container” tickets.

🛠️ DevOps Perspective — “Expected State vs Observed State” applies cleanly to DNS. Expected: web resolves to a 172.x container address via 127.0.0.11. Observed: web does not resolve at all. The gap between those two statements tells you where to look — the resolver config, the network attachment, or the name itself — before you touch anything.

Building a Tiny Lab

So the commands have something real to resolve, create a user-defined network and a service named web, then attach a Kali container to the same network:

docker network create labnet
docker run -d --name web --network labnet nginx
docker run --rm -it --network labnet kalilinux/kali-rolling bash
  • docker network create labnet creates a user-defined bridge network. This is the step that turns on embedded service-name DNS.
  • docker run -d --name web --network labnet nginx starts a background (-d, detached) nginx container named web on that network. The --name is the DNS name other containers will resolve.
  • The Kali docker run uses --rm (remove the container on exit), -it (-i keeps STDIN open, -t allocates a TTY so you get an interactive shell), and --network labnet to place Kali on the same network as web.

From here on, the commands run inside the Kali container.

Command 1: Read the Resolver Config

Start by asking the container what it thinks its DNS server is:

cat /etc/resolv.conf
  • cat prints a file; /etc/resolv.conf is the standard Linux resolver configuration that every DNS-aware program reads to learn which nameserver to query.

On a user-defined network you will see something like:

nameserver 127.0.0.11
options ndots:0

That nameserver 127.0.0.11 is the signal you are looking for: this container is wired to Docker’s embedded DNS, so automatic service-name resolution should work. If instead you see your host’s or a public resolver’s address (for example nameserver 8.8.8.8) with no 127.0.0.11, the container is almost certainly on the default bridge — and service names will never resolve there.

🔎 Troubleshooting Tip — Make /etc/resolv.conf your first stop, always. If nameserver 127.0.0.11 is present, DNS plumbing is correct and you should suspect the network attachment or the name. If it is absent, stop debugging the name and go fix the network the container is on — no amount of retrying dig web will help.

Command 2: Resolve a Service Name the Way Apps Do

getent hosts web
  • getent queries the system’s Name Service Switch (NSS) — the same resolution path your actual applications use (files, then DNS, in the order /etc/nsswitch.conf defines). hosts web asks it to resolve the host web.

A healthy result prints the resolved address and name:

172.18.0.2      web

Because getent follows the real application resolution path, it is the most faithful test of “will my service actually find web?” If getent hosts web succeeds but your app still fails to connect, you have proven the problem is past DNS — a port, a firewall, or the service itself — not name resolution. If getent hosts web prints nothing and exits non-zero, the name did not resolve, and the next command tells you why.

Command 3: Query the Resolver Directly

dig web
  • dig is a DNS lookup tool (install it in Kali with apt-get update && apt-get install -y --no-install-recommends dnsutils if it is missing). Unlike getent, dig talks straight to the nameserver in /etc/resolv.conf and shows you the full transaction — which server answered, the status code, and the returned records.

Read the SERVER: line and the status: in the header:

  • SERVER: 127.0.0.11#53 confirms Docker’s embedded DNS answered.
  • status: NOERROR with an ANSWER SECTION means the name resolved.
  • status: NXDOMAIN means the server answered but does not know that name — a strong hint the service name is wrong or the container is on a different network.

dig shines for external names too. Run dig example.com to prove that forwarding to the host’s upstream resolvers works. If dig web succeeds but dig example.com returns SERVFAIL or times out, the embedded resolver is healthy but the host’s upstream DNS is the problem — a completely different fix.

🏭 Why This Matters in Production — In CI and orchestrated environments, “service can’t reach service” pages on-call constantly. Being able to say, in three commands, “resolution is fine, the fault is downstream” (or “the resolver never answered, it’s a network-attachment problem”) turns a 40-minute guessing session into a two-minute diagnosis.

The Resolution Path

Every one of the scenarios below is a break at one specific link in this chain. Knowing the chain tells you which command isolates which link:

Container

Network Attachment

Docker DNS

Service Name

External Resolver
  • Container → Network Attachment: is Kali on the same user-defined network as the target? (docker inspect, /etc/resolv.conf)
  • Network Attachment → Docker DNS: is 127.0.0.11 the nameserver? (cat /etc/resolv.conf)
  • Docker DNS → Service Name: does the embedded resolver know the name? (getent hosts web, dig web)
  • Service Name → External Resolver: for non-container names, does forwarding work? (dig example.com)

Try It Yourself

With the lab from earlier still running, work the chain top to bottom from inside the Kali container:

🧪 Try It — Run these in order and predict each result before you read it:

  1. cat /etc/resolv.conf — confirm nameserver 127.0.0.11.
  2. getent hosts web — expect the container IP and the name web.
  3. dig web — confirm SERVER: 127.0.0.11#53 and status: NOERROR.
  4. dig example.com — confirm external forwarding returns an answer.
  5. Now break it on purpose: exit, then start a Kali container with no --network flag (docker run --rm -it kalilinux/kali-rolling bash) and run getent hosts web again. It fails — because the default bridge has no service-name DNS. You just reproduced the single most common cause.

Common Problems

Container cannot resolve another service

This is the headline symptom. Walk the resolution path in order; each step rules out one link.

Symptom: getent hosts web prints nothing, or your app logs could not resolve host: web / Name or service not known.

Diagnostic steps:

  1. Check the resolver. cat /etc/resolv.conf. No nameserver 127.0.0.11? The container is on the default bridge or has custom DNS — service names won’t resolve. Recreate it with --network <your-user-defined-net>.
  2. Check the network attachment. From the host: docker inspect -f '{{json .NetworkSettings.Networks}}' <container> for both the Kali container and web. They must list the same user-defined network. A container attached to the wrong network cannot see the other’s name.
  3. Check the service name. dig web returning NXDOMAIN on a working 127.0.0.11 almost always means the name is wrong. Confirm the real name: docker ps --format '{{.Names}}' (or, under Compose, the service key in compose.yaml, not the generated container name). Typos and using the container name where a service alias is expected are common.
  4. Isolate external DNS. If container names resolve but dig example.com fails (SERVFAIL/timeout), the fault is the host’s upstream resolver, not Docker. Test the host directly; fix /etc/docker/daemon.json dns settings or the host’s resolvers.
  5. Check the search domain. If short names behave oddly, look at the search line and ndots in /etc/resolv.conf. A stray search domain can make a bare name expand into a fully-qualified name that doesn’t exist; try the name with a trailing dot (dig web.) to bypass search-domain expansion and compare.
  6. Check the DNS configuration. A container started with an explicit --dns 8.8.8.8 overrides Docker’s embedded resolver entirely, so it loses service-name resolution while still reaching the internet. Drop the override (or add it only on the daemon for external resolution) so 127.0.0.11 handles container names.

Mapping each scenario to the path: no 127.0.0.11 = network attachment; wrong network = network attachment; NXDOMAIN = service name; external SERVFAIL = external resolver; odd short-name behavior = search domain; a --dns override = DNS configuration.

💡 Note — Restarting containers can change their IPs, but the name stays stable on a user-defined network — that stability is exactly why you resolve by service name instead of hardcoding an address.

What You Learned

  • Docker’s embedded DNS lives at 127.0.0.11 and provides automatic service-name resolution only on user-defined networks — the default bridge does not.
  • cat /etc/resolv.conf confirms the resolver, getent hosts web tests the real application resolution path, and dig web shows the full transaction and status code.
  • The resolution path — Container → Network Attachment → Docker DNS → Service Name → External Resolver — lets you isolate a failure to one specific link.
  • NXDOMAIN points at a wrong service name or wrong network; a working dig web but failing dig example.com points at the host’s upstream resolver.
  • Search-domain expansion and explicit --dns overrides are subtler causes worth checking once the obvious two are ruled out.
  • Systematic “Expected vs Observed” thinking turns a vague “can’t reach the service” into a precise, one-link diagnosis.

Affiliate Disclosure: Some links on this page are affiliate links. If you purchase through one of these links, DevOps AI Toolkit may earn a commission at no additional cost to you. See our affiliate disclosure.

← Back to Kali Linux on Docker Back to Kali Linux

Related on DevOps AI Toolkit