π§± Home Server Chronicles: My Docker-Powered Ecosystem β Part 1
An in-depth look at the journey of building a modular, containerized home server using Docker Compose on a Beelink SER8 mini PC.
Words
934
Read Time
5 min read
Category
General
Recent articles you open here will appear in this quick history.
π‘ Welcome to My Home Lab
This is Part 1 of an ongoing series where I document my self-hosted infrastructure journeyβsetting up, securing, and scaling an efficient and modular Docker ecosystem on my home server. Iβll take you through the choices I made, services I run, and challenges I solved.
For context: I'm running this system on a π₯οΈ Beelink SER8 mini PC, equipped with:
- AMD Ryzen 7 8745HS
- 12GB DDR5 RAM
- 1TB NVMe SSD (boot + Docker)
- 3.6TB NVMe SSD (media & Immich storage)
- 932GB External SSD (backups & overflow)
- Ubuntu 24.04 LTS
This machine replaced my Mac mini for Docker workloads and now acts as the heart of my home cloud, developer platform, and AI lab.
Additionally, I maintain a backup VPS on Oracle Cloud Infrastructure (OCI) that serves as an off-site backup location and disaster recovery solution. I migrated from Digital Ocean to OCI for better performance and cost efficiency β see my migration post for details.
π¦ Why Docker?
I chose Docker for the following reasons:
- π§± Isolation: Each service runs in its own container
- π Reproducibility: No more βit works on my machineβ issues
- π Portability: Move the stack between devices
- π Declarative Configuration: All setup lives in
docker-composefiles
π§ Design Principles
My goal was to keep things modular, composable, and resilient. Hereβs what that looked like:
- πΉ Split Compose files into roles:
core.yml,media.yml,infra.yml,extras.yml,immich.yml - πΉ Avoid monolithic configurations
- πΉ Use external networks defined in a central
networks.yml - πΉ Enable restart policies and volume mapping for persistence
- πΉ Log and monitor every service via Netdata
Each service is deployed headlessly, accessed either via browser, REST APIs, or reverse proxy.
ποΈ Overview of the Series
| Part | Title | |------|-------| | 1οΈβ£ | Intro & Architecture (you are here) | | 2οΈβ£ | Core Services: Nginx Proxy Manager, Authentik, Tailscale | | 3οΈβ£ | Infra Layer: Portainer, Netdata, Watchtower, Backups | | 4οΈβ£ | Media Stack: Jellyfin, Sonarr, Radarr, Lidarr, Navidrome | | 5οΈβ£ | Productivity & Photos: Nextcloud, Immich, Paperless-NGX, Vaultwarden |
Letβs begin with the big pictureβhow itβs all wired together.
π§± Architecture
Here's a birdβs eye view of my setup:
+-----------------------+
| Beelink SER8 (Host) |
+-----------------------+
|
+------------------------+-------------------------+
| | |
Docker Compose External Access VPN Tunnel
(core.yml + others) (NPM, Authentik) (Tailscale)
|
+--------------+---------------------+------------------+
| | | |
Core Stack Media Stack Productivity AI & Tools
(NPM, Auth, (Jellyfin, Sonarr, (Nextcloud, Immich, (Open WebUI,
MariaDB) Radarr, Lidarr) Paperless-NGX) PodcastAI)
Every service belongs to a category and communicates through pre-defined Docker networks, with networks.yml acting as the shared config.
π Backup & Disaster Recovery: My setup includes an Oracle Cloud (OCI) VPS that serves as an off-site backup location, running the portfolio and critical services with data redundancy and quick recovery in case of hardware failure.
π Modularity with Compose
β File Structure
docker_services/
βββ core.yml
βββ infra.yml
βββ media.yml
βββ extras.yml
βββ immich.yml
βββ networks.yml
βββ .env
π§© Why Split Files?
This modular split helps in:
- β Running specific layers independently
- β Upgrading only what you need
- β Easier debugging and configuration
- β Clear separation of concern
I also prefix volumes and container names per file to avoid naming conflicts.
π Networks & Naming
Defined in networks.yml:
networks:
proxy_net:
name: proxy_net
driver: bridge
attachable: true
ipam:
config:
- subnet: 172.28.0.0/24
gateway: 172.28.0.1
core_net:
name: core_net
driver: bridge
internal: true # Isolates DBs from direct internet access
media_net:
name: media_net
driver: bridge
infra_net:
name: infra_net
driver: bridge
extras_net:
name: extras_net
driver: bridge
Services declare these external networks in their own files. This ensures containers are interoperable across layers without duplicating definitions.
π Secrets and Security
Security is critical. Even a home server should have strong hygiene:
- π
.envfiles store secrets (never committed) - π Authentik SSO + Nginx Proxy Manager enable 2FA and domain routing
- π Tailscale manages zero-config VPN with ACLs
All admin UIs are hidden behind TOTP authentication or VPN entry.
π§ Reverse Proxy Flow
The reverse proxy stack routes requests like this:
User β https://service.jay739.dev
β³ Nginx Proxy Manager
β³ Authentik (SSO/2FA if protected)
β³ Internal Docker container
Each app is accessible via a subdomain thanks to NPM + wildcard DNS setup via Porkbun DDNS, with local DNS resolution handled by dnsmasq pointing to the LAN IP (10.0.0.101).
π Monitoring & Maintenance
Every containerβs health is tracked using Netdata, running on a dedicated infra container and exposed via:
π https://metrics.jay739.dev
I also have a custom Telegram bot for real-time alerting on service health β covered in a separate post.
π§° Core Tools Installed on Host
Even though most things run in Docker, I have some native tools:
- π
tailscaleβ for remote access - π³
docker,docker-composeβ core engine - π¦
fail2banβ SSH brute force protection - π
rsync,cronβ automated local backups - π
htop,btopβ system resource monitoring
π Whatβs Next?
In the next part of this series, Iβll walk you through the Core Services stack in detail: reverse proxy, domain mapping, VPN access, and 2FA gateways.
Stay tuned, and feel free to reach out if you want to replicate this setup or have questions on customizing your own server stack! π¬
π Part 2 β Core Services (Nginx Proxy Manager, Authentik, Tailscale)
β Jayakrishna
Follow This Topic
Keep exploring through related builds and skill areas connected to this post.
Related Projects