Files
ulicraft-server-v1/.claude/skills/deploy/SKILL.md
Oier Bravo Urtasun 8a71709048 docs(deploy): caddy conf bind mounts are inode-pinned — recreate, not reload
Document the gotcha hit fixing distribution CORS: caddy/conf.d/*.caddy are
single-file bind mounts pinned to the host inode at container creation. git pull
rewrites tracked files via atomic rename (new inode), so a running caddy keeps
the old config; `restart`/`caddy reload` reuse the stale inode. Apply conf
changes with `docker compose up -d --force-recreate caddy` (or the --hard
down/up). Added to plan/14-deploy.md and the deploy skill guardrails.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 02:26:42 +02:00

4.2 KiB

name, description
name description
deploy Redeploy the Ulicraft Minecraft stack to the production host `cochi` — git pull on main then a hard restart (compose down + up). Use when the user says "deploy", "redeploy", "deploy to cochi", "push to prod", "ship it", or "restart the server" for this project. Causes brief Minecraft downtime.

Deploy Ulicraft to cochi

Redeploy the running stack on the production host. Full reference: plan/14-deploy.md.

Fixed parameters

  • Host: cochi (SSH alias)
  • Path: /home/ubuntu/mc/ulicraft-server-v1
  • Branch: main
  • Stack: single unified docker-compose.yml (drasl, minecraft, mc-backup, caddy, nmsr, uptime-kuma)
  • Auth: Drasl
  • Restart: hard (down → up) — players are disconnected for a few minutes

Procedure

This is an outward-facing, downtime-causing action on production. The user invoking this skill is the authorization to proceed, but:

  1. Pre-check (read-only). See what would change before tearing anything down:

    ssh cochi 'cd /home/ubuntu/mc/ulicraft-server-v1 && git fetch && git log --oneline HEAD..@{u}'
    

    Report the incoming commits. If the list is empty, tell the user the host is already up to date and ask whether to restart anyway (they may want a plain restart). If git fetch fails (host unreachable, auth), STOP and report.

  2. Pull, ensure authlib, then update-all.sh --hard (single SSH session, halts on any error):

    ssh cochi 'set -e
      cd /home/ubuntu/mc/ulicraft-server-v1
      git pull --ff-only
      tooling/fetch-authlib.sh
      ./update-all.sh --hard'
    
    • --ff-only refuses to merge — if the pull is not a fast-forward, STOP and report (local changes on the host need manual resolution).
    • fetch-authlib.sh ensures runtime/authlib-injector.jar exists (gitignored; skips if already valid; NOT part of update-all since it rarely changes). Missing jar = minecraft crashloops with "Error opening zip file or JAR manifest missing". Run it before update-all so the jar is present when compose brings minecraft up.
    • update-all.sh is the single source of truth for the post-pull build + restart steps (render drasl/nmsr configs from .env, sync server mods, regen the landing mod list, rebuild www/, then apply via docker compose). It is also runnable on its own for a lighter rolling update (no --hard = change-detected restart, no world downtime). --hard here does down --remove-orphans && up -d --build for the deliberate full restart. render-config.sh halts on an invalid REGISTRATION_MODE (must be invite or open); a missing distribution jar halts sync-server-mods.sh. The landing rebuild is unconditional (the gitignored www/ is never updated by git pull), so no separate landing step is needed.
  3. Verify.

    ssh cochi 'cd /home/ubuntu/mc/ulicraft-server-v1 && docker compose ps'
    

    Confirm caddy, drasl, minecraft, mc-backup, nmsr, uptime-kuma are Up. Tail the minecraft log briefly and confirm it reaches Done (server ready):

    ssh cochi 'cd /home/ubuntu/mc/ulicraft-server-v1 && timeout 120 docker compose logs -f minecraft' 2>/dev/null | grep -m1 "Done"
    

Guardrails

  • Never git reset --hard or discard changes on cochi without telling the user first — there may be host-local edits.
  • Caddy conf changes need a recreate, not reload/restart. If the deploy touched any caddy/conf.d/*.caddy or the Caddyfile and you did a rolling update-all.sh (not --hard), the change WON'T apply: those are single-file bind mounts pinned to the host inode, and git pull gives the file a new inode. restart/caddy reload reuse the stale inode. Run docker compose up -d --force-recreate caddy, then verify with docker compose exec caddy cat /etc/caddy/conf.d/<file>. The --hard path (full down/up) already recreates, so it's unaffected.
  • Volumes (mc_data, drasl_state, kuma_data) persist across down; the world and monitors are safe. Do NOT pass -v/--volumes to down.
  • If a step fails, STOP and surface the exact error + the failing command. Do not improvise recovery on production.