| caddy | ||
| docker-compose-files | ||
| docs | ||
| .env.sample | ||
| .gitignore | ||
| ipfconfig | ||
| README.md | ||
| setup-homeassistant.sh | ||
| setup-node-red.sh | ||
| substitute_env.sh | ||
Homelab Docker Services
Docker Compose templates for home lab services, featuring security best practices, resource management, and comprehensive health monitoring.
🚀 Quick Start
# 1. Clone the repository
git clone https://github.com/brianpooe/homelab-blueprint.git
cd homelab-blueprint
# 2. Copy and configure environment
cp .env.sample .env
nano .env # Fill in your configuration
# 3. Generate Docker Compose files
./substitute_env.sh docker-compose-files/arr-stack/template.yaml docker-compose.arr-stack.yml
./substitute_env.sh docker-compose-files/postgres/template.yaml docker-compose.postgres.yml
./substitute_env.sh docker-compose-files/vault/template.yaml docker-compose.vault.yml
./substitute_env.sh docker-compose-files/socket-proxy/template.yaml docker-compose.beszel-proxy.yml
./substitute_env.sh docker-compose-files/beszel-agent/template.yaml docker-compose.beszel-agent.yml
./substitute_env.sh caddy/Caddyfile_template caddy/Caddyfile .env
./substitute_env.sh docker-compose-files/caddy/template.yaml docker-compose.caddy.yml .env
# 4. Deploy
docker-compose -f docker-compose.arr-stack.yml up -d
docker-compose -f docker-compose.postgres.yml up -d
docker-compose -f docker-compose.vault.yml up -d
docker-compose -f docker-compose.beszel-proxy.yml up -d
docker-compose -f docker-compose.beszel-agent.yml up -d
📦 Available Stacks
🎬 Media Stack (arr-stack/)
Complete automated media management with VPN protection and security hardening.
Services:
- Gluetun - VPN container (WireGuard/OpenVPN)
- qBittorrent - Torrent client (through VPN)
- SABnzbd - Usenet client (through VPN)
- Prowlarr - Indexer manager
- Radarr - Movie collection manager
- Sonarr - TV series collection manager
- Bazarr - Subtitle manager
- Emby - Media server
- Seerr - Request management
- FlareSolverr - Captcha solver
- Recyclarr - Quality profile sync (TRaSH Guides)
Features:
- ✅ VPN kill-switch for download clients
- ✅ Health checks and dependency management
- ✅ Resource limits to prevent system exhaustion
- ✅ Security hardening (no-new-privileges, internal networks)
📈 Monitoring Stack (socket-proxy/ + beszel-agent/)
Host-level telemetry stack for Beszel Hub with restricted Docker API access.
Services:
- Beszel Socket Proxy - Restricted Docker API proxy on localhost
- Beszel Agent - Host metrics and Docker telemetry collector
Features:
- ✅ Official Beszel agent container setup
- ✅ Restricted Docker API access via socket-proxy (instead of direct socket mount)
- ✅ Host networking for interface metrics visibility
- ✅ Persistent state volume and constrained memory limit
🗄️ Database Stack (postgres/)
PostgreSQL with pgAdmin web interface.
Services:
- PostgreSQL 17 - Alpine-based database
- pgAdmin 4 - Web-based administration
Features:
- ✅ Health-aware dependency management
- ✅ Automated backups ready
- ✅ Resource limits configured
- ✅ Persistent data volumes
🔐 Secrets Stack (vault/)
HashiCorp Vault for secrets management.
Services:
- Vault 1.19.2 - Secrets management
Features:
- ✅ Production-ready configuration
- ✅ Pinned Vault version for predictable upgrades
- ✅ IPC_LOCK capability for security
- ✅ Health monitoring
🏠 Home Automation Stack (homeassistant/)
Home Assistant with MQTT broker and Zigbee2MQTT for local smart home control.
Services:
- Home Assistant - Home automation platform
- Eclipse Mosquitto - MQTT broker (v2.x)
- Zigbee2MQTT - Zigbee coordinator bridge
Features:
- ✅ All services on a shared bridge network (container-name routing)
- ✅ SMLIGHT SLZB-06U over PoE+ (TCP socket, no USB passthrough needed)
- ✅ Mosquitto 2.x with persistence and WebSocket listener
- ✅ Zigbee2MQTT 2.x with Home Assistant MQTT discovery
- ✅ Health checks and dependency ordering
Config templates (copy and fill in before first run):
homeassistant/config/mosquitto.conf→./appdata/mqtt/config/mosquitto.confhomeassistant/config/zigbee2mqtt_configuration.yaml→./appdata/zigbee2mqtt/configuration.yamlhomeassistant/config/ha_configuration.yaml→./appdata/homeassistant/configuration.yaml(viasubstitute_env.sh— sets Caddy trusted proxy)
Caddy Reverse Proxy (caddy/)
Dedicated Raspberry Pi reverse proxy with Cloudflare DNS-01 support.
Features:
- Custom Caddy image with the Cloudflare DNS module
- 256 MB runtime limit suitable for a 1 GB Raspberry Pi
- Persistent certificate and ACME state
- DMZ deployment at
10.0.15.5
🔴 Node-RED (node-red/)
Standalone Node-RED with the Home Assistant websocket integration pre-installed. Joins the HA network so it can reach Home Assistant by container name without going through a reverse proxy.
Services:
- Node-RED - Flow-based automation editor (custom image built locally)
Features:
- ✅
node-red-contrib-home-assistant-websocketbaked into the image at build time - ✅ Joins
ha-network— reaches Home Assistant athttp://homeassistant:8123 - ✅ Credential secret substituted at setup time (not a runtime env var)
- ✅ Persistent flow and credential storage under
./appdata/node-red
First-time HA connection:
After starting the container, open http://<host>:1880, drag in any Home Assistant node, add a server config with:
- URL:
$(HA_URL) - Token:
$(HA_TOKEN)
Node-RED expands these from the container env vars at runtime. The actual token stays in .env and never gets written into your flow files — updating it only requires changing .env and restarting.
🔒 Security Features
Additional Security
- No-new-privileges on all containers
- Read-only filesystems where applicable
- Internal networks for service isolation
- Resource limits to prevent DoS
- Health checks for reliability
🗂️ Repository Structure
docker-compose-files/
arr-stack/
template.yaml # Compose template
config/
recyclarr_template.yml # Recyclarr app config template
beszel-agent/
template.yaml
caddy/
Dockerfile
README.md
template.yaml
gramps-web/
template.yaml
config/
config_template.cfg
homeassistant/
template.yaml
config/
mosquitto.conf # Mosquitto 2.x config (copy to host before first run)
zigbee2mqtt_configuration.yaml # Zigbee2MQTT config template
node-red/
template.yaml
Dockerfile # Custom image — installs HA websocket node at build time
config/
settings.js # Node-RED settings template (credentialSecret substituted by setup script)
postgres/
template.yaml
socket-proxy/
template.yaml
technitium/
README.md # Deployment and Raspberry Pi troubleshooting
template.yaml
vault/
template.yaml
Each stack lives in its own folder alongside any config files it needs. The workflow is always the same:
# 1. Generate the compose file from the template
./substitute_env.sh docker-compose-files/<stack>/template.yaml docker-compose.<stack>.yml
# 2. (If the stack has config templates) copy or substitute them into place
cp docker-compose-files/<stack>/config/<file> ./appdata/<service>/
# or substitute variables into them first
./substitute_env.sh docker-compose-files/<stack>/config/<file> ./appdata/<service>/<file>
# 3. Deploy
docker-compose -f docker-compose.<stack>.yml up -d
📋 Prerequisites
Required
- Linux host with Docker & Docker Compose installed
- SSH access enabled
- Basic knowledge of Docker and command line
Recommended
- Static IP for your host
- Domain name for reverse proxy (optional)
- VPN subscription for Gluetun (AirVPN, Mullvad, etc.)
⚙️ Configuration
1. Environment Variables
Edit .env file with your settings:
# arr-stack only
DOCKERCONFDIR=/opt/arr-stack/appdata
DOCKERSTORAGEDIR=/mnt/unas/arr-data
ARR_DATA_MARKER=.arr-stack-storage
PUID=1000
PGID=1000
LXC_IDMAP_BASE=100000
TZ=Africa/Johannesburg
# Docker Logging
DOCKERLOGGING_MAXFILE=3
DOCKERLOGGING_MAXSIZE=10m
# VPN Configuration
VPN_SERVICE_PROVIDER=airvpn
WIREGUARD_PRIVATE_KEY=your_private_key
WIREGUARD_PRESHARED_KEY=your_preshared_key
WIREGUARD_ADDRESSES=10.x.x.x/32
FIREWALL_VPN_INPUT_PORTS=12345
SERVER_COUNTRIES=Netherlands
# Beszel Socket Proxy
BESZEL_SOCKET_PROXY_IMAGE_TAG=latest
BESZEL_SOCKET_PROXY_BIND_IP=127.0.0.1
BESZEL_SOCKET_PROXY_PORT=2375
BESZEL_SOCKET_PROXY_LOG_LEVEL=info
BESZEL_SOCKET_PROXY_MEM_LIMIT=64m
# Beszel Agent
BESZEL_AGENT_KEY=<public_key_from_hub>
BESZEL_AGENT_TOKEN=<token_from_hub>
BESZEL_AGENT_HUB_URL=https://beszel.example.com
BESZEL_AGENT_LISTEN=45876
BESZEL_AGENT_IMAGE_TAG=latest
BESZEL_AGENT_MEM_LIMIT=128m
# Caddy reverse proxy template
CADDY_TLS_EMAIL=admin@example.com
CADDY_BASE_DOMAIN=home.example.com
CADDY_HOST_IP=10.0.15.5
CLOUDFLARE_DNS_TOKEN=restricted_cloudflare_api_token
CADDY_MEM_LIMIT=256m
CADDY_LAN_PREFIX=10.0.1
CADDY_IOT_PREFIX=10.0.30
CADDY_OFFICE_PREFIX=10.0.10
# DNS
DNS_BIND_IP=10.0.10.3
# Home Automation
SLZB06_HOST=10.0.30.X
# Node-RED
HA_TOKEN=your_long_lived_access_token # HA Profile → Security → Long-lived access tokens
HA_URL=http://homeassistant:8123 # optional — this is the default
NODE_RED_CREDENTIAL_SECRET= # auto-generated by setup-node-red.sh if left empty
# Database
POSTGRES_USER=postgres
POSTGRES_PASSWORD=strong_password
POSTGRES_DB=maindb
PGADMIN_EMAIL=admin@example.com
PGADMIN_PASSWORD=strong_password
Get your PUID/PGID:
id $USER
Beszel agent required values:
BESZEL_AGENT_KEY,BESZEL_AGENT_TOKEN, andBESZEL_AGENT_HUB_URLcome from Beszel Hub when adding a system.- Keep
BESZEL_AGENT_LISTEN=45876unless you intentionally changed the agent listen port in Beszel. - Keep
BESZEL_SOCKET_PROXY_BIND_IP=127.0.0.1so the Docker API is not exposed on your LAN.
2. Recyclarr Configuration
Copy and configure Recyclarr for quality profile management:
# Generate config from template
./substitute_env.sh docker-compose-files/arr-stack/config/recyclarr_template.yml /opt/arr-stack/appdata/recyclarr/recyclarr.yml
# Edit with your API keys
nano /opt/arr-stack/appdata/recyclarr/recyclarr.yml
Get API Keys:
- Sonarr: Settings → General → Security → API Key
- Radarr: Settings → General → Security → API Key
Important: Use service names (http://sonarr:8989), NOT localhost!
This repository's template uses Recyclarr v8 guide-backed profiles and is pinned to ghcr.io/recyclarr/recyclarr:8.6.0.
3. Directory Structure
For the complete UNAS NFS, Proxmox bind mount, ownership, and verification procedure, follow docs/DEPLOYMENT.md. After the storage chain is verified, create the arr-stack directories inside the LXC:
# Config directories
sudo mkdir -p /opt/arr-stack/appdata/{gluetun,qbittorrent,sabnzbd,prowlarr,radarr,sonarr,bazarr,emby,seerr,recyclarr,unpackerr}
# Shared NFS-backed storage directories
sudo -u '#1000' mkdir -p /mnt/unas/arr-data/torrents/{movies,tv}
sudo -u '#1000' mkdir -p /mnt/unas/arr-data/usenet/{incomplete,complete/{movies,tv}}
sudo -u '#1000' mkdir -p /mnt/unas/arr-data/media/{movies,tv}
sudo -u '#1000' touch /mnt/unas/arr-data/.arr-stack-storage
# Configs stay on local LXC disk
sudo chown -R 1000:1000 /opt/arr-stack
🚀 Deployment
Option 1: Deploy All Stacks
./substitute_env.sh docker-compose-files/arr-stack/template.yaml docker-compose.arr-stack.yml
./substitute_env.sh docker-compose-files/postgres/template.yaml docker-compose.postgres.yml
./substitute_env.sh docker-compose-files/vault/template.yaml docker-compose.vault.yml
./substitute_env.sh docker-compose-files/socket-proxy/template.yaml docker-compose.beszel-proxy.yml
./substitute_env.sh docker-compose-files/beszel-agent/template.yaml docker-compose.beszel-agent.yml
./substitute_env.sh docker-compose-files/homeassistant/template.yaml docker-compose.homeassistant.yml
./substitute_env.sh caddy/Caddyfile_template caddy/Caddyfile .env
./setup-node-red.sh
docker-compose -f docker-compose.arr-stack.yml up -d
docker-compose -f docker-compose.postgres.yml up -d
docker-compose -f docker-compose.vault.yml up -d
docker-compose -f docker-compose.beszel-proxy.yml up -d
docker-compose -f docker-compose.beszel-agent.yml up -d
docker-compose -f docker-compose.homeassistant.yml up -d
docker-compose -f docker-compose.node-red.yml up -d --build
Option 2: Deploy Specific Stack
# Media stack only
./substitute_env.sh docker-compose-files/arr-stack/template.yaml docker-compose.arr-stack.yml
docker-compose -f docker-compose.arr-stack.yml up -d
# Home Assistant stack only
./substitute_env.sh docker-compose-files/homeassistant/template.yaml docker-compose.homeassistant.yml
docker-compose -f docker-compose.homeassistant.yml up -d
# Node-RED only (requires HA stack to be running first)
./setup-node-red.sh
docker-compose -f docker-compose.node-red.yml up -d --build
# Verify deployment
docker ps
docker logs -f gluetun
Option 3: Deploy Individual Services
# Start only specific services
docker-compose -f docker-compose.arr-stack.yml up -d gluetun qbittorrent prowlarr radarr sonarr
🔍 Verification
Check Service Health
# View all containers
docker ps
# Check specific service logs
docker logs gluetun
# Check health status
docker inspect gluetun | grep -A 10 Health
Test VPN Connection
# Check VPN is connected
docker logs gluetun | grep "connected"
# Test qBittorrent is using VPN
docker exec qbittorrent curl ifconfig.me
# Should show VPN IP, not your real IP
📊 Resource Allocation
Total resources if all services running:
| Resource | Reserved | Limit | Notes |
|---|---|---|---|
| Memory | 4.00 GB | 15.00 GB | CPU limits are intentionally omitted |
Per-service limits configured to prevent resource exhaustion
🔧 Common Tasks
Update Containers
# Manual update
docker-compose -f docker-compose.arr-stack.yml pull
docker-compose -f docker-compose.arr-stack.yml up -d
View Logs
# Follow logs
docker logs -f radarr
# Last 100 lines
docker logs --tail 100 sonarr
# All services
docker-compose -f docker-compose.arr-stack.yml logs -f
Restart Service
# Single service
docker-compose -f docker-compose.arr-stack.yml restart radarr
# All services
docker-compose -f docker-compose.arr-stack.yml restart
Stop/Start Stack
# Stop everything
docker-compose -f docker-compose.arr-stack.yml down
# Start everything
docker-compose -f docker-compose.arr-stack.yml up -d
# Stop but keep data
docker-compose -f docker-compose.arr-stack.yml stop
📚 Documentation
Detailed Guides
- Documentation Index - Current operational documentation
- Proxmox LXC arr-stack Deployment - Command-by-command UNAS NFS, Proxmox bind mount, UID mapping, and hardlink setup
- Recyclarr Setup - Quality profile configuration
- Troubleshooting - Common issues and solutions
- Technitium Deployment - DNS/ad-block server setup
- Caddy Raspberry Pi Deployment - Docker installation and DMZ reverse-proxy setup
- UDM Pro SE Zones and VLAN Migration - UniFi custom zones, firewall policies, and DNS enforcement
- Rack Layout - Current UNAS and MikroTik rack layout
External Resources
- TRaSH Guides - File structure and quality profiles
- Servarr Wiki - Arr stack documentation
- Gluetun Wiki - VPN configuration
🛠️ Troubleshooting
Quick Diagnostics
# Check container status
docker ps -a
# Check resource usage
docker stats
# Check networks
docker network ls
docker network inspect vpn_network
# Validate compose file
docker-compose -f docker-compose.arr-stack.yml config
Common Issues
Recyclarr: "base_url must start with http"
Fix: Use service names in recyclarr.yml:
base_url: http://sonarr:8989 # ✅ Correct
base_url: http://localhost:8989 # ❌ Wrong
Recyclarr: "Unable to find include template with name ..."
Cause: Old pre-v8 recyclarr.yml still using include: - template:.
Fix: Regenerate from docker-compose-files/arr-stack/config/recyclarr_template.yml and recreate Recyclarr. See docs/RECYCLARR.md.
qBittorrent: No connection
Fix: Check Gluetun VPN is connected:
docker logs gluetun | grep -i "connected"
Full troubleshooting guide: docs/TROUBLESHOOTING.md
🎯 Best Practices
Security
- ✅ Use strong passwords in
.env - ✅ Never commit
.envto git - ✅ Regularly update containers
Performance
- ✅ Adjust resource limits based on your host specs
- ✅ Monitor with
docker stats - ✅ Use SSD for Docker volumes if possible
- ✅ Enable hardware transcoding in Emby/Jellyfin
Maintenance
- ✅ Regular backups of
/opt/arr-stack/appdata - ✅ Monitor logs for errors
- ✅ Test updates in staging before production
- ✅ Document any custom configurations
🤝 Contributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Test your changes thoroughly
- Submit a pull request
📝 License
This project is provided as-is for personal and educational use.
🙏 Credits
- TRaSH Guides - Quality profiles and best practices
- Hotio - Excellent container images
- LinuxServer.io - Container images and documentation
- Gluetun - VPN container
📧 Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Last Updated: 2026-02-14 Version: 2.1 Compatibility: Docker Compose 1.27.0+