Demo — what's runnable today
Use
127.0.0.1, notlocalhost. Many distros'/etc/hostsmaplocalhostto both127.0.0.1and::1. Most browsers/curl try IPv6 first; the engine container's port publish is IPv4-only in some podman configs and the connection times out / TLS handshake fails.127.0.0.1always works.
This is the honest version of the demo. Three things you can actually do; two things that work but need one more wiring step; the rest is documented in tasks.md.
The hardest part is already done
A DOSBox-X DOS prompt rendered in your browser. Real keyboard input. ~1280×800 desktop area inside KasmVNC's noVNC-style client. It's running in a Linux container; KasmVNC serves the JS client, the X server runs Xvnc, DOSBox-X is an X client. That's the "engine" tier of the architecture, in full.
Run the standalone engine demo (no Nextcloud needed)
docker build -t ash-nazg-dosbox-x:demo \
-f engines/dosbox-x/Dockerfile engines/dosbox-x/
docker run -d --name engine-demo \
--security-opt label=disable \
-p 16901:8444 \
ash-nazg-dosbox-x:demo
# Wait 12 s
sleep 12
# Browser
xdg-open 'https://127.0.0.1:16901/vnc.html' 2>/dev/null \
|| echo 'Browse to https://127.0.0.1:16901/vnc.html'
- Accept the self-signed cert
- Login: demo / ash_nazg
- Click Connect. DOSBox-X DOS prompt appears.
To run a real DOS binary, mount it and set FILE_PATH:
docker run -d --name engine-demo \
--security-opt label=disable \
-p 16901:8444 \
-v "$(pwd)/keen1.exe:/programs/keen1.exe:ro,z" \
-e FILE_PATH=/programs/keen1.exe \
ash-nazg-dosbox-x:demo
Stop: docker rm -f engine-demo.
Run the full stack (Nextcloud + ExApp + engine)
# Workarounds for rootless podman; no-ops on Docker rootful
chmod 0666 /run/user/$(id -u)/podman/podman.sock
# (one-time per host) allow insecure local registry
mkdir -p ~/.config/containers
cat > ~/.config/containers/registries.conf <<'EOF'
[[registry]]
location = "127.0.0.1:5000"
insecure = true
EOF
docker compose -f scripts/local-nextcloud-stack.yml up -d
./scripts/bootstrap-nextcloud.sh # registers ash_nazg as an ExApp
# enable (the occ enable hangs sometimes; fall back to direct DB)
docker exec scripts_nextcloud_1 php -r "
\$p = new PDO('pgsql:host=postgres;dbname=nextcloud','nextcloud','nextcloud-local-dev');
\$p->exec(\"UPDATE oc_ex_apps SET enabled = 1 WHERE appid = 'ash_nazg'\");
"
docker exec scripts_valkey_1 valkey-cli FLUSHDB
docker compose -f scripts/local-nextcloud-stack.yml restart nextcloud
What you can now visit:
| URL | What you see | Credentials |
|---|---|---|
http://localhost:8088 |
Nextcloud login | admin / admin-local-dev |
http://localhost:8088/index.php/settings/apps |
Apps list — Ash Nazg shown as installed | admin |
https://127.0.0.1:16901/vnc.html |
DOSBox-X DOS prompt | demo / ash_nazg |
Tear down: docker compose -f scripts/local-nextcloud-stack.yml down -v.
What works today, end-to-end
- NC 32 + AppAPI 5.x + HaRP spins up reproducibly.
- ash_nazg ExApp registers via
app_api:app:registerwith ourinfo.xml, gets pulled from the local registry, spawned by HaRP, attached to the compose network, and reportsenabled: True / status.error: ''. oc_ex_apps_routespopulated with 6 PUBLIC/USER/ADMIN routes — the AppAPI route-allowlist mechanism works as designed.- DOSBox-X engine container runs (KasmVNC + Xvnc + dosbox-x); the noVNC web client serves on port 8444 inside / 16901 outside.
- Browser sees DOSBox-X at
https://127.0.0.1:16901/vnc.html.
What works "almost" — one wiring step short
-
Right-click → Run with Ash Nazg in Files. The
frontend/src/files-action.tsbundle is built and would openhttps://127.0.0.1:16901/vnc.htmlin a new tab when itsexecruns. But NC doesn't automatically loadhost/static/js/files-action-*.jsinto the Files-app HTML — that needs an entry ininfo.xmlunder<external-app><scripts>plus a corresponding row inoc_ex_ui_files_actions. Not yet added. The next step for the integrated demo is wiring AppAPI's script-injection mechanism (a few lines ininfo.xml). -
AppAPI proxy URL. Visiting
http://localhost:8088/index.php/apps/app_api/proxy/ash_nazg/...fromcurl -u admin:...still 404s. The path itself is plumbed (NC routes it to AppAPI's proxy controller); the issue is auth — Caddy may be stripping theAuthorizationheader, or AppAPI's proxy might require a session cookie instead of basic auth. Browser-based access (with a real logged-in session) hasn't been tested yet. Probably 30 min of debugging away.
What's deferred to later changes
- Per-Run engine spawn via HaRP (current demo runs one
always-on engine). The host shim's
/rundispatcher that asks HaRP to spawn a fresh engine per session is wire-dosbox- engine §5. - WebDAV mount of user Files inside the engine container.
Currently
FILE_PATHis a bind-mount or unset. The proper davfs2 mount lands in §7. - AppAPI websocket proxy so the KasmVNC stream renders in
an iframe inside NC's chrome (instead of a new browser tab).
That's the
streaming-proxychange — a separate proposal afterwire-dosbox-engine.
Security note
This demo runs KasmVNC with no VNC-protocol auth (-SecurityTypes
None) and a self-signed cert. The HTTP-layer login (demo/
ash_nazg) is the only gate. Don't ship this configuration.
Production replaces it with per-session tokens issued by the
host shim and routed through AppAPI's HaRP proxy.