Sharing a VPN container's network namespace gives your application the tunnel's interfaces and routes. It does not give it the tunnel's resolver, or a merged copy of anything else on the host. That gap produces a very specific failure: public names resolve, internal names do not, and the app that fails looks like it is using the wrong DNS server because it is. The repair is usually smaller than the diagnosis suggests.

Step 1: Test from the app, not the host

Run the lookup inside the container that has the problem, not on the host and not in a browser. docker exec app-container getent hosts db.internal answers the only question that matters, which is what this process's resolver returns.

If the host resolves the name and the container does not, you have found the fault. Everything after this is choosing a supported way to fix it.

Step 2: Read the runtime's supported model

Docker's network documentation records restrictions on DNS flags for containers that share another container's network mode. In Compose, network_mode: service:vpn ties the app to the VPN container's namespace, and per-service dns settings do not behave the way they do for an ordinary service. The resolution you get is the one the shared namespace has.

User-defined bridge networks also use Docker's embedded DNS differently from the default bridge. That is why a dns stanza copied from a working bridge example can do nothing at all in a shared stack. Check the arrangement before copying the stanza.

A loopback address always refers to the relevant network context. Inside a shared namespace, 127.0.0.1 is not the host's resolver.

Step 3: Follow the query to its recipient

Read the app's resolver configuration, then any application-specific encrypted DNS the app ships with, because an app that runs its own resolver ignores the file you edited. Then check whether the selected resolver is reachable under the VPN's routes and firewall policy. A resolver address on the far side of the tunnel is useless if the namespace has no route to it. Confirm the recipient before you edit any file.

A browser IP-check page cannot tell you where name queries went. It tells you where one HTTP connection went.

Step 4: Fix the two failure classes differently

If service names fail while public names work, the problem is service discovery inside the container network, not the public resolver list. Changing every public DNS address will not create records the network's discovery mechanism was never asked for.

If both classes fail, start with reachability to the resolver. If only one fails, start with the discovery mechanism. The two have different owners, which is why one repair never covers both.

Step 5: Retest after recreation

Change the configuration through the runtime's supported mechanism, then recreate the containers rather than editing files inside a running one. Test a fresh private name, a fresh public name, and the application request that follows the lookup. An edit to /etc/resolv.conf inside a container disappears on recreation and will convince you the fix worked when it did not.

Record the resolver owner and the expected namespace beside the shared network definition. The next person will need both.

Sɛbɛn minnu bɛ tali kɛ