diff --git a/.claude/skills/deploy/SKILL.md b/.claude/skills/deploy/SKILL.md new file mode 100644 index 0000000..1bf3255 --- /dev/null +++ b/.claude/skills/deploy/SKILL.md @@ -0,0 +1,66 @@ +--- +name: deploy +description: Redeploy the Ulicraft Minecraft stack to the production host `cochi` — git pull on main then a hard restart (compose down + build-stack.sh --up online). 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` +- Run mode: `online` → compose files `docker-compose.yml` + `docker-compose.static.yml` +- Auth: Drasl (base stack) +- 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: + ```bash + 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 + hard restart** (single SSH session, halts on any error): + ```bash + ssh cochi 'set -e + cd /home/ubuntu/mc/ulicraft-server-v1 + git pull --ff-only + docker compose -f docker-compose.yml -f docker-compose.static.yml down --remove-orphans + tooling/build-stack.sh --up online' + ``` + - `--ff-only` refuses to merge — if the pull is not a fast-forward, STOP and + report (local changes on the host need manual resolution). + - `build-stack.sh --up online` renders configs (needs `.env` complete: + `BASE_DOMAIN`, `HOST_LAN_IP`, `RCON_PASSWORD`) and runs `compose up -d`. + +3. **Verify.** + ```bash + ssh cochi 'cd /home/ubuntu/mc/ulicraft-server-v1 && docker compose -f docker-compose.yml -f docker-compose.static.yml ps' + ``` + Confirm `caddy`, `drasl`, `minecraft`, `mc-backup` are Up. Tail the minecraft + log briefly and confirm it reaches `Done` (server ready): + ```bash + ssh cochi 'cd /home/ubuntu/mc/ulicraft-server-v1 && timeout 120 docker compose -f docker-compose.yml -f docker-compose.static.yml 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. +- Volumes (`mc_data`, `drasl_state`) persist across `down`; the world is 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. +- Blessing Skin variant or `airgap` mode changes the compose file set — if the + user asks for those, follow `plan/14-deploy.md` instead of the fixed commands + above. diff --git a/plan/14-deploy.md b/plan/14-deploy.md new file mode 100644 index 0000000..008ffbe --- /dev/null +++ b/plan/14-deploy.md @@ -0,0 +1,86 @@ +# Deployment — redeploy to `cochi` + +Production host for the Ulicraft stack. + +| | | +|---|---| +| Host | `cochi` (SSH alias) | +| Path | `/home/ubuntu/mc/ulicraft-server-v1` | +| Branch | `main` | +| Run mode | `online` (compose files: `docker-compose.yml` + `docker-compose.static.yml`) | +| Auth | Drasl (base stack — no Blessing Skin override) | +| Restart | **hard** (`compose down` → `build-stack.sh --up`) — brief full downtime | + +## Routine redeploy + +```bash +ssh cochi +cd /home/ubuntu/mc/ulicraft-server-v1 +git pull --ff-only +# hard restart: tear the stack down, then bring it back up (renders configs first) +docker compose -f docker-compose.yml -f docker-compose.static.yml down --remove-orphans +tooling/build-stack.sh --up online +``` + +Or as a one-shot from your workstation: + +```bash +ssh cochi 'set -e + cd /home/ubuntu/mc/ulicraft-server-v1 + git pull --ff-only + docker compose -f docker-compose.yml -f docker-compose.static.yml down --remove-orphans + tooling/build-stack.sh --up online' +``` + +`build-stack.sh --up online` runs preflight (checks `.env`), `render-config.sh` +(which renders configs + `render-pack.sh` for the packwiz pack), then +`docker compose ... up -d` with the online file set. + +## What survives a hard restart + +Named volumes persist — world and auth data are safe: +- `mc_data` — world + installed NeoForge/mods +- `drasl_state` — Drasl accounts/skins +- `backups/` — mc-backup snapshots + +`down` removes **containers**, not volumes. Players are disconnected during the +restart (a few minutes); they reconnect once `minecraft` is healthy again. + +## Prerequisites (one-time, on `cochi`) + +- SSH access as the `cochi` alias. +- `.env` present and complete: `BASE_DOMAIN`, `HOST_LAN_IP`, `RCON_PASSWORD` + (`render-config.sh` halts on any unset var, even in online mode). +- Docker + compose plugin, `packwiz`, `envsubst`, `git`. +- **First deploy only** — heavy online prep (fetch launcher, pre-bake the server + volume, etc.): + ```bash + tooling/build-stack.sh --prep + ``` + Not needed for routine redeploys; `--up` alone re-syncs the pack and configs. + +## Verify + +```bash +docker compose -f docker-compose.yml -f docker-compose.static.yml ps +docker compose -f docker-compose.yml -f docker-compose.static.yml logs -f minecraft # watch for "Done" +curl -fsS "http://auth.$(grep '^BASE_DOMAIN=' .env | cut -d= -f2)/" >/dev/null && echo "auth ok" +``` + +## Rollback + +```bash +git log --oneline -5 # find the last-good commit +git checkout # or: git reset --hard +docker compose -f docker-compose.yml -f docker-compose.static.yml down --remove-orphans +tooling/build-stack.sh --up online +``` + +## Notes + +- **Online mode needs internet** on `cochi` at restart (no air-gap mirror): the + server installs NeoForge + mods over the network. For an internet-less deploy, + switch to `airgap` (needs `--prep` first) — see `plan/13-dns-and-run-modes.md`. +- Switching to the **Blessing Skin** auth variant changes the file set to + `-f docker-compose.yml -f docker-compose.blessingskin.yml` (see + `plan/03b-blessing-skin.md`); update the `down`/`up` commands accordingly.