Add fotos.carloselugo.com photo-upload service

Event photo upload app with OAuth2 (Google Drive), Caddy route, and
env-var-driven compose config. Refresh token persists to token.json
so re-auth isn't needed after container restarts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-22 23:24:00 +00:00
co-authored by Claude Sonnet 5
parent 0b6dcb037e
commit 6ee4022d21
13 changed files with 1364 additions and 0 deletions
+2
View File
@@ -12,6 +12,7 @@ Self-hosted infrastructure running on a single server, reverse-proxied by Caddy
| 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.
@@ -78,3 +79,4 @@ git push
- 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.