My Home Server Setup
A list of hardware and software that powers our home.
Recently I migrated from a bunch of Raspberry PIs to a proper home server. I thought I might as well document the setup for future generations.

Before

After
Hardware
Server
One of the main requirements I had for the new build was compact size, since its predecessors were a couple of Raspberry PIs, which take nearly no space, and I don't have a proper server room at home just yet.
All components were available on Czech marketplaces, except the case, which I had to order from AliExpress, since I found exactly 0 compact mini-ITX cases with a space for a full-sized HDD on Czech marketplaces.
| Component | Name | Link |
|---|---|---|
| Motherboard | ASROCK N100DC-ITX | Alza |
| RAM | Kingston FURY 16GB DDR4 3200MHz CL16 Beast Black | Alza |
| System storage | Apacer AS2280P4 256GB | Alza |
| Data storage | Seagate IronWolf 8TB CMR | Alza |
| Case | HTPC Case MINI-ITX Fanless Chassis with 3.5" HDD Bay | AliExpress |
| Zigbee adapter | SONOFF Zigbee 3.0 USB Dongle Plus E | Alza |
Other
For displaying various sensor data, I use Waveshare 8,8" LCD
Software
The server runs Ubuntu 24.04.3 LTS with Docker — and that's it for system-level installs. Everything else runs in containers.
Smart Home Stack
- Home Assistant — integrations hub that ties everything together, exposes devices to Apple HomeKit, and provides dashboards
- Node-RED — all automations live here instead of HA's YAML, gives me a visual flow editor and much more control
- Mosquitto — MQTT broker sitting between HA and all the WiFi/Zigbee devices
- Zigbee2MQTT — bridges Zigbee devices (lights, buttons, sensors, sockets) to MQTT via a USB dongle
- ESPHome — firmware for ESP32 microcontrollers acting as switches, relays, sensors, and BLE proxies
- Shelly — off-the-shelf WiFi switches, relays, and energy meters that speak MQTT natively

Home Assistant dashboard

Apple HomeKit
Media Stack
- Jellyfin — media server for streaming movies, shows, and music to all devices
- Radarr — monitors and manages the movie library
- Sonarr — same as Radarr but for TV shows
- Bazarr — automatically fetches subtitles for everything in Radarr/Sonarr
- Prowlarr — indexer manager that feeds search results to Radarr and Sonarr
- FlareSolverr — bypasses Cloudflare protection on indexer sites for Prowlarr
- Deluge — grabs media files and puts them into the library

Radarr

Jellyfin
Infra Stack
- Portainer — web UI for managing all Docker containers, stacks, and volumes across the server
- Display — custom UI application that connects to Home Assistant via WebSocket and serves data displayed on a living room screen (temperatures, weather forecast, plant statuses, etc.)
Docker Compose
The entire stack in a single compose file:
services:
mosquitto:
image: eclipse-mosquitto
restart: unless-stopped
container_name: mosquitto
volumes:
- ./data/mosquitto:/mosquitto/data
- ./mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf
ports:
- 1883:1883
zigbee2mqtt:
container_name: zigbee2mqtt
image: koenkk/zigbee2mqtt:latest
volumes:
- ./data/z2m:/app/data
- /run/udev:/run/udev:ro
devices:
- /dev/serial/by-id/usb-ITEAD_SONOFF_Zigbee_3.0_USB_Dongle_Plus_V2:/dev/ttycinka
restart: unless-stopped
ports:
- 8080:8080
privileged: true
logging:
options:
max-size: "10m"
max-file: "3"
environment:
- TZ=Europe/Amsterdam
node-red:
container_name: node-red
image: nodered/node-red:latest
restart: unless-stopped
ports:
- 1880:1880
environment:
- TZ=Europe/Amsterdam
volumes:
- ./data/nodered:/data
homeassistant:
container_name: homeassistant
image: ghcr.io/home-assistant/home-assistant:stable
volumes:
- ./data/hass:/config
environment:
- TZ=Europe/Amsterdam
restart: unless-stopped
network_mode: host
logging:
options:
max-size: "10m"
max-file: "3"
jellyfin:
image: jellyfin/jellyfin
container_name: jellyfin
ports:
- 8096:8096
volumes:
- ./jellyfin/config:/config
- ./jellyfin/cache:/cache
- type: bind
source: /mnt/media/data/media
target: /media
read_only: true
restart: unless-stopped
display:
image: ghcr.io/dodvarko/display:0.8
restart: unless-stopped
container_name: display
network_mode: host
volumes:
- ./data/plants:/mounted/plants
radarr:
container_name: radarr
image: ghcr.io/hotio/radarr:latest
restart: unless-stopped
logging:
driver: json-file
ports:
- 7878:7878
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Amsterdam
volumes:
- /etc/localtime:/etc/localtime:ro
- ./radarr:/config
- /mnt/media/data:/data
sonarr:
container_name: sonarr
image: ghcr.io/hotio/sonarr:latest
restart: unless-stopped
logging:
driver: json-file
ports:
- 8989:8989
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Amsterdam
volumes:
- /etc/localtime:/etc/localtime:ro
- ./sonarr:/config
- /mnt/media/data:/data
bazarr:
container_name: bazarr
image: ghcr.io/hotio/bazarr:latest
restart: unless-stopped
logging:
driver: json-file
ports:
- 6767:6767
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Amsterdam
volumes:
- /etc/localtime:/etc/localtime:ro
- ./bazarr:/config
- /mnt/media/data:/data
deluge:
restart: unless-stopped
container_name: deluge
image: binhex/arch-delugevpn
ports:
- 8112:8112
- 6881:6881
- 6881:6881/udp
volumes:
- ./deluge:/config
- /mnt/media/data/grabs:/data/grabs
environment:
- PUID=1000
- PGID=1000
- VPN_ENABLED=no
prowlarr:
restart: unless-stopped
container_name: prowlarr
image: ghcr.io/hotio/prowlarr
ports:
- 9696:9696
volumes:
- ./prowlarr:/config
environment:
- PUID=1000
- PGID=1000
flaresolverr:
image: ghcr.io/flaresolverr/flaresolverr:latest
container_name: flaresolverr
restart: unless-stopped
ports:
- 8191:8191
portainer:
image: portainer/portainer-ce:latest
container_name: portainer
restart: unless-stopped
ports:
- 9000:9000
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./portainer:/data