Pi Hole, TailScale, and Docker on an Orange Pi
Tags: digital-minimalism, raspberry-pi • Categories: Learning
I’ve always been fascinated by this super cheap and relatively fast hardware you can buy now. A while back I bought a Raspberry Pi and a friend recently told me about the Orange Pi. I decided to give it a shot primarily because it supports an eMMC chip which allows super fast ssd IO (170mb+ writes in my case).
I was nervous about compatibility issues, but I was pleasantly surprised that it worked out of the box without any real issues. The hardest part was actually getting the eMMC working (which I’ll detail in another post).
Here’s a walkthrough of what I did to get the orange pi up and running.
Installing the OS
- http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/service-and-support/Orange-pi-3-LTS.html
- Click on the system type you want. I chose ubuntu. You’ll be sent to a google drive to download a file. Unzip the archive and you’ll find a
.img
which is the OS image. - Download Etcher Balena to copy the OS image to your SD card.
- Plug the SD card into the orange pi and you’ll be good to go.
General Setup
The default username and password is orangepi
(same for both). Change the default password using:
passwd
You’ll probably want to change the hostname:
sudo nano /etc/hostname
And, to avoid having to input your password all of the time, add your orangepi user to the sudo group:
sudo usermod -aG sudo orangepi
Similar to Raspberry Pi, there’s a system command you can use to configure most of the core system settings:
sudo orangepi-config
Add your SSH key to the machine:
ssh-add-key orangepi@orange
Docker
The get-docker
script did not work for me, but the default ubuntu installation did I ran my customized pie -hole dockerized installation without any issues.
ghcr.io
I’ve been using the GitHub Container Registry for my docker containers recently. You’ll need to login to the registry to download images from ghcr:
echo "password" | docker login ghcr.io -u iloveitaly --password-stdin
Tailscale
Tailscale Ubuntu installation worked great. No problems. Honestly, I was really surprised here. I expected this package not to work properly.
Tailscale with PiHole
Tailscale even has a guide to setting up pihole This is really pretty neat because it allows you to use your pie for DNS resolution regardless of where you physically are.
sudo tailscale down
tailscale up --accept-dns=false
DNS resolution was still lightning-fast (<1ms) even when routing through tailscale (I’d love to learn more about exactly how Tailscale works. It’s really like magic.)
One thing to note is you can’t reorder the DNS servers once they are set.
Swap Increase
This guide worked great. I’ve done this a dozen times but can never remember the exact process:
sudo swapoff -a
sudo dd if=/dev/zero of=/swapfile bs=1G count=8
sudo mkswap /swapfile
sudo swapon /swapfile
# make sure this exists in fstab: /swapfile swap swap defaults 0 0"
Pihole on Orange Pi
My main goal for buying the Orange Pi was to install Pi-Hole and have it wired up to my router to reduce latency. My Raspberry Pi is wired into another eero that is not connected via Ethernet and acts as a NAS and does a bunch of other stuff, so it can sometimes be slow.
One thing I was pleasantly surprised about is while I was setting up the Orange Pi and installing Python, Ruby, and other system packages, which completely maxed out all four cores, the performance on the Dockerized Pi-hole was incredibly fast.
❯ dig @192.168.7.32 apple.com
; <<>> DiG 9.10.6 <<>> @192.168.7.32 apple.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41751
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;apple.com. IN A
;; ANSWER SECTION:
apple.com. 420 IN A 17.253.144.10
;; Query time: 1 msec
;; SERVER: 192.168.7.32#53(192.168.7.32)
;; WHEN: Tue Feb 06 09:30:43 MST 2024
;; MSG SIZE rcvd: 54
Obviously in this case, the domain query was cached on the pi hole side, but even with a fresh domain, it’s still clocked in and under 30 milliseconds. This is while all cores were maxed out at 100% on the machine and before I installed a emmc (running off a 16gb probably slow SD card).
Disable Dnsmasq & Dns Stubbing
As detailed here on Ubuntu systemd-resolved can occupy port 53, which is DNS. Here’s how to fix it:
sudo sed -r -i.orig 's/#?DNSStubListener=yes/DNSStubListener=no/g' /etc/systemd/resolved.conf
sudo sh -c 'rm /etc/resolv.conf && ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf'
sudo systemctl restart systemd-resolved
sudo systemctl disable --now dnsmasq
I’m not sure exactly how, but dnsmasq started up after I had removed resolved
which is why I turn it off here.
Pi Hole Docker Compose Configuration
Here’s the docker-compose.yml I used to setup pihole. Note that I’m using a customized pihole container that allows for disabling certain websites on a schedule.
version: "3.8"
services:
pihole:
container_name: pihole
image: iloveitaly/pihole-scheduled-blocking:latest
restart: always
environment:
TZ: "America/Denver" # Put your own timezone here.
WEBPASSWORD: "PASSWOR" # Put a strong password here.
ports:
- "53:53/tcp"
- "53:53/udp"
- "80:80/tcp"
volumes:
- pihole-config:/etc
volumes:
pihole-config:
I know /etc
isn’t the "right" thing to do here, but this made things much easier for me since my custom pi hole container has some additional configuration modifications.
Custom Pi Hole DNS Entries
Pi hole supports custom DNS entries can be broadcasted. For instance:
192.168.7.35 service.hole
Now, if you have tailscale + magic DNS enabled you can do:
raspberrypi service.hole
Here’s how to copy the custom.list
file into the correct location:
docker compose cp custom.list pihole:/etc/pihole/custom.list
docker compose restart pihole
Homebrew on Orange Pi
Linux Homebrew is not supported on ARM (raspberrypi or orangepi). I followed these instructions
apt-get install ruby
ruby --version
sudo git clone --depth=1 https://github.com/Homebrew/brew /opt/homebrew
sudo chown -R $(whoami) /opt/homebrew
# now it should be installed, we can source the activation script and start working
eval "$(/opt/homebrew/bin/brew shellenv)"
brew update --force --verbose
brew --version
Unfortunately, Ruby 3.0 is the latest version supported by the Ubuntu package register on OrangePi. I got this error when attempting to brew update
.
Error: No Homebrew ruby 3.1.4 available for aarch64 processors!
Error: Failed to install Homebrew Portable Ruby and cannot find another Ruby 3.1!
If there's no Homebrew Portable Ruby available for your processor:
- install Ruby 3.1 with your system package manager (or rbenv/ruby-build)
- make it first in your PATH
- try again
What I tried next was installing Python and Ruby using ADSF. There were a couple core packages missing so I had to install them and then reinstall python and ruby via asdf.
sudo apt-get install -y libbz2-dev libffi-dev libreadline-dev libsqlite3-dev tk-dev liblzma-dev
sudo apt-get install -y build-essential autoconf bison libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev
(Both of the packages in this list were auto-generated by ChatGPT by me pasting the error output from ADSF. )
Even after installing Ruby successfully, I still got the same error. I couldn’t figure out how to get brew to respect the asdf installation. I ended up giving up and just asking ChatGPT to convert my Brewfile to apt-get install
.
Lesson learned: don’t attempt to use homebrew on a raspberry pi / orange pi.