# 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.

## 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`, and the Let's Encrypt block
  (`render-config.sh` halts on an unset `BASE_DOMAIN`).
- 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 <sha>              # or: git reset --hard <sha>
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`).
