Overview
A self-hosted infrastructure running on a Raspberry Pi 4 (8GB) that serves as my personal DevOps sandbox. The entire stack uses production-grade patterns: GitOps for deployments, Cloudflare Zero Trust for secure external access, and automated monitoring with alerting.
This project is a living experiment — every pattern I apply at work (ArgoCD, Helm, GitOps) gets field-tested here first, without a safety net.
Stack at a Glance
┌─────────────────────────────────────────────────────┐
│ Raspberry Pi 4 · 8GB RAM · 256GB SSD (USB 3.0) │
│ │
│ Cloudflare Tunnel ──▶ Traefik ──▶ Services │
│ (reverse proxy + TLS) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Portainer │ │ Gitea │ │ Uptime │ │
│ │(Docker UI)│ │(Git+CI/CD)│ │ Kuma │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Nextcloud │ │Vault- │ │Watch- │ │
│ │(files) │ │warden │ │tower │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────┘
Key Design Decisions
Cloudflare Tunnel over open ports — No port forwarding in the router, no exposed IP, DDoS protection by default, and free TLS certificates for all subdomains.
Traefik with Docker label-based routing — Adding a new service to the platform is a one-liner in the docker-compose. Traefik auto-discovers it through Docker socket.
Gitea Actions for CI/CD — Self-hosted runners, no GitHub Actions minutes burned. The same YAML syntax, so skills transfer directly to professional contexts.
CI/CD Pipeline Example
# .gitea/workflows/deploy.yml
name: Deploy Service
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t ${{ secrets.REGISTRY }}/my-service:${{ github.sha }} .
- name: SSH deploy
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.PI_HOST }}
username: ${{ secrets.PI_USER }}
key: ${{ secrets.SSH_KEY }}
script: |
docker pull ${{ secrets.REGISTRY }}/my-service:latest
docker compose -f /opt/services/my-service/compose.yml up -d
docker image prune -f
What This Teaches That Production Doesn’t
Running your own infra forces you to care about things that managed services abstract away: SD card wear levels, log rotation preventing disk fill, unattended-upgrades without breaking running containers, and the real cost of not having a health check on a slow-starting service.
Read the full technical write-up → homelab-raspberry-pi-devops