# Deployment — redeploy to `cochi` Production host for the Ulicraft stack. | | | |---|---| | Host | `cochi` (SSH alias) | | Path | `/home/ubuntu/mc/ulicraft-server-v1` | | Branch | `main` | | Compose | single `docker-compose.yml` (no overrides) | | Auth | Drasl (password login) | | Ingress | host nginx (Let's Encrypt TLS) → caddy → services (see 15-letsencrypt.md) | | Restart | **hard** (`compose down` → `compose up --build`) — brief full downtime | ## Routine redeploy ```bash ssh cochi cd /home/ubuntu/mc/ulicraft-server-v1 git pull --ff-only tooling/render-config.sh # re-render drasl/nmsr/pack configs from .env docker compose down --remove-orphans docker compose up -d --build ``` Or as a one-shot from your workstation: ```bash ssh cochi 'set -e cd /home/ubuntu/mc/ulicraft-server-v1 git pull --ff-only tooling/render-config.sh docker compose down --remove-orphans docker compose up -d --build' ``` `render-config.sh` re-renders configs (and `render-pack.sh` for the packwiz pack) from `.env` before the stack comes back up. ### Landing rebuild (not part of `compose`) The landing site (incl. `/register`) is static `www/`, gitignored — a `git pull` does **not** update it. Rebuild on the host whenever `landing/` changed or you toggled `REGISTRATION_MODE` (it bakes the invite-field on/off at build, and Drasl's `RequireInvite` is derived from the same key by `render-config.sh`): ```bash ( cd landing && set -a && . ../.env && set +a && pnpm run build ) # → www/ docker compose restart drasl # apply CORS / RateLimit / RequireInvite ``` `down`/`up` is not needed for a landing-only or flag-only change — rebuild `www/` and restart `drasl`. ## 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 - `kuma_data` — Uptime Kuma config/history - `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`, `RCON_PASSWORD`, `CADDY_HTTP_PORT`, `CADDY_HTTP_BIND`, `DISTRIBUTION_WEB_ROOT`, `REGISTRATION_MODE` (`invite`|`open`, defaults `invite`), and the Let's Encrypt block (`render-config.sh` halts on an unset `BASE_DOMAIN` or an invalid `REGISTRATION_MODE`). - Docker + compose plugin, `packwiz`, `envsubst`, `git`. - Host nginx + Let's Encrypt certs installed once — see `15-letsencrypt.md`. - **First deploy only** — online prep (build landing, fetch launcher, fetch authlib into `runtime/`). Not needed for routine redeploys. ## Verify ```bash docker compose ps # caddy, drasl, minecraft, mc-backup, nmsr, uptime-kuma up docker compose logs -f minecraft # watch for "Done" curl -fsS "https://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 down --remove-orphans docker compose up -d --build ``` ## Notes - Production needs internet on `cochi` at restart: the server installs/re-syncs NeoForge + mods over the network. - All ingress goes through host nginx → caddy. After a redeploy, nginx config is unchanged; only re-run `tooling/render-nginx.sh --install` if `BASE_DOMAIN` / `CADDY_HTTP_PORT` changed (see `15-letsencrypt.md`).