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/
|
└── roles/
|
||||||
├── postgres/ # the database, and this app's network on the cluster
|
├── postgres/ # the database, and this app's network on the cluster
|
||||||
├── valkey/ # this app's network on the cache
|
├── 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
|
└── 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/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 |
|
| `~/.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/` | the whole `/var/www/html` |
|
||||||
| `~/podman-data/nextcloud/nextcloud.env` | `POSTGRES_*` + `REDIS_HOST`, mode `0600` |
|
| `~/podman-data/nextcloud/nextcloud.env` | `POSTGRES_*`, mode `0600` |
|
||||||
| `~/podman-data/nextcloud/redis-session.ini` | mounted into the image; see [below](#the-php-session-file) |
|
|
||||||
|
|
||||||
## What is state, and what is not
|
## What is state, and what is not
|
||||||
|
|
||||||
@@ -88,12 +87,11 @@ of downtime for every attached app; see
|
|||||||
|
|
||||||
**Valkey.** The same, via
|
**Valkey.** The same, via
|
||||||
[valkey/roles/attach](../valkey/roles/attach/tasks/main.yaml), with
|
[valkey/roles/attach](../valkey/roles/attach/tasks/main.yaml), with
|
||||||
`NetworkAlias=redis`. `redis` is not a name this playbook chose: `REDIS_HOST` is
|
`NetworkAlias=redis`: the attach puts `nextcloud_net` on the cache container and
|
||||||
what the image writes PHP's session config from, and Redis is where the setup
|
makes the host `redis` resolve from Nextcloud. What *uses* it is `config.php`, and
|
||||||
wizard puts `memcache.locking`. An unresolvable `redis` therefore breaks uploads
|
this playbook does not write that — see "Redis" below. The recreate costs a few
|
||||||
at write time rather than at startup, which is why the attach is flushed before
|
seconds of cache availability, and the keys survive it
|
||||||
the app starts as well. The recreate costs a few seconds of cache availability;
|
(see [valkey/readme.md](../valkey/readme.md)).
|
||||||
the keys survive it (see [valkey/readme.md](../valkey/readme.md)).
|
|
||||||
|
|
||||||
## Background jobs
|
## Background jobs
|
||||||
|
|
||||||
@@ -127,7 +125,7 @@ Quadlet units is the alternative, and it is two small files.
|
|||||||
| `container_port` | `80`, what Caddy proxies to |
|
| `container_port` | `80`, what Caddy proxies to |
|
||||||
| `env_file` | `~/podman-data/nextcloud/nextcloud.env`, mode `0600` |
|
| `env_file` | `~/podman-data/nextcloud/nextcloud.env`, mode `0600` |
|
||||||
| `pg_*` / `db_host` | The database, its credentials, and the `db` alias |
|
| `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 |
|
| `nextcloud_admin_user` / `nextcloud_admin_password` | Empty by default; set both to install unattended |
|
||||||
| `cron_minute` | The `cron.php` interval |
|
| `cron_minute` | The `cron.php` interval |
|
||||||
| `caddy_*` | The shared Caddy unit and its Caddyfile |
|
| `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
|
`123456`. It lives in `nextcloud.env` at mode `0600` rather than in the
|
||||||
world-readable unit file.
|
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
|
It deliberately does **not** set `REDIS_HOST`, which is the one Redis variable the
|
||||||
/entrypoint.sh:121
|
image acts on. That variable exists to write PHP's session config, with a redirect
|
||||||
} > /usr/local/etc/php/conf.d/redis-session.ini
|
into `/usr/local/etc/php/conf.d` — a directory the image owns as root and this
|
||||||
```
|
container cannot write:
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
cannot create /usr/local/etc/php/conf.d/redis-session.ini: Permission denied
|
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
|
The entrypoint exits `2` before Apache is reached, `Restart=always` retries it, and
|
||||||
over that exact path. A bind-mounted file replaces the directory entry, so the
|
systemd's start limit marks the unit `failed`. Leaving `REDIS_HOST` unset skips
|
||||||
directory's ownership stops mattering and the write lands on a file owned by
|
that write entirely; the only thing lost is PHP session storage, which falls back
|
||||||
`podman_user`. Apache's own runtime directories need none of this — the same base
|
to the container's own filesystem.
|
||||||
image chowns `/var/run/apache2`, `/var/lock/apache2` and `/var/log/apache2` to
|
|
||||||
`www-data` and chmods them `1777`.
|
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
|
## First run and updates
|
||||||
|
|
||||||
|
|||||||
@@ -17,22 +17,6 @@
|
|||||||
group: "{{ podman_user }}"
|
group: "{{ podman_user }}"
|
||||||
mode: '0755'
|
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
|
# 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
|
# starts. Mode 0600: POSTGRES_PASSWORD is in it, and the unit file is
|
||||||
# world-readable.
|
# world-readable.
|
||||||
|
|||||||
@@ -32,11 +32,6 @@ Network={{ network_name }}.network
|
|||||||
# rsyncs new code in and upgrades the database in place.
|
# rsyncs new code in and upgrades the database in place.
|
||||||
Volume={{ host_directory }}:{{ webroot }}
|
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]
|
[Service]
|
||||||
Restart=always
|
Restart=always
|
||||||
# A first start initialises the webroot; a start after an image bump rsyncs code
|
# 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.
|
# 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
|
# 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
|
# installed instance they only have to agree with config.php.
|
||||||
# every start — the entrypoint regenerates PHP's session config from it.
|
#
|
||||||
|
# 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_DB={{ pg_database }}
|
||||||
POSTGRES_USER={{ pg_user }}
|
POSTGRES_USER={{ pg_user }}
|
||||||
POSTGRES_PASSWORD={{ pg_password }}
|
POSTGRES_PASSWORD={{ pg_password }}
|
||||||
POSTGRES_HOST={{ db_host }}
|
POSTGRES_HOST={{ db_host }}
|
||||||
REDIS_HOST={{ redis_host }}
|
|
||||||
{% if nextcloud_admin_user | length > 0 and nextcloud_admin_password | length > 0 %}
|
{% 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
|
# Consumed only while there is no config.php, by the entrypoint's unattended
|
||||||
# install. Empty by default, which leaves the setup wizard in charge.
|
# 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
|
# asserts that nextcloud.network already exists, and notifies the "Restart
|
||||||
# Valkey" handler defined in this role.
|
# Valkey" handler defined in this role.
|
||||||
#
|
#
|
||||||
# `redis` is the alias the app connects to, not the container name: REDIS_HOST is
|
# `redis` is the alias the app connects to, not the container name: it is the host
|
||||||
# what the image writes the PHP session handler from, and what this play puts in
|
# an instance configured for Redis has in config.php. This playbook does not write
|
||||||
# config.php's Redis configuration on an unattended install. Renaming it would
|
# that configuration, it only makes the name resolvable.
|
||||||
# mean editing a live instance's configuration for nothing.
|
|
||||||
|
|
||||||
- name: Attach Nextcloud to Valkey
|
- name: Attach Nextcloud to Valkey
|
||||||
ansible.builtin.include_tasks: "{{ playbook_dir }}/../valkey/roles/attach/tasks/main.yaml"
|
ansible.builtin.include_tasks: "{{ playbook_dir }}/../valkey/roles/attach/tasks/main.yaml"
|
||||||
|
|||||||
@@ -58,12 +58,11 @@ pg_user: postgres
|
|||||||
pg_password: '123456'
|
pg_password: '123456'
|
||||||
pg_database: nextcloud
|
pg_database: nextcloud
|
||||||
|
|
||||||
# Valkey, and the alias its attach role adds. REDIS_HOST is not cosmetic:
|
# Valkey, which the attach role puts this app's network on with the alias
|
||||||
# config.php puts `memcache.locking` on Redis, so an unresolvable `redis` breaks
|
# `redis`. Whether Nextcloud uses it is config.php's decision: the cache and
|
||||||
# uploads rather than merely slowing them down.
|
# `memcache.locking` live there, not in this playbook. See readme.md.
|
||||||
valkey_container: valkey
|
valkey_container: valkey
|
||||||
valkey_unit: "{{ valkey_container }}.service"
|
valkey_unit: "{{ valkey_container }}.service"
|
||||||
redis_host: redis
|
|
||||||
|
|
||||||
caddy_name: caddy
|
caddy_name: caddy
|
||||||
caddyfile_path: "{{ podman_data_dir }}/{{ caddy_name }}/conf/Caddyfile"
|
caddyfile_path: "{{ podman_data_dir }}/{{ caddy_name }}/conf/Caddyfile"
|
||||||
|
|||||||
Reference in new issue
Block a user