# carloselugo.com — Docker Stack Self-hosted infrastructure running on a single server, reverse-proxied by Caddy with automatic HTTPS. ## Services | Service | URL | Description | |---|---|---| | Frontend | [carloselugo.com](https://carloselugo.com) | Personal site — Vite + nginx (multi-stage build) | | Uptime Kuma | [uptime.carloselugo.com](https://uptime.carloselugo.com) | Uptime monitoring | | Netdata | [metrics.carloselugo.com](https://metrics.carloselugo.com) | System metrics | | ntfy | [ntfy.carloselugo.com](https://ntfy.carloselugo.com) | Push notifications | | Dozzle | [logs.carloselugo.com](https://logs.carloselugo.com) | Container log viewer | | Gitea | [git.carloselugo.com](https://git.carloselugo.com) | Self-hosted Git | | Fotos | [fotos.carloselugo.com](https://fotos.carloselugo.com) | Event photo upload → Google Drive (OAuth2, admin panel at `/admin`) | > uptime, metrics, and logs are restricted to whitelisted IPs + basic auth. ## Structure ``` /opt/web/ ├── Caddyfile # Reverse proxy config (TLS, routing, auth) ├── docker-compose.yml # All services ├── frontend/ # Personal site source │ ├── Dockerfile │ ├── src/ │ └── nginx.conf ├── ntfy/ │ └── config/ │ └── server.yml └── dozzle/ └── data/ ``` ## Stack - **Reverse proxy** — Caddy 2 (automatic HTTPS via Let's Encrypt, HTTP/3) - **Frontend** — Vite build → nginx:alpine - **Git** — Gitea (SQLite, SSH on port 2222) - **Monitoring** — Netdata (host metrics) + Uptime Kuma (endpoint checks) - **Notifications** — ntfy (push to mobile, auth-protected) - **Logs** — Dozzle ## Usage ```bash # Start all services docker compose up -d # Start a single service docker compose up -d gitea # View logs docker compose logs -f caddy # Reload Caddy config without downtime docker exec caddy caddy reload --config /etc/caddy/Caddyfile ``` ## Git workflow Push to this repo from the server: ```bash git remote add origin ssh://git@localhost:2222/carlitosbond/web.git git push ``` From an external machine (port 2222 must be open in firewall): ```bash git remote add origin ssh://git@git.carloselugo.com:2222/carlitosbond/web.git git push ``` ## Notes - Umami analytics is disabled (commented out in `docker-compose.yml`) — uncomment to re-enable. - Netdata is pinned to CPUs 0–1 with low CPU priority to avoid impacting other workloads. - ntfy denies all access by default — users must be created with `ntfy user add`. - The `fotos` service reads its secrets from `/opt/web/.env` (compose-level, gitignored) — `DRIVE_FOLDER_ID`, `ADMIN_PASSWORD`, `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, `GOOGLE_OAUTH_REFRESH_TOKEN`, `OAUTH_REDIRECT_URI`. The live refresh token is persisted separately in `photo-upload/token.json` (bind-mounted, gitignored, overwrites the bootstrap `.env` value once regenerated from `/admin`). The OAuth client in Google Cloud Console must have `OAUTH_REDIRECT_URI`'s exact value registered under Authorized redirect URIs, and — while the app is in Testing publishing status — the signing-in Google account must be added under Audience → Test users, or Google blocks the callback.