diff --git a/DEPLOY.md b/DEPLOY.md new file mode 100644 index 0000000..9227ab6 --- /dev/null +++ b/DEPLOY.md @@ -0,0 +1,82 @@ +# Deploy runbook — librenotes + +Derived from [`netcup/DEPLOY-TEMPLATE.md`](https://git.librete.ch/libretech/netcup/src/branch/main/DEPLOY-TEMPLATE.md). +Section ordering and headings stable across stacks. + +## 1. Target + +| Field | Value | +|-------|-------| +| Vhost | `ln.cloud.librete.ch` | +| Server path | `/srv/librenotes/` | +| Repo | `git.librete.ch/public/librenotes` | +| Image source | `${LIBRENOTES_IMAGE}` from `git.librete.ch/public/librenotes` (registry image, no source build on remote) | +| Cert | edge caddy via INWX DNS-01 | +| Edge net container name | `librenotes` (matches `caddy/Caddyfile` reverse_proxy target on `:8080`) | + +## 2. Required env / secrets + +`/srv/librenotes/.env` (gitignored, mode 0600): + +| Variable | Notes | +|----------|-------| +| `LIBRENOTES_IMAGE` | published tag, e.g. `git.librete.ch/public/librenotes:v0.1.0` | +| `LIBRENOTES_BASE_URL` | `https://ln.cloud.librete.ch` | +| `LIBRENOTES_JWT_SECRET` | `openssl rand -base64 48` | +| `LIBRENOTES_SMTP_HOST`, `..._PORT`, `..._USER`, `..._PASS`, `..._FROM` | outbound mail (uberspace per `netcup/.env`) | + +## 3. First-time deploy + +```sh +ssh netcup 'docker network ls | grep -q edge || docker network create edge' +ssh netcup 'mkdir -p /srv && cd /srv && git clone ssh://tengo@git.librete.ch:41240/public/librenotes.git' +scp librenotes/.env netcup:/srv/librenotes/.env +ssh netcup 'chmod 600 /srv/librenotes/.env' +ssh netcup 'cd /srv/librenotes && docker compose -f compose.yaml -f compose.netcup.yaml pull && docker compose -f compose.yaml -f compose.netcup.yaml up -d' +``` + +## 4. Update deploy + +```sh +n-deploy librenotes +# Bump LIBRENOTES_IMAGE in /srv/librenotes/.env then: +ssh netcup 'cd /srv/librenotes && docker compose -f compose.yaml -f compose.netcup.yaml pull && docker compose -f compose.yaml -f compose.netcup.yaml up -d' +``` + +## 5. Smoke / health + +```sh +n-ping ln.cloud.librete.ch +n-cert ln.cloud.librete.ch +n-svcs librenotes +n-logs librenotes librenotes --tail=200 +``` + +UI smoke: signup magic-link email arrives, login succeeds, note creation persists. + +## 6. Logs + troubleshooting + +| Symptom | First check | +|---------|-------------| +| 502 from edge | container off `edge` net or down | +| SMTP failure | `LIBRENOTES_SMTP_*` correct; firewall to uberspace | +| State loss | bind-mount `./state:/var/lib/librenotes` permissions | + +## 7. Rollback + +```sh +# Edit LIBRENOTES_IMAGE to prior tag in /srv/librenotes/.env, then: +ssh netcup 'cd /srv/librenotes && docker compose -f compose.yaml -f compose.netcup.yaml pull && docker compose -f compose.yaml -f compose.netcup.yaml up -d' +``` + +## 8. Stack-specific notes + +- **Bind mounts** `./data:/data` (notes payload) and `./state:/var/lib/librenotes` (DB/state) — back up both. +- Multi-tenant by base URL — single image instance per tenant config. +- Image is published from `public/librenotes` CI; never builds on remote. + +## 9. Issue tracking + +- Deploy issues: `git.librete.ch/public/librenotes/issues` +- Cross-stack: `libretech/netcup` +- After every deploy: append to `netcup/deployments.md`. diff --git a/README.md b/README.md index b9c3b6c..4ec2cc5 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ Cloud-native, multi-tenant notes application. A fork of authentication, per-user data isolation, sync, and PWA support so it can run as a hosted service at [librenot.es](https://librenot.es). +> **Deploy / operate on netcup:** see [DEPLOY.md](DEPLOY.md) (canonical netcup runbook). + ## Features - Markdown notes with bi-directional links (Zettelkasten / evergreen notes)