Raspberry Pi Home Server
I recently soft-bricked my Raspberry Pi docker installation (i.e. I can’t be bothered to keep googling the cryptic error messages), and it was still on Raspbian Stretch which no longer receives support…
So time to reinstall everything on my Raspberry Pi! Might as well document this in case I need to perform disaster recovery.
The audience of this blog is myself in the future.
Hardware
- A Raspberry Pi.
- I have a Raspberry Pi 3 Model B Rev 1.2
- SD card
- A way to write to SD cards (an SD card slot or adapter)
- (optional) External hard drive with a separate power supply
- Ideally is formatted as ext4 or with an ext4 partition. Mine has a small ext4 partition.
Burning Image to SD Card
Use imager: https://www.raspberrypi.com/software/ to install the latest Raspberry Pi OS for your Raspberry Pi.
Configure password in settings, and enable SSH via username and password, OR go ahead and add an ssh key at this step.
Network Config
Now connect the ethernet (if you haven’t already)
Go to your Router and look for something like “DHCP Reservation”. Assign an IP like 192.168.1.201
Enabling Safe(r) SSH
Do this if you didn’t already set up an ssh key while configuring the image.
First, add a ssh client public key to ~/.ssh/authorized_keys
ssh <username>@192.168.1.201
cd ~/
mkdir .ssh
vi .ssh/authorized_keys
Then, disable password auth
sudo vi /etc/ssh/sshd_config
Set
PasswordAuthentication no
You may also have to check /etc/ssh/sshd_config.d/ for any override files.
Then run
sudo systemctl restart ssh
Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
rm get-docker.sh
sudo usermod -a -G docker <username>
sudo systemctl enable docker
I do not recommend rootless anymore, it’s easier when moving docker files into another partition.
Then relogin in. Confirm success with a docker ps and docker run hello-world
If that fails due to connect: network is unreachable…
Detour: Fix resolvconf
sudo apt install resolvconf
sudo vi /etc/resolvconf/resolv.conf.d/original
Remove this line:
nameserver 192.168.1.1
sudo vi /etc/resolvconf/resolv.conf.d/base
Add these lines:
nameserver 8.8.8.8
nameserver 8.8.4.4
Run
sudo resolvconf -u
Detour of Detour: Fix personal router DNS
Servers allocated with DHCP requests:
DHCP DNS Type: Default Servers Custom Servers
Primary DNS:
Secondary DNS:
Then sudo reboot now
Disable desktop on boot
raspi-config can do this, just boot to command line instead of GUI.
Now that there are no “lite” images published, this has to be done.
External Hard Drive
Assuming external hard drive is located at /dev/sda2
sudo mkdir -p /path/to/hard/drive
sudo mount /dev/sda2 /path/to/hard/drive -o uid=<username>,gid=<username>
To mount on startup, first find the uuid of the hard drive
lsblk -f
Then edit the file system table, /etc/fstab, and add:
UUID=<UUID> /path/to/hard/drive ntfs defaults,noatime,nofail 0 2
Replace ntfs with the correct filesystem. Be careful! This could brick your boot if incorrectly.
Docker containers/images on External Hard Drive
You may want to do this in combination with the next step (OverlayFS to reduce writes) so docker images are stored on the hard drive, not the SD card.
First, a place for docker files:
mkdir -p /mnt/path/to/docker
sudo nano /etc/docker/daemon.json
{
"data-root": "/mnt/path/to/docker"
}
Additionally, after Docker 29, also a place for containerd images:
sudo nano /etc/containerd/config.toml
Add root = "/var/lib/containerd"
Finally, require mounting your hard drive partition before starting Docker:
sudo systemctl edit docker
[Unit]
RequiresMountsFor=/mnt/path/to/docker
OverlayFS to reduce writes
This step will make every other operation more of a pain in the ass due to the write protection, so do this last.
Generally followed https://www.and-e.co.uk/sysadmin/raspberryPiOverlayFileSystem.html
raspi-config
Answer yes to both “Would you like the overlay file system to be enabled?” and “Would you like the boot partition to be write-protected?” but do NOT reboot yet.
If you have an external hard drive, you’ll want to first make sure external hard drives are not write protected.
sudo mount -o remount,rw /boot/firmware
sudoedit /boot/firmware/cmdlint.txt from
Change overlayroot=tmpfs to overlayroot=tmpfs:recurse=0
Then undo the temporary mount
sudo mount -o remount,ro /boot/firmware
And then you can reboot.
Docker Containers
Remember to use image for the right architecture for your Raspberry Pi model. For my model, it’s arm64v81.
linuxserver.io has a lot of community maintained images for popular server software.
I keep all my docker-compose files on the hard drive, which makes the docker images below even easier to recover when the SD card corrupts (which it does often!)
Set PUID and GUID to your non-root user, probably 1000, but you can check using
id -u <username>
restart: unless-stopped allows these containers to be restarted on host startup
ddclient
---
version: "2"
services:
ddclient:
image: linuxserver/ddclient:arm64v8-latest
container_name: ddclient
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/London
volumes:
- /path/to/hard/drive/ddclient/config:/config
restart: unless-stopped
Transmission
---
version: "2"
services:
transmission:
image: linuxserver/transmission:arm64v8-2.94-r1-ls14
container_name: transmission
environment:
- PUID=1000
- PGID=1000
- TZ=America/Los_Angeles
volumes:
- /path/to/hard/drive/transmission/config:/config
- /path/to/hard/drive/transmission/downloads:/downloads
- /path/to/hard/drive/transmission/watch:/watch
ports:
- 9091:9091
- 51413:51413
- 51413:51413/udp
restart: unless-stopped
Plex
---
version: "2"
services:
plex:
image: linuxserver/plex:arm64v8-1.32.2
container_name: plex
network_mode: host
environment:
- PUID=1000
- GUID=1000
- TZ=America/Chicago
volumes:
- /path/to/hard/drive/media:/mnt/media
restart: unless-stopped
Operating
sudo docker compose up -d
Not using sudo will cause issues.
Containers should start back up on restart, too.
This guide has been used 2 times by myself and saved my ass.Footnotes
-
In the first version of this post I went through these instructions for
arm32v7, only to learn at the end that support for it is getting removed at the beginning of July.. So I went through all of these steps again forarm64v8. This also meant this blog was immediately useful to me less than 24 hours later :) ↩