Compare commits

..
6 Commits
Author SHA1 Message Date
oierandClaude Opus 5.5 f4bd786140 chore(uptime-kuma): bump image to :2
The :1 image runs Node 18 (EOL), which gets no fix for the October 2026
Node.js security release. :2 migrates kuma.db in place on first start;
back up kuma_data per host before pulling (see plan/10-uptime-kuma.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 12:33:37 +01:00
oierandClaude Opus 5 d457713186 chore(mods): classify owo-lib as both
Dependency library declaring side=BOTH; keep server-side so any
server-loaded dependent doesn't crash on a missing lib.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CAvxmMjspjDw7Fkkmy86EN
2026-09-12 17:00:04 +02:00
oierandClaude Opus 5 556f86f852 chore(mods): classify 2 new distribution jars as both
craftabletotemofundying (recipe addition) and friendsforlife (pet QoL)
both declare side=BOTH and need server-side loading. Pack now 192 jars,
160 server-side.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CAvxmMjspjDw7Fkkmy86EN
2026-09-12 16:50:39 +02:00
oierandClaude Opus 5 6b9b8bd96c chore(mods): bump sodium + supplementaries jar names
Distribution updated sodium 0.8.12-alpha.4 → 0.8.13 and
supplementaries 3.5.26 → 3.7.7. Rename the mods-sides.json keys so
sync-server-mods.sh doesn't halt on the missing old jars.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E6PydPB5dvyQ7wxrzS7JvQ
2026-09-06 15:41:04 +02:00
oierandClaude Opus 5 fe91bf7778 chore(mods): resync mods-sides.json with 2026-09-06 distribution
The distro release dropped craftingstation and added create_jet_boots +
flightapi, but mods-sides.json still listed craftingstation as `both`.
sync-server-mods.sh halts on a selected jar missing from the source, so
update-all.sh would have failed — and under --hard that lands after
`docker compose down`, leaving the stack down.

classify-mods.py also picked up sawmill and supplementaries, which had no
entry at all and were therefore never synced to the server. All four new
entries default to `both`.

mods-sides.json entries now 190 = jars in distribution 190.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Wz4tizJzjivT4FhdsqAMb
2026-09-06 15:05:52 +02:00
oierandClaude Opus 5 0176a674e3 fix(tls): absolutise CERT_DIR so cron renewals actually install
acme.sh persists the --install-cert paths and replays them on every cron
renewal, where cwd is $HOME rather than the repo. The relative default
resolved to ~/certs/... so renewals wrote nothing: acme.sh kept renewing
cleanly while nginx served the stale copy until it expired. Apex, auth. and
pack. served expired certs on 2026-09-06.

Absolutise CERT_DIR in issue-letsencrypt.sh and document the failure mode,
the recovery command, and off-host verification in plan/15-letsencrypt.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018UJzZrBaZUoU6qHMLpLz64
2026-09-06 00:36:23 +02:00
5 changed files with 66 additions and 6 deletions

No files matched your search

+1 -1
View File
@@ -376,7 +376,7 @@ services:
# Status monitoring + public status page. caddy proxies status. -> :3001.
# Joins mcnet so monitors probe the stack by internal service name.
uptime-kuma:
image: louislam/uptime-kuma:1
image: louislam/uptime-kuma:2
container_name: uptime-kuma
restart: unless-stopped
volumes:
+8 -2
View File
@@ -74,12 +74,13 @@
"coroutil-neoforge-1.21.0-1.3.9.jar": "both",
"corpse-neoforge-1.21.1-1.1.13.jar": "both",
"corpsecurioscompat-1.21.1-NeoForge-4.0.1.jar": "both",
"craftingstation-neoforge-1.21.1-5.jar": "both",
"craftabletotemofundying-1.21.1-0.1.jar": "both",
"create-1.21.1-6.0.10.jar": "both",
"create-central-kitchen-2.5.0.jar": "both",
"create-enchantment-industry-2.4.1.jar": "both",
"create-integrated-farming-1.2.6.jar": "both",
"create_connected-1.2.2-mc1.21.1.jar": "both",
"create_jet_boots-1.21.1-1.1.3-6.0.6.jar": "both",
"create_jetpack-forge-5.1.2.jar": "both",
"create_jetpack_curios-1.2.0-neoforge-1.21.1.jar": "both",
"create_mechanical_chicken-1.21.1-1.3.3-6.0.6.jar": "both",
@@ -111,6 +112,8 @@
"fastleafdecay-35.jar": "both",
"ferritecore-7.0.3-neoforge.jar": "both",
"fishingoverhaul-1.21.1-1.2.1.jar": "both",
"flightapi-neoforge-1.1.1.jar": "both",
"friendsforlife-1.2.1.jar": "both",
"ftb-chunks-neoforge-2101.1.17.jar": "both",
"ftb-essentials-neoforge-2101.1.9.jar": "both",
"ftb-library-neoforge-2101.1.33.jar": "both",
@@ -148,6 +151,7 @@
"moonlight-neoforge-1.21.1-3.0.22.jar": "both",
"morefunctionalstorage-1.2.3.jar": "both",
"moreoverlays-1.24.2-mc1.21.1-neoforge.jar": "client",
"owo-lib-neoforge-0.12.15.5-beta.1+1.21.jar": "both",
"polymorph-neoforge-1.1.0+1.21.1.jar": "both",
"ponderjs-neoforge-1.21.1-2.4.0.jar": "client",
"rechiseled-1.2.5-neoforge-mc1.21.jar": "both",
@@ -155,12 +159,13 @@
"resourcefullib-neoforge-1.21-3.0.12.jar": "both",
"rhino-2101.2.7-build.85.jar": "both",
"rightclickharvest-neoforge-4.6.1+1.21.1.jar": "both",
"sawmill-1.21-1.7.2-neoforge.jar": "both",
"seamless-loading-screen-2.2.1+1.21-neoforge.jar": "client",
"simplemagnets-1.1.12c-neoforge-mc1.21.jar": "both",
"sliceanddice-forge-4.2.4.jar": "both",
"smartfeedingtroughs-neoforge-1.21.1-1.2.0.jar": "both",
"sodium-extra-neoforge-0.8.7+mc1.21.1.jar": "client",
"sodium-neoforge-0.8.12-alpha.4+mc1.21.1.jar": "client",
"sodium-neoforge-0.8.13+mc1.21.1.jar": "client",
"solcarrot-1.21.1-1.16.6.jar": "both",
"sophisticatedbackpacks-1.21.1-3.25.55.1852.jar": "both",
"sophisticatedbackpackscreateintegration-1.21.1-0.1.6.99.jar": "both",
@@ -171,6 +176,7 @@
"stattweaks-neoforge-v2.0.0.jar": "both",
"supermartijn642configlib-1.1.8-neoforge-mc1.21.jar": "both",
"supermartijn642corelib-1.1.21-neoforge-mc1.21.jar": "both",
"supplementaries-neoforge-1.21.1-3.7.7.jar": "both",
"tagtooltips-neoforge-1.21.1-1.2.0.jar": "client",
"titanium-1.21-4.0.43.jar": "both",
"toolsjs-0.1.1.jar": "both",
+8 -2
View File
@@ -5,13 +5,13 @@
> card. Both ping `minecraft` over `mcnet` but serve different purposes.
Status monitoring + public status page. Service `uptime-kuma`
(`louislam/uptime-kuma:1`), web UI on `:3001`, reached only through caddy at
(`louislam/uptime-kuma:2`), web UI on `:3001`, reached only through caddy at
`https://status.${BASE_DOMAIN}`. Joined to `mcnet`, so it can probe every other
service by its internal container name.
## Add a Minecraft monitor
Uptime Kuma 1.x ships a built-in **Minecraft Server** monitor type. It uses the
Uptime Kuma ships a built-in **Minecraft Server** monitor type. It uses the
Server List Ping protocol (the same ping the vanilla multiplayer list uses):
unauthenticated, so it works fine with `ONLINE_MODE=FALSE` /
`ENFORCE_SECURE_PROFILE=FALSE`. It reports latency, online/max players, and MOTD.
@@ -53,6 +53,12 @@ monitor stays green. Run both to tell *server down* apart from *path broken*.
`https://auth.${BASE_DOMAIN}`, `https://distribution.${BASE_DOMAIN}`,
`https://${BASE_DOMAIN}`, `https://files.${BASE_DOMAIN}` — a red
`distribution.` here explains client mod-mismatch join failures.
- **1 → 2 upgrade (2026-10-25)** — moved off `:1`, whose image runs Node 18
(EOL, no fix for the Oct 2026 Node CVEs). The first `:2` start migrates
`kuma.db` in place (one-way, minutes on a ~140M DB; status page down until it
finishes — don't interrupt). Per host: `docker compose stop uptime-kuma`, tar
the `kuma_data` volume into `./backups/`, then `pull` + `up -d uptime-kuma`.
Rollback = restore the tarball + revert the tag to `:1`.
> **An HTTP monitor cannot see an SPA break.** It asserts "the server returned
> 200", which is a much weaker claim than "the app works". `files.` (Filestash)
+43
View File
@@ -36,6 +36,49 @@ Certs install to `certs/<name>/{cert.pem,key.pem}` (gitignored). acme.sh adds a
cron for renewal; `--reloadcmd` reloads nginx automatically on renew. Override
the reload with `RELOAD_CMD=...` if nginx isn't systemd-managed.
### Gotcha — install paths must be ABSOLUTE (silent expiry, 2026-09-06)
`--install-cert` paths are **persisted in acme.sh's domain conf**
(`~/.acme.sh/<name>_ecc/<name>.conf` → `Le_RealKeyPath` /
`Le_RealFullChainPath`) and replayed on every cron renewal. The cron runs with
`cwd=$HOME`, not the repo — so a **relative** path (`certs/<name>/key.pem`)
resolves to `~/certs/...` and the install writes nothing.
Failure mode is silent and delayed: `acme.sh --list` shows every cert freshly
renewed with a future `Renew` date, `~/.acme.sh/<name>_ecc/fullchain.cer` is
valid — while `certs/<name>/cert.pem` is frozen at the last **manual** run and
nginx serves that until it expires. There is no error anywhere. Cost: apex,
`auth.` and `pack.` served expired certs on 2026-09-06.
Fix / recovery — re-run `--install-cert` with absolute paths, which both copies
the current cert and rewrites the persisted paths:
```bash
APP=/home/ubuntu/mc/ulicraft-server-v1
for d in $(ls $APP/certs); do
~/.acme.sh/acme.sh --install-cert -d "$d" --ecc \
--key-file "$APP/certs/$d/key.pem" \
--fullchain-file "$APP/certs/$d/cert.pem" \
--reloadcmd "sudo systemctl reload nginx || true"
done
```
`issue-letsencrypt.sh` now absolutises `CERT_DIR` so a fresh issue can't
reintroduce it.
**Verify from off-host, not from the files** — the installed file and what nginx
serves are the same thing here, but the acme.sh copy is not:
```bash
for h in ulicraft.net auth.ulicraft.net avatar.ulicraft.net status.ulicraft.net \
distribution.ulicraft.net files.ulicraft.net upload.ulicraft.net \
monitor.ulicraft.net generators.ulicraft.net; do
printf '%-30s ' "$h"
echo | openssl s_client -servername $h -connect $h:443 2>/dev/null \
| openssl x509 -noout -enddate
done
```
## nginx
1. Bring the stack up (caddy publishes on `127.0.0.1:${CADDY_HTTP_PORT}`):
+6 -1
View File
@@ -52,7 +52,12 @@ ACME="${ACME_SH:-$HOME/.acme.sh/acme.sh}"
curl https://get.acme.sh | sh -s email=${LE_EMAIL}
then re-run (or set ACME_SH=/path/to/acme.sh)."
CERT_DIR="${CERT_DIR:-certs}"
# MUST be absolute: acme.sh persists these paths in its domain conf and replays
# them on every cron renewal, where cwd is $HOME, not the repo. A relative path
# there makes the renewal install silently write nothing -- acme.sh keeps renewing
# happily while nginx serves the stale (eventually expired) copy. Bit us 2026-09-06.
CERT_DIR="${CERT_DIR:-$PWD/certs}"
case "$CERT_DIR" in /*) ;; *) CERT_DIR="$PWD/$CERT_DIR" ;; esac
read -r -a SUBDOMAINS <<< "${LE_SUBDOMAINS:-auth pack distribution www avatar status}"
if [ "${LE_STAGING:-0}" = "1" ]; then