Remote build appliance
Production Windows+WSL2 box for interactive nornir-build with shared NAS mounts
and a co-located MQTT dashboard. Keep this role separate from the programmer Dev
Container (run-cursor-dev.ps1) and the Cursor AI worker (start-cursor-worker.ps1).
Quickstart: new production box
One-time (4 steps)
Prerequisites: Docker Desktop + WSL2, CIFS module on WSL (
modprobe cifs/ modules-load), NVIDIA driver if GPU, Git.Clone the monorepo with submodules (scripts/compose only — images come from GHCR).
Initialize once (layout + pull + dashboard):
.\nornir-docker\Initialize-NornirBuildAppliance.ps1 # prompts for monorepo root; Enter accepts parent of nornir-docker # or: -MonorepoRoot D:\src\git\nornir # On auth failure: docker login ghcr.io -u <github-user> (PAT with read:packages)
Edit site-specific files only:
<ROOT>\Run\nornir-net-mounts\net-mounts\nas-mounts.tsv<ROOT>\Run\nornir-net-mounts\secrets\net-creds\*.credUNC/WSL host paths in
.run.nornir-net-mounts.envwhen needed
Every session (1 step):
& "$env:NORNIR_DOCKER_USER_ROOT\Builds\nornir-build\start-nornir-build.ps1"
# GPU probe picks nornir:cupy vs nornir:prod; path-B CIFS; interactive shell
To refresh images later without re-running initialize:
.\nornir-docker\docker-pull.ps1 -IncludeDashboard -ContinueOnError
# or pin to monorepo VERSION: -PreferVersioned
Dashboard UI: http://127.0.0.1:8087 — see Build dashboard (co-located).
Environment variables
Host variables and the shared run-env file configure layout, GHCR, NAS mounts, and
MQTT. start-nornir-build.ps1 loads
<ROOT>\Run\nornir-net-mounts\.run.nornir-net-mounts.env when present (template:
nornir-docker/example.nornir-net-mounts.run.env). Dashboard-only keys live in
Run\nornir-dashboard\dashboard.run.env (see Build dashboard (co-located)).
Host / run-env (set before launch or in ``.run.nornir-net-mounts.env``)
Variable |
Expected value |
|---|---|
|
Machine-local Docker root for Builds / Run / mounted-configs. Default
|
|
GHCR namespace for pull/push ( |
|
Host directory that contains |
|
Host directory of per-share |
|
MQTT broker hostname as seen from the build container. Appliance default
|
|
MQTT port. Default |
|
|
|
|
|
Soft/hard |
|
Optional extra |
Inside the appliance container
Variable |
Expected value |
|---|---|
|
|
|
Path to the mount table inside the container. Default
|
|
Read-only credentials dir. Default |
|
Passed through from the host so |
|
Optional root for persistent Nornir session logs (unified logging convention). Not required for mounts; set if you want file logs under a known host-visible path. |
Open file limits
Production, cursor-dev, and cursor-worker containers ship with nofile 65536 (Compose ulimits or docker run --ulimit). Heavy tile assembly on CIFS can exhaust the default 1024 limit. After starting a container, confirm with ulimit -n.
Roles (do not collapse)
Role |
Image / stack |
Launcher |
|---|---|---|
Programmer |
|
|
Cursor AI |
|
|
Build appliance (GPU) |
|
|
Build appliance (CPU) |
|
|
nornir:dev-cursor-base is a shared base layer, not the AI image. Use
-Image nornir:dev-cursor-base -Clone on the appliance only when you need live
git packages in /workspace.
Verify checklist
Inside the appliance shell:
echo "$NORNIR_NET_MOUNTS" # expect 1
findmnt -t cifs
# expect shares from nas-mounts.tsv (e.g. /storage4)
# CAP_SYS_ADMIN should be dropped after entry when setpriv/capsh are present
Interactive shells print a short welcome with nornir-build usage and list
entry wrappers in ~/scripts (on PATH): TEMImport, TEMBuild,
TEMBuild-import, TEMAlign. Bind-mounted workspace trees refresh
those scripts from nornir-buildmanager/scripts on container start
(extension stripped for the TEM* entry points).
On the host: open http://127.0.0.1:8087 for the dashboard.
Troubleshooting
Symptom |
Likely cause |
|---|---|
Missing |
Run initializer; edit site files |
|
Caps/override missing (path B not applied) |
|
|
|
Bad/missing |
No GPU / wrong image |
|
Dashboard unreachable |
|
Maintainer publish (build machine)
Not part of the operator checklist:
.\nornir-docker\docker-build.ps1
.\nornir-docker\docker-push.ps1 -IncludeDashboard