Skip to content

Instantly share code, notes, and snippets.

@xirixiz
Last active August 13, 2024 07:31
Show Gist options
  • Save xirixiz/ecad37bac9a07c2a1204ab4f9a17db3c to your computer and use it in GitHub Desktop.
Save xirixiz/ecad37bac9a07c2a1204ab4f9a17db3c to your computer and use it in GitHub Desktop.
Add a PiHole instance on a macvlan enabled Docker network (Synology eth0 example)
#!/bin/bash
# NAS IP: 192.168.1.10 in this example
# DHCP scope reservation for macvlan: 192.168.1.210/28 (Details below)
## Network: 192.168.1.210/28
## HostMin: 192.168.1.211
## HostMax: 192.168.1.224
## Hosts/Net: 14
# Create a Synology macvlan0 bridge network attached to the physical eth0, and add the ip range scope (sudo)
ip link add macvlan0 link eth0 type macvlan mode bridge
# Specify part of the eth0 scope you'd like to reserve for macvlan0
ip addr add 192.168.1.210/28 dev macvlan0
# Bring up the macvlan0 adapter
ip link set macvlan0 up
# Check virtual adapter status with ifconfig
ifconfig
# Output should be something like this:
macvlan0 Link encap:Ethernet HWaddr 92:8D:43:0E:E2:D8
inet addr:192.168.1.210 Bcast:0.0.0.0 Mask:255.255.255.240
inet6 addr: fe80::908d:43ff:fe0e:e2d8/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:79 errors:0 dropped:0 overruns:0 frame:0
TX packets:48 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:34863 (34.0 KiB) TX bytes:16322 (15.9 KiB)
# Create a macvlan Docker network using eth0
docker network create --driver=macvlan --gateway=192.168.1.1 --subnet=192.168.1.0/24 --ip-range=192.168.1.210/28 -o parent=eth0 macvlan
# It's also possible to create a scheduled task at startup as the root user, it's wise to append the following in front of the above commands
while ! ip link show eth0 | grep -q 'state UP'; do
sleep 1
done
# Perform a basic test with NGINX
docker run --net=macvlan -dit --name nginx-test-01 --ip=192.168.1.211 nginx:alpine nginx-debug -g 'daemon off;'
# Browse to http://192.168.1.211 in your local network, you should see the nginx welcome page! ...Don't forget to remove the container afterwards...
docker rm nginx-test-01 --force
# Now start PiHole on a macvlan enabled IP address f.e.
# Also I've added a fake mac address so the container always uses the samen mac, handy to make a reservation in your DHCP scope or do whatever you like to do with it.
DOCKERHOME=<some path>
NAME=pihole-macvlan
IMAGE=pihole/pihole
docker run --detach \
--name ${NAME} \
--restart always \
--volume /etc/localtime:/etc/localtime:ro \
--volume ${DOCKERHOME}/data/${NAME}/config:/etc/pihole \
--volume ${DOCKERHOME}/data/${NAME}/dnsmasq.d:/etc/dnsmasq.d \
--cap-add NET_ADMIN \
--dns=127.0.0.1 \
--dns=1.1.1.1 \
--env "DNS1=1.1.1.1" \
--env "DNS2=1.0.0.1" \
--env "ServerIP=192.168.1.212" \
--env "DNSMASQ_LISTENING=all" \
--env "WEBPASSWORD=<secret>" \
--env "TZ=Europe/Amsterdam" \
--network macvlan \
--ip "192.168.1.212" \
--mac-address "02:42:c0:a8:01:d7" \
${IMAGE}
# Cleanup macvlan
ip link set macvlan0 down
ip link delete macvlan0
docker network rm macvlan
# Happy days!
@xirixiz
Copy link
Author

xirixiz commented Apr 19, 2020

Did not think of that either, but great job finding it out! 👍 🥳

@solidus1983
Copy link

Was struggling to do with with protainer Pihole container, just followed your commands and boom i now have a working pihole container that is on the local network as if it was a physical computer connected to my main network!

So much for using Portainers GUI to do this it was forever causing ARP'ing issues. Always said CLI was better this proves it.

Thank you

@canadadanac
Copy link

Hi Bram. I signed up to GitHub specifically so I could thank you for posting this! Extremely helpful! I did a lot of research on this topic (Pihole in Docker on Synology with macvlan). This is by far the best resource I've found! Thanks!

@xirixiz
Copy link
Author

xirixiz commented Sep 7, 2020

Hi @canadadanac, how nice to specially register to tell me this! Thanks, much appreciated! Glad it helped you out a lot! 👍

@markdumay
Copy link

markdumay commented Sep 19, 2020

Hi Bram, great gist, very helpful! I created a script inspired by your guide here, it might help others too. I added a static route from the host to the Pi-hole container to get it to work for my particular Synology setup (which uses a custom Docker installation). It should also persist reboots and DSM updates.

@xirixiz
Copy link
Author

xirixiz commented Sep 22, 2020

Hi @markdumay, good job! I hope it'll help people.

Currently I`m not using Pi-Hole anymore as adguard has a much better way of solving this. So per client I can specify the upstream dns servers, block specific services, and enable/enforce other stuff. This works out great to separate rules for our kids and us as parents!

image

@markdumay
Copy link

Thanks! AdGuard Home looks promising indeed, especially when looking at this comparison. It seems Home Assistant provides integration support too. Out of curiosity, are you running a containerized version of AdGuard yourself?

@xirixiz
Copy link
Author

xirixiz commented Sep 22, 2020

Yes, I run everyting in Docker (when possible :))

@rsessa
Copy link

rsessa commented Oct 9, 2020

Hi! Thank you very much for your work. Let's see if you can help me, this error gives me when I try to create the network in docker:
Error response from daemon: Pool overlaps with other one on this address space.
I have followed these steps:

#iPhone NAS 192.168.10.251

ip link add macvlan0 link ovs_eth0 type macvlan mode bridge
ip addr add 192.168.10.100/28 dev macvlan0
ip link set macvlan0 up
Ifconfig
2DDB8123-71E4-41C6-AAA9-A53F58012AD5

ip router show
1B1EB603-C435-4FE1-9F24-D85BCF356005

docker network create --driver=macvlan --gateway=192.168.10.1 --subnet=192.168.10.0/24 -o parent=ovs_eth0 macvlan
F3ABF986-518F-4D3B-8E2E-DA98D1265CDD

@xirixiz
Copy link
Author

xirixiz commented Oct 9, 2020

Might be easy, try service docker restart first. Most of the times this solves it for these kind of errors

Or:

docker-compose down
docker network prune

Also check the existing Docker network config:
docker network ls

Maybe there's a duplicate network specified.

@rsessa
Copy link

rsessa commented Oct 9, 2020

Solved. Thank you!

@lazynomad
Copy link

Thanks for this.
I see you cleanup macvlan at the end of the script. I suppose it's just to show how to delete it, if needed. However, we shouldn't do that if piHole must be running right ?

@xirixiz
Copy link
Author

xirixiz commented Jan 21, 2021

Correct! It's indeed only some info if you need to remove macvlan. However, as you're mentioning Pi-Hole, I swtiched to Adguard. Adguard has the ability to specify rules and upstream DNS servers per subnet. So I now have a single instance of Adguard running, serving multiple subnets, all with their own configuration so f.e. the subnet of the kids has many limitiations. Pi-Hole is not going to add such a feature unfortunatly and I don't wan't to manage multiple Pi-Hole instances.

@titanbird
Copy link

Hello everyone!

Really like it! :-)

I feel that I am almost finished with a running pihole in docker on a synology nas. But the DNS is not working.
If I use it, the browser outputs an DNS ERROR:

DNS_PROBE_FINISHED_BAD_CONFIG

My router has the ip 192.168.0.1.
The nas has 192.168.0.100
DHCP (running on the nas) ip range: 192.168.0.100 - 192.168.0.199

All the commands that I uses are:

ip link add macvlanpihole link eth0 type macvlan mode bridge
ip addr add 192.168.0.200/28 dev macvlanpihole
ip link set macvlanpihole up
ifconfig

Output:

...
macvlanpi Link encap:Ethernet  HWaddr 82:08:AC:9D:26:77  
          inet addr:192.168.0.200  Bcast:0.0.0.0  Mask:255.255.255.240
          inet6 addr: fe80::8008:acff:fe9d:2677/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:28208 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1301 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          RX bytes:3215747 (3.0 MiB)  TX bytes:173829 (169.7 KiB)

docker network create --driver=macvlan --gateway=192.168.0.1 --subnet=192.168.0.0/24 --ip-range=192.168.0.200/28 -o parent=eth0 macvlan

docker run --net=macvlan -dit --name nginx-test-01 --ip=192.168.0.215 nginx:alpine nginx-debug -g 'daemon off;'

192.168.0.215 is shown in the router as connected client.
browsing to 192.168.0.215 shows nginx page.
ssh into the container, executing ping google.de is successful.

docker rm nginx-test-01 --force

NAME=pihole-macvlanpihole
IMAGE=pihole/pihole
docker run --detach \
           --name ${NAME} \
           --restart always \
           --cap-add NET_ADMIN \
           --dns=127.0.0.1 \
           --dns=1.1.1.1 \
           --env "DNS1=1.1.1.1" \
           --env "DNS2=1.0.0.1" \
           --env "ServerIP=192.168.0.201" \
           --env "DNSMASQ_LISTENING=all" \
           --env "DNSMASQ_USER=root" \
           --env "WEBPASSWORD=cVJNKQyYrJ7e" \
           --env "TZ=Europe/Amsterdam" \
           --network macvlan \
           --ip "192.168.0.201" \
           --mac-address "02:42:c0:a8:01:d7" \
           ${IMAGE}

I can browse to the pihole gui by visiting 192.168.0.201 with my browser.
The query log is showing all the request. So they are there, that's fine.
But browsing to google.com with my browser leads to DNS_PROBE_FINISHED_BAD_CONFIG.

I noticed the following: Ssh into the container, executing ping google.com leads to:
ping: google.com: Temporary failure in name resolution
I think that's a problem?
So my container does "not have" an internet connection?

@xirixiz
Copy link
Author

xirixiz commented Feb 14, 2022

Hi, nice work! A couple of questions:

  • Is the DHCP server set to use 192.168.0.201 as a DNS server for all clients?
  • I believe the config of pihole might have changes slightly, can you try it like this:
NAME=pihole-macvlanpihole
IMAGE=pihole/pihole
docker run --detach \
           --name ${NAME} \
           --restart always \
           --cap-add NET_ADMIN \
           --dns=1.1.1.1 \
           --env "DNSMASQ_USER=root" \
           --env "WEBPASSWORD=cVJNKQyYrJ7e" \
           --env "TZ=Europe/Amsterdam" \
           --network macvlan \
           --ip "192.168.0.201" \
           --mac-address "02:42:c0:a8:01:d7" \
           ${IMAGE}

@titanbird
Copy link

titanbird commented Feb 14, 2022

Hi xirixiz.

Is the DHCP server set to use 192.168.0.201 as a DNS server for all clients?

Nope. For my tests, I change my desktop computer's connection settings to static and I set there 192.168.0.201 as the dns value.

I believe the config of pihole might have changes slightly, can you try it like this:

Oh okay. I will give it a try tomorrow. Which of the parameters do you think could lead now to success?

Best
titanbird

@titanbird
Copy link

Hi again :-)

No success yet. I deleted the pihole container and created a new one with

NAME=pihole-macvlanpihole
IMAGE=pihole/pihole
docker run --detach \
           --name ${NAME} \
           --restart always \
           --cap-add NET_ADMIN \
           --dns=1.1.1.1 \
           --env "DNSMASQ_USER=root" \
           --env "WEBPASSWORD=cVJNKQyYrJ7e" \
           --env "TZ=Europe/Amsterdam" \
           --network macvlan \
           --ip "192.168.0.201" \
           --mac-address "02:42:c0:a8:01:d7" \
           ${IMAGE}

But the same error happens (DNS_PROBE_FINISHED_BAD_CONFIG or DNS_PROBE_STARTED).
From inside the new container, ping google.com still leads to the same error as yesterday.

Very confusing because I can see all the queries within the pihole management gui:

grafik

grafik

Cheers and thanks
titanbird

@xirixiz
Copy link
Author

xirixiz commented Feb 15, 2022

I switched to AdGuard a while ago as AdGuard has an intergrated solution to handle different upstream DNS servers per subnet/client.
However, can you validate the upstream DNS servers in PiHole. Maybe set those to a basic non-tls upstream just to validate whether it's working.

https://discourse.pi-hole.net/t/how-do-i-choose-an-upstream-dns-server/258/10

Could also be the settings on the listening part of the interfaces (allowed list). Please validate that as well. Must be something like that.

image

@titanbird
Copy link

titanbird commented Feb 15, 2022

Thanks for the helpful stuff.

The interface listening behavior was already fine and the dns settings were also fine.
No success.

I retried everything from scretch. Now it is working... Somehow?! :-))

Here is all I had to do in short (please note the little ip changes, maybe there is the key to success in my case):

docker network create --driver=macvlan --gateway=192.168.0.1 --subnet=192.168.0.100/24 --ip-range=192.168.0.200/28 -o parent=eth0 macvlan0

ip link add macvlan-shim link eth0 type macvlan mode bridge

ip addr add 192.168.0.205/28 dev macvlan-shim

ip link set macvlan-shim up

I thought maybe i have to set this one for eth0:
sudo ip link set eth0 promisc on
But in the end, it's not needed.
So I restored it to off in my case:
sudo ip link set eth0 promisc off

ifconfig macvlan-shim
Output:

macvlan-s Link encap:Ethernet  HWaddr A2:CA:BE:14:B5:3B
          inet addr:192.168.0.205  Bcast:0.0.0.0  Mask:255.255.255.240
          inet6 addr: fe80::a0ca:beff:fe14:b53b/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:21169 errors:0 dropped:0 overruns:0 frame:0
          TX packets:987 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:2407069 (2.2 MiB)  TX bytes:133060 (129.9 KiB)
NAME=pihole-vlan
IMAGE=pihole/pihole
docker run --detach \
           --name ${NAME} \
           --restart always \
           --cap-add NET_ADMIN \
           --dns=1.1.1.1 \
           --env "DNSMASQ_USER=root" \
           --env "WEBPASSWORD=cVJNKQyYrJ7e" \
           --env "TZ=Europe/Amsterdam" \
           --network macvlan0 \
           --ip "192.168.0.200" \
           --mac-address "02:42:c0:a8:01:d7" \
           ${IMAGE}

I tried a ping command within the freshly created docker container to test if the gateway is accessible:
docker exec -ti pihole-vlan ping -c 4 192.168.0.1
Output:

PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=1.28 ms
64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=0.989 ms
64 bytes from 192.168.0.1: icmp_seq=3 ttl=64 time=1.12 ms
64 bytes from 192.168.0.1: icmp_seq=4 ttl=64 time=1.75 ms

--- 192.168.0.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 6ms
rtt min/avg/max/mdev = 0.989/1.281/1.745/0.288 ms

I tested it on my notebook right beside me.
Static DNS setting:
dns=192.168.0.200
It works.

grafik
grafik

I did not make any settings in the pihole gui itself, it worked out of the box this way.
Off course, you need a system startup script to execute the ip-commands above once a boot. 👍

@xirixiz
Copy link
Author

xirixiz commented Feb 15, 2022

Great! Good you managed to fix it! 🚀

@donluca87
Copy link

What about:
route add -net 192.168.0.212 netmask 255.255.255.254 dev macvlan0 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment