A 2012 Mac mini from an e-waste pile runs my whole setup
My wife found a late-2012 Mac mini in an e-waste pile. After a RAM upgrade it was a desktop for a while, and when macOS stopped supporting it I installed Ubuntu Server 24.04. It's been the home server since. I drew a map of what runs on it and how data moves between the pieces. Hardware Mac mini (late 2012), Intel i5-3210M (2 cores, 4 threads), 16 GB RAM 250 GB SSD for the system, 1 TB for files, two 8 TB drives (photos and archive on one, local backups on the other) Home Assistant runs on a separate Home Assistant Green, so the home automations don't go down with the server What runs, and what it replaces Nextcloud – Google Drive, Dropbox Immich – Google Photos Paperless-ngx – a filing cabinet. A scanner with a document feeder drops scans into the folder it watches Stirling PDF – iLovePDF, Smallpdf SplitPro, with a few of my own changes – Splitwise, after it put features behind a paywall AdGuard Home – Pi-hole, NextDNS PriceBuddy – CamelCamelCamel, Keepa Uptime Kuma – UptimeRobot Kopia – versioned local backups, plus an encrypted offsite copy A meal planner I wrote. It plans the week and a small Chrome extension adds the shopping list to the supermarket cart BirdNET with a USB mic at the window. It identifies birds by sound and shows them as an illustrated collage (a fork of Avian Visitors) Most of it runs in Docker. The bird setup runs in an LXD container (see below). Access No ports forwarded. The few public things go out through a Cloudflare Tunnel, some of them behind Cloudflare Access. Everything else is Tailscale only. Things that bit me The CPU has AVX but not AVX2. Current tflite-runtime wheels die instantly with "Illegal instruction". tflite-runtime 2.14 with numpy 1.26 works. The BirdNET installer assumes it owns the machine: it reboots at the end, upgrades packages and adds broad sudo rules. So it lives in an LXD container. After a reboot the USB mic came up under a different ALSA card number, and the container got the internal sound card instead. It recorded silence for about 20 hours while the web UI looked completely healthy. A timer now checks the mic every 2 minutes. My first mic was a wireless voice receiver with an 8 kHz ceiling, so high-pitched birds never showed up. A cheap wired USB lavalier fixed it. The map is part of a small static page about the setup, with status dots from Uptime Kuma. I built the page and the meal planner with a lot of help from Claude Code. Happy to answer questions about any of it.