Self-Hosted Development & Infrastructure Lab
Quantifiable Outcomes
Why I Built This
I wanted to build a practical self-hosted environment that could handle real development and infrastructure workloads while giving me a deeper understanding of how the underlying technologies work.
Rather than starting with dedicated server hardware, I began with two always-on laptops, both running Linux and different OS’s depending on the system config and requirements
The goal was to gradually offload development, monitoring, backups, automation, and other infrastructure-related activities from my primary development machines while using the environment as a hands-on platform for learning and experimentation.
Architecture
The two machines remain powered and connected to Wi-Fi continuously and are accessible through a self-hosted NetBird VPN.
Docker is used as the primary application runtime, allowing the different workloads to remain isolated while making it easy to deploy, update, and remove services.
The environment hosts development environments for multiple full-stack applications, infrastructure monitoring, centralized logging, backups, automation, and various self-hosted applications.
The infrastructure uses Cloudflare and Cloudflare Tunnels to securely expose selected public services, alongside a self-hosted VPN for remote development access. The primary server hosts full-stack development environments and core infrastructure services, including PostgreSQL and Redis for data and caching, Prometheus + Grafana for monitoring, Loki for centralized logging, MinIO for backups and object storage, n8n for automation, PocketBase and Immich for application services, and various infrastructure & development tools. A second server is dedicated to smaller, lightweight internal tools and applications.
Two production applications have dedicated development environments on the server. Their frontends and backends can be deployed locally, allowing changes to be tested in an environment much closer to production before deployment.
These applications share a local Dockerized PostgreSQL database and Redis instance, reducing duplicated infrastructure and making development deployments faster.
The environment also hosts another complete full-stack application with its frontend, backend, database, and cache running entirely as Docker containers.
Development & Deployment
The server acts as a development platform for multiple applications rather than simply being a collection of self-hosted services.
- Development servers: Full-stack environments for an e-commerce platform and a rewards platform.
- Build environment: The same development infrastructure is used to build applications for production deployment.
- Shared infrastructure: PostgreSQL and Redis are shared between development workloads where appropriate.
- Rapid deployment: A custom deployment script pushes local changes to the development environment through the private VPN in under 3–5 seconds.
- Remote development: NetBird provides private network connectivity, allowing the development machines to interact with the server as if they were on the same local network.
This significantly reduces the development feedback loop. Instead of manually SSHing into the server and transferring or deploying updates over the public internet, a developer can trigger a deployment and begin testing almost immediately.
Monitoring, Logging & Backups
The server also acts as an infrastructure monitoring and observability platform for production systems.
- Monitoring: Prometheus collects metrics from 4 separate production backends, with Grafana providing visualization and dashboards.
- Logging: Loki is used to centralize logs from production applications.
- Backups: MinIO provides self-hosted object storage for encrypted backups from both production and development environments.
- Health automation: n8n is used to build and test automations such as production health checks and SSL certificate checks.
This allows the same infrastructure used for development to provide visibility into the production systems it supports.
Security & Remote Management
The infrastructure is designed around private network access rather than exposing services directly to the public internet.
- Private access: A self-hosted NetBird VPN provides persistent remote access to the machines.
- Public exposure: Cloudflare Tunnels expose only the specific development or application services that need to be reachable externally.
- Administrative access: Cockpit is exposed through a Cloudflare Tunnel protected by Cloudflare Zero Trust email verification.
- Container management: Portainer provides a web interface for managing Docker containers and images.
- File management: File Browser provides remote filesystem access.
- Network independence: The VPN allows the server to be managed remotely as though it were part of the local network.
The separate Cloudflare-protected management path is particularly useful when VPN access is unavailable, such as during certain network or connectivity failures.
Additional Self-Hosted Services
The environment also serves as a general-purpose self-hosting and experimentation platform.
- PocketBase provides a lightweight backend-as-a-service environment for a small application.
- Immich provides self-hosted image and photo storage.
- Static frontends are hosted directly from the infrastructure.
- Kubernetes practice: I use KIND (Kubernetes in Docker) to create local self-hosted Kubernetes clusters for experimenting with Kubernetes workloads and practicing ArgoCD-based GitOps deployments.
- ArgoCD experimentation: Local KIND clusters provide an isolated environment for learning ArgoCD, testing application deployments, and experimenting with Kubernetes manifests and GitOps workflows without affecting production infrastructure.
- Additional development and self-hosting projects are tested on the machines as the environment evolves.
This makes the infrastructure both a useful development platform and a sandbox for learning technologies that may eventually be used in larger environments.
Lessons Learned
- Small hardware can still be useful infrastructure: Starting with two low-powered laptops forced me to think carefully about resource usage, workload placement, and the actual requirements of each service.
- Docker makes heterogeneous workloads manageable: Containerizing most services provides isolation and makes it practical to run many unrelated applications on limited hardware.
- Fast internal deployment changes the development workflow: A sub-5-second deployment path makes development testing feel much closer to local development than traditional remote deployment workflows.
- Private networking simplifies remote infrastructure: NetBird allows the machines and development environments to behave like they are on the same private network without repeatedly exposing administrative services to the internet.
- Self-hosting exposes the entire stack: Running monitoring, logging, databases, backups, networking, deployment tooling, and applications personally provides a much deeper understanding of how the individual components interact.
- The infrastructure is intentionally evolving: Rather than designing a large platform upfront, I started with existing hardware and gradually added services as real development and learning requirements emerged.