From 9b12225ec8302efc3aeaefcea07f641cefc08233 Mon Sep 17 00:00:00 2001 From: Joakim Date: Tue, 16 Dec 2025 20:40:25 +0100 Subject: [PATCH] MILE: All current services confirmed working on a fresh arch vps --- roles/nextcloud/README.md | 46 +++++++++++++++-- roles/nextcloud/tasks/main.yml | 49 ++++++++++++------- roles/nextcloud/templates/nextcloud.container | 3 -- .../templates/redis-session-override.ini.j2 | 16 ------ roles/postgresql/tasks/main.yml | 7 ++- roles/valkey/tasks/main.yml | 5 ++ 6 files changed, 83 insertions(+), 43 deletions(-) delete mode 100644 roles/nextcloud/templates/redis-session-override.ini.j2 diff --git a/roles/nextcloud/README.md b/roles/nextcloud/README.md index 44abf0b..b111423 100644 --- a/roles/nextcloud/README.md +++ b/roles/nextcloud/README.md @@ -78,6 +78,40 @@ nextcloud_php_memory_limit: "512M" nextcloud_php_upload_limit: "512M" ``` +## Deployment Strategy + +This role uses a **two-phase deployment** approach to work correctly with the Nextcloud container's initialization process: + +### Phase 1: Container Initialization (automatic) +1. Create empty directories for volumes +2. Deploy environment configuration (`.env`) +3. Start Nextcloud container +4. Container entrypoint detects first-time setup (no `version.php`) +5. Container copies Nextcloud files to `/var/www/html/` +6. Container runs `occ maintenance:install` with PostgreSQL +7. Installation creates `config.php` with database credentials + +### Phase 2: Custom Configuration (automatic) +8. Ansible waits for `occ status` to report `installed: true` +9. Ansible deploys custom `redis.config.php` (overwrites default) +10. Container restart applies custom configuration + +**Why this order?** + +The Nextcloud container's entrypoint uses `version.php` as a marker to determine if installation is needed. If you deploy any files into `/opt/nextcloud/config/` before the container starts, the initialization process fails: + +- Container copies files including `version.php` +- Entrypoint sees `version.php` exists → assumes already installed +- Skips running `occ maintenance:install` +- Result: Empty `config.php`, 503 errors + +By deploying custom configs **after** installation completes, we: +- ✅ Allow the container's auto-installation to run properly +- ✅ Override specific configs (like Redis) after the fact +- ✅ Maintain idempotency (subsequent runs just update configs) + +See the official [Nextcloud Docker documentation](https://github.com/nextcloud/docker#auto-configuration-via-environment-variables) for more details on the auto-configuration process. + ## Usage ### Include in Playbook @@ -232,11 +266,13 @@ This role disables Redis sessions by **not setting** `REDIS_HOST` in the environ **If you need Redis sessions** (e.g., multi-server setup with session sharing), you must: 1. Enable `REDIS_HOST` in `nextcloud.env.j2` -2. Set proper lock parameters in a custom PHP ini file -3. Increase FPM workers significantly (15-20+) -4. Monitor for orphaned session locks - -See `templates/redis-session-override.ini.j2` for an example of session lock tuning. +2. Add a custom PHP ini file with proper lock parameters: + - `redis.session.lock_expire = 30` (locks expire after 30 seconds) + - `redis.session.lock_retries = 100` (max 100 retries, not infinite) + - `redis.session.lock_wait_time = 50000` (50ms between retries) +3. Mount the ini file with `zz-` prefix to load after the entrypoint's redis-session.ini +4. Increase FPM workers significantly (15-20+) +5. Monitor for orphaned session locks ## Troubleshooting diff --git a/roles/nextcloud/tasks/main.yml b/roles/nextcloud/tasks/main.yml index b873c6a..626d0b2 100644 --- a/roles/nextcloud/tasks/main.yml +++ b/roles/nextcloud/tasks/main.yml @@ -52,21 +52,12 @@ notify: restart nextcloud tags: [config] -- name: Deploy custom Redis caching configuration - template: - src: redis.config.php.j2 - dest: "{{ nextcloud_config_dir }}/redis.config.php" - mode: '0640' - notify: restart nextcloud - tags: [config, redis] +# NOTE: Custom Redis config is deployed AFTER installation completes (see below) +# to avoid interfering with the container's first-time initialization process -- name: Deploy Redis session lock override configuration - template: - src: redis-session-override.ini.j2 - dest: "{{ nextcloud_home }}/redis-session-override.ini" - mode: '0644' - notify: restart nextcloud - tags: [config, redis] +# NOTE: redis-session-override.ini is NOT deployed because we use file-based sessions +# (not Redis sessions). If you enable REDIS_HOST in the future, you'll need to add +# proper session lock configuration. - name: Create Quadlet systemd directory (system scope) file: @@ -130,21 +121,43 @@ delay: 10 tags: [verification] +- name: Wait for Nextcloud installation to complete + shell: podman exec nextcloud php occ status --output=json 2>/dev/null || echo '{"installed":false}' + register: nc_status + until: (nc_status.stdout | from_json).installed | default(false) == true + retries: 60 + delay: 5 + changed_when: false + tags: [verification] + +- name: Deploy custom Redis caching configuration (post-installation) + template: + src: redis.config.php.j2 + dest: "{{ nextcloud_config_dir }}/redis.config.php" + mode: '0644' + notify: restart nextcloud + tags: [config, redis] + - name: Display Nextcloud deployment status debug: msg: | ✅ Nextcloud Cloud Storage deployed successfully! 🌐 Domain: {{ nextcloud_domain }} - 🗄️ Database: {{ nextcloud_db_name }} (Unix socket) - 🗄️ Cache: Valkey DB {{ nextcloud_valkey_db }} (Unix socket) + 🗄️ Database: {{ nextcloud_db_name }} (PostgreSQL via Unix socket) + 🗄️ Cache: Valkey DB {{ nextcloud_valkey_db }} (Redis-compatible via Unix socket) 🐳 Container: FPM via Podman Quadlet 🔒 Admin: {{ nextcloud_admin_user }} + ⚙️ Configuration: + - Redis caching enabled (application-level cache & file locking) + - PHP sessions use file-based storage (not Redis) + - Custom redis.config.php deployed post-installation + 🚀 Ready for file storage and collaboration! 📋 Next Steps: - - Access https://{{ nextcloud_domain }} to complete setup + - Access https://{{ nextcloud_domain }} to log in - Install desired Nextcloud apps - - Configure user accounts + - Configure user accounts and storage quotas tags: [verification] diff --git a/roles/nextcloud/templates/nextcloud.container b/roles/nextcloud/templates/nextcloud.container index d36c272..4f3d112 100644 --- a/roles/nextcloud/templates/nextcloud.container +++ b/roles/nextcloud/templates/nextcloud.container @@ -26,9 +26,6 @@ Volume={{ nextcloud_config_dir }}:/var/www/html/config:Z # Custom apps (world-readable) Volume={{ nextcloud_custom_apps_dir }}:/var/www/html/custom_apps:Z -# Redis session configuration override (zz- prefix ensures it loads last) -Volume={{ nextcloud_home }}/redis-session-override.ini:/usr/local/etc/php/conf.d/zz-redis-session-override.ini:Z,ro - # Infrastructure sockets (mounted with world-readable permissions on host) Volume={{ postgresql_unix_socket_directories }}:{{ postgresql_unix_socket_directories }}:Z Volume={{ valkey_unix_socket_path | dirname }}:{{ valkey_unix_socket_path | dirname }}:Z diff --git a/roles/nextcloud/templates/redis-session-override.ini.j2 b/roles/nextcloud/templates/redis-session-override.ini.j2 deleted file mode 100644 index b5f4e1b..0000000 --- a/roles/nextcloud/templates/redis-session-override.ini.j2 +++ /dev/null @@ -1,16 +0,0 @@ -; Redis Session Lock Override for Nextcloud -; Prevents orphaned session locks from causing infinite hangs -; -; Default Nextcloud container settings: -; redis.session.lock_expire = 0 (locks NEVER expire - causes infinite hangs) -; redis.session.lock_retries = -1 (infinite retries - causes worker exhaustion) -; redis.session.lock_wait_time = 10000 (10 seconds per retry - very slow) -; -; These settings ensure locks auto-expire and failed requests don't block workers forever: -; - Locks expire after 30 seconds (prevents orphaned locks) -; - Max 100 retries = 5 seconds total wait time (prevents infinite loops) -; - 50ms wait between retries (reasonable balance) - -redis.session.lock_expire = 30 -redis.session.lock_retries = 100 -redis.session.lock_wait_time = 50000 diff --git a/roles/postgresql/tasks/main.yml b/roles/postgresql/tasks/main.yml index 13cee55..ed97cd7 100644 --- a/roles/postgresql/tasks/main.yml +++ b/roles/postgresql/tasks/main.yml @@ -126,6 +126,11 @@ delay: 3 when: postgresql_service_state == "started" and postgresql_unix_socket_enabled and postgresql_listen_addresses == "" +# Containerized applications mount socket directories. If handlers run at the end of playbooks this will mount stale sockets. +- name: Flush handlers for socket connection + meta: flush_handlers + tags: always + - name: Display PostgreSQL infrastructure status debug: msg: | @@ -136,4 +141,4 @@ 📊 Checksums: {{ 'Enabled' if postgresql_data_checksums else 'Disabled' }} {% if postgresql_unix_socket_enabled %}🔌 Socket: {{ postgresql_unix_socket_directories }} (mode {{ postgresql_unix_socket_permissions }}){% endif %} - 🏗️ Ready for applications to create databases/users \ No newline at end of file + 🏗️ Ready for applications to create databases/users diff --git a/roles/valkey/tasks/main.yml b/roles/valkey/tasks/main.yml index ab5fced..aab78f5 100644 --- a/roles/valkey/tasks/main.yml +++ b/roles/valkey/tasks/main.yml @@ -143,6 +143,11 @@ failed_when: valkey_ping_result_socket.stdout != "PONG" when: valkey_service_state == "started" and valkey_unix_socket_enabled +# Containerized applications mount socket directories. If handlers run at the end of playbooks this will mount stale sockets. +- name: Flush handlers for socket connection + meta: flush_handlers + tags: always + - name: Display Valkey infrastructure status debug: msg: |