Skip to content Skip to table of contents

Home Server

An old laptop at home that runs my password manager, music, files and ad blocking for the home network.

I run the services I use every day on an old laptop at home with Ubuntu Server. It keeps my passwords, my music and my files, and it blocks ads for every device on the home network. I reach it from anywhere over Tailscale, a VPN that puts my devices on one private network.

My phone and laptop Devices at home Tailscale DNS via the router Laptop at home: Ubuntu Server Vaultwarden passwords Pi-hole DNS and ad blocking Navidrome music Nextcloud files Homepage dashboard Uptime Kuma monitoring weekly backup alerts USB drive Telegram
Every service runs as a Docker container. Devices at home get Pi-hole as their DNS server from the router.

What runs on it

ServiceWhat I use it for
VaultwardenPasswords, synced to the Bitwarden apps and browser extension
NavidromeStreaming my music library to my phone
NextcloudFiles, like a self-hosted Google Drive
Pi-holeDNS and ad blocking for every device at home
HomepageOne dashboard with a link to each service and its status
Uptime KumaChecks every service and messages me on Telegram when one goes down

One Docker Compose file in a git repository defines all six containers. Git holds only the configuration. The data lives on the server and in the backups.

Backups

Every Sunday at 2 a.m. a script copies the data to a USB drive. The password and file databases are SQLite files that the services write to all the time, so a plain copy can catch one halfway through a write. The script takes a snapshot with SQLite’s online backup instead. Every run also pings Uptime Kuma. If a backup fails, or no backup arrives for about eight days, Uptime Kuma sends an alert to Telegram.

The backup is one copy on one drive, plugged into the server itself. An offsite copy is the next step.

What broke

I worked through each of these with Claude Code, an AI coding assistant, over SSH.

The empty password vault. One day in September the Bitwarden app on my phone showed no passwords. The data on the server was fine. The app had updated itself to a version that needs a newer Vaultwarden. The server still ran the image I had pulled in April, because a :latest tag only changes when you pull it again. Pulling the new image and logging in again brought the vault back. Nothing updates the server automatically, so the mismatch will come back unless I update it when the apps update.

Updating all services at once. Running docker compose pull for the whole stack would have moved Nextcloud forward several major versions in one step. Nextcloud refuses to skip a major version, so it would have stayed down. Now I update one service at a time and keep a copy of its database and old image first. Nextcloud goes up one major version at a time.

The home internet outage. My devices on Tailscale send their DNS lookups to Pi-hole at home. When the home connection dropped, my laptop on a phone hotspot could not look up any name. It looked as if Tailscale had broken the internet. A public DNS server as a fallback would let ads through. Tailscale asks all its DNS servers at once and uses the fastest answer, so the public server would answer some lookups first. Until there is a second resolver, sudo tailscale set --accept-dns=false turns off Tailscale’s DNS on that device and gets name lookups working again.

The backup drive after a reboot. The kernel log after one reboot showed the USB drive mount and then drop off the USB bus 47 seconds later. It came back as a new device, and nothing mounted it again. Without a check, the next backup would have written into an empty folder on the laptop’s own disk. The script checks that the drive is mounted before it copies anything, so a backup in that state stops and sends the alert.