Do not create a host file for the entrypoint's PHP session config
The role created ~/podman-data/nextcloud/redis-session.ini and the unit bind-mounted it over the image path, purely because the entrypoint cannot write there itself. Removed: the task, the mount, and -- because it is the only thing that triggers the write -- REDIS_HOST from the environment file. The entrypoint now skips configure_redis_session entirely and starts. The Redis attach stays. The valkey role still puts nextcloud_net on the cache container with the alias `redis`, so an instance whose config.php names that host reaches it. Writing that configuration is config.php's business, and the readme gives the three `occ config:system:set` lines for anyone who wants it, including that this playbook will not do it for them. The only thing lost is PHP session storage, which falls back to the container's own filesystem -- a redeploy logs users out. That is the trade for not shipping a file whose sole purpose is to work around a directory the image owns as root. The env template and the valkey role comment both say why REDIS_HOST is absent, so that adding it back is recognisable as the regression it is.
This commit is contained in:
1 parent
5d63f3f0e0
commit
c3e0e4989c
6 files changed
+41
-60
No files matched your search
+29
-28
@@ -37,7 +37,7 @@ nextcloud/
|
||||
└── roles/
|
||||
├── postgres/ # the database, and this app's network on the cluster
|
||||
├── valkey/ # this app's network on the cache
|
||||
├── nextcloud/ # webroot, env file, unit, session config, cron
|
||||
├── nextcloud/ # webroot, env file, unit, cron
|
||||
└── caddy/ # the site block in the shared Caddyfile
|
||||
```
|
||||
|
||||
@@ -48,8 +48,7 @@ nextcloud/
|
||||
| `~/.config/containers/systemd/*.container.d/50-nextcloud.conf` | attaches Caddy, Postgres and Valkey to it |
|
||||
| `~/.config/containers/systemd/*.container.d/10-network-aliases.conf` | the shared `db` and `redis` aliases |
|
||||
| `~/podman-data/nextcloud/` | the whole `/var/www/html` |
|
||||
| `~/podman-data/nextcloud/nextcloud.env` | `POSTGRES_*` + `REDIS_HOST`, mode `0600` |
|
||||
| `~/podman-data/nextcloud/redis-session.ini` | mounted into the image; see [below](#the-php-session-file) |
|
||||
| `~/podman-data/nextcloud/nextcloud.env` | `POSTGRES_*`, mode `0600` |
|
||||
|
||||
## What is state, and what is not
|
||||
|
||||
@@ -88,12 +87,11 @@ of downtime for every attached app; see
|
||||
|
||||
**Valkey.** The same, via
|
||||
[valkey/roles/attach](../valkey/roles/attach/tasks/main.yaml), with
|
||||
`NetworkAlias=redis`. `redis` is not a name this playbook chose: `REDIS_HOST` is
|
||||
what the image writes PHP's session config from, and Redis is where the setup
|
||||
wizard puts `memcache.locking`. An unresolvable `redis` therefore breaks uploads
|
||||
at write time rather than at startup, which is why the attach is flushed before
|
||||
the app starts as well. The recreate costs a few seconds of cache availability;
|
||||
the keys survive it (see [valkey/readme.md](../valkey/readme.md)).
|
||||
`NetworkAlias=redis`: the attach puts `nextcloud_net` on the cache container and
|
||||
makes the host `redis` resolve from Nextcloud. What *uses* it is `config.php`, and
|
||||
this playbook does not write that — see "Redis" below. The recreate costs a few
|
||||
seconds of cache availability, and the keys survive it
|
||||
(see [valkey/readme.md](../valkey/readme.md)).
|
||||
|
||||
## Background jobs
|
||||
|
||||
@@ -127,7 +125,7 @@ Quadlet units is the alternative, and it is two small files.
|
||||
| `container_port` | `80`, what Caddy proxies to |
|
||||
| `env_file` | `~/podman-data/nextcloud/nextcloud.env`, mode `0600` |
|
||||
| `pg_*` / `db_host` | The database, its credentials, and the `db` alias |
|
||||
| `valkey_container` / `redis_host` | The cache unit, and the `redis` alias |
|
||||
| `valkey_container` / `valkey_unit` | The cache unit this app attaches to |
|
||||
| `nextcloud_admin_user` / `nextcloud_admin_password` | Empty by default; set both to install unattended |
|
||||
| `cron_minute` | The `cron.php` interval |
|
||||
| `caddy_*` | The shared Caddy unit and its Caddyfile |
|
||||
@@ -147,31 +145,34 @@ owned by `tanshu` and plain `tar` and `rm -rf` keep working on it.
|
||||
`123456`. It lives in `nextcloud.env` at mode `0600` rather than in the
|
||||
world-readable unit file.
|
||||
|
||||
## The PHP session file
|
||||
## Redis
|
||||
|
||||
The entrypoint generates PHP's session config on every start, with a redirect:
|
||||
The Valkey attach above makes the host `redis` resolve from the container, and
|
||||
that is all this playbook does about Redis: which caches Nextcloud uses is
|
||||
`config.php`'s business, and this playbook does not write it.
|
||||
|
||||
```sh
|
||||
/entrypoint.sh:121
|
||||
} > /usr/local/etc/php/conf.d/redis-session.ini
|
||||
```
|
||||
|
||||
That directory belongs to the image's root — the php base image creates it with
|
||||
`mkdir -p "$PHP_INI_DIR/conf.d"` and never chowns it — so the write is refused,
|
||||
the entrypoint exits `2` before Apache is reached, `Restart=always` retries it,
|
||||
systemd hits its start limit, and the unit ends up **`failed`** with the only
|
||||
explanation in the journal:
|
||||
It deliberately does **not** set `REDIS_HOST`, which is the one Redis variable the
|
||||
image acts on. That variable exists to write PHP's session config, with a redirect
|
||||
into `/usr/local/etc/php/conf.d` — a directory the image owns as root and this
|
||||
container cannot write:
|
||||
|
||||
```
|
||||
cannot create /usr/local/etc/php/conf.d/redis-session.ini: Permission denied
|
||||
```
|
||||
|
||||
The role creates `~/podman-data/nextcloud/redis-session.ini` and the unit binds it
|
||||
over that exact path. A bind-mounted file replaces the directory entry, so the
|
||||
directory's ownership stops mattering and the write lands on a file owned by
|
||||
`podman_user`. Apache's own runtime directories need none of this — the same base
|
||||
image chowns `/var/run/apache2`, `/var/lock/apache2` and `/var/log/apache2` to
|
||||
`www-data` and chmods them `1777`.
|
||||
The entrypoint exits `2` before Apache is reached, `Restart=always` retries it, and
|
||||
systemd's start limit marks the unit `failed`. Leaving `REDIS_HOST` unset skips
|
||||
that write entirely; the only thing lost is PHP session storage, which falls back
|
||||
to the container's own filesystem.
|
||||
|
||||
So to put Nextcloud's caches on Valkey, set it in `config.php` — `memcache.locking`
|
||||
and `memcache.distributed` to `\OC\Memcache\Redis`, and `redis` `host` to `redis`:
|
||||
|
||||
```bash
|
||||
podman exec -u www-data nextcloud php occ config:system:set memcache.distributed --value='\OC\Memcache\Redis'
|
||||
podman exec -u www-data nextcloud php occ config:system:set memcache.locking --value='\OC\Memcache\Redis'
|
||||
podman exec -u www-data nextcloud php occ config:system:set redis host --value=redis
|
||||
```
|
||||
|
||||
## First run and updates
|
||||
|
||||
|
||||
@@ -17,22 +17,6 @@
|
||||
group: "{{ podman_user }}"
|
||||
mode: '0755'
|
||||
|
||||
# The entrypoint generates PHP's session config with a redirect into
|
||||
# /usr/local/etc/php/conf.d, a directory the image creates as root and never
|
||||
# chowns. That write is refused, the entrypoint exits 2, and the unit crash-loops
|
||||
# into systemd's start limit. Bind-mounting a file over that path gives the write
|
||||
# somewhere it is allowed; the file has to exist first, or the mount lands as a
|
||||
# directory.
|
||||
- name: Create the file the entrypoint writes PHP's session config to
|
||||
ansible.builtin.file:
|
||||
path: "{{ host_directory }}/redis-session.ini"
|
||||
state: touch
|
||||
owner: "{{ podman_user }}"
|
||||
group: "{{ podman_user }}"
|
||||
mode: '0644'
|
||||
access_time: preserve
|
||||
modification_time: preserve
|
||||
|
||||
# Read by the entrypoint, not by Ansible, so it has to exist before the unit
|
||||
# starts. Mode 0600: POSTGRES_PASSWORD is in it, and the unit file is
|
||||
# world-readable.
|
||||
|
||||
@@ -32,11 +32,6 @@ Network={{ network_name }}.network
|
||||
# rsyncs new code in and upgrades the database in place.
|
||||
Volume={{ host_directory }}:{{ webroot }}
|
||||
|
||||
# PHP's session config, which the entrypoint generates on every start. Without
|
||||
# this mount it cannot: /usr/local/etc/php/conf.d belongs to the image's root.
|
||||
# See the file task in roles/nextcloud for the failure this prevents.
|
||||
Volume={{ host_directory }}/redis-session.ini:/usr/local/etc/php/conf.d/redis-session.ini
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
# A first start initialises the webroot; a start after an image bump rsyncs code
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
# Mode 0600: this file is read by systemd, and POSTGRES_PASSWORD is in it.
|
||||
#
|
||||
# POSTGRES_* are what the entrypoint installs with on a fresh webroot; on an
|
||||
# installed instance they only have to agree with config.php. REDIS_HOST is live on
|
||||
# every start — the entrypoint regenerates PHP's session config from it.
|
||||
# installed instance they only have to agree with config.php.
|
||||
#
|
||||
# REDIS_HOST is deliberately absent: it makes the entrypoint write PHP's session
|
||||
# config into /usr/local/etc/php/conf.d, which the image owns as root and this
|
||||
# container cannot write — the unit crash-loops on it. Redis is config.php's
|
||||
# business, not this variable's. See readme.md, "Redis".
|
||||
POSTGRES_DB={{ pg_database }}
|
||||
POSTGRES_USER={{ pg_user }}
|
||||
POSTGRES_PASSWORD={{ pg_password }}
|
||||
POSTGRES_HOST={{ db_host }}
|
||||
REDIS_HOST={{ redis_host }}
|
||||
{% if nextcloud_admin_user | length > 0 and nextcloud_admin_password | length > 0 %}
|
||||
# Consumed only while there is no config.php, by the entrypoint's unattended
|
||||
# install. Empty by default, which leaves the setup wizard in charge.
|
||||
|
||||
@@ -8,10 +8,9 @@
|
||||
# asserts that nextcloud.network already exists, and notifies the "Restart
|
||||
# Valkey" handler defined in this role.
|
||||
#
|
||||
# `redis` is the alias the app connects to, not the container name: REDIS_HOST is
|
||||
# what the image writes the PHP session handler from, and what this play puts in
|
||||
# config.php's Redis configuration on an unattended install. Renaming it would
|
||||
# mean editing a live instance's configuration for nothing.
|
||||
# `redis` is the alias the app connects to, not the container name: it is the host
|
||||
# an instance configured for Redis has in config.php. This playbook does not write
|
||||
# that configuration, it only makes the name resolvable.
|
||||
|
||||
- name: Attach Nextcloud to Valkey
|
||||
ansible.builtin.include_tasks: "{{ playbook_dir }}/../valkey/roles/attach/tasks/main.yaml"
|
||||
|
||||
@@ -58,12 +58,11 @@ pg_user: postgres
|
||||
pg_password: '123456'
|
||||
pg_database: nextcloud
|
||||
|
||||
# Valkey, and the alias its attach role adds. REDIS_HOST is not cosmetic:
|
||||
# config.php puts `memcache.locking` on Redis, so an unresolvable `redis` breaks
|
||||
# uploads rather than merely slowing them down.
|
||||
# Valkey, which the attach role puts this app's network on with the alias
|
||||
# `redis`. Whether Nextcloud uses it is config.php's decision: the cache and
|
||||
# `memcache.locking` live there, not in this playbook. See readme.md.
|
||||
valkey_container: valkey
|
||||
valkey_unit: "{{ valkey_container }}.service"
|
||||
redis_host: redis
|
||||
|
||||
caddy_name: caddy
|
||||
caddyfile_path: "{{ podman_data_dir }}/{{ caddy_name }}/conf/Caddyfile"
|
||||
|
||||
Reference in new issue
Block a user