Files
Art-gallery/infra/docker/DEPLOY-truenas.md
Danila KhodjaefandCursor bc8369e373 Add public curator notes and U-shaped hall wall hang.
Paintings get editable curator notes with brass plates in the 3D hall, and visit order now uses the far/end wall between left and right.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-25 14:21:22 +03:00

5.5 KiB

Deploy Gallery on TrueNAS Scale

Production deployment for the Express API + built Vite SPA container. PostgreSQL stays on the host at 192.168.10.122:5432. Public URL: https://gallery.mysuperlab.netcraze.pro (Keenetic → TrueNAS :5173, protocol to device http).

Not for daily work. Develop on dev (gallery_dev, https://devgallery.mysuperlab.netcraze.pro). Use this guide when releasing to prod (~weekly): build/push image, sync data/images if needed, restart the TrueNAS app.

See also Documentation/environments.md.

Architecture

Browser (HTTPS)
    → Keenetic (KeenDNS, SSL termination)
    → gallery-web container on TrueNAS (:5173, HTTP)
    → PostgreSQL (192.168.10.122:5432) → gallery_prod
    → /mnt/BasePool/Applications/Gallery/data/images (volume)
    → SMB share Gallery → \\192.168.10.122\Gallery (image sync from dev PC)

Prerequisites

Item Notes
TrueNAS Scale 25.04+ Apps → Custom App support
PostgreSQL gallery_prod (dev: gallery_dev on same host) — split via pgAdmin script
Gitea registry gitea.mysuperlab.netcraze.pro — image danilka/gallery-web:latest pushed before deploy
SMB share Gallery at /mnt/BasePool/Applications/Gallery for images:sync-to-prod
Keenetic gallery.mysuperlab.netcraze.pro192.168.10.122:5173, protocol http, Preserve Host ON

If deploy fails with manifest unknown, the image is not in Gitea yet — complete §1 Build and push first.

1. Build and push image (dev machine)

Where: Dev PC — PowerShell as Administrator (LAN push hosts entry), Docker Desktop running

cd T:\Repo\Gallery
docker login gitea.mysuperlab.netcraze.pro
npm run prod:docker:publish

Push only (already built): npm run prod:docker:push-only

Image: gitea.mysuperlab.netcraze.pro/danilka/gallery-web:latest

Gitea registry tokens

Machine Token scope
Build PC write:package
TrueNAS pull read:package

Register on TrueNAS: Apps → Configuration → Sign in to a Docker registry — URL https://gitea.mysuperlab.netcraze.pro, username danilka (lowercase for registry).

Registry token URL fix

If docker push fails with internal HTTP token URL, set Gitea ROOT_URL to https://gitea.mysuperlab.netcraze.pro/ and restart Gitea. Full walkthrough: Drunkmeyou gitea-https-keenetic-npm-setup.md.

Offline fallback (no registry)

On dev PC: .\infra\docker\save-for-truenas.ps1 → copy gallery-web.tar via SMB Gallery share.

On TrueNAS shell: sudo bash truenas-load-image.sh /path/to/gallery-web.tar

In Custom App YAML: pull_policy: if_not_present, then redeploy.

2. Prepare TrueNAS storage

Where: TrueNAS — Shell, as root

mkdir -p /mnt/BasePool/Applications/Gallery/data/images/portraits
mkdir -p /mnt/BasePool/Applications/Gallery/data/images/paintings/thumbs
chown -R 1001:1001 /mnt/BasePool/Applications/Gallery
chmod -R u+rwX,g+rwX /mnt/BasePool/Applications/Gallery

Enable SMB share Gallery/mnt/BasePool/Applications/Gallery (for image sync from dev PC).

3. Sync images (first deploy)

Where: Dev PC — PowerShell (normal), repo root

net use \\192.168.10.122\Gallery /user:YOUR_TRUENAS_USER
cd T:\Repo\Gallery
npm run devtoprod:images

UNC destination: \\192.168.10.122\Gallery\data\images

4. Install Custom App

Where: TrueNAS — Web UI

  1. Apps → Discover Apps → Custom App
  2. Paste compose.truenas.yaml
  3. Set DB_PASSWORD (replace YOUR_POSTGRES_PASSWORD)
  4. Deploy → wait for gallery-web Running

5. Keenetic (production)

Field Value
Domain gallery.mysuperlab.netcraze.pro
Upstream 192.168.10.122:5173
Protocol to device http
Preserve Host ON

Wrong IP or https to device → 502 / 504 from Keenetic (Server: Web server).

6. Verify

Bypass Keenetic (should be instant JSON):

curl.exe -s http://192.168.10.122:5173/api/bounds

Public URL:

curl.exe -sk https://gallery.mysuperlab.netcraze.pro/api/bounds

Open https://gallery.mysuperlab.netcraze.pro/ — timeline and /images/paintings/... should load.

On TrueNAS shell: bash infra/docker/truenas-verify.sh

7. Update production

After code changes on dev PC:

npm run prod:docker:publish

Restart gallery-web on TrueNAS (or rely on pull_policy: always).

Troubleshooting

Issue Fix
manifest unknown Run npm run prod:docker:publish first; or offline truenas-load-image.sh
502 / 504 public URL Keenetic → 192.168.10.122:5173, protocol http; verify LAN curl above
Container cannot reach Postgres DB_HOST=192.168.10.122; extra_hosts in compose
Empty timeline DB_NAME=gallery_prod; run pgAdmin split if still on legacy Gallery
Missing images npm run devtoprod:images; check volume mount and chown 1001:1001
Pull 401 Gitea registry credentials on TrueNAS; read:package token
Push fails on dev PC Gitea ROOT_URL HTTPS fix; use Admin PowerShell for LAN push