f3845bde2b5eaa044eafdc3351463602ae43d5ae
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
05452127ec |
Cut the Nextcloud role back to what it actually needs
The role had grown machinery that the problem does not require. Removed: - The init-sync lock pre-create. It guarded against one file in the webroot being owned by a subuid, which is cosmetic: the file is 0644, so it is readable and removable by host-side tools either way. - The image ID read/pull pair. No other service playbook pulls an image, and the update path is two commands the readme now spells out. - redis-session.ini.j2 and its three variables. The mount is load-bearing -- the entrypoint cannot write into the image's conf.d and dies trying -- but the template is not: the entrypoint writes that file itself on every start. One touched empty file and one Volume line replace the template and the variables. - The config.php stat, the wizard note, the maintenance-mode wait, the occ status report, the getent checks, the timer report. The installed/not-installed branching existed only because the readiness gates were written for an installed instance; with a gate that fits both, none of the branching is needed. - Comments that narrated this play's earlier runs rather than the system. What is left is four tasks before the start, a start-plus-gate block whose rescue collects the journal, and four tasks for the background-job timer: 149 lines and about 130 of them code, against 313 before. The readme loses its migration-era bulk for the same reason and is 297 lines, in line with the other services'. The one gate is now Nextcloud's own status.php inside the container. It answers only once the entrypoint has finished -- including any `occ upgrade`, which runs before Apache starts, so an update in progress is waited out rather than missed -- it reports `installed` either way, so a fresh webroot and an installed instance go through the same check, and it carries `maintenance` as well, which is the one state a probe would otherwise call healthy while every page returned 503. |
||
|
|
be53cec757 |
Make the Nextcloud playbook standalone: first run installs, later runs update
The playbook is meant to be usable on its own, on any host, the way every other one here is: the first run creates the container, and every run after that converges it. It had picked up a migration shape instead -- a readme that assumed a webroot copied in from monoco, a warning that nagged when config.php was missing, and, worse, readiness gates that only passed for an instance that was already installed. That last one was a real bug for the intended use. On a host with no webroot, the image initialises the code, writes no config.php because it has no admin credentials to install with, and serves the setup wizard -- so `occ status` never reports installed: true, and the play would have spent its whole retry budget and then failed on a first run that was going exactly as designed. What replaces it: - The readiness gate is Apache answering status.php inside the container, which is Nextcloud's own endpoint and reports `installed` either way. It is the one thing `is-active` cannot tell us, and it passes for a wizard that has not been completed. - config.php's presence then decides the report: wait for maintenance mode to clear and print `occ status` for an instance, or say what is left for a human to do for a fresh one -- and succeed. The two optional credentials in vars/default.yml install unattended instead, in which case the same endpoints come back installed and the wizard note never appears. - The app creates its own database. Postgres is a shared unit with one default database and nothing else in this repo knows this app's database name, so a fresh cluster previously reached the installer and failed on "database nextcloud does not exist". It is a lookup and a `createdb`, a no-op afterwards, and it fails with the instruction to run postgres/playbook.yml if the cluster is not there rather than with a bare psql error. - Updates. An update in a Quadlet deployment is "pull, then recreate": the unit names a tag, `podman run` reuses the local image, and nothing fetches a newer one. The role pulls on every run and compares the image ID either side, so an unchanged tag is not a change and a running site is not restarted for nothing. - Handlers are flushed before verification, so a queued recreate -- new image, changed unit, changed environment -- happens before the checks rather than after them, and the checks describe what will keep running. Removed: the entire monoco migration section and its copy commands, the config.php warning that existed only to serve it, the host-specific notes, and the narrative comments about this play's first runs. References to the audit and migration planning docs go with them; the ownership reasoning is stated inline, since it does not depend on where an instance came from. `hosts:` is now the only host-specific thing in the directory. The readme is rewritten around the two paths it now has -- "First run" and "Updates" -- with the deploy order, the session-file trap and the debugging commands kept. |
||
|
|
43ea43e88b |
Run Nextcloud as a rootless Podman Quadlet
Replaces the docker_container playbook, which bind-mounted /var/lib/nextcloud at /var/www/html on monoco and ran cron.php from root's crontab. Nextcloud now runs on emily behind the shared Caddy, with its database in the shared Postgres and its cache in the shared Valkey, each attached the way every other service attaches to them. /var/www/html is the unusual part: it holds the code as well as the state -- version.php, core/, lib/ and apps/ alongside config/config.php, data/ and custom_apps/ -- and the entrypoint's version check reads version.php from the mount. That is why the migration copies the whole tree rather than only the three irreplaceable directories (docs/backup-plan.md 2.1 lists the rest as regenerable, and they are, but only from an image that is the same version or newer). It is also what makes an image bump an in-place upgrade: a newer image rsyncs its code in and runs `occ upgrade` on first start, and an older one refuses to start at all, so the version on both hosts is worth checking before the copy. UserNS=keep-id:uid=33,gid=33. 33 is www-data, the uid the server actually writes as -- `docker exec nextcloud id -u` reports 0, because the entrypoint drops privileges after starting (docs/podman-compat-audit.md 3.2). 33 is also what the data is owned by on monoco, so the copy needs no chown pass: extracting as the connection user is already the ownership the container expects. One file is created by container-root and never chowned, the entrypoint's nextcloud-init-sync.lock, so the role pre-creates it -- the entrypoint truncates that file rather than recreating it, so its owner then never changes, and the webroot ends up with no subuid-owned file in it. The Valkey attach is not optional. config.php carries memcache.locking pointed at Redis, written by the image from REDIS_HOST, and the same variable rewrites PHP's session-handler config on every start -- so an unresolvable `redis` does not just make things slower, it fails uploads at write time. Hence the `redis` alias rather than the container name, and hence roles/valkey flushing handlers before the app starts, the same as roles/postgres. cron.php moves from root's crontab to a systemd user timer, because root cannot `podman exec` into another user's rootless containers and there is no container user to own a crontab (docs/podman-migration.md 8b). Unlike the Quadlet units this pair is plain and is genuinely enabled, which is what brings it back after a reboot; journalctl --user -u nextcloud-cron shows every run, which the crontab never did. Readiness is three gates, because no one of them is sufficient: is-active (which Restart=always satisfies even while crash-looping), `occ status` reporting installed, and status.php served over loopback by Apache rather than by the PHP CLI. The second is followed by a wait for maintenance mode to clear rather than an assert: maintenance mode is on for the whole of a first-start `occ upgrade`, so asserting it off would fail a healthy deploy halfway through. The case that never clears is a config.php copied with `maintenance => true`, which docs/backup-plan.md 3.4 tells an operator to set before a consistent dump, and which is invisible from outside because status.php is exempt from maintenance mode -- so the play names it and prints the command that clears it. Register and attach ordering is the same as the other service playbooks: register runs in pre_tasks, because the unit references nextcloud.network and Quadlet fails unit generation when that file does not exist, and both attaches flush handlers before the app starts, which is also what pulls Caddy onto the network. The Caddy snippet is unchanged, HSTS header included; only caddyfile_path moves, from /var/lib/caddy/conf/Caddyfile to ~/podman-data/caddy/conf/Caddyfile. The Docker-era roles/network is deleted rather than ported: it existed to attach an already-created container to a network with the `redis` alias, and podman_network has no connected:/appends: equivalent (docs/podman-compat-audit.md 3.3). Nothing is published host-side; Caddy reaches nextcloud:80 over nextcloud_net. The rootless-Podman prerequisites are not applied here: they are the shared task file at caddy/roles/podman, and a host that has run caddy/playbook.yml has them. valkey/playbook.yml has to have been run first, or the first Restart Valkey handler fails against a unit that does not exist yet. |