Nocturne preview drain¶
The preview drain is in effect. The gallery writer is nocturne-gallery on
CaptainKangapoo (192.168.3.17), healthy, published on 0.0.0.0:8427.
Workers are 10, with a 12 CPU cap and a 6g memory limit. saltierpoop's
nocturne-gallery is exited with restart=no. Leave that as the
required state while the PC is the writer.
Why this shape¶
The gallery process is the worker pool. The share .env still has
GALLERY_WORKERS=4 and GALLERY_CPUS=4.0. The PC override sets
GALLERY_WORKERS=10, cpus: "12.0", and mem_limit: 6g, and those
win. There is no separate worker to send away. Ten single-thread
ffmpeg jobs under a 4 CPU cap would not drain faster. Docker on this
PC sees 32 CPUs and about 46 GiB, so the container cap is 12: enough
for the ten workers plus uvicorn, with the rest left for the OS and
Docker. The image's worker_count() clamps the env at 8. The Prawns
share is read-only, so the override bind-mounts
/home/someone/nocturne-drain-library.py over /app/library.py with
that ceiling raised to 10. At 4 workers the container was using about
1.5 GiB of a 2g limit, mostly file cache (anonymous memory was under
500 MB). 6g covers ten ffmpeg jobs without an oversized limit.
CaptainKangapoo (192.168.3.17) is off prox. The personal VLAN can
mount 192.168.6.215:/volume9/Prawns over NFSv4. The PC has no SSH and
no Docker API (SMB, RDP, and Ollama only), so the PC steps below are
run on that machine, not from infra-services.
Public route¶
This drain's public route is the PC via /opt/traefik/nocturne.yml on
saltierpoop, with Authentik in front. The service URL is
http://192.168.3.17:8427 (it was http://nocturne-gallery:8427). TLS
and the Host rule are unchanged. Websecure middlewares include
authentik@docker after cloudflarewarp@docker, plus the previous
header middlewares. https://nocturne.realemail.app returns 302 to
Authentik when the browser has no session.
Authenticated sessions reach the gallery. Uvicorn trusts
X-Forwarded-Proto only from the TCP peer in FORWARDED_ALLOW_IPS.
The share .env still has GALLERY_TRUSTED_PROXIES=172.19.0.0/16
(the saltbox bridge). On the PC, Docker publishes 8427 through the
bridge gateway 172.20.0.1, so Traefik's X-Forwarded-Proto: https
was ignored, the app treated the request as HTTP, and it returned
308 to https://nocturne.realemail.app/ (the same URL). Traefik added
x-content-type-options and x-robots-tag on the way out.
cloudflarewarp does not rewrite the scheme for non-Cloudflare LAN
clients. The drain override sets FORWARDED_ALLOW_IPS to
172.19.0.0/16,172.20.0.0/16,192.168.6.0/24. A trusted
X-Forwarded-Proto: https then returns 200 from the app. A direct
HTTP request with no forwarded proto still 308s.
The route depends on UniFi policy 10011 (Saltierpoop -> CaptainKangapoo
4 Nocturne). It allows 192.168.6.243 → 192.168.3.17 TCP 8427, with
the port on the destination, the same shape as policy 10007. Rule 30012
is only the derived established/related return. Block inter-VLAN is
40000. Leave policy 10011 in place while the PC might run the gallery
again. Do not delete it on move-back, and do not add other firewall
edits for this drain.
Do not¶
- Do not edit
gallery/compose.yamlon the Prawns share. It joins the externalsaltboxnetwork, which exists only on saltierpoop. - Do not put
/opt/nocturne-galleryon NFS. The catalog is SQLite and the gallery requires that state on local disk. - Do not run two containers. Two writers corrupt
/data. - Do not start saltierpoop
nocturne-gallerywhile the PC container is the writer. Required state on saltierpoop until step 7: exited,restart=no. - Do not point Traefik at
http://nocturne-gallery:8427before that container exists. Do not leave the service URL onhttp://192.168.3.17:8427after the saltierpoop container is the writer. - Do not stop the saltierpoop container until the PC has the library mounted and a local directory ready for the state copy.
Layout¶
| Piece | Where |
|---|---|
| Compose and image source | /mnt/local/Media/Prawn/4. Reddit/_reddit-explorer/gallery on the Prawns NFS share |
| State on saltierpoop | /opt/nocturne-gallery (idle while the PC is the writer) |
| State on the PC | /home/someone/nocturne-gallery in WSL Ubuntu |
| Library on the PC | NFSv4, read-only, at /mnt/prawns |
| Publish | 0.0.0.0:8427 on the PC. saltierpoop's container is exited |
| Public route | /opt/traefik/nocturne.yml → http://192.168.3.17:8427, Authentik, UniFi policy 10011 |
| PC override | nocturne-drain.compose.yaml |
| Worker ceiling | /home/someone/nocturne-drain-library.py bind-mounted over /app/library.py |
The override drops saltbox, publishes 8427 on all PC interfaces,
sets 10 workers, a 12 CPU cap, and a 6g memory limit, bind-mounts the
local library.py that raises the image ceiling from 8 to 10, and sets
FORWARDED_ALLOW_IPS so Uvicorn trusts the PC docker gateway
(172.20.0.1) plus 192.168.6.0/24 and the old saltbox range.
Drain¶
Steps 1–6 are already done. Do not repeat them while the PC is the writer. Step 7 is the move back.
- On CaptainKangapoo, mount the Prawns library with NFSv4, for example
192.168.6.215:/volume9/Prawns. Confirmgallery/compose.yamlis visible. If the mount fails, stop. Leave saltierpoop running. - On the PC, create a local state directory, not a path on the NFS
mount. The live copy is
/home/someone/nocturne-galleryin WSL Ubuntu. - On saltierpoop, stop
nocturne-galleryand setrestart=no. That is the CPU win. The public URL stays on the PC only after/opt/traefik/nocturne.ymlpoints athttp://192.168.3.17:8427and UniFi policy 10011 allows TCP 8427 to that host. - Copy
/opt/nocturne-galleryto the PC local directory (rsync -a). One side only. Do not start the saltierpoop container again while the PC copy is the writer. - On the PC, from the gallery directory on the share, with
GALLERY_STATE_ROOTset to that local directory andGALLERY_MEDIA_ROOTset to the read-only Reddit library (/mnt/prawns):
Do not load the saltierpoop .env bind address (GALLERY_BIND=192.168.6.243).
The override replaces the published port.
6. Keep the PC awake until previews catch up. Sleep pauses the queue
the same way a CPU cap would.
7. Move the writer back to saltierpoop. One writer the whole time, and
Traefik stays on the PC address until the saltierpoop container
exists. Do not point the file at http://nocturne-gallery:8427
while that container is down, and do not leave it on
http://192.168.3.17:8427 after the name-based service is up.
Leave UniFi policy 10011 in place.
- Stop the PC container. Do not start saltierpoop yet.
rsync -a/home/someone/nocturne-galleryback to/opt/nocturne-galleryon saltierpoop. One side only.- Start
nocturne-galleryon saltierpoop and set its restart policy tounless-stopped. Traefik is still aimed at the stopped PC, so this start is not a second writer. - Set the Traefik service URL in
/opt/traefik/nocturne.ymlback tohttp://nocturne-gallery:8427. Leave TLS, the Host rule, and the middlewares (includingauthentik@dockeraftercloudflarewarp@docker) as they are. The file provider watches that file, so the 502 window between the container start and the reload is short.
Checked 2026-10-09¶
- Writer: CaptainKangapoo
192.168.3.17, containernocturne-gallery, healthy, published0.0.0.0:8427. State is/home/someone/nocturne-galleryin WSL Ubuntu. The NFS library is read-only at/mnt/prawns.GALLERY_WORKERS=10, NanoCpus12000000000(12 CPUs), memory limit 6g.http://127.0.0.1:8427/healthreturns ok, andworker_count()is 10. - saltierpoop
nocturne-galleryis exited withrestart=no. /opt/traefik/nocturne.ymlserveshttp://192.168.3.17:8427. Unauthenticatedhttps://nocturne.realemail.appreturns 302 to Authentik. The PC override trusts172.20.0.0/16(docker gateway peer172.20.0.1), so a forwardedhttpsproto is 200 from uvicorn instead of a 308 to the same URL.- UniFi policy 10011 allows
192.168.6.243→192.168.3.17TCP 8427 (port on the destination). Rule 30012 is the derived established/related return. Block inter-VLAN is 40000. - Prawns export allows
192.168.3.0/24. An NFSv4 mount from192.168.3.37succeeded. NFSv3 from the same host was reset. - From the lab,
192.168.3.17answered SMB, RDP, and Ollama. Port 22 and the Docker API were closed, so the container was started on the PC, not over SSH from infra-services.