The demo runs permanently as systemd services behind Caddy + Cloudflare.
Cloudflare (TLS, orange cloud)
│
▼
Caddy ledgerfactor.unitynodes.com (CF Origin cert *.unitynodes.com)
│
├── /api/* ─────▶ lf-server :8080 (Node gateway + AI scoring)
│ │
│ ▼
│ lf-jsonapi :7575 (Daml JSON Ledger API)
│ │
│ ▼
│ lf-sandbox :6865 (Canton sandbox, in-memory)
│
└── /* ─────▶ /var/www/ledgerfactor (static SPA build)
Three units in /etc/systemd/system/ (sources in scripts/systemd/), all
User=claude, Restart=always, enabled on boot. The chain is ordered and
cascades: lf-jsonapi and lf-server are PartOf / Requires their
dependency, so restarting lf-sandbox restarts the whole chain.
systemctl status lf-sandbox lf-jsonapi lf-server
journalctl -u lf-server -f # follow gateway logs
sudo systemctl restart lf-sandbox # cascades to json-api + serverThe Canton sandbox is in-memory, so every (re)start yields a fresh ledger. The server bootstrap is idempotent: it reuses existing parties and only seeds the demo scene when the ledger is empty, so a crash/restart never duplicates data.
Appended block in /etc/caddy/Caddyfile (backup at
Caddyfile.bak-before-ledgerfactor):
ledgerfactor.unitynodes.com {
encode gzip zstd
tls /etc/ssl/cf-origin-unitynodes.pem /etc/ssl/cf-origin-unitynodes-key.pem
handle /api/* { reverse_proxy localhost:8080 }
handle {
root * /var/www/ledgerfactor
try_files {path} /index.html
file_server
}
}
Reload after edits: sudo caddy validate --config /etc/caddy/Caddyfile && sudo systemctl reload caddy.
One record, proxied like the other subdomains:
A ledgerfactor <origin-ip> (Proxied 🟠)
# frontend
cd web && npm run build && sudo cp -r dist/. /var/www/ledgerfactor/
# backend / daml
daml build && sudo systemctl restart lf-sandbox # cascades + re-seeds