Building a Simple Rackmount Home Server with Docker Compose
Not long ago, my home server I set up in 2020 died. It was time to rebuild it, but (much) better. Here’s what I did:
Hardware
I used the same hardware I had been using previously: an old Thinkstation S30 workstation. This time, I stripped it out of the factory case and reinstalled it in a compact rackmount 3U server chassis. This setup has two Seagate IronWolf 4TB NAS disks set up with software RAID 1 for redundancy and an SSD for the operating system.
I wall mounted a 6U network rack and slid the server in to occupy the bottom 3U.
The top 3U are occupied by a Cyberpower 300W UPS, a patch panel with an unmanaged switch behind it, and brush passthrough panel to run ethernet through.
Software
The home server runs Ubuntu Server. On it, I installed Docker. Then, I created a GitHub repository with a Docker Compose file. In that Docker Compose file, I set up a few containers (with their appropriate mounts):
kaive/docker-web-gui
: a simple GUI app for viewing Docker containers and logsnextcloud
: my personal storagecaddy
: a simple reverse proxy for routing requests to containersjpillora/dnsmasq
: a DNS server for my local network ()hwdsl2/ipsec-vpn-server
: a VPN server for remote accessghcr.io/akarys42/cloudflare-ddns-docker
: to update my Cloudflare DNS records when my IP changeshomebridge
: a bridge for my non-HomeKit devices to HomeKitbackup-to-s3
: backs up nextcloud to S3 on a regular basisgrahamleslie/docker-host-sensor-page
: monitors the heat of the home server
I also created a few networks to isolate containers. In particular, I networked the DNS container and VPN container together with static IPs to solve a big gotcha: the VPN container needs an environment variable VPN_DNS_SRV1
set with the static internal IP of the DNS container to resolve DNS requests in the home network.
I also added a script to generate an adblock list to the repo. I modified it to output to a file called ads.hosts
.
I included a simple dnsmasq.conf
to configure dnsmasq
and mounted it to the dnsmasq
container (along with the adblock list):
log-queries
no-resolv
server=1.1.1.1 # Use Cloudflare DNS.
server=1.0.0.1
strict-order
address=/home/192.168.86.2 # Route all requests ending in `.home` to my home server.
addn-hosts=/etc/ads.hosts # Include the adblock list.
To host a DNS server in Ubuntu Server, you need to modify /etc/systemd/resolved.conf
to disable the default listener on port 53.
Last, I created a Caddyfile
to configure caddy
. It just has an entry for each domain (example: nextcloud.home
) and routes it to the correct port exposed by the container.
Docker
I then cloned that repo to the server, created some .env
files to include the secrets for each container, and ran the adblock list generator to create the file that will mount to dnsmasq
. I can just run docker-compose up -d
and everything starts up.
The last step was to set a static IP for the home server and forward the necessary ports for external access. A simple home server with a configuration in GitHub–easy to rebuild if something goes wrong.