diff --git a/.gitignore b/.gitignore index d2df166..1141f86 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .env .DS_Store .idea +build_and_push.sh diff --git a/README.md b/README.md index 4b4ef89..4582ed2 100644 --- a/README.md +++ b/README.md @@ -1,134 +1,11 @@ # Pi-Hole + Unbound on Docker -#### (Synology-compatible!) +### Use Docker to run [Pi-Hole](https://pi-hole.net) with an upstream [Unbound](https://nlnetlabs.nl/projects/unbound/about/) resolver. -## Description +Changing this repo to support 2 different docker-compose configurations now: -Running Pi-Hole in Docker can be challenging due to networking requirements by Pi-Hole, this is especially true when the ports that Pi-Hole uses are shared by the host it's running on (this is true for Synology in the default configuration). - -This project uses a [`macvlan` Docker network](https://docs.docker.com/network/macvlan/) to place your containers on your main network, with their own IP addresses and MAC addresses. - -- This docker-compose runs the following 2 containers - - Pi-Hole ([pihole/pihole](https://hub.docker.com/r/pihole/pihole)) - Official from Pi-Hole - - Unbound ([mvance/unbound](https://hub.docker.com/r/mvance/unbound)) - There are several choices here but I like this one the best - -Pi-Hole uses Unbound as it's resolver, and Unbound uses Cloudflare (1.1.1.1) and CleanBrowsing upstream in order to support DNSSEC and DNS-over-TLS. **This is an important detail** about this particular setup-- we are not making queries direct to the root servers as some of the Pi-Hole docs show in their examples. Here's a snippet from the [Unbound config](https://github.com/MatthewVance/unbound-docker/blob/master/1.8.3/unbound.sh) (v1.8.3 as of writing this doc) showing what's happening: - -``` -... - forward-zone: - # Forward all queries (except those in cache and local zone) to - # upstream recursive servers - name: "." - - # Queries to this forward zone use TLS - forward-tls-upstream: yes - - # https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Test+Servers - - - # Cloudflare - forward-addr: 1.1.1.1@853#cloudflare-dns.com - forward-addr: 1.0.0.1@853#cloudflare-dns.com - - # CleanBrowsing - forward-addr: 185.228.168.9@853#security-filter-dns.cleanbrowsing.org - forward-addr: 185.228.169.9@853#security-filter-dns.cleanbrowsing.org -... -``` - -If you want to change any of this Unbound config then you can fork MatthewVance's [unbound-docker repo](https://github.com/MatthewVance/unbound-docker) and modify his `unbound.sh` file. - -## Disclaimer - -Using this type of configuration on a Synology NAS is somewhat of an advanced use-case, and it should come with some security/stability considerations: - -- Enabling SSH on your Synology NAS is non-default and should be done with care. - - I would recommend __(1)__ configuring SSH to not use default port 22 and __(2)__ to __never__ forward the SSH port outside of your home network. -- Poking around in the Synology CLI can lead to bad things in your NAS if you you don't know what you're doing. As a rule of thumb I would not touch any files outside of the `/volumeX/` folders unless you know what you're doing. These are the folders which are reflected to the user inside of `File Station` GUI. - - -## Instructions - -### Hold your horses and configure some stuff first... - -- Update `docker-compose.yaml` to match your environment, eg. IP addresses/subnets. - - Take note of the `networks.home.driver_opts.parent` value, the default value of `ovs_eth1` is for using the 2nd ethernet port on a Synology NAS with `Open vSwitch` enabled (configured in `Control Panel` -> `Network` -> `Network Interface` -> `Manage`), if disabled use `eth1` instead, or whichever other interface you might be using in your setup. -- Add a `.env` file next to the docker-compose.yaml so you can pass in the `${WEBPASSWORD}` - this is your Pi-Hole admin password. You can optionally leave this step out and set the password via CLI (`pihole -a -p`) after the Pi-Hole is running -- Update the secondary/backup nameserver in the `pihole/config/resolv.conf` file, or remove it if you don't have a backup (would recommend having one!) -- Lastly, optionally, you can provide some manual DNS entries in the `pihole/config/dnsmasq.conf` and/or `pihole/config/hosts` files - -### Run it! - -Copy the files up to your Docker host (eg Synology) - -> __Note__: Synology does not support `docker-compose` via their GUI but the running containers that get created here will be visible there when you're done. - -On client machine: - -```bash -# Make sure the target directory exists first! -# Can use something like `mkdir -p /volume1/docker/pihole-unbound` - -cd docker-pihole-unbound -scp -r ./* myuser@synology.local:/volume1/docker/pihole-unbound/ -``` - -On the Docker host (eg Synology) - -```bash -cd /volume1/docker/pihole-unbound -sudo docker-compose up -d -``` - -__Note__: If you're using Synology, you'll need to `scp` these files to your NAS and run it from the CLI since `docker-compose` is not currently supported through their DSM GUI. - -### Test it! - -Test your configuration with dig - -> __Note__: change the IP to your new Pi-Hole's IP - -```bash -dig google.com @192.168.1.5 -# Expecting "status: NOERROR" -``` - -You can also test for DNSSEC functionality: - -```bash -dig sigfail.verteiltesysteme.net @192.168.1.5 -# Expecting "status: SERVFAIL" - -dig sigok.verteiltesysteme.net @192.168.1.5 -# Expecting "status: NOERROR" -``` - -### Serve it! - -If all looks good, configure your router/DHCP server to serve your new Pi-Hole IP address (`192.168.1.5`) to your clients. - -> Note: it may take some time for the current DHCP leases to renew and for clients to get the new DNS service info -- generally the default is 24 hours or less. - -### Update it! - -When updated container images are released you can execute these commands on your Docker host to pull them in and run them - -```bash -cd /volume1/docker/pihole-unbound -sudo docker-compose pull -sudo docker-compose down -sudo docker-compose up -d -``` - -## Acknowledgements - -- [http://tonylawrence.com/posts/unix/synology/free-your-synology-ports/][synology-ports] -- [https://github.com/MatthewVance/unbound-docker][unbound-docker] -- [https://pi-hole.net][pihole] -- [https://nlnetlabs.nl/projects/unbound/about/][unbound] - -[synology-ports]: http://tonylawrence.com/posts/unix/synology/free-your-synology-ports/ -[unbound-docker]: https://github.com/MatthewVance/unbound-docker -[pihole]: https://pi-hole.net -[unbound]: https://nlnetlabs.nl/projects/unbound/about/ +- [`one-container`](one-container/) (new) - Install Unbound directly into the Pi-Hole container + - This configuration contacts the DNS root servers directly, please read the Pi-Hole docs on [Pi-hole as All-Around DNS Solution](https://docs.pi-hole.net/guides/unbound/) to understand what this means. + - With this approach, we can also simply our networking since `macvlan` is no longer necessary. +- [`two-container`](two-container/) (legacy) - Use separate containers for Pi-Hole and Unbound + - This configuration uses MatthewVance's [unbound-docker](https://github.com/MatthewVance/unbound-docker) container to implement encrypted DNS to third party DNS resolvers (eg Cloudflare). This is arguably less privacy-friendly since you're handing your DNS queries to those 3rd party providers. diff --git a/one-container/README.md b/one-container/README.md new file mode 100644 index 0000000..96a5379 --- /dev/null +++ b/one-container/README.md @@ -0,0 +1,47 @@ +# Pi-Hole + Unbound - 1 Container + +## Description + +This Docker deployment runs both Pi-Hole and Unbound in a single container. + +The base image for the container is the [official Pi-Hole container](https://hub.docker.com/r/pihole/pihole), with an extra build step added to install the Unbound resolver directly into to the container based on [instructions provided directly by the Pi-Hole team](https://docs.pi-hole.net/guides/unbound/). + +## Usage + +First create a `.env` file to substitute variables for your deployment. + + +### Required environment variables + +> Vars and descriptions replicated from the [official pihole container](https://github.com/pi-hole/docker-pi-hole/): + +| Docker Environment Var | Description| +| --- | --- | +| `ServerIP: `
| **--net=host mode requires** Set to your server's LAN IP, used by web block modes and lighttpd bind address +| `TZ: `
| Set your [timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) to make sure logs rotate at local midnight instead of at UTC midnight. +| `WEBPASSWORD: `
| http://pi.hole/admin password. Run `docker logs pihole \| grep random` to find your random pass. +| `REV_SERVER: <"true"|"false">`
| Enable DNS conditional forwarding for device name resolution +| `REV_SERVER_DOMAIN: `
| If conditional forwarding is enabled, set the domain of the local network router +| `REV_SERVER_TARGET: `
| If conditional forwarding is enabled, set the IP of the local network router +| `REV_SERVER_CIDR: `
| If conditional forwarding is enabled, set the reverse DNS zone (e.g. `192.168.0.0/24`) + +Example `.env` file in the same directory as your `docker-compose.yaml` file: + +``` +ServerIP=192.168.1.10 +TZ=America/Los_Angeles +WEBPASSWORD=QWERTY123456asdfASDF +REV_SERVER=true +REV_SERVER_DOMAIN=local +REV_SERVER_TARGET=192.168.1.1 +REV_SERVER_CIDR=192.168.0.0/16 +``` + + +### Running the stack + +```bash +docker-compose up -d +``` + +> If using Portainer, just paste the `docker-compose.yaml` contents into the stack config and add your *environment variables* directly in the UI. \ No newline at end of file diff --git a/one-container/docker-compose.yaml b/one-container/docker-compose.yaml new file mode 100644 index 0000000..9c4e545 --- /dev/null +++ b/one-container/docker-compose.yaml @@ -0,0 +1,32 @@ +version: '2' + + +services: + pihole: + container_name: pihole + image: cbcrowe/pihole-unbound:latest + hostname: pihole + domainname: pihole.local + ports: + - 8443:443/tcp + - 53/tcp + - 53/udp + - 8080:80/tcp + # - 22/tcp # Uncomment to enable SSH + environment: + ServerIP: ${ServerIP} + TZ: ${TZ} + WEBPASSWORD: ${WEBPASSWORD} + REV_SERVER: ${REV_SERVER} + REV_SERVER_TARGET: ${REV_SERVER_TARGET} + REV_SERVER_DOMAIN: ${REV_SERVER_DOMAIN} + REV_SERVER_CIDR: ${REV_SERVER_CIDR} + DNS1: 127.0.0.1#5335 # Hardcoded to our Unbound server + DNS2: 127.0.0.1#5335 # Hardcoded to our Unbound server + DNSSEC: "true" # Enable DNSSEC + network_mode: "host" + volumes: + - etc_pihole-unbound:/etc/pihole:rw + - etc_pihole_dnsmasq-unbound:/etc/dnsmasq.d:rw + restart: unless-stopped + diff --git a/one-container/pihole-unbound/Dockerfile b/one-container/pihole-unbound/Dockerfile new file mode 100644 index 0000000..49b56a9 --- /dev/null +++ b/one-container/pihole-unbound/Dockerfile @@ -0,0 +1,9 @@ +FROM pihole/pihole:latest +RUN apt update && apt install -y unbound + +COPY lighttpd-external.conf /etc/lighttpd/external.conf +COPY unbound-pihole.conf /etc/unbound/unbound.conf.d/pi-hole.conf +COPY install_unbound_and_s6_init.sh install_unbound_and_s6_init.sh + +RUN chmod +x install_unbound_and_s6_init.sh +ENTRYPOINT ./install_unbound_and_s6_init.sh \ No newline at end of file diff --git a/one-container/pihole-unbound/VERSION b/one-container/pihole-unbound/VERSION new file mode 100644 index 0000000..60453e6 --- /dev/null +++ b/one-container/pihole-unbound/VERSION @@ -0,0 +1 @@ +v1.0.0 \ No newline at end of file diff --git a/one-container/pihole-unbound/install_unbound_and_s6_init.sh b/one-container/pihole-unbound/install_unbound_and_s6_init.sh new file mode 100755 index 0000000..c7dd36a --- /dev/null +++ b/one-container/pihole-unbound/install_unbound_and_s6_init.sh @@ -0,0 +1,3 @@ +#!/bin/bash -e +/etc/init.d/unbound start +/s6-init \ No newline at end of file diff --git a/one-container/pihole-unbound/lighttpd-external.conf b/one-container/pihole-unbound/lighttpd-external.conf new file mode 100644 index 0000000..8685d5e --- /dev/null +++ b/one-container/pihole-unbound/lighttpd-external.conf @@ -0,0 +1,6 @@ +$HTTP["url"] =~ "^/admin/" { + # Allow using Pi-Hole admin in iframes (eg, for Home Assistant) + setenv.set-response-header += ( + "X-Frame-Options" => "Allow" + ) +} \ No newline at end of file diff --git a/one-container/pihole-unbound/unbound-pihole.conf b/one-container/pihole-unbound/unbound-pihole.conf new file mode 100644 index 0000000..ff07a82 --- /dev/null +++ b/one-container/pihole-unbound/unbound-pihole.conf @@ -0,0 +1,55 @@ +# Config pulled from https://docs.pi-hole.net/guides/unbound/ + +server: + # If no logfile is specified, syslog is used + # logfile: "/var/log/unbound/unbound.log" + verbosity: 0 + + interface: 127.0.0.1 + port: 5335 + do-ip4: yes + do-udp: yes + do-tcp: yes + + # May be set to yes if you have IPv6 connectivity + do-ip6: no + + # You want to leave this to no unless you have *native* IPv6. With 6to4 and + # Terredo tunnels your web browser should favor IPv4 for the same reasons + prefer-ip6: no + + # 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: "/var/lib/unbound/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 + + # 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. + num-threads: 1 + + # Ensure kernel buffer is large enough to not lose messages in traffic spikes + so-rcvbuf: 1m + + # Ensure privacy of local IP ranges + private-address: 192.168.0.0/16 + private-address: 169.254.0.0/16 + private-address: 172.16.0.0/12 + private-address: 10.0.0.0/8 + private-address: fd00::/8 + private-address: fe80::/10 \ No newline at end of file diff --git a/two-container/README.md b/two-container/README.md new file mode 100644 index 0000000..9ee1a67 --- /dev/null +++ b/two-container/README.md @@ -0,0 +1,134 @@ +# Pi-Hole + Unbound - 2 Containers + +#### (Synology-compatible!) + +## Description + +Running Pi-Hole in Docker can be challenging due to networking requirements by Pi-Hole, this is especially true when the ports that Pi-Hole uses are shared by the host it's running on (this is true for Synology in the default configuration). + +This project uses a [`macvlan` Docker network](https://docs.docker.com/network/macvlan/) to place your containers on your main network, with their own IP addresses and MAC addresses. + +- This docker-compose runs the following 2 containers + - Pi-Hole ([pihole/pihole](https://hub.docker.com/r/pihole/pihole)) - Official from Pi-Hole + - Unbound ([mvance/unbound](https://hub.docker.com/r/mvance/unbound)) - There are several choices here but I like this one the best + +Pi-Hole uses Unbound as it's resolver, and Unbound uses Cloudflare (1.1.1.1) and CleanBrowsing upstream in order to support DNSSEC and DNS-over-TLS. **This is an important detail** about this particular setup-- we are not making queries direct to the root servers as some of the Pi-Hole docs show in their examples. Here's a snippet from the [Unbound config](https://github.com/MatthewVance/unbound-docker/blob/master/1.8.3/unbound.sh) (v1.8.3 as of writing this doc) showing what's happening: + +``` +... + forward-zone: + # Forward all queries (except those in cache and local zone) to + # upstream recursive servers + name: "." + + # Queries to this forward zone use TLS + forward-tls-upstream: yes + + # https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Test+Servers + + + # Cloudflare + forward-addr: 1.1.1.1@853#cloudflare-dns.com + forward-addr: 1.0.0.1@853#cloudflare-dns.com + + # CleanBrowsing + forward-addr: 185.228.168.9@853#security-filter-dns.cleanbrowsing.org + forward-addr: 185.228.169.9@853#security-filter-dns.cleanbrowsing.org +... +``` + +If you want to change any of this Unbound config then you can fork MatthewVance's [unbound-docker repo](https://github.com/MatthewVance/unbound-docker) and modify his `unbound.sh` file. + +## Disclaimer + +Using this type of configuration on a Synology NAS is somewhat of an advanced use-case, and it should come with some security/stability considerations: + +- Enabling SSH on your Synology NAS is non-default and should be done with care. + - I would recommend __(1)__ configuring SSH to not use default port 22 and __(2)__ to __never__ forward the SSH port outside of your home network. +- Poking around in the Synology CLI can lead to bad things in your NAS if you you don't know what you're doing. As a rule of thumb I would not touch any files outside of the `/volumeX/` folders unless you know what you're doing. These are the folders which are reflected to the user inside of `File Station` GUI. + + +## Instructions + +### Hold your horses and configure some stuff first... + +- Update `docker-compose.yaml` to match your environment, eg. IP addresses/subnets. + - Take note of the `networks.home.driver_opts.parent` value, the default value of `ovs_eth1` is for using the 2nd ethernet port on a Synology NAS with `Open vSwitch` enabled (configured in `Control Panel` -> `Network` -> `Network Interface` -> `Manage`), if disabled use `eth1` instead, or whichever other interface you might be using in your setup. +- Add a `.env` file next to the docker-compose.yaml so you can pass in the `${WEBPASSWORD}` - this is your Pi-Hole admin password. You can optionally leave this step out and set the password via CLI (`pihole -a -p`) after the Pi-Hole is running +- Update the secondary/backup nameserver in the `pihole/config/resolv.conf` file, or remove it if you don't have a backup (would recommend having one!) +- Lastly, optionally, you can provide some manual DNS entries in the `pihole/config/dnsmasq.conf` and/or `pihole/config/hosts` files + +### Run it! + +Copy the files up to your Docker host (eg Synology) + +> __Note__: Synology does not support `docker-compose` via their GUI but the running containers that get created here will be visible there when you're done. + +On client machine: + +```bash +# Make sure the target directory exists first! +# Can use something like `mkdir -p /volume1/docker/pihole-unbound` + +cd docker-pihole-unbound +scp -r ./* myuser@synology.local:/volume1/docker/pihole-unbound/ +``` + +On the Docker host (eg Synology) + +```bash +cd /volume1/docker/pihole-unbound +sudo docker-compose up -d +``` + +__Note__: If you're using Synology, you'll need to `scp` these files to your NAS and run it from the CLI since `docker-compose` is not currently supported through their DSM GUI. + +### Test it! + +Test your configuration with dig + +> __Note__: change the IP to your new Pi-Hole's IP + +```bash +dig google.com @192.168.1.5 +# Expecting "status: NOERROR" +``` + +You can also test for DNSSEC functionality: + +```bash +dig sigfail.verteiltesysteme.net @192.168.1.5 +# Expecting "status: SERVFAIL" + +dig sigok.verteiltesysteme.net @192.168.1.5 +# Expecting "status: NOERROR" +``` + +### Serve it! + +If all looks good, configure your router/DHCP server to serve your new Pi-Hole IP address (`192.168.1.5`) to your clients. + +> Note: it may take some time for the current DHCP leases to renew and for clients to get the new DNS service info -- generally the default is 24 hours or less. + +### Update it! + +When updated container images are released you can execute these commands on your Docker host to pull them in and run them + +```bash +cd /volume1/docker/pihole-unbound +sudo docker-compose pull +sudo docker-compose down +sudo docker-compose up -d +``` + +## Acknowledgements + +- [http://tonylawrence.com/posts/unix/synology/free-your-synology-ports/][synology-ports] +- [https://github.com/MatthewVance/unbound-docker][unbound-docker] +- [https://pi-hole.net][pihole] +- [https://nlnetlabs.nl/projects/unbound/about/][unbound] + +[synology-ports]: http://tonylawrence.com/posts/unix/synology/free-your-synology-ports/ +[unbound-docker]: https://github.com/MatthewVance/unbound-docker +[pihole]: https://pi-hole.net +[unbound]: https://nlnetlabs.nl/projects/unbound/about/ diff --git a/docker-compose.yaml b/two-container/docker-compose.yaml similarity index 99% rename from docker-compose.yaml rename to two-container/docker-compose.yaml index 65e2f1e..5c26cb0 100755 --- a/docker-compose.yaml +++ b/two-container/docker-compose.yaml @@ -52,4 +52,4 @@ networks: config: - subnet: 192.168.1.0/24 gateway: 192.168.1.1 - ip_range: 192.168.1.5/30 # 192.168.1.5 and 192.168.1.6 + ip_range: 192.168.1.5/30 # 192.168.1.5 and 192.168.1.6 \ No newline at end of file diff --git a/pihole/config/dnsmasq.conf b/two-container/pihole/config/dnsmasq.conf similarity index 100% rename from pihole/config/dnsmasq.conf rename to two-container/pihole/config/dnsmasq.conf diff --git a/pihole/config/hosts b/two-container/pihole/config/hosts similarity index 100% rename from pihole/config/hosts rename to two-container/pihole/config/hosts diff --git a/pihole/config/pihole-FTL.conf b/two-container/pihole/config/pihole-FTL.conf similarity index 100% rename from pihole/config/pihole-FTL.conf rename to two-container/pihole/config/pihole-FTL.conf diff --git a/pihole/config/resolv.conf b/two-container/pihole/config/resolv.conf similarity index 100% rename from pihole/config/resolv.conf rename to two-container/pihole/config/resolv.conf diff --git a/pihole/volume/files b/two-container/pihole/volume/files similarity index 100% rename from pihole/volume/files rename to two-container/pihole/volume/files