EN

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.

A mess of Raspberry PIs and cables

Before

Clean home server with status display

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.

ComponentNameLink
MotherboardASROCK N100DC-ITXAlza
RAMKingston FURY 16GB DDR4 3200MHz CL16 Beast BlackAlza
System storageApacer AS2280P4 256GBAlza
Data storageSeagate IronWolf 8TB CMRAlza
CaseHTPC Case MINI-ITX Fanless Chassis with 3.5" HDD BayAliExpress
Zigbee adapterSONOFF Zigbee 3.0 USB Dongle Plus EAlza

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
BLEZigbeeApple HomeKitvoice & mobileNode-REDadvanced flowsCloud IntegrationsSomfy, LG, Xiaomi, ...Home Assistantintegrations hubMosquittoMQTT brokerESPHomeswitches, relays, sensorsShellyswitches, relays, energyZigbee2MQTTUSB dongle bridgeBLE Devicesplant monitorsZigbee Deviceslights, buttons, sensors, sockets
Home Assistant dashboard showing rooms, devices, weather, and media controls

Home Assistant dashboard

Apple HomeKit app showing smart home devices and rooms

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
Prowlarrindexer managerFlareSolverrCloudflare bypassRadarrmoviesSonarrTV showsBazarrsubtitlesDelugetransfer clientJellyfinmedia server
Radarr movie library management interface

Radarr

Jellyfin media server showing movie collection

Jellyfin

Infra Stack

  • Portainer — web UI for managing all Docker containers, stacks, and volumes across the server
  • Displaycustom 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