refactor!: unify into one compose, drop airgap/mirror/dnsmasq/avahi/blessingskin

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>
This commit is contained in:
2026-06-09 02:14:09 +02:00
parent ff645de2c8
commit 67d1f82e6a
53 changed files with 522 additions and 2244 deletions

View File

@@ -1,25 +1,17 @@
# TLS — Let's Encrypt (OVH DNS-01) + host nginx ingress
Production serves real, publicly-trusted certs via the **host's nginx**. Caddy is
no longer the production ingress — it moved to its own compose file for the
LAN/air-gap path.
## Two ingress paths
| Path | Ingress | Compose | TLS |
|------|---------|---------|-----|
| Production | host **nginx** | `docker-compose.yml` + `docker-compose.nginx.yml` | Let's Encrypt (this doc) |
| LAN / air-gap | **caddy** container | `docker-compose.yml` + `docker-compose.caddy.yml` (+ static/mirror) | Caddy internal CA |
`build-stack.sh` drives the caddy path (adds `docker-compose.caddy.yml`
automatically). The nginx path is a manual deploy (below). This supersedes the
ingress part of `plan/14-deploy.md` for production.
Production serves real, publicly-trusted certs via the **host's own nginx**.
nginx terminates TLS and reverse-proxies every vhost to the caddy container
(published localhost-only on `${CADDY_HTTP_PORT}`) by Host header. caddy is the
internal router; nginx is the public TLS terminator. This is the only ingress
path — there are no compose overrides.
## Certs: one per name, via OVH DNS-01
`tooling/issue-letsencrypt.sh` issues a **separate** cert for the apex and each
subdomain (`${BASE_DOMAIN}`, `auth.…`, `pack.…`) using acme.sh + the OVH DNS-01
challenge — no inbound ports needed, so it works even on a LAN-only host.
subdomain (`${BASE_DOMAIN}`, `auth.…`, `pack.…`, plus the rest of
`LE_SUBDOMAINS`) using acme.sh + the OVH DNS-01 challenge — no inbound ports
needed, so it works regardless of public reachability.
### One-time setup
@@ -36,7 +28,7 @@ challenge — no inbound ports needed, so it works even on a LAN-only host.
### Issue
```bash
tooling/issue-letsencrypt.sh # real certs
tooling/issue-letsencrypt.sh # real certs
LE_STAGING=1 tooling/issue-letsencrypt.sh # dry run against the LE staging CA
```
@@ -46,31 +38,30 @@ the reload with `RELOAD_CMD=...` if nginx isn't systemd-managed.
## nginx
1. Stack up with the nginx override (publishes drasl on `127.0.0.1:25585`):
1. Bring the stack up (caddy publishes on `127.0.0.1:${CADDY_HTTP_PORT}`):
```bash
docker compose -f docker-compose.yml -f docker-compose.nginx.yml up -d
docker compose up -d --build
```
2. Render + install the vhost (`nginx/ulicraft.conf.tmpl`):
2. Render + install the vhost (`nginx/ulicraft-caddy.conf.tmpl`):
```bash
APP_DIR=/home/ubuntu/mc/ulicraft-server-v1 BASE_DOMAIN=ulicraft.net \
envsubst '$APP_DIR $BASE_DOMAIN' \
< nginx/ulicraft.conf.tmpl | sudo tee /etc/nginx/sites-available/ulicraft.conf
sudo ln -sf /etc/nginx/sites-available/ulicraft.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
tooling/render-nginx.sh --install
```
nginx then: apex + `pack.*` as static files (`www`, `pack`, `custom`),
`auth.*` → drasl. Ensure `www-data` can read `$APP_DIR/{www,pack,custom,certs}`.
This substitutes `$BASE_DOMAIN $APP_DIR $CADDY_HTTP_PORT`, writes to
`sites-available`, symlinks `sites-enabled`, runs `nginx -t`, and reloads
nginx. nginx then terminates TLS per vhost (certs under `$APP_DIR/certs`) and
reverse-proxies each Host to caddy on `127.0.0.1:${CADDY_HTTP_PORT}`. Ensure
`www-data` can read `$APP_DIR/certs`.
## DNS
Point the public/party DNS for `${BASE_DOMAIN}`, `auth.${BASE_DOMAIN}`,
`pack.${BASE_DOMAIN}` at the host. The Minecraft container reaches them via
`extra_hosts: host-gateway` (set in `docker-compose.nginx.yml`) and uses HTTPS —
the JVM trusts Let's Encrypt with no CA import (the big win over the internal CA).
Point the public DNS for `${BASE_DOMAIN}` and every subdomain
(`auth.` `pack.` `avatar.` `status.` `distribution.` `www.`) at the host running
nginx. DNS is configured **outside this repo**. The Minecraft container reaches
the stack's own names via caddy's `mcnet` aliases, not public DNS.
## Why DNS-01 (not HTTP-01)
`HOST_LAN_IP` shows a LAN host; HTTP-01/TLS-ALPN-01 need public inbound on 80/443.
DNS-01 only needs the OVH API, so it issues regardless of public reachability —
and `ulicraft.net` is a real OVH-managed domain, which LE requires (it never
issues for `.lan`/`.local`).
issues for `.lan`/`.local`). HTTP-01/TLS-ALPN-01 would need public inbound on
80/443. The JVM trusts the resulting Let's Encrypt certs with no CA import.