fix(docker): address external review of the all-in-one image (#1042)
Seven findings, all verified against the code before applying.
- The built-in backup system wrote nowhere. Migrations 029/030 seed
/backup/picpeak and /backup/database as destinations, and this image neither
created nor mounted /backup — so backups failed, and anything written there
would have died with the container. /backup is now a symlink into
/data/backup, so the seeded defaults work and the archives land on the volume
like everything else.
- Database backups need the sqlite3 CLI. DatabaseBackupService spawns it for
.backup and PRAGMA integrity_check; the npm module does not provide the
binary. The compose image omits it because it always runs Postgres — this one
defaults to SQLite, so it failed with ENOENT. Added.
- Every AIO install served literal ${BRAND_TITLE}. index.html carries
placeholders that frontend/docker-entrypoint.sh substitutes at start, and
this image runs no nginx and never invoked it. Rendered at build with the
same defaults that entrypoint applies, and the build now fails if any
${BRAND_*} token survives. Browser testing missed this because the SPA
rewrites document.title at runtime — the og:/twitter: cards and view-source
still showed the raw token.
- The SPA fallback swallowed backend file-route 404s. nginx gives /api,
/photos, /thumbnails and /health their own location blocks, so try_files
never applies to them; excluding only /api/ made the fallback strictly
broader than the behaviour it claimed parity with, turning a missing photo
into a 200 HTML body under an image URL. Now excludes the same set.
- Docs claimed DB_* alone switches the engine. It does not: the image declares
DATABASE_CLIENT=sqlite3 and the resolver treats a declared client as
explicit, so DATABASE_CLIENT=pg is required. Corrected, and /data/backup
added to the documented layout.
- The AIO Trivy upload reused the backend's SARIF category, so the two scans
replaced each other's results instead of both being retained.
- The AIO build reused the backend's buildx cache scope, so two concurrent jobs
wrote the same cache object from different Dockerfiles.
Verified on a rebuilt image: sqlite3 3.53.2 present, <title>PicPeak</title>,
/backup -> /data/backup with both seeded subdirectories, /photos + /thumbnails
+ /api back to 404 while /setup /impressum /gallery/x /admin/login stay 200.
This commit is contained in:
@@ -62,6 +62,7 @@ Everything that must survive a container replacement lives under `/data`:
|
||||
| `/data/db` | `picpeak.db` (+ `-wal`/`-shm`) and `SETUP_TOKEN` |
|
||||
| `/data/storage` | originals, thumbnails, archives |
|
||||
| `/data/logs` | application logs |
|
||||
| `/data/backup` | built-in backup output (`/backup` is symlinked here) |
|
||||
|
||||
One mount point is the whole point. Back up `/data` and you have backed up the
|
||||
install.
|
||||
@@ -80,7 +81,8 @@ Only `JWT_SECRET` is required. Everything else has a working default.
|
||||
| `PORT` | `3000` | Listen port inside the container. |
|
||||
| `FRONTEND_URL` | — | Public URL. Set it once you are behind a domain, so emails and share links point at the right host. |
|
||||
| `SMTP_*` | — | Outbound email. Without it, PicPeak runs fine but sends nothing. |
|
||||
| `DB_HOST`, `DB_USER`, `DB_PASSWORD`, `DB_NAME` | — | Point at an **external** PostgreSQL. Setting these switches the engine off SQLite. |
|
||||
| `DATABASE_CLIENT` | `sqlite3` | Set to `pg` to use an external PostgreSQL. Required — the image declares `sqlite3`, and the boot resolver treats a declared client as an explicit instruction, so `DB_*` alone will **not** switch engines. |
|
||||
| `DB_HOST`, `DB_USER`, `DB_PASSWORD`, `DB_NAME` | — | Connection details, used when `DATABASE_CLIENT=pg`. |
|
||||
|
||||
### Using an external PostgreSQL
|
||||
|
||||
|
||||
Reference in New Issue
Block a user