ProjectActive
Project Homenet
A continuously evolving self-hosted home infrastructure project focused on learning and applying networking, security, virtualization, automation and service operations in a real environment.
It started as a way to run a few services myself instead of relying entirely on external platforms, and has grown into a structured environment rather than a loose collection of containers: network segmentation, dedicated infrastructure roles, controlled ingress, separate storage, monitoring and automated deployment, all being built out deliberately.
I add services incrementally, when there's a real use for them — not to grow a service count.
Problem
I wanted an environment where I could run real services, experiment safely, and get hands-on experience with infrastructure that's hard to learn from an isolated lab:
- hosting useful services for myself
- keeping trusted devices, public-facing workloads, IoT, management and storage traffic apart from each other
- exposing only what needs to be exposed
- making deployments repeatable instead of hand-editing a production server
Architecture
The environment runs on Proxmox virtualization, with separate virtual machines or containers for different infrastructure roles rather than one general-purpose box. The network is segmented by trust and function instead of a single flat LAN — separate zones for trusted clients, public-facing services, private services, IoT devices, management, lab workloads and storage.
A dedicated NGINX reverse proxy is the ingress layer for web applications: public traffic reaches it first and is forwarded only to the intended internal service. It runs separately from the application workloads themselves, so a containerized application can be replaced or redeployed without touching the ingress host. Storage is likewise kept separate from compute, with a NAS handling persistent data and media.
The service layer on top of that base grows incrementally, only when there's a real use for something — this site's own deployment path is one example already running (see Engineering decisions below). Game hosting, media services, document management, photo management, monitoring, DNS filtering and printing are areas I'm actively working on or still only planning; not all of them are live yet.
Technologies
- Proxmox VE
- Debian / Linux
- Docker
- NGINX
- UniFi networking
- VLANs
- Cloudflare
- GitHub Actions
- GitHub Container Registry
- NAS (separate storage tier)
- SSH
- systemd
Engineering decisions
- Segment the network by trust and workload role instead of using a flat LAN.
- Rationale
Reduces unnecessary reachability between devices and makes security boundaries explicit — public services, private applications, IoT devices, management interfaces and storage don't need the same level of access. I considered a flat network for simplicity, but rejected it: it would make experimentation easier early on at the cost of the isolation properties I specifically wanted to learn and operate.
- Use a dedicated reverse proxy instead of exposing each application directly.
- Rationale
Gives public web services one ingress point and separates external traffic handling from the hosts running applications, so deploying an application doesn't require touching the ingress system. I chose NGINX over Caddy because I wanted direct experience with a technology that's also relevant to professional web and security infrastructure.
- Keep deployment infrastructure separate from application infrastructure.
- Rationale
For sandgruben.ch, the build and test pipeline runs on external CI, while the production deployment is initiated from inside the environment itself rather than from the outside. That keeps production access and the deployment credential inside the network. I considered having the external CI provider connect inward to deploy, but rejected it — that would require an inbound path into the environment and storing a highly privileged deployment credential with a third party.
- Deploy immutable application images by digest instead of modifying a live application in place.
- Rationale
The exact container image tested in CI is the one that reaches production — a content digest identifies that specific immutable image, rather than a mutable tag like `latest`. Deployment verifies a candidate container first, then activates it while keeping previous images around for rollback. More controlled and reproducible than copying changed files onto a production server.
Security considerations
Security is part of the architecture here, not a layer added afterward:
- network segmentation by trust and service role
- minimizing cross-network access rather than allowing broad inter-VLAN communication
- a dedicated ingress layer for public web traffic
- keeping management interfaces separate from client and public workloads
- key-based deployment authentication instead of passwords
- keeping the production deployment key inside the homelab
- read-only registry credentials in production
- immutable deployment artifacts
- this site's own security response headers verified automatically as part of deployment
- testing deployment candidates before they're activated
This isn't a finished or perfectly hardened enterprise network — it's a continuously evolving homelab. Some controls, monitoring, documentation and service isolation are still being improved as new workloads go in, and part of the point of running it for real is finding those limitations through actual operation rather than assuming a design is correct on paper.
Challenges & lessons
- Moving from manually deployed, static applications to a repeatable container deployment model without breaking the live site.
- Lesson
Separating build, deployment, ingress and application runtime makes a migration much easier to reason about. Keeping the old application path alive while validating the new container let me migrate incrementally instead of one risky cutover.
- Container networking and firewall behavior didn't always match the intuitive host-firewall model.
- Lesson
Docker's networking rules can bypass assumptions about normal host firewall filtering. Binding published services explicitly to the intended interface and controlling access at the network boundary is safer than assuming a host firewall automatically protects every published container port.
- Automation increases the impact of credentials.
- Lesson
A deployment account that can control Docker is effectively highly privileged. Keeping deployment initiation inside the environment let the private key stay local instead of storing it in GitHub.