# -weight: 500;">docker-compose.yml
services: postgres: image: postgres:17 -weight: 500;">restart: always volumes: - pgdata:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: ${DB_PASSWORD} ports: - "127.0.0.1:5432:5432" backup: image: prodrigestivill/postgres-backup-local volumes: - ./backups:/backups environment: POSTGRES_HOST: postgres POSTGRES_DB: myapp SCHEDULE: "@daily" BACKUP_KEEP_DAYS: 30
volumes: pgdata:
# -weight: 500;">docker-compose.yml
services: postgres: image: postgres:17 -weight: 500;">restart: always volumes: - pgdata:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: ${DB_PASSWORD} ports: - "127.0.0.1:5432:5432" backup: image: prodrigestivill/postgres-backup-local volumes: - ./backups:/backups environment: POSTGRES_HOST: postgres POSTGRES_DB: myapp SCHEDULE: "@daily" BACKUP_KEEP_DAYS: 30
volumes: pgdata:
# -weight: 500;">docker-compose.yml
services: postgres: image: postgres:17 -weight: 500;">restart: always volumes: - pgdata:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: ${DB_PASSWORD} ports: - "127.0.0.1:5432:5432" backup: image: prodrigestivill/postgres-backup-local volumes: - ./backups:/backups environment: POSTGRES_HOST: postgres POSTGRES_DB: myapp SCHEDULE: "@daily" BACKUP_KEEP_DAYS: 30
volumes: pgdata:
# Example: Authon with Docker Compose
services: authon: image: authon/server:latest environment: DATABASE_URL: postgres://authon:secret@postgres:5432/authon JWT_SECRET: ${JWT_SECRET} ports: - "127.0.0.1:3100:3100" depends_on: - postgres
# Example: Authon with Docker Compose
services: authon: image: authon/server:latest environment: DATABASE_URL: postgres://authon:secret@postgres:5432/authon JWT_SECRET: ${JWT_SECRET} ports: - "127.0.0.1:3100:3100" depends_on: - postgres
# Example: Authon with Docker Compose
services: authon: image: authon/server:latest environment: DATABASE_URL: postgres://authon:secret@postgres:5432/authon JWT_SECRET: ${JWT_SECRET} ports: - "127.0.0.1:3100:3100" depends_on: - postgres
services: umami: image: ghcr.io/umami-software/umami:postgresql-latest environment: DATABASE_URL: postgres://umami:secret@postgres:5432/umami ports: - "127.0.0.1:3000:3000" depends_on: - postgres
services: umami: image: ghcr.io/umami-software/umami:postgresql-latest environment: DATABASE_URL: postgres://umami:secret@postgres:5432/umami ports: - "127.0.0.1:3000:3000" depends_on: - postgres
services: umami: image: ghcr.io/umami-software/umami:postgresql-latest environment: DATABASE_URL: postgres://umami:secret@postgres:5432/umami ports: - "127.0.0.1:3000:3000" depends_on: - postgres
- Traefik (reverse proxy + auto SSL)
- PostgreSQL 17
- Gitea
- Umami
- Uptime Kuma
- Headscale (WireGuard mesh)
- Authon (auth for side projects)
- Miniflux (RSS reader, because I still use RSS)
- Traefik (reverse proxy + auto SSL)
- PostgreSQL 17
- Gitea
- Umami
- Uptime Kuma
- Headscale (WireGuard mesh)
- Authon (auth for side projects)
- Miniflux (RSS reader, because I still use RSS)
- Traefik (reverse proxy + auto SSL)
- PostgreSQL 17
- Gitea
- Umami
- Uptime Kuma
- Headscale (WireGuard mesh)
- Authon (auth for side projects)
- Miniflux (RSS reader, because I still use RSS) - VPS prices dropped — you can get 4 vCPU / 8GB RAM for under $20/month from providers like Hetzner, Netcup, or Oracle's free tier
- Docker Compose is mature — most self-hosted projects have a -weight: 500;">docker-compose.yml that just works
- Reverse proxy tooling is great — Traefik, Caddy, and nginx-proxy-manager make SSL and routing easy
- Backup tools are better — Restic, Borgmatic, and rclone handle backups reliably - Keycloak — enterprise-grade, Java-based, resource-heavy but feature-complete. Best for SAML/enterprise SSO.
- Authentik — Python-based, modern UI, good for identity-aware proxying. Nice if you want SSO for your self-hosted apps.
- Authon — Node-based, lighter weight, focused on developer APIs. Good if you're building a product that needs auth as an API.
- Zitadel — Go-based, good performance, built-in OIDC support. - Umami — the one I recommend most. Clean, fast, privacy-focused. 10 minutes to deploy.
- Plausible — similar to Umami, slightly more opinionated. Has a hosted option too.
- PostHog — more than analytics (feature flags, session replays), but heavier to run. - Gitea — lightweight, Go-based, fast. Closest to a "light GitHub."
- Forgejo — Gitea fork with community governance. - Automate backups from day one. Not "I'll set it up later." Day one.
- Use Docker Compose for everything. Don't -weight: 500;">install packages on the host.
- Pin image versions. postgres:17 not postgres:latest. You want predictable updates.
- Set up monitoring before you need it. Uptime Kuma takes 5 minutes. Do it.
- Keep a -weight: 500;">docker-compose.yml in version control. Your server config IS your infrastructure-as-code.
- Test your restore process. Backups are useless if you've never tested restoring from them.
- Don't self-host things your team depends on for daily work unless you're confident in your uptime.