One shared login (htpasswd) for all players, writable. Config is rendered
from a template and mounted read-only, so git stays authoritative — the
admin console loads but cannot save, by design.
Filestash's OIDC/SAML middlewares are enterprise-only, so Keycloak SSO is
out; FILES_AUTH keeps htpasswd/passthrough switchable for later. Auth-off
(passthrough) is only valid once the host is off the public internet —
render-config.sh warns loudly when rendering it.
Three traps, all found by testing against the pinned image:
- the `local` backend is admin-gated: without LOCAL_BACKEND_SECRET in the
connection params every login fails with "backend error - Not Allowed"
- the htpasswd plugin only accepts $2a$ bcrypt, so a $2y$ hash from
`htpasswd -B` fails every login silently — use `openssl passwd -6`.
render-config.sh rejects the wrong format rather than shipping it
- APPLICATION_URL/ADMIN_PASSWORD env make filestash rewrite config.json at
boot, which fails on the :ro mount — both live in the rendered config
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The pack service was already gone from compose/caddy and the landing is
off packwiz. Remove the remaining live references: the pack. TLS vhost in
the host nginx template, pack from LE_SUBDOMAINS, and stale docs in README
and CLAUDE.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collapse the override-file matrix into a single docker-compose.yml holding the
whole stack: drasl, minecraft, mc-backup, caddy, nmsr, uptime-kuma. Bring-up is
now just `docker compose up -d --build`.
Removed features (dead-ends for this deployment):
- airgap / full asset mirror (mirror-airgap.sh, mirror-mods.sh, 20-mirror.caddy,
caddy local-CA export, /ca.crt)
- dnsmasq + avahi/mDNS + dns-records.sh + mdns-host-setup.sh + ENABLE_MDNS;
DNS is now handled outside this repo (HOST_LAN_IP dropped)
- Blessing Skin auth variant (compose + 00-core-blessingskin.caddy + BS_* env)
- host-nginx-static variant (docker-compose.nginx.yml, nginx/ulicraft.conf.tmpl)
- build-stack.sh and its run modes (online/airgap/core)
Production ingress is the only path now: host nginx terminates TLS (LE certs)
in front of caddy on a localhost-only port; caddy routes every vhost by Host
header. Launcher downloads move mirror/launcher -> launcher/.
Docs: README, deploy skill, and plan/ rewritten to match; obsolete plan docs
(dnsmasq, blessing-skin, assets-mirror, full-airgap-mirror, dns-and-run-modes)
deleted.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add docker-compose.status.yml (louislam/uptime-kuma) layered on the caddy
ingress, joining mcnet so it probes the stack by internal service name and
the public vhosts end-to-end. Host port bound to 127.0.0.1:3001 only; public
access via nginx -> caddy.
- caddy/conf.d/50-status.caddy: status. -> uptime-kuma:3001
- nginx caddy-front template: status. TLS vhost + websocket upgrade headers
for Kuma's live UI; status. added to the HTTP->HTTPS redirect list
- status added to LE_SUBDOMAINS defaults (.env.example, issue-letsencrypt.sh)
- README: Status monitoring section + recommended monitor list (incl. native
Minecraft-protocol ping)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add Strict-Transport-Security (max-age 1y, includeSubDomains) to every TLS
server block in both vhost templates. Combined with the existing port-80
301 redirect, browsers refuse plain HTTP to these names after first visit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add tooling/render-nginx.sh: pulls BASE_DOMAIN/CADDY_HTTP_PORT from .env,
defaults APP_DIR to the repo checkout, renders a vhost template (default the
caddy-front one) to stdout, or --install writes + symlinks + nginx -t + reloads.
Document it in the README, replacing the manual envsubst one-liner.
Also add the www.${BASE_DOMAIN} canonical 301->apex block and put www in the
LE_SUBDOMAINS default so its cert is issued.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The `http2 on;` directive needs nginx 1.25.1+; older builds reject it. Move
http2 onto the listen line (`listen 443 ssl http2;`) which works on old and
new nginx alike. Applied to both vhost templates.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Serve a static site at distribution.${BASE_DOMAIN} whose web root lives in
another repo (DISTRIBUTION_WEB_ROOT, bind-mounted read-only into caddy):
- caddy/conf.d/30-distribution.caddy file_server vhost
- docker-compose.distribution.yml mount snippet + external web root
- issue-letsencrypt.sh / .env.example add distribution to LE_SUBDOMAINS
- ulicraft-caddy.conf.tmpl TLS-front block proxying to caddy
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Make the caddy host-published port configurable (CADDY_HTTP_PORT /
CADDY_HTTP_BIND, default 0.0.0.0:80 unchanged) so the machine's own nginx
can terminate TLS and reverse-proxy to caddy on a localhost-only port.
Add nginx/ulicraft-caddy.conf.tmpl: a TLS-terminator vhost set that proxies
apex/auth/pack to caddy by Host header, letting caddy stay the single ingress
for all routing. Alternative to ulicraft.conf.tmpl (nginx-as-static + drasl
proxy). minecraft still reaches caddy internally over http via mcnet aliases.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>