5d63f3f0e03658a6c81fadae2de93162f577de6b
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5d63f3f0e0 |
Schedule Nextcloud's cron.php in the user's crontab, not a systemd timer
The timer was justified partly on XDG_RUNTIME_DIR: a user crontab "would need it faked into every line". That is wrong here. The caddy playbook enables lingering, so /run/user/<uid> exists whether or not anyone is logged in, and that is where podman keeps the state `exec` reads. Nothing needs to be set. The one real constraint is that the job cannot go in root's crontab: root cannot `podman exec` into another user's rootless containers. This user's crontab is fine, and the play runs as that user, so `ansible.builtin.cron` with no `user:` writes exactly there. That replaces four tasks and two template files with one task and no files, and it is what the service had before the Quadlet conversion. The cost is that cron sends its output to local mail instead of the journal; the readme says so and names the timer as the alternative. While here, the XDG_RUNTIME_DIR asides come out of the comments that carried them: the play runs over SSH, so `systemctl --user` works because systemd's user manager is reachable over that connection, and that is all a reader needs to know. |
||
|
|
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. |