Docker DNS Error on Raspberry Pi

I have a Raspberry Pi 3 Model B Plus Rev 1.3, running Debian GNU/Linux 12 (bookworm). uname -a prints:

Linux raspberrypi 6.12.25+rpt-rpi-v8 #1 SMP PREEMPT Debian 1:6.12.25-1+rpt1 (2025-04-30) aarch64 GNU/Linux

It is running Docker version 28.5.1, build e180ab8.

I have a Docker container that works fine when run in Docker on my PC, but when run on my Raspberry Pi, I get DNS errors.

The bot’s log output, on Docker in Raspbian, is:

logging output
Logging in
node:internal/deps/undici/undici:14900
      Error.captureStackTrace(err);
            ^

TypeError: fetch failed
    at node:internal/deps/undici/undici:14900:13
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5) {
  [cause]: Error: getaddrinfo EAI_AGAIN lemmy.zip
      at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:dns:122:26) {
    errno: -3001,
    code: 'EAI_AGAIN',
    syscall: 'getaddrinfo',
    hostname: 'lemmy.zip'
  }
}

Node.js v22.21.1

If I do ping lemmy.zip, outside of Docker, it works absolutely fine.

My Pi’s DNS settings are:

/etc/resolv.conf
search Home
nameserver 9.9.9.9
nameserver 149.112.112.112

I assume, but do not know for sure, that this is loosely related to my earlier issue with even doing a docker pull, which users on here were able to successfully assist me with, and reducing my resolv.conf down to what it is now seemed to be the solution.

I have created this minimal script to test it out. It makes an HTTP request to a list of sample sites and returns if it was able to contact them.

Code
const https = require('https');

const TEST_ENDPOINTS = [
  'https://www.google.com',
  'https://api.github.com',
  'https://www.nytimes.com/games/connections',
  'https://example.com',
  'https://lemmy.zip'
];

function testConnection(url) {
  return new Promise((resolve, reject) => {
    const req = https.get(url, { timeout: 5000 }, (res) => {
      res.on('data', () => {});
      res.on('end', () => resolve(true));
    });

    req.on('error', reject);
    req.on('timeout', () => {
      req.destroy();
      reject(new Error('Timeout'));
    });
  });
}

async function main() {
  const results = await Promise.allSettled(
    TEST_ENDPOINTS.map(url => testConnection(url))
  );
  
  const successCount = results.filter(r => r.status === 'fulfilled').length;
  console.log(`\n${successCount}/${results.length} successful`);
  process.exit(successCount === 0 ? 1 : 0);
}

main();

If I run it with npm start on my PC, or by building a Docker container and then running the container on my PC, it works. The output is 5/5 successful. But when I build it on my Raspberry Pi and run the Docker container on there, it is 0/5 successful

The whole point of this is not to install Node directly on the Pi, but I simulated the same code by running

curl -s -o /dev/null -w "%{http_code}" --max-time 5 https://www.google.com
curl -s -o /dev/null -w "%{http_code}" --max-time 5 https://api.github.com
curl -s -o /dev/null -w "%{http_code}" --max-time 5 https://www.nytimes.com/games/connections
curl -s -o /dev/null -w "%{http_code}" --max-time 5 https://example.com
curl -s -o /dev/null -w "%{http_code}" --max-time 5 https://lemmy.zip

In every case, the result was 200.

Just to be safe, I also did

wget -q --spider --timeout=5 https://www.google.com && echo "success" || echo "fail"
wget -q --spider --timeout=5 https://api.github.com && echo "success" || echo "fail"
wget -q --spider --timeout=5 https://www.nytimes.com/games/connections && echo "success" || echo "fail"
wget -q --spider --timeout=5 https://example.com && echo "success" || echo "fail"
wget -q --spider --timeout=5 https://lemmy.zip && echo "success" || echo "fail"

I get five successes.

If I run it with

docker run --network host docker-network-test

It is able to succeed, getting 5/5. I’m not 100% sure what this does, or if/why it’s bad to do. It certainly feels inelegant.

I saw some other guides suggesting something about a Docker bridge, but as far as I can tell that should be for connections between pods, not necessary for connecting a Docker pod to the Internet?

Are you using the same DNS resolvers on your PC?

On the Pi, cat /etc/resolv.conf:

# Generated by NetworkManager
search Home
nameserver 9.9.9.9
nameserver 149.112.112.112

On my PC, on Windows, Network settings show IPv4 DNS servers: 9.9.9.9, 149.112.112.112

And just to be safe, my router’s LAN IPv4 setting has:

Primary DNS Server: 9.9.9.9
Secondary DNS Server: 149.112.112.112

And its WAN connection has:

Primary DNS Server: 9.9.9.9
Secondary DNS Server: 149.112.112.112


I also tried running, on the Pi:

$ docker run --rm alpine nslookup google.com
nslookup: can't connect to remote host (9.9.9.9): Network unreachable

So the problem seems not to be with the DNS configuration, but something else.

What are you running exactly? Where did you get the “Debian GNU/Linux 12 (bookworm)” image?

Why not run Raspberry Pi OS, which is Pi-customized and a derivative of Debian?

I am running Raspbian, obtained from the official Raspberry Pi website, the latest version of which is presumably based on Debian Bookworm. “Debian GNU/Linux 12 (bookworm)” is what you get with cat /etc/os-release, anyway.

Running uname -a outputs

Linux raspberrypi 6.12.25+rpt-rpi-v8 #1 SMP PREEMPT Debian 1:6.12.25-1+rpt1 (2025-04-30) aarch64 GNU/Linux

Which I assume is the full version of Raspbian that I’m running.

I noticed I was getting this error on startup:

docker WARNING: IPv4 forwarding is disabled. Networking will not work.

So I fixed that by editing /etc/sysctl.conf to include:

net.ipv4.ip_forward=1

After restarting the Pi (because I could not figure out how to just restart the networking…), I then tried the Docker container again.

Unfortunately this does not appear to have helped:

TypeError: fetch failed
    at node:internal/deps/undici/undici:14900:13
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5) {
  [cause]: Error: getaddrinfo EAI_AGAIN lemmy.zip
      at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:dns:122:26) {
    errno: -3001,
    code: 'EAI_AGAIN',
    syscall: 'getaddrinfo',
    hostname: 'lemmy.zip'
  }
}

I also tried passing --network host. This did work, with the network call getting through.

Is --network host a recommended approach? Is it some sort of security issue to be doing that? Or is there another way to get network calls to work?

Of course not. Network isolation is there for a reason. A process in a container doesn’t have to know anything about your real network that can be used for attacks, and definitely doesn’t have to be able to listen on any chosen IP address, whihc by the way also can be used for stealing data if an attacker starts a server to browse all the data mounted to the container.

Docker containers by default using bridge network. There is a default bridge and you can create custom bridge networks. This is what Docker Compose does for example. It is not only for communication between containers, but it is true, containers can communicate over network only on the same bridge network. The bridge makes the connection between the container’s network namespace and the host to be able to reach the internet.

When using a host network, there is no network isolation, so whatever incompatibility there is betwen the physical network and container network, you won’t have that when you disable network isolation by using host network. That is not a special kind of network driver, but the lack of network isolation. Similar to passing --pid host to disable process isolation and see all the processes on the host from the container. Disabling any type of isolation is generally a security issue, so do it only when you know the goal requires that and there is no other way..

Quickly checking the linked previous topic, I don’t see possible network collision mentioned so I mention here.

A docker bridge gets its own IP range. If you have something in your network in an intersecting ip range, that could cause the described error. But Docker detects local networks, so if it is some kind of network collision, it is not directly on the Docker host.

You can list all subnets by using this command:

docker network ls --format '{{ .Name }}' \
  | xargs -I '{}' -- docker network inspect {} \
  | jq -r '.[].IPAM.Config | select(. != null) | .[].Subnet' \
  | sort

If all subnets are starting with 172, you can try

docker network create --subnet 192.168.99.0/24 testnet
docker run --rm -it --network testnet curlimages/curl https://example.org

If the networks start with 192 then you can try a subnet in 10.x.x.x or 172.20.1.0/24 for example if available.

1 Like

Of course not. Network isolation is there for a reason.

Thanks, I thought so, but wasn’t able to find a clear explanation, since it has so far been the only way I’ve been able to get a network connection in Docker on my Pi.

It is not only for communication between containers

Ah ok, thanks a bunch. I must have misread something at some point, then. I think this might be a useful course for me to pursue to fix the issue.

docker network ls --format '{{ .Name }}' \
  | xargs -I '{}' -- docker network inspect {} \
  | jq -r '.[].IPAM.Config | select(. != null) | .[].Subnet' \
  | sort

I had to install jq, but once I did, response is the empty string.

docker network ls gives

NAME DRIVER SCOPE
host host   local
none null   local

The docker network inspect for both networks contains

"IPAM": {
    "Driver": "default",
    "Options": null,
    "Config": null
},

If it helps, ifconfig shows eth0, lo, and wlan0, but there is no docker0. I’m not completely sure, or sure why, but it seems like Docker on my Pi didn’t install a default bridge?

This can’t be right!. Afaik, It should even be re-created when docker starts/restarts, unless it’s somehow prevented by configuration in /etc/docker/daemon.json or the docker systemd unit.

1 Like

Whelp. You solved it! :man_facepalming:

One of the many things I tried in solving my previous issue was following some site’s guide to creating a custom daemon.json, which included (among other things) "bridge": "none". Had completely forgotten about it, since that wasn’t what actually solved the problem for me. Deleted the entire file, restarted Docker, and eureka!

Thanks!

I am glad, it’s finally sorted out!

I would always be careful with guides written by enthusiasts. They have their heart at the right place, and want to share what worked for them.. But often times they lack the in-depth knowledge an expert has, and suggest things an expert never would.

On long term, its easier and less time-consuming to learn the concept and mechanics of docker, as it allows understanding and solve problems, rather than just gamble on whether a tutorial might still work, or not.