diff --git a/.github/workflows/manually-build-unbound.yaml b/.github/workflows/manually-build-unbound.yaml
index a964116..884ca99 100644
--- a/.github/workflows/manually-build-unbound.yaml
+++ b/.github/workflows/manually-build-unbound.yaml
@@ -57,7 +57,7 @@ jobs:
uses: docker/build-push-action@v5
env:
DOCKERHUB_SLUG: "madnuttah/unbound"
- UNBOUND_DOCKER_IMAGE_VERSION: "1.20.0-3"
+ UNBOUND_DOCKER_IMAGE_VERSION: "1.20.0-4"
with:
platforms: linux/386,linux/arm/v6,linux/arm/v7,linux/arm64,linux/amd64
builder: ${{ steps.buildx.outputs.name }}
diff --git a/doc/DETAILS.md b/doc/DETAILS.md
index 55e5dee..571a782 100644
--- a/doc/DETAILS.md
+++ b/doc/DETAILS.md
@@ -89,7 +89,7 @@ When NLnet Labs publishes a new stable Unbound release, the image will be built,
> [!NOTE]
> We're not manually building release candidates of Unbound anymore, instead there are automated canary builds which will be created from the most recent NLnet Labs Unbound GitHub commit at 20:00 UTC from Monday to Friday if you want to ride on the bleeding edge of the development of Unbound.
-The `latest` image is scanned for vulnerabilities using the [Aqua Security Trivy](https://trivy.dev/) and [Docker Scout](https://docs.docker.com/scout/) vulnerability scan on a daily schedule. If vulnerabilities have been detected, they'll show up in [Security](https://github.com/madnuttah/unbound-docker/security). The `canary` build only shows the results in the workflow's run details and are being scanned an buildtime. You need to be logged into GitHub to view the logs.
+The `latest` image is scanned for vulnerabilities using the [Aqua Security Trivy](https://trivy.dev/) and [Docker Scout](https://docs.docker.com/scout/) vulnerability scan on a daily schedule. If vulnerabilities have been detected, they'll show up in [Security](https://github.com/madnuttah/unbound-docker/security). The `canary` build only shows the results in the workflow's run details and are being scanned at buildtime. You need to be logged into GitHub to view the logs.
## Installation
@@ -116,7 +116,7 @@ Luckily Unbound can load configs through a `include:` clause. To provide a bette
>
> ***Don't forget to secure your setup when everything runs.***
-The splitted configuration files located in [`doc/examples/usr/local/unbound`](https://github.com/madnuttah/unbound-docker/tree/main/doc/examples/usr/local/unbound) are only meant to give you an impression on how to separating and structuring the configs. Please mind that those files are **examples** which also needs to be edited to make them work for your environment if you intend to use them. It might be necessary to fix permissions and ownership of the files put in the persistent volumes if unbound refuses to start.
+The splitted configuration files located in [`doc/examples/usr/local/unbound`](https://github.com/madnuttah/unbound-docker/tree/main/doc/examples/usr/local/unbound) are only meant to give you an impression on how to separating and structuring the configs. Please mind that those files are **examples** which also needs to be edited to make them work for your environment if you intend to use them.
> [!NOTE]
> Splitting ain't really necessary as the included default [`unbound.conf`](https://raw.githubusercontent.com/madnuttah/unbound-docker/main/unbound/root/usr/local/unbound/unbound.conf) will perfectly do the job after you adapted the settings to suit your environment. You don't need to bind mount the config folders, just ignore them.
@@ -128,39 +128,40 @@ The splitted configuration files located in [`doc/examples/usr/local/unbound`](h
Filesystem
```
-...
-usr/local/
-├── unbound/
-│ ├── cachedb.d/
-│ │ └── redis.sock
-│ ├── certs.d/
-│ │ └── ...
-│ ├── conf.d/
-│ │ └── *.conf
-│ ├── iana.d/
-│ │ ├── root.hints
-│ │ ├── root.key
-│ │ └── root.zone
-│ ├── log.d/
-│ │ └── unbound.log
-│ ├── sbin/
-│ │ ├── healthcheck.sh
-│ │ └── unbound.sh
-│ ├── unbound.d/
-│ │ ├── sbin/
-│ │ │ ├── unbound
-│ │ │ ├── unbound-anchor
-│ │ │ ├── unbound-checkconf
-│ │ │ ├── unbound-control
-│ │ │ ├── unbound-control-setup
-│ │ │ └── unbound-host
-│ │ ├── null
-│ │ ├── random
-│ │ ├── urandom
-│ │ └── unbound.pid
-│ ├── zones.d/
-│ │ └── *.conf
-│ └── unbound.conf
+/
+├── entrypoint
+├── usr
+│ ├── local
+│ │ └── unbound
+│ │ ├── certs.d
+│ │ │ └── ...
+│ │ ├── conf.d
+│ │ │ └── *.conf
+│ │ ├── iana.d
+│ │ │ ├── root.hints
+│ │ │ ├── root.key
+│ │ │ └── root.zone
+│ │ ├── log.d
+│ │ │ └── unbound.log
+│ │ ├── sbin
+│ │ │ ├── healthcheck.sh
+│ │ │ └── unbound.sh
+│ │ ├── unbound.conf
+│ │ ├── unbound.d
+│ │ │ ├── null -> /dev/null
+│ │ │ ├── random -> /dev/random
+│ │ │ ├── sbin
+│ │ │ │ ├── unbound
+│ │ │ │ ├── unbound-anchor
+│ │ │ │ ├── unbound-checkconf
+│ │ │ │ ├── unbound-control
+│ │ │ │ ├── unbound-control-setup
+│ │ │ │ └── unbound-host
+│ │ │ ├── unbound.pid
+│ │ │ └── urandom -> /dev/urandom
+│ │ └── zones.d
+│ │ └── *.conf
+│ └── ...
...
```
@@ -170,7 +171,7 @@ usr/local/
- Command list
+ Commands list
```
. fg shift
@@ -213,10 +214,15 @@ false sh
| Variable | Default | Value | Description |
| -------- | ------- | ----- | ---------- |
-| `DISABLE_SET_PERMS` | `false` | `BOOL` | Set this to `true` for complete rootless mode and define user `_unbound` |
+| `HEALTHCHECK_PORT` | `5335` | `INT` | The port Unbound uses (only used by the extended healthcheck) |
+| `EXTENDED_HEALTHCHECK` | `false` | `BOOL` | Set this to `true` if you want to use the extended healthcheck |
+| `EXTENDED_HEALTHCHECK_DOMAIN` | `nlnetlabs.nl` | `string` | The domain/host to run the extended healthcheck against |
+| `DISABLE_SET_PERMS` | `false` | `BOOL` | Set this to `true` and define user `_unbound` for full rootless mode like as it was before v1.20.0-2. The `UNBOUND_UID` and `UNBOUND_GID` will both be overridden with `1000` in that case |
> [!CAUTION]
-> Setting `DISABLE_SET_PERMS` to `true` *without* defining `user: _unbound` or `--user _unbound` will run the container under root!
+> Setting `DISABLE_SET_PERMS` to `true` ***without*** defining `user: _unbound` or `--user _unbound` will run the container under the root account. The init screen in the log will show you the user who is running Unbound.
+>
+> ***If you ain't sure what this variable does, you'll most likely don't need it.***
### Networking
@@ -249,7 +255,7 @@ forward-zone:
...
```
-This image can also be used as a standalone DNS resolver _without_ Pi-hole or AdGuard Home. The given ports must be changed to `53` (TCP/UDP) in your `unbound.conf` and `docker-compose.yaml` then. Additionally verify that connections to localhost are allowed (see [`healthcheck`](https://github.com/madnuttah/unbound-docker/blob/main/doc/DETAILS.md#Healthcheck)). You need to enable a capability in your compose file as the `_unbound` user only has limited permissions, see [`issue 54`](https://github.com/madnuttah/unbound-docker/issues/54). You can find more information about runtime privileges and Linux capabilities [here](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities).
+This image can also be used as a standalone DNS resolver _without_ Pi-hole or AdGuard Home. The given ports must be changed to `53` (tcp/udp) in your `unbound.conf` and `docker-compose.yaml` then. Additionally verify that connections to localhost are allowed (see [`healthcheck`](https://github.com/madnuttah/unbound-docker/blob/main/doc/DETAILS.md#Healthcheck)). You need to enable a capability in your compose file as the `_unbound` user only has limited permissions, see [`issue 54`](https://github.com/madnuttah/unbound-docker/issues/54). You can find more information about runtime privileges and Linux capabilities [here](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities).
```
cap_add:
@@ -288,7 +294,7 @@ Create a new entry for cachedb in your `unbound.conf` with the content of this [
If using structured directories uncomment the line `include: "/usr/local/unbound/conf.d/*.conf"` of this [`unbound.conf`](https://raw.githubusercontent.com/madnuttah/unbound-docker/main/unbound/root/usr/local/unbound/unbound.conf).
-You can verify the connection to redis in the `unbound.log` or by typing `docker logs unbound` in the shell:
+You can verify the connection to redis in the `unbound.log` or by typing `docker logs unbound` in the shell (for alternative methods like monitoring using the `redis-cli` consult the corresponding documentation):
```
...
@@ -325,7 +331,7 @@ The healthcheck can be enabled and configured quite self-explanatory in your com
The default healthcheck _only_ checks for opened Unbound ports using netstat and grep. We got asked why we don't include netcat (nc) into the image to _actually_ connect to opened ports, [this](https://www.sciencedirect.com/science/article/abs/pii/B9781597492577000054) is the reason.
-To enable the _extended_ healthcheck, which uses NLnet Labs' [LDNS](https://www.nlnetlabs.nl/documentation/ldns/index.html) drill tool to query domains or hosts, please download the [`Unbound healthcheck`](https://raw.githubusercontent.com/madnuttah/unbound-docker/main/unbound/root/healthcheck.sh) script and put it in your persistent Unbound volume, make it available in your compose file's volume definition, fix permissions and make the file executable. Set the variable `EXTENDED=0` to `EXTENDED=1` and save the file, you will need to restart the Unbound container afterwards. To change the domain or host to query in the healthcheck, modify the `DOMAIN=` variable, if you need a different port than `5335`, edit the `PORT=` variable accordingly.
+To enable the _extended_ healthcheck, which uses NLnet Labs' [LDNS](https://www.nlnetlabs.nl/documentation/ldns/index.html) drill tool to query domains or hosts, please set the [optional environment variables](https://github.com/madnuttah/unbound-docker/blob/main/doc/DETAILS.md#Optional-Environment-Variables) in your compose file or run command.
> [!NOTE]
> The _extended_ healthcheck is deactivated by default in favor of your privacy and security.
@@ -334,21 +340,21 @@ To verify that the healthcheck is working and the container is doing what it is
Standard healthcheck console output:
-```
+```bash
yourdockerhost:~# docker exec -ti unbound /usr/local/unbound/sbin/healthcheck.sh
✅ Port 5335 open
```
Standard healthcheck console output showing an issue:
-```
+```bash
yourdockerhost:~# docker exec -ti unbound /usr/local/unbound/sbin/healthcheck.sh
⚠️ Port 5335 not open
```
Extended healthcheck console output:
-```
+```bash
yourdockerhost:~# docker exec -ti unbound /usr/local/unbound/sbin/healthcheck.sh
✅ Port 5335 open
✅ Domain 'unbound.net' resolved to '185.49.140.10'
@@ -356,7 +362,7 @@ yourdockerhost:~# docker exec -ti unbound /usr/local/unbound/sbin/healthcheck.sh
Extended healthcheck console output showing an issue:
-```
+```bash
yourdockerhost:~# docker exec -ti unbound /usr/local/unbound/sbin/healthcheck.sh
✅ Port 5335 open
⚠️ Domain 'unbound.net' not resolved
@@ -385,7 +391,7 @@ We also created a [`companion project`](https://github.com/madnuttah/unbound-doc
# Known Issues
-- There's a difference between 'vanilla' Docker and the variant Synology uses. If the container won't spin up when trying to use a privileged port like `53 tcp/udp` you might need to set `user: root` in the compose file's Unbound service section. See [`issue #62`](https://github.com/madnuttah/unbound-docker/issues/62).
+- There's a difference between 'vanilla' Docker and the variant Synology uses. If the container won't spin up when trying to use a privileged port like `53 tcp/udp` you might need to run the container in `root mode` by setting the `DISABLE_SET_PERMS` environment variable to `true` without a `user` definition or define `user: root` in the compose file's Unbound service section or your shell command.
# Troubleshooting
@@ -396,9 +402,9 @@ We also created a [`companion project`](https://github.com/madnuttah/unbound-doc
```
server:
- username="" # Is set in Dockerfile at buildtime
+ username="" # Not set in config but compose or command if needed
chroot="" # Distroless, so no chroot necessary
- directory: "/usr/local/unbound" # This is the folder where Unbound lives in
+ directory="/usr/local/unbound" # This is the folder where Unbound lives in
```
* If you have trouble spinning up the container, start it with the [minimal config](https://raw.githubusercontent.com/madnuttah/unbound-docker/main/doc/examples/docker-compose-minimal.yaml) first. Analyze the logs using `docker logs unbound` or your `unbound.log` and fix warnings and errors there. When it runs, attach volumes one by one. Success means to adapt the default `unbound.conf` to your needs then.
@@ -428,4 +434,4 @@ In-depth documentation for NLnet Labs Unbound is available on the [Unbound docum
# Contributing
-You have found a bug, found something to make better or have an idea for a shiny new feature? That's amazing! Feel free to submit a pull request, we ❤️ contributions by the open source community.
+You have found a bug, got something to make better, have an idea for a shiny new feature or just a question? That's amazing! Feel free to submit an issue or a pull request, we ❤️ contributions by the open source community.
diff --git a/doc/examples/docker-compose-bridge.yaml b/doc/examples/docker-compose-bridge.yaml
index 44ffedc..21f79d8 100644
--- a/doc/examples/docker-compose-bridge.yaml
+++ b/doc/examples/docker-compose-bridge.yaml
@@ -62,8 +62,9 @@ services:
TZ: #e.g. "America/New_York"
UNBOUND_UID: 1000 #optional
UNBOUND_GID: 1000 #optional
- ServerIP: #e.g. 172.20.0.253 or fd11:aa:1234:1234::505
- VIRTUAL_HOST:
+ HEALTHCHECK_PORT: 5335 #optional
+ EXTENDED_HEALTHCHECK: false #optional
+ EXTENDED_HEALTHCHECK_DOMAIN: #optional
volumes:
- ./unbound.conf:/usr/local/unbound/unbound.conf:rw #Your local path to Unbound
- ./conf.d/:/usr/local/unbound/conf.d/:rw
diff --git a/doc/examples/docker-compose-macvlan.yaml b/doc/examples/docker-compose-macvlan.yaml
index d5d3c3b..21f90f7 100644
--- a/doc/examples/docker-compose-macvlan.yaml
+++ b/doc/examples/docker-compose-macvlan.yaml
@@ -68,8 +68,9 @@ services:
TZ: #e.g. "America/New_York"
UNBOUND_UID: 1000 #optional
UNBOUND_GID: 1000 #optional
- ServerIP: #e.g. 192.168.1.253 or fd11:aa:1234:1234::505
- VIRTUAL_HOST:
+ HEALTHCHECK_PORT: 5335 #optional
+ EXTENDED_HEALTHCHECK: false #optional
+ EXTENDED_HEALTHCHECK_DOMAIN: #optional
volumes:
- ./unbound.conf:/usr/local/unbound/unbound.conf:rw #Your local path to Unbound
- ./conf.d/:/usr/local/unbound/conf.d/:rw
diff --git a/doc/examples/docker-compose-madnuttah.yaml b/doc/examples/docker-compose-madnuttah.yaml
index 4005914..99ac5f7 100644
--- a/doc/examples/docker-compose-madnuttah.yaml
+++ b/doc/examples/docker-compose-madnuttah.yaml
@@ -66,9 +66,12 @@ services:
docker:
ipv4_address: x.x.x.x
environment:
+ TZ: "Europe/Berlin"
UNBOUND_UID: 1000
UNBOUND_GID: 1000
- TZ: "Europe/Amsterdam"
+ HEALTHCHECK_PORT: 5335
+ EXTENDED_HEALTHCHECK: true
+ EXTENDED_HEALTHCHECK_DOMAIN: "nlnetlabs.nl"
volumes:
- /etc/localtime:/etc/localtime:ro
- ./unbound/usr/local/unbound/sbin/healthcheck.sh:/usr/local/unbound/sbin/healthcheck.sh:ro
diff --git a/unbound/root/entrypoint b/unbound/root/entrypoint
index bff3979..75dee64 100644
--- a/unbound/root/entrypoint
+++ b/unbound/root/entrypoint
@@ -1,45 +1,24 @@
#!/bin/sh
-BLD='\033[1;97m'
-CLR='\033[1;92m'
-STD='\033[0m'
+DISABLE_SET_PERMS=${DISABLE_SET_PERMS:-false}
+UNBOUND_UID=${UNBOUND_UID:-1000}
+UNBOUND_GID=${UNBOUND_GID:-1000}
-DISABLE_SET_PERMS=${DISABLE_SET_PERMS:-"false"}
-UNBOUND_UID=${UNBOUND_UID:-"1000"}
-UNBOUND_GID=${UNBOUND_GID:-"1000"}
-
-function info {
-echo -e "╔═════════════════════════════════════════════════════╗
-║ ║
-║ ${BLD}MΛDИVTTΛH Unbound Docker${STD} ║
-║ ║
-║ https://github.com/madnuttah/unbound-docker ║
-║ https://hub.docker.com/r/madnuttah/unbound ║
-║ ║
-╚═════════════════════════════════════════════════════╝
-
-UNBOUND_UID: ${CLR}$(id -u _unbound)${STD}
-UNBOUND_GID: ${CLR}$(id -g _unbound)${STD}
-"
-}
-
-BOOL=$DISABLE_SET_PERMS
-if $BOOL; then
- info
+bool=$DISABLE_SET_PERMS
+if $bool; then
exec /usr/local/unbound/sbin/unbound.sh
else
- SET_PERMS=0
- if [ "$(id -u _unbound)" -ne "$UNBOUND_UID" ]; then
- usermod -o -u "$UNBOUND_UID" _unbound
- SET_PERMS=1
+ set_perms=0
+ if [ $(id -u _unbound) -ne $UNBOUND_UID ]; then
+ usermod -o -u $UNBOUND_UID _unbound
+ set_perms=1
fi
- if [ "$(id -g _unbound)" -ne "$UNBOUND_GID" ]; then
- groupmod -o -g "$UNBOUND_GID" _unbound
- SET_PERMS=1
+ if [ $(id -g _unbound) -ne $UNBOUND_GID ]; then
+ groupmod -o -g $UNBOUND_GID _unbound
+ set_perms=1
fi
- if [ "$SET_PERMS" -eq 1 ]; then
- chown -R "$UNBOUND_UID":"$UNBOUND_GID" /usr/local/unbound/ >/dev/null 2>&1
+ if [ $set_perms -eq 1 ]; then
+ chown -R $UNBOUND_UID:$UNBOUND_GID /usr/local/unbound/ >/dev/null 2>&1
fi
- info
- exec su-exec "$UNBOUND_UID":"$UNBOUND_GID" /usr/local/unbound/sbin/unbound.sh
+ exec su-exec $UNBOUND_UID:$UNBOUND_GID /usr/local/unbound/sbin/unbound.sh
fi
diff --git a/unbound/root/healthcheck.sh b/unbound/root/healthcheck.sh
index b3a87e2..8c10aba 100644
--- a/unbound/root/healthcheck.sh
+++ b/unbound/root/healthcheck.sh
@@ -2,28 +2,24 @@
## Healthcheck
-# Change to the port Unbound is listening on 127.0.0.1 (localhost)
-PORT="5335"
-
-# Change this to "1" if you would like to verify name resolution using drill
-# in the extended healthcheck
-EXTENDED="0"
-
-# The domain/host to query in the extended check
-DOMAIN="unbound.net"
+# Environment variables
+HEALTHCHECK_PORT=${HEALTHCHECK_PORT:-5335}
+EXTENDED_HEALTHCHECK=${EXTENDED_HEALTHCHECK:-false}
+EXTENDED_HEALTHCHECK_DOMAIN=${EXTENDED_HEALTHCHECK_DOMAIN:-nlnetlabs.nl}
# Check for opened tcp/udp port(s) with netstat, grep port count and save
# the result into a variable
-CHECK_PORT="$(netstat -ln | grep -c ":$PORT")" &> /dev/null
+check_port="$(netstat -ln | grep -c ":$HEALTHCHECK_PORT")" &> /dev/null
# If opened port count is equal 0 exit ungracefully
-if [[ "$CHECK_PORT" -eq 0 ]]; then
- echo "⚠️ Port $PORT not open"
+if [ $check_port -eq 0 ]; then
+ echo "⚠️ Port $HEALTHCHECK_PORT not open"
exit 1
else
- echo "✅ Port $PORT open"
+ echo "✅ Port $HEALTHCHECK_PORT open"
# If extended check disabled exit gracefully
- if [[ "$EXTENDED" = "0" ]]; then
+ bool=$EXTENDED_HEALTHCHECK
+ if ! $bool; then
exit 0
fi
# Otherwise continue, we don't exit here
@@ -33,13 +29,13 @@ fi
# Use NLnet Labs drill to query localhost for a domain/host and save the result
# into a variable
-IP="$(drill -Q -p $PORT $DOMAIN @127.0.0.1)" &> /dev/null
+ip="$(drill -Q -p $HEALTHCHECK_PORT $EXTENDED_HEALTHCHECK_DOMAIN @127.0.0.1)" &> /dev/null
# Check the errorlevel of the last command, if not equal 0 exit ungracefully
-if [[ $? -ne 0 ]]; then
- echo "⚠️ Domain '$DOMAIN' not resolved"
+if [ $? -ne 0 ]; then
+ echo "⚠️ Domain '$EXTENDED_HEALTHCHECK_DOMAIN' not resolved"
exit 1
else
- echo "✅️ Domain '$DOMAIN' resolved to '$IP'"
+ echo "✅️ Domain '$EXTENDED_HEALTHCHECK_DOMAIN' resolved to '$ip'"
exit 0
fi
diff --git a/unbound/root/unbound.sh b/unbound/root/unbound.sh
index 0ffc429..428b91f 100644
--- a/unbound/root/unbound.sh
+++ b/unbound/root/unbound.sh
@@ -1,3 +1,41 @@
#!/bin/sh
+
+DISABLE_SET_PERMS=${DISABLE_SET_PERMS:-false}
+
+bi_white='\033[1;97m'
+bi_blue='\033[1;94m'
+bi_red='\033[1;91m'
+bi_green='\033[1;92m'
+color_default='\033[0m'
+
+echo -e "╔═════════════════════════════════════════════════════╗
+║ ║
+║ ${bi_white}MΛDИVTTΛH Unbound${color_default} ║
+║ ║
+║ https://github.com/madnuttah/unbound-docker ║
+║ https://hub.docker.com/r/madnuttah/unbound ║
+║ ║
+╚═════════════════════════════════════════════════════╝
+"
+
+bool=$DISABLE_SET_PERMS
+if $bool; then
+ color_user=$bi_green
+ color_group=$bi_green
+ if [ $(id -u) -eq 0 ]; then
+ color_user=$bi_red
+ fi
+ if [ $(id -g) -eq 0 ]; then
+ color_group=$bi_red
+ fi
+ echo -e "User: $color_user$(id -un)${color_default}
+Group: $color_group$(id -gn)${color_default}
+"
+else
+ echo -e "UNBOUND_UID: ${bi_blue}$(id -u _unbound)${color_default}
+UNBOUND_GID: ${bi_blue}$(id -g _unbound)${color_default}
+"
+fi
+
/usr/local/unbound/unbound.d/sbin/unbound-anchor -a /usr/local/unbound/iana.d/root.key
exec /usr/local/unbound/unbound.d/sbin/unbound -d -c /usr/local/unbound/unbound.conf