MatthewVance / unbound-docker-rpi

Run Unbound with latest version of OpenSSL on Raspberry Pi with Docker.
MIT License
136 stars 23 forks source link

Will Not Start: Seems Unable to Read .conf file. #9

Closed johntdavis84 closed 3 years ago

johntdavis84 commented 3 years ago

Hello,

Thanks for making this available. I'd much rather have it inside docker than risk screwing up my entire system trying to run it, especially since I've never tinkered with DNS servers before outside of pi-hole.

I'm running into an issue getting unbound to start on my Raspberry Pi 4b using the latest version of docker and docker-compose.

The service comes up, but fails to read the unbound.conf file correctly.

Logged errors:

[1611992491] unbound[1:0] fatal error: Could not read config file: /opt/unbound/etc/unbound/unbound.conf. Maybe try unbound -dd, it stays on the commandline to see more errors, or unbound-checkconf
│ /opt/unbound/etc/unbound/unbound.conf:13: error: unknown keyword 'do-ipv4'
│ /opt/unbound/etc/unbound/unbound.conf:13: error: stray ':'
│ /opt/unbound/etc/unbound/unbound.conf:13: error: unknown keyword 'yes' │ /opt/unbound/etc/unbound/unbound.conf:14: error: unknown keyword 'do-ipv6'
│ /opt/unbound/etc/unbound/unbound.conf:14: error: stray ':'
│ /opt/unbound/etc/unbound/unbound.conf:14: error: unknown keyword 'yes'
│ /opt/unbound/etc/unbound/unbound.conf:17: error: unknown keyword 'prefer-ipv6'
│ /opt/unbound/etc/unbound/unbound.conf:17: error: stray ':'
│ /opt/unbound/etc/unbound/unbound.conf:17: error: unknown keyword 'yes'
│ read /opt/unbound/etc/unbound/unbound.conf failed: 9 errors in configuration file

Here is the relevant portion of my docker-compose.yml file.

 unbound:
    container_name: unbound
    image: mvance/unbound-rpi:latest
    volumes:
       - './vUnbound:/opt/unbound/etc/unbound'
    ports:
      - "5053:53/tcp"
      - "5053:53/udp"
    # healthcheck:
    #  disable: true
    restart: always

the vUnbound folder exists in the same directory as my docker-compose.yml file, and looks like this: vUnbound/

unbound.conf looks like this: ]$ cat unbound.conf

server:

SOURCE: https://www.xfelix.com/2020/09/pihole-unbound-docker-setup-on-raspberry-pi/

# DOCS: https://nlnetlabs.nl/documentation/unbound/unbound.conf/
# MODIFICATIONS BASED ON: https://calomel.org/unbound_dns.html (See: "Authoritative, validating, recursive caching DNS (example 3)")
# If no logfile is specified, syslog is used
logfile: "var/log/unbound/unbound.log"
verbosity: 1
directory: "/opt/unbound/etc/unbound"

interface: 0.0.0.0
port: 53

do-ipv4: yes
do-ipv6: yes

# ONLY ENABLE IF native IPv6 is available:
prefer-ipv6: yes

do-udp: yes
do-tcp: yes

access-control: 172.18.0.0/16 allow
access-control: fd28:165f:7c15:1360::/112 allow
access-control: 127.0.0.0/8 allow
access-control: ::1/128 allow

# EXPLAINER: https://medium.com/nlnetlabs/aggressive-use-of-the-dnssec-validated-cache-in-unbound-1ab3e315d13f
aggressive-nsec: yes
cache-max-ttl: 14400

# ID SECURITY SETTINGS
# If enabled id.server and hostname.bind queries are refused:
hide-identity: yes
# If enabled version.server and version.bind queries are refused.
hide-version: yes

# Use this only when you downloaded the list of primary root servers!
# If you use the default dns-root-data package, unbound will find it automatically
root-hints: "./root.hints"

# Trust glue only if it is within the server's authority
harden-glue: yes

# Require DNSSEC data for trust-anchored zones, if such data is absent, the zone becomes BOGUS
harden-dnssec-stripped: yes

# Don't use Capitalization randomization as it known to cause DNSSEC issues sometimes
# see https://discourse.pi-hole.net/t/unbound-stubby-or-dnscrypt-proxy/9378 for further details
use-caps-for-id: no

# Reduce EDNS reassembly buffer size.
# Suggested by the unbound man page to reduce fragmentation reassembly problems
edns-buffer-size: 1472

# Perform prefetching of close to expired message cache entries
# This only applies to domains that have been frequently queried
prefetch: yes

# If yes, Unbound rotates RRSet order in response (the random number
# is taken from the query ID, for speed  and  thread  safety).
# Default is yes.
rrset-roundrobin: yes
        so-reuseport: yes

# RPi Defaul from Instructions: One thread should be sufficient, can be increased on beefy machines. In reality for most users running on small networks or on a single machine, it should be unnecessary to seek performance enhancement by increasing num-threads above 1.
# Additional lines added from colomel.org instructions.
num-threads: 4
msg-cache-slabs: 8
rrset-cache-slabs: 8
infra-cache-slabs: 8
key-cache-slabs: 8
msg-cache-size: 256M
rrset-cache-size: 512M
outgoing-range: 8192
num-queries-per-thread: 4096

# Ensure kernel buffer is large enough to not lose messages in traffic spikes
so-rcvbuf: 1m

# Ensure privacy of local IP ranges
private-address: 172.18.0.0/16
private-address: fd28:165f:7c15:1360::/112
private-address: 127.0.0.0/8
private-address: ::1/128

# Ensure privacy of local domains
# private-domain: "host.domain"

# Optimizations
unwanted-reply-threshold: 10000
val-clean-additional: yes
auto-trust-anchor-file: "./root.key"
MatthewVance commented 3 years ago

Thanks for the detailed issue report. That's always helpful.

I think it's having trouble reading the unbound.conf file due to how the volume is being mounted. Try this minor change:

    volumes:
       - './vUnbound:/opt/unbound/etc/unbound/'
johntdavis84 commented 3 years ago

Thanks for the detailed issue report. That's always helpful.

I think it's having trouble reading the unbound.conf file due to how the volume is being mounted. Try this minor change:

    volumes:
       - './vUnbound:/opt/unbound/etc/unbound/'

Thanks for your quick reply. I thought I might have gone a bit overboard when I wrote the post; I'm glad to know that it was useful.

I implemented the change you suggested, but I'm still getting the same error.

I should note I'm trying to use a single docker-compose.yml file to bring up both the unbound and pihole services. Compose version is 2.4. I need to update this compose file to version 3, but I haven't had the time yet.

I've also confirmed it can write to (and presumably read from?) the volume. Whenever I try to bring up the unbound service, it creates /dev/ and /var/ folders in there and populates them with what I assume are the default configs.

I'm a bit confused on one thing: How can it tell me about alleged syntax errors at specific lines if it can't read the config file?

Here's what the unbound part of the docker-compose looks like now. (Line numbers are provided by bat, which is a fancier version of cat. Line numbers do not appear in the docker-compose.yml file.)

16 │ services: 17 │ unbound: 18 │ container_name: unbound 19 │ image: mvance/unbound-rpi:latest 20 │ volumes: 21 │ - './vUnbound:/opt/unbound/etc/unbound/' 22 │ ports: 23 │ - "5053:53/tcp" 24 │ - "5053:53/udp" 25 │ # healthcheck: 26 │ # disable: true 27 │ restart: always

MatthewVance commented 3 years ago

I see what you mean. When I saw [1611992491] unbound[1:0] fatal error: Could not read config file: /opt/unbound/etc/unbound/unbound.conf. Maybe try unbound -dd, it stays on the commandline to see more errors, or unbound-checkconf at the top of the error, my first thought was it wasn't loading correctly.

This may be one of the cases where it'd be good to exec into the container . It'd be helpful to cd into /opt/unbound/etc/unbound/ to confirm the config files you're passing in as a volume are loading correctly.

This discussion on pihole with my image may help: https://github.com/MatthewVance/unbound-docker/issues/21#issuecomment-510300642. Here's what the unbound part of that user's docker-compose looks like:

unbound:
container_name: rpiDev-unbound
image: mvance/unbound-rpi:latest
hostname: rpiDev-unbound.jabba.lan
mac_address: d0:ca:ab:cd:ef:02
ports:
- "53:53/tcp"
- "53:53/udp"
volumes:
- /home/pi/Documents/docker/configs/unbound/:/opt/unbound/etc/unbound/
networks:
home:
ipv4_address: 192.168.1.6
restart: always

The thing that stood out to me is the / on the left side of the volume mount. That's different that what I said above, but it may work.

I haven't taken the time to convert my setup to docker-compose yet. I have for Stubby, but not plain Unbound. Running both from the same compose file should work fine. I also need to take some time to create a test setup with pi-hole so I can better help when those issues come up.

johntdavis84 commented 3 years ago

There's some stuff in that docker-compose config I don't fully understand. I've never had to set a MAC address or a hostname for a container before, for one thing.

I can't exec in, unfortunately. From ctop (basically top for containers; I prefer it to the graphical managers for quick troubleshooting and status checks), I can see that the service goes down almost instantly; it wouldn't stay up long enough for me to exec in.

I'm going to explore that thread you linked closer tomorrow morning, when I'm a bit sharper. (It's 1030p here.) Thanks for pointing me at it.

I did change the name of my customized conf file (which I will probably end up replacing/merging with your .conf file), so that unbound would generate its own. I thought that perhaps there was some poorly-formed white space from when I pasted text into the conf file or something, and that was keeping it from reading correctly. Since it failed with the autogenerated version, I'm assuming that's not the case. (Good job, me. :P )

I did notice that you mentioned the security problems related to not including: username: "_unbound"

I'm not using this, and I wonder if that could be it. If it's not using the correct username within the container, that could certainly cause a permissions issue...

Will try in the morning.

MatthewVance commented 3 years ago

I wondered about the user name as well. I should have mentioned that as a possibility but didn't because I didn't see it set wrong in your config.

As far as setting the MAC and such, that shouldn't be needed. I believe it was unique to that one setup.

On Sat, Jan 30, 2021, 10:38 PM johntdavis84 notifications@github.com wrote:

There's some stuff in that docker-compose config I don't fully understand. I've never had to set a MAC address or a hostname for a container before, for one thing.

I can't exec in, unfortunately. From ctop (basically top for containers; I prefer it to the graphical managers for quick troubleshooting and status checks), I can see that the service goes down almost instantly; it wouldn't stay up long enough for me to exec in.

I'm going to explore that thread you linked closer tomorrow morning, when I'm a bit sharper. (It's 1030p here.) Thanks for pointing me at it.

I did change the name of my customized conf file (which I will probably end up replacing/merging with your .conf file), so that unbound would generate its own. I thought that perhaps there was some poorly-formed white space from when I pasted text into the conf file or something, and that was keeping it from reading correctly. Since it failed with the autogenerated version, I'm assuming that's not the case. (Good job, me. :P )

I did notice that you mentioned the security problems related to not including: username: "_unbound"

I'm not using this, and I wonder if that could be it. If it's not using the correct username within the container, that could certainly cause a permissions issue...

Will try in the morning.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/MatthewVance/unbound-docker-rpi/issues/9#issuecomment-770324541, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAUMHOQMRZ7MXEDNM5DLZADS4TNE7ANCNFSM4W2CBTSQ .

johntdavis84 commented 3 years ago

I wondered about the user name as well. I should have mentioned that as a possibility but didn't because I didn't see it set wrong in your config. As far as setting the MAC and such, that shouldn't be needed. I believe it was unique to that one setup.

Tried it with the username. Still failed, but I got errors on different line numbers, even though it still starts with the original "cannot read" error.

Also disabled health check in the docker-compose.yml file. No change. Re-enabled.

I do get this message when I bring unbound up:

pi-hole]$ sudo docker-compose up -d unbound Building with native build. Learn about native build in Compose here: https://docs.docker.com/go/compose-native-build/

This seems innocuous, though (?).

I just had a thought. I wonder if I've got a permissions issue with the .conf file: unbound.conf is owned by my non-administrator normal user. I run docker and docker-compose using sudo, so they run as root. When I try to bring up the unbound instance, it creates a /dev/ folder owned by root, and a /var/ folder owned by my host's non-root user.

What permissions do you have your unbound.conf file set to?

(Once I get the unbound instance to come up, I'm going to stop and really try to grok your unbound.conf file. It's very different than mine in terms of customization.)

MatthewVance commented 3 years ago

I do get this message when I bring unbound up:

pi-hole]$ sudo docker-compose up -d unbound Building with native build. Learn about native build in Compose here: https://docs.docker.com/go/compose-native-build/

This seems innocuous, though (?).

That's new to me. I had to look at the Docker docs. It sounds innocuous, but it seems to imply it's trying to build something. That seems odd because it should just pull down a pre-built image from Docker Hub.

What permissions do you have your unbound.conf file set to?

Well, I have the benefit of using the built-in config rather than mounting a custom one. However, I do customize the forward-records. For it, the permissions are (like you, I run docker with sudo):

drwxr-xr-x  2 pi pi 4096 Dec 27 21:30 .
drwxr-xr-x 17 pi pi 4096 Jan 11 19:48 ..
-rw-r--r--  1 pi pi 2172 Dec 27 21:29 forward-records.conf

Within the container, here's what /opt/unbound/etc/unbound looks like:

drwxr-xr-x 1 root     root      4096 Jan 12 03:47 .
drwxr-xr-x 1 root     root      4096 Dec 22 04:40 ..
-rw-r--r-- 1 root     root       134 Dec 22 03:06 a-records.conf
drwxr-xr-x 2 root     root      4096 Jan 29 18:12 dev
-rw-r--r-- 1 _unbound _unbound  2172 Dec 28 03:29 forward-records.conf
-rw-r--r-- 1 root     root        95 Dec 22 03:06 srv-records.conf
-rw-r--r-- 1 root     root     12915 Jan 12 03:47 unbound.conf
-rw-r--r-- 1 root     root     44643 Dec 22 04:40 unbound.conf.example
-rw-r--r-- 1 _unbound _unbound     2 Jan 29 18:12 unbound.pid
drwx------ 2 _unbound _unbound  4096 Jan 31 22:48 var

I don't launch it with compose currently, but sharing this in case it helps:

sudo docker run \
--name=unbound-rpi \
--volume=$(pwd)/my_conf/forward-records.conf:/opt/unbound/etc/unbound/forward-records.conf:ro \
--publish=53:53/tcp \
--publish=53:53/udp \
--restart=unless-stopped \
--detach=true \
mvance/unbound-rpi:latest

Here's my full unbound.conf (generated from the shell script):

server:
    ###########################################################################
    # BASIC SETTINGS
    ###########################################################################
    # Time to live maximum for RRsets and messages in the cache. If the maximum
    # kicks in, responses to clients still get decrementing TTLs based on the
    # original (larger) values. When the internal TTL expires, the cache item
    # has expired. Can be set lower to force the resolver to query for data
    # often, and not trust (very large) TTL values.
    cache-max-ttl: 86400

    # Time to live minimum for RRsets and messages in the cache. If the minimum
    # kicks in, the data is cached for longer than the domain owner intended,
    # and thus less queries are made to look up the data. Zero makes sure the
    # data in the cache is as the domain owner intended, higher values,
    # especially more than an hour or so, can lead to trouble as the data in
    # the cache does not match up with the actual data any more.
    cache-min-ttl: 300

    # Set the working directory for the program.
    directory: "/opt/unbound/etc/unbound"

    # RFC 6891. Number  of bytes size to advertise as the EDNS reassembly buffer
    # size. This is the value put into  datagrams over UDP towards peers.
    # The actual buffer size is determined by msg-buffer-size (both for TCP and
    # UDP). Do not set higher than that value.
    # Default  is  1232 which is the DNS Flag Day 2020 recommendation.
    # Setting to 512 bypasses even the most stringent path MTU problems, but
    # is seen as extreme, since the amount of TCP fallback generated is
    # excessive (probably also for this resolver, consider tuning the outgoing
    # tcp number).
    edns-buffer-size: 1232

    # Listen to for queries from clients and answer from this network interface
    # and port.
    interface: 0.0.0.0@53

    # Rotates RRSet order in response (the pseudo-random number is taken from
    # the query ID, for speed and thread safety).
    rrset-roundrobin: yes

    # Drop user  privileges after  binding the port.
    username: "_unbound"

    ###########################################################################
    # LOGGING
    ###########################################################################

    # Do not print log lines to inform about local zone actions
    log-local-actions: no

    # Do not print one line per query to the log
    log-queries: no

    # Do not print one line per reply to the log
    log-replies: no

    # Do not print log lines that say why queries return SERVFAIL to clients
    log-servfail: no

    # Further limit logging
    logfile: /dev/null

    # Only log errors
    verbosity: 0

    ###########################################################################
    # PRIVACY SETTINGS
    ###########################################################################

    # RFC 8198. Use the DNSSEC NSEC chain to synthesize NXDO-MAIN and other
    # denials, using information from previous NXDO-MAINs answers. In other
    # words, use cached NSEC records to generate negative answers within a
    # range and positive answers from wildcards. This increases performance,
    # decreases latency and resource utilization on both authoritative and
    # recursive servers, and increases privacy. Also, it may help increase
    # resilience to certain DoS attacks in some circumstances.
    aggressive-nsec: yes

    # Extra delay for timeouted UDP ports before they are closed, in msec.
    # This prevents very delayed answer packets from the upstream (recursive)
    # servers from bouncing against closed ports and setting off all sort of
    # close-port counters, with eg. 1500 msec. When timeouts happen you need
    # extra sockets, it checks the ID and remote IP of packets, and unwanted
    # packets are added to the unwanted packet counter.
    delay-close: 10000

    # Prevent the unbound server from forking into the background as a daemon
    do-daemonize: no

    # Add localhost to the do-not-query-address list.
    do-not-query-localhost: no

    # Number  of  bytes size of the aggressive negative cache.
    neg-cache-size: 4M

    # Send minimum amount of information to upstream servers to enhance
    # privacy (best privacy).
    qname-minimisation: yes

    ###########################################################################
    # SECURITY SETTINGS
    ###########################################################################
    # Only give access to recursion clients from LAN IPs
    access-control: 127.0.0.1/32 allow
    access-control: 192.168.0.0/16 allow
    access-control: 172.16.0.0/12 allow
    access-control: 10.0.0.0/8 allow
    # access-control: fc00::/7 allow
    # access-control: ::1/128 allow

    # File with trust anchor for  one  zone, which is tracked with RFC5011
    # probes.
    auto-trust-anchor-file: "var/root.key"

    # Enable chroot (i.e, change apparent root directory for the current
    # running process and its children)
    chroot: "/opt/unbound/etc/unbound"

    # Deny queries of type ANY with an empty response.
    deny-any: yes

    # Harden against algorithm downgrade when multiple algorithms are
    # advertised in the DS record.
    harden-algo-downgrade: yes

    # RFC 8020. returns nxdomain to queries for a name below another name that
    # is already known to be nxdomain.
    harden-below-nxdomain: yes

    # Require DNSSEC data for trust-anchored zones, if such data is absent, the
    # zone becomes bogus. If turned off you run the risk of a downgrade attack
    # that disables security for a zone.
    harden-dnssec-stripped: yes

    # Only trust glue if it is within the servers authority.
    harden-glue: yes

    # Ignore very large queries.
    harden-large-queries: yes

    # Perform additional queries for infrastructure data to harden the referral
    # path. Validates the replies if trust anchors are configured and the zones
    # are signed. This enforces DNSSEC validation on nameserver NS sets and the
    # nameserver addresses that are encountered on the referral path to the
    # answer. Experimental option.
    harden-referral-path: no

    # Ignore very small EDNS buffer sizes from queries.
    harden-short-bufsize: yes

    # Refuse id.server and hostname.bind queries
    hide-identity: yes

    # Refuse version.server and version.bind queries
    hide-version: yes

    # Report this identity rather than the hostname of the server.
    identity: "DNS"

    # These private network addresses are not allowed to be returned for public
    # internet names. Any  occurrence of such addresses are removed from DNS
    # answers. Additionally, the DNSSEC validator may mark the  answers  bogus.
    # This  protects  against DNS  Rebinding
    private-address: 10.0.0.0/8
    private-address: 172.16.0.0/12
    private-address: 192.168.0.0/16
    private-address: 169.254.0.0/16
    # private-address: fd00::/8
    # private-address: fe80::/10
    # private-address: ::ffff:0:0/96

    # Enable ratelimiting of queries (per second) sent to nameserver for
    # performing recursion. More queries are turned away with an error
    # (servfail). This stops recursive floods (e.g., random query names), but
    # not spoofed reflection floods. Cached responses are not rate limited by
    # this setting. Experimental option.
    ratelimit: 1000

    # Use this certificate bundle for authenticating connections made to
    # outside peers (e.g., auth-zone urls, DNS over TLS connections).
    tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt

    # Set the total number of unwanted replies to eep track of in every thread.
    # When it reaches the threshold, a defensive action of clearing the rrset
    # and message caches is taken, hopefully flushing away any poison.
    # Unbound suggests a value of 10 million.
    unwanted-reply-threshold: 10000

    # Use 0x20-encoded random bits in the query to foil spoof attempts. This
    # perturbs the lowercase and uppercase of query names sent to authority
    # servers and checks if the reply still has the correct casing.
    # This feature is an experimental implementation of draft dns-0x20.
    # Experimental option.
    use-caps-for-id: yes

    # Help protect users that rely on this validator for authentication from
    # potentially bad data in the additional section. Instruct the validator to
    # remove data from the additional section of secure messages that are not
    # signed properly. Messages that are insecure, bogus, indeterminate or
    # unchecked are not affected.
    val-clean-additional: yes

    ###########################################################################
    # PERFORMANCE SETTINGS
    ###########################################################################
    # https://nlnetlabs.nl/documentation/unbound/howto-optimise/
    # https://nlnetlabs.nl/news/2019/Feb/05/unbound-1.9.0-released/

    # Number of slabs in the infrastructure cache. Slabs reduce lock contention
    # by threads. Must be set to a power of 2.
    infra-cache-slabs: 4

    # Number of incoming TCP buffers to allocate per thread. Default
    # is 10. If set to 0, or if do-tcp is "no", no  TCP  queries  from
    # clients  are  accepted. For larger installations increasing this
    # value is a good idea.
    incoming-num-tcp: 10

    # Number of slabs in the key cache. Slabs reduce lock contention by
    # threads. Must be set to a power of 2. Setting (close) to the number
    # of cpus is a reasonable guess.
    key-cache-slabs: 4

    # Number  of  bytes  size  of  the  message  cache.
    # Unbound recommendation is to Use roughly twice as much rrset cache memory
    # as you use msg cache memory.
    msg-cache-size: 131294549

    # Number of slabs in the message cache. Slabs reduce lock contention by
    # threads. Must be set to a power of 2. Setting (close) to the number of
    # cpus is a reasonable guess.
    msg-cache-slabs: 4

    # The number of queries that every thread will service simultaneously. If
    # more queries arrive that need servicing, and no queries can be jostled
    # out (see jostle-timeout), then the queries are dropped.
    # This is best set at half the number of the outgoing-range.
    # This Unbound instance was compiled with libevent so it can efficiently
    # use more than 1024 file descriptors.
    num-queries-per-thread: 4096

    # The number of threads to create to serve clients.
    # This is set dynamically at run time to effectively use available CPUs
    # resources
    num-threads: 3

    # Number of ports to open. This number of file descriptors can be opened
    # per thread.
    # This Unbound instance was compiled with libevent so it can efficiently
    # use more than 1024 file descriptors.
    outgoing-range: 8192

    # Number of bytes size of the RRset cache.
    # Use roughly twice as much rrset cache memory as msg cache memory
    rrset-cache-size: 262589098

    # Number of slabs in the RRset cache. Slabs reduce lock contention by
    # threads. Must be set to a power of 2.
    rrset-cache-slabs: 4

    # Do no insert authority/additional sections into response messages when
    # those sections are not required. This reduces response size
    # significantly, and may avoid TCP fallback for some responses. This may
    # cause a slight speedup.
    minimal-responses: yes

    # # Fetch the DNSKEYs earlier in the validation process, when a DS record
    # is encountered. This lowers the latency of requests at the expense of
    # little more CPU usage.
    prefetch: yes

    # Fetch the DNSKEYs earlier in the validation process, when a DS record is
    # encountered. This lowers the latency of requests at the expense of little
    # more CPU usage.
    prefetch-key: yes

    # Have unbound attempt to serve old responses from cache with a TTL of 0 in
    # the response without waiting for the actual resolution to finish. The
    # actual resolution answer ends up in the cache later on.
    serve-expired: yes

    # Open dedicated listening sockets for incoming queries for each thread and
    # try to set the SO_REUSEPORT socket option on each socket. May distribute
    # incoming queries to threads more evenly.
    so-reuseport: yes

    ###########################################################################
    # LOCAL ZONE
    ###########################################################################

    # Include file for local-data and local-data-ptr
    include: /opt/unbound/etc/unbound/a-records.conf
    include: /opt/unbound/etc/unbound/srv-records.conf

    ###########################################################################
    # FORWARD ZONE
    ###########################################################################

    include: /opt/unbound/etc/unbound/forward-records.conf

remote-control:
    control-enable: no
johntdavis84 commented 3 years ago

tl;dr: Problem appears fixed. Do two things if this happens to you: 1. Create the indicated empty files in your unbound config folder. Unbound needs them to launch. 2. If you had the key : value pairs in your config that I had initially included below, remove them. This version of unbound doesn't like them.

Longer explanation of my fumblings:

That's new to me. I had to look at the Docker docs. It sounds innocuous, but it seems to imply it's trying to build something. That seems odd because it should just pull down a pre-built image from Docker Hub.

I've never seen that message prior to the latest docker-compose update. I think it's some sort of new auto-printed notice about how compose builds things. The container comes up entirely too quickly for it to actually be compiling/building software every time it runs...

I didn't see anything in your permissions that looked immediately different from mine. Since the container won't stay up, I can't exec in and check the permissions there, but looking at it did give me an idea:

If I designate a persistent storage volume, but don't create the folder structure myself, docker-compose will create it for me when the container goes up. I changed the name of vUnbound to vUnbound.bak, and tried to bring up the container again.

This revealed a whole different set of interesting errors:

image

I do recall instructions to create a-records.conf before running unbound, lest it crash out. Perhaps it needs srv-records.conf and forward-records.conf to be pre-created as well in order to come up correctly.

Will try that and return.

**EDIT: I've been reading "cannot open" as an actual failure to open the file at all. But it can clearly read alleged syntax errors at certain line numbers. I'm now reading "cannot open" as "I opened it, but syntax errors kept me from reading all ofi it, and now I crash, confused."

EDIT 2, Solution to Original Post: Wow. Okay. So, creating those empty files didn't do the trick, and it kept throwing very specific syntax errors. I noticed on looking at your example that you did not have the key: value pairs that was keeping my container from launching.

So I commented out these (line numbers overlaid by cat, not part of file): 13 │ interface: 0.0.0.0@53 14 │ # do-ipv4: yes 15 │ # do-ipv6: yes 16 │ # prefer-ipv6: yes 65 │ # numthreads: 1

The container now launches.

I'm boggling because those keys are all in the official documentation and should work: https://nlnetlabs.nl/documentation/unbound/unbound.conf/

I'm going to be rebuilding the .conf file based on your example. Yours is much more sophisticated and complete than mine. Any idea why this happened? I am very confused.

The container still crashes out. It now fails because of some PID error I don't understand yet, but now it actually generates a log file I can study.

1 │ [1612142970] unbound[1:0] notice: init module 0: validator 2 │ [1612142970] unbound[1:0] error: unable to open ./root.key for reading: Permission denied 3 │ [1612142970] unbound[1:0] error: error reading auto-trust-anchor-file: ./root.key 4 │ [1612142970] unbound[1:0] error: validator: error in trustanchors config 5 │ [1612142970] unbound[1:0] error: validator: could not apply configuration settings. 6 │ [1612142970] unbound[1:0] error: module init for module validator failed 7 │ [1612142970] unbound[1:0] fatal error: failed to setup modules 8 │ [1612142972] unbound[1:0] notice: init module 0: validator

This is my root.key file's permissions, in my host's real file system:

-rwx------ 1 root root 83 Jan 29 20:17 root.key

Everything else has permissions that look like this: -rw-r--r-- 1 myuser myuser 3760 Jan 31 19:29 unbound.conf

I created the root.key file based on a tutorial that, in retrospect, I realize was written for bare metal unbound--no docker. So it makes sense that a different permissions setting would be required.

I'm going to make it match the other files and see what happens.

EDIT 3: Container now up and stable. setting the permissions on the root.key to 644 and the owership to myuser:myuser fixed it.

MatthewVance commented 3 years ago

Is yours working with IPv6. I ask because the Docker daemon doesn't enable IPv6 support by default. I cannot ensure everyone has enabled it on their host so that's why the default config in this image is IPv4 only.

You should be able to safely leave off the root.key and root.hints. See https://github.com/MatthewVance/unbound-docker/issues/28#issuecomment-541953720.

1. Create the indicated empty files in your unbound config folder. Unbound needs them to launch.

I wouldn't think that would be needed. With mine, I only volume mounted forward-records.conf but you'll noticed my listing of files in the container still had srv-records.conf. That's because those should be auto-injected with defaults upon launch. I haven't tested with mounting a directory versus specific files so I wonder if that causes the difference?

johntdavis84 commented 3 years ago

Is yours working with IPv6. I ask because the Docker daemon doesn't enable IPv6 support by default. I cannot ensure everyone has enabled it on their host so that's why the default config in this image is IPv4 only.

I haven't tested the v6 support yet, but it looks like it's enabled by default (see the docs, below). EDIT: Here's a test with dig:

vUnbound]$ dig AAAA ipv6.google.com @172.18.0.2 -p 53

; <<>> DiG 9.16.11 <<>> AAAA ipv6.google.com @172.18.0.2 -p 53 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26618 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 1232 ;; QUESTION SECTION: ;ipv6.google.com. IN AAAA

;; ANSWER SECTION: ipv6.google.com. 86400 IN CNAME ipv6.l.google.com. ipv6.l.google.com. 300 IN AAAA 2607:f8b0:4000:806::200e

;; Query time: 91 msec ;; SERVER: 172.18.0.2#53(172.18.0.2) ;; WHEN: Sun Jan 31 21:44:11 CST 2021 ;; MSG SIZE rcvd: 93

So it can definitely pull AAAA records when it needs to. I'm having more trouble getting it to respond by querying the supposed v6 address of the container.

I've got an extra package running as a systemd service (https://github.com/robbertkl/docker-ipv6nat) that's letting me easily use IPv6 with docker containers. I've verified that the unbound container has a v6 address, but I haven't tested whether the v6 support works yet.

(There's experimental built-in support for IPv6 in the latest docker, but it's still buggy enough I haven't switched over yet.)

From the official docs:

do-ip6: <yes or no>
              Enable  or  disable  whether ip6 queries are answered or issued.
              **Default is yes.**  If disabled, queries are not answered on  IPv6,
              and  queries  are  not sent on IPv6 to the internet nameservers.
              With this option you can disable the ipv6 transport for  sending
              DNS traffic, it does not impact the contents of the DNS traffic,
              which may have ip4 and ip6 addresses in it.

You should be able to safely leave off the root.key and root.hints. See MatthewVance/unbound-docker#28 (comment).

1. Create the indicated empty files in your unbound config folder. Unbound needs them to launch.

I wouldn't think that would be needed. With mine, I only volume mounted forward-records.conf but you'll noticed my listing of files in the container still had srv-records.conf. That's because those should be auto-injected with defaults upon launch. I haven't tested with mounting a directory versus specific files so I wonder if that causes the difference?

It definitely failed without srv-records.conf. I had a typo in the file name at one point (serv-records.conf) and it failed to launch.

When I switched to your sample file, I did remove my root.key, as you provided your own in the volume's /var/ and I wasn't going to mess with a known working config for no reason. :)

There's still a root.hints in the vUnbound/ folder, but at this point I cannot remember if it is mine or if it's auto-generated. I haven't touched it since I managed to get unbound to come up. I'll try to remember to remove it and see if things still work, but that might be tomorrow.

MatthewVance commented 3 years ago

I haven't tested the v6 support yet, but it looks like it's enabled by default (see the docs, below).

I'm under the impression that it's not enabled by default (though it is supported by default on Linux). Per Docker's official docs:

Before you can use IPv6 in Docker containers or swarm services, you need to enable IPv6 support in the Docker daemon. Afterward, you can choose to use either IPv4 or IPv6 (or both) with any container, service, or network.

If you have it enabled, it should work. It's not something I want to enable in this image or support.

It definitely failed without srv-records.conf. I had a typo in the file name at one point (serv-records.conf) and it failed to launch.

Thanks for letting me know.

So it can definitely pull AAAA records when it needs to. I'm having more trouble getting it to respond by querying the supposed v6 address of the container.

I'm no help there. All I can say is you may need to use the IPv6 address of the host, not the container (unless you've setup Docker networking to behave differently). For instance, when I run dig to check things for IPv4, I always use the host address assigned to my Pi rather than dig @172.x.

EDIT: For what it's worth, mine also returns IPv6 answers with my IPv4 only container (albeit, I'm currently configured to forward [and cache] queries rather than recursively resolve them).

dig AAAA ipv6.google.com @x.x.x.x -p 53

; <<>> DiG 9.10.6 <<>> AAAA ipv6.google.com @x.x.x.x -p 53
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10782
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;ipv6.google.com.       IN  AAAA

;; ANSWER SECTION:
ipv6.google.com.    300 IN  AAAA    2001:4860:4802:32::78

;; Query time: 186 msec
;; SERVER: x.x.x.x#53(x.x.x.x)
;; WHEN: Sun Jan 31 21:57:05 CST 2021
;; MSG SIZE  rcvd: 72
johntdavis84 commented 3 years ago

Sorry. I was a bit confusing in my response.

  1. Docker does not support ipv6 by default in the same way it supports ipv4. I have this enabled docker-wide through an add-on service that makes ipv6 in docker behave just like ipv4. I'm currently using this to get IPv6 support across all my docker containers. Not necessarily because I need it, but because it's there. The useless Mt Everest of network configurations. :-P (Actually, pihole appears not to do IPv6 correctly unless its container has IPv6 connectivity.)
  2. There is currently an experimental feature being tested in docker that will make docker work just like the third party add-on I am currently using.

Reading the unbound official documentation, the software appears to support returning AAAA records (IPv6 records) by default.

That is not the same thing as supporting incoming connections over IPv6. For that, you need it enabled at the interface level and the access control level.

To turn this on, three things are (apparently?) required:

  1. An additional interface entry directly under the one in your example --> interface: ::0@53
  2. An additional access control entry for v6 localhost --> access-control: ::1/128 allow
  3. An additional access control entry for v6 within the docker container's network --> fd28:165f:7c15:1360::/112 allow

Note: I got mine from docker network inspect <network name>, by copying-and-pasting the v6 subnet. If there is no v6 subnet, your docker network does not have IPv6 enabled properly. Yours will be different than the one I'm showing, hopefully.

Mine now recognizes incoming connections to the IPv6 address of the server:

~]$ dig AAAA ipv6.google.com @fd28:165f:7c15:1360::2 -p 53

; <<>> DiG 9.16.11 <<>> AAAA ipv6.google.com @fd28:165f:7c15:1360::2 -p 53 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40286 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 1232 ;; QUESTION SECTION: ;ipv6.google.com. IN AAAA

;; ANSWER SECTION: ipv6.google.com. 86400 IN CNAME ipv6.l.google.com. ipv6.l.google.com. 300 IN AAAA 2607:f8b0:4000:808::200e

;; Query time: 175 msec ;; SERVER: fd28:165f:7c15:1360::2#53(fd28:165f:7c15:1360::2) ;; WHEN: Sun Jan 31 22:32:34 CST 2021 ;; MSG SIZE rcvd: 93

And as I said above, I have no idea why this would be particularly useful, but it appears to work.

scrapix commented 1 year ago

@MatthewVance thank you for your great docker image!

I've just set it up and have one improvement proposal after spending quite some time to find the error. The image won't start properly if it can't read the config. and it can't read the config due to just one minor volume mapping inconsistancy.

Usually you would map volumes in docker like:

` volumes:

No additional slashes in the ends of both paths (host & container)

for this specific unbound image we actually have to provide an additional slash in the end of the container path as you have mentioned in one of the comments here. Only after this the image would start properly. Does it make sense to address this issue and remove the need for this additional slash?

I think it's having trouble reading the unbound.conf file due to how the volume is being mounted. Try this minor change:

    volumes:
       - './vUnbound:/opt/unbound/etc/unbound/'