compose.netcup.yaml no longer builds locally; pulls ${LIBRENOTES_IMAGE} (default git.librete.ch/public/librenotes:main).
.gitea/workflows/deploy.yml builds + pushes to ${REGISTRY}/public/librenotes (main → :main + :<sha7>; tag → :vX.Y.Z + :latest), then SSHes to the deploy host and reruns compose. Tag pushes pin LIBRENOTES_IMAGE in the host .env via perl -i.
Both workflow jobs (and ci.yml) run inside catthehacker/ubuntu:runner-latest because the default node:20-bookworm runner image lacks make and a docker CLI. The build job bind-mounts /var/run/docker.sock; the runner repo's config.yaml whitelists that path under valid_volumes.
A main push will only run anything once DEPLOY_ENABLED=true; the workflow is safe to merge before secrets are set.
Closes #39.
## Summary
- `compose.netcup.yaml` no longer builds locally; pulls `${LIBRENOTES_IMAGE}` (default `git.librete.ch/public/librenotes:main`).
- `.gitea/workflows/deploy.yml` builds + pushes to `${REGISTRY}/public/librenotes` (main → `:main` + `:<sha7>`; tag → `:vX.Y.Z` + `:latest`), then SSHes to the deploy host and reruns compose. Tag pushes pin `LIBRENOTES_IMAGE` in the host `.env` via `perl -i`.
- Both workflow jobs (and `ci.yml`) run inside `catthehacker/ubuntu:runner-latest` because the default `node:20-bookworm` runner image lacks `make` and a docker CLI. The build job bind-mounts `/var/run/docker.sock`; the runner repo's `config.yaml` whitelists that path under `valid_volumes`.
- Renamed `docker-compose.{yml,prod.yml}` → `compose.{yaml,prod.yaml}` (Compose v2 spec).
- `docs/operations.md` + `docs/self-hosting.md` updated with the new secret matrix, compose invocations, rollback example, and Gitea runner notes.
## Out-of-band tasks (left for the operator)
- [ ] Create a Gitea robot account or PAT with `package:write` on the `public` org.
- [ ] Set repo secrets at `https://git.librete.ch/public/librenotes/settings/actions/secrets`:
`REGISTRY=git.librete.ch`, `REGISTRY_USER`, `REGISTRY_PASS`,
`DEPLOY_HOST=root@netcup`, `DEPLOY_KEY` (passphrase-less private key),
`DEPLOY_PATH=/srv/librenotes`,
`HEALTH_URL=https://ln.cloud.librete.ch/healthz`.
- [ ] Set repo variable `DEPLOY_ENABLED=true`.
- [ ] Restart the netcup runner so the new `valid_volumes` entry is loaded.
- [ ] On netcup `/srv/librenotes/.env`, add `LIBRENOTES_IMAGE=git.librete.ch/public/librenotes:v0.1.0`.
## Verification
- `yq -e .` parses all touched YAML.
- `docker compose -f compose.yaml -f compose.netcup.yaml config` resolves.
- A `main` push will only run anything once `DEPLOY_ENABLED=true`; the workflow is safe to merge before secrets are set.
compose.netcup.yaml now references ${LIBRENOTES_IMAGE} with pull_policy: always
and resets the base build context. .env.netcup.example documents the new
LIBRENOTES_IMAGE key (default git.librete.ch/public/librenotes:main, pin to
immutable tag for prod). Rollback: edit .env LIBRENOTES_IMAGE + up -d.
- Image base is now ${REGISTRY}/public/librenotes (matches Gitea owner/repo).
- Remote step writes LIBRENOTES_IMAGE on tag pushes via perl, then pulls and
restarts using the new compose.yaml + compose.netcup.yaml stack files.
- Both jobs run inside catthehacker/ubuntu:runner-latest; the default
node:20-bookworm runner image lacks make + docker. The build job
bind-mounts /var/run/docker.sock for build-push-action; the runner config
must whitelist that path under valid_volumes.
operations.md lists the full secret/variable matrix the deploy workflow
expects, the new compose.yaml + compose.netcup.yaml invocation, and a
note on why both workflow jobs pin catthehacker/ubuntu:runner-latest.
self-hosting.md updates the example LIBRENOTES_IMAGE value to the Gitea
Packages path and switches the quick-start to compose.netcup.yaml.
First deploy now works without manual .env priming: the remote step
unconditionally rewrites LIBRENOTES_IMAGE, then runs git pull --ff-only
so the host picks up the renamed compose.* files before pull/up.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #39.
Summary
compose.netcup.yamlno longer builds locally; pulls${LIBRENOTES_IMAGE}(defaultgit.librete.ch/public/librenotes:main)..gitea/workflows/deploy.ymlbuilds + pushes to${REGISTRY}/public/librenotes(main →:main+:<sha7>; tag →:vX.Y.Z+:latest), then SSHes to the deploy host and reruns compose. Tag pushes pinLIBRENOTES_IMAGEin the host.envviaperl -i.ci.yml) run insidecatthehacker/ubuntu:runner-latestbecause the defaultnode:20-bookwormrunner image lacksmakeand a docker CLI. The build job bind-mounts/var/run/docker.sock; the runner repo'sconfig.yamlwhitelists that path undervalid_volumes.docker-compose.{yml,prod.yml}→compose.{yaml,prod.yaml}(Compose v2 spec).docs/operations.md+docs/self-hosting.mdupdated with the new secret matrix, compose invocations, rollback example, and Gitea runner notes.Out-of-band tasks (left for the operator)
package:writeon thepublicorg.https://git.librete.ch/public/librenotes/settings/actions/secrets:REGISTRY=git.librete.ch,REGISTRY_USER,REGISTRY_PASS,DEPLOY_HOST=root@netcup,DEPLOY_KEY(passphrase-less private key),DEPLOY_PATH=/srv/librenotes,HEALTH_URL=https://ln.cloud.librete.ch/healthz.DEPLOY_ENABLED=true.valid_volumesentry is loaded./srv/librenotes/.env, addLIBRENOTES_IMAGE=git.librete.ch/public/librenotes:v0.1.0.Verification
yq -e .parses all touched YAML.docker compose -f compose.yaml -f compose.netcup.yaml configresolves.mainpush will only run anything onceDEPLOY_ENABLED=true; the workflow is safe to merge before secrets are set.compose.netcup.yaml now references ${LIBRENOTES_IMAGE} with pull_policy: always and resets the base build context. .env.netcup.example documents the new LIBRENOTES_IMAGE key (default git.librete.ch/public/librenotes:main, pin to immutable tag for prod). Rollback: edit .env LIBRENOTES_IMAGE + up -d.- Image base is now ${REGISTRY}/public/librenotes (matches Gitea owner/repo). - Remote step writes LIBRENOTES_IMAGE on tag pushes via perl, then pulls and restarts using the new compose.yaml + compose.netcup.yaml stack files. - Both jobs run inside catthehacker/ubuntu:runner-latest; the default node:20-bookworm runner image lacks make + docker. The build job bind-mounts /var/run/docker.sock for build-push-action; the runner config must whitelist that path under valid_volumes.