I’m trying to run Pi-hole + Unbound in Docker on my server, with the help of Chatgpt, but I keep running into issues with Unbound. Pi-hole works fine, but Unbound keeps crashing with this error:
/unbound.sh: line 36: /opt/unbound/etc/unbound/unbound.conf: Is a directory
input in flex scanner failed
unbound exited with code 2
Verified unbound.conf is a file and not a directory
Placed unbound.conf inside a config directory
Ran docker-compose down -v and docker-compose up -d
Checked the file inside the container using:
docker run -it --rm -v ~/docker/unbound/config:/opt/unbound/etc/unbound mvance/unbound:latest sh
The unbound.conf file is visible inside /opt/unbound/etc/unbound
Problem:
Unbound still fails with the message that unbound.conf is a directory, even though the file exists in the config folder. I suspect something is wrong with the Docker volume mounting.
Has anyone successfully run Unbound in Docker with Pi-hole as upstream DNS? How should I configure the volumes and paths so that Unbound starts correctly?
I let ChatGPT compose a reply, as he knows the problem better than I do:
I switched from mvance/unbound to klutchell/unbound as suggested and updated my docker-compose.yml to use the newer Pi-hole v6 environment variables (FTLCONF_*).
At this point:
Pi-hole starts correctly (still in “health: starting”, but no crashes)
Unbound no longer shows the “unbound.conf is a directory” error
My unbound.conf validates and runs fine when I start it manually inside a container (unbound -d -c ...)
However, I’m still running into an issue where the Unbound container keeps restarting:
unbound Restarting
And DNS queries fail:
dig @127.0.0.1 -p 5335 google.com
;; no servers could be reached
I’ve verified the following:
unbound.conf is a file (not a directory)
File permissions are correct (readable)
Paths in docker-compose.yml are correct (../unbound/...)
Unbound runs fine manually in a test container with the same config
So it seems like: The config itself is valid But something in the container startup is still causing it to exit
At this point I suspect either:
an issue with how the container is started (command / entrypoint), or
a mismatch between expected paths inside the image
Does anyone see something obvious I’m missing in this setup?
I’m resuming my ChatGPT session, but it seems to not be able to resolve the problem and I’m in a loop. Could someone take a look at my docker-compose.yml file and reply with some suggestions or preferably rewrite my docker-compose.yml file?
I thought I could set this up with the help of ChatGPT, whith almost 0 knowledge of Linux/Debian… but seems not. I did learn some commands and things, but else I have no clue…
I think AI is not giving you the most correct information.
Unrelated to your issue: the version: element is obsolete since v2, so you can remove this line from every compose file.
This is usually not necessary if you are using Klutchell's image.
Note about volumes:
ChatGPT recommendation for the volumes is different than the official compose file.
Your compose file is mounting a file (unbound.conf) as a directory /etc/unbound/unbound.conf/ (ending with a /). This is probably causing issues.
Also, as explained here, you don't need to modify the default config in /etc/unbound as it is configured to load custom configs from /etc/unbound/custom.conf.d.
You can use AI help, but don't believe the answer was correct without checking using other sources. My suggestion is to also read a lot to understand what the AI answer is doing.
In this case, I think the suggested image was a good choice (I actually use Klutchell's image here), but comparing the suggested compose file with the official example shows a lot of differences (and possibly mistakes).
Try to paste the error message (or file contents) inside a code block, using one line containing ``` before and another one after the error message, like this:
```
My error message
```
The result will be:
My error message
Also, you can simply copy and paste images directly on the post, when necessary.
volumes:
pihole:
services:
pihole:
container_name: pihole
image: pihole/pihole:latest
ports:
'53:53/tcp'
'53:53/udp'
'80:80/tcp'
'443:443/tcp' *# FTL will generate a self-signed certificate. Not required to use*
networks:
default
environment:
# Sets upstream DNS to unbound sibling container*
FTLCONF_dns_upstreams: unbound
# If using Docker's default \`bridge\` network setting the dns listening mode should be set to 'all'*
FTLCONF_dns_listeningMode: all
# Set the appropriate timezone for your location*
# See* https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
# e.g. Europe/Paris, US/Pacific, Asia/Tokyo*
TZ: 'Europe/Amsterdam'
# See* https://github.com/pi-hole/docker-pi-hole *for all options*
volumes:
pihole:/etc/pihole'
restart: unless-stopped
unbound:
image: klutchell/unbound
networks:
default
healthcheck:
# Use the drill wrapper binary to reduce the exit codes to 0 or 1 for healthchecks*
test: \['CMD', 'drill-hc', '@127.0.0.1', 'dnssec.works'\]
interval: 30s
timeout: 30s
retries: 3
start_period: 30s
volumes:
/path/to/config:/etc/unbound/custom.conf.d
restart: unless-stopped
networks:
default:
driver: bridge
At this point, the main issue seems to be that the Unbound container is stuck in a restart loop. It never stays up long enough to accept connections, which explains why queries to 127.0.0.1:5335 fail with “connection refused”.
From the logs, I only see the generic Unbound usage output, which suggests that it is not successfully loading the configuration file.
Earlier, I also ran into an issue where unbound.conf was accidentally created as a directory instead of a file. I have since removed that and recreated it as a proper file, so that specific issue should be resolved now.
Those **-** don't look like they really would be part of your compose file.
Could you please update your post and correct that?
You likely see that message as there is nothing listening on port 5335, which seems correct with your current configuration:
The above compose doesn't expose any ports for its unbound container - it is meant to be accessible only to containers on the same network, i.e. from the pihole container on the same default brigde network.
You'd still need to adjust unbound's volume as rdwebdesign mentioned, e.g. to read:
Sorry for the screenshots above, but this forum won’t let met post this as text. Some error message because I’m new user and can’t name another username or something.
There's no point in sharing your AI conversation.
It just clutters the topic with obsolete contents.
The relevant information isn't with AI, but with you - what you observe on your system, how your configuration looks like, and any errors you encounter.
Try following rdwebdesign's recommendations for pasting text:
Judging by how your ls -l output shows that directory as populated, it would seem that ./unbound/config was the folder you've already been using for mvance/unbound. The folder would be empty for klutchell.
In that case, you'd be starting klutchell/unbound with mvance's configuration, which quite probably isn't matching klutchell.
Please edit your docker compose file to replace your volumes lines as suggested, and start up your containers afresh with that file.
It's correctly showing unbound as Pi-hole's sole upstream, as custom DNS server.
Note that any option that you control via your Pi-hole container's environment variables will become read-only in Pi-hole's UI.
Accordingly, you'd need to edit your docker compose file if you'd want to change such an option's value.
No, unbound is your Pi-hole's upstream.
Your DNS resolution chain looks like this:
client Pi-hole unbound public authoritative DNS servers.
That is a statistical figure, not an indicator of blocking quality.
It can be expected to fluctuate over time, even wildly, according to the domains your clients try to connect to.
If you had only a single client spending time on Pi-hole's forum, your blocking rate would be close to 0%.
And at 100% blocking rate, you wouldn't be able to connect to anything.