Files
Art-gallery/infra/docker/DEPLOY-truenas.md
T
Danila KhodjaefandCursor 2edf577faf Add dev/prod environments with TrueNAS Docker production deploy.
Split PostgreSQL into gallery_dev and gallery_prod, add Docker/Gitea deploy tooling,
SMB image sync, pgAdmin split script, dev:web on Keenetic :5173, and operator docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 15:15:19 +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).

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 C:\Users\SNAP\Nextcloud\Personal\Repo\Gallery

docker login gitea.mysuperlab.netcraze.pro

npm run docker:publish

Push only (already built): npm run docker:publish: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 C:\Users\SNAP\Nextcloud\Personal\Repo\Gallery

npm run images:sync-to-prod

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 docker:publish

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

Troubleshooting

| Issue | Fix |

|-------|-----|

| manifest unknown | Run npm run 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 images:sync-to-prod; 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 |