diff --git a/ansible/roles/nextcloud/defaults/main.yml b/ansible/roles/nextcloud/defaults/main.yml index 7d2c51c..37f44a6 100644 --- a/ansible/roles/nextcloud/defaults/main.yml +++ b/ansible/roles/nextcloud/defaults/main.yml @@ -34,3 +34,12 @@ nextcloud_trusted_domains: # PHP memory limit nextcloud_php_memory_limit: "512M" nextcloud_php_upload_limit: "16G" + +# Collabora Office configuration +collabora_enabled: true +collabora_domain: "office.{{ client_domain }}" +collabora_admin_user: "admin" +# Password stored in secrets: collabora_admin_password + +# Two-factor authentication +twofactor_enforced: true diff --git a/ansible/roles/nextcloud/tasks/apps.yml b/ansible/roles/nextcloud/tasks/apps.yml new file mode 100644 index 0000000..dfc8565 --- /dev/null +++ b/ansible/roles/nextcloud/tasks/apps.yml @@ -0,0 +1,82 @@ +--- +# Install and configure Nextcloud apps + +- name: Install Collabora Office app (richdocuments) + shell: docker exec -u www-data nextcloud php occ app:install richdocuments + register: collabora_install + changed_when: "'richdocuments installed' in collabora_install.stdout" + failed_when: collabora_install.rc != 0 and 'richdocuments already installed' not in collabora_install.stderr + when: collabora_enabled | default(true) + +- name: Enable Collabora Office app + shell: docker exec -u www-data nextcloud php occ app:enable richdocuments + when: collabora_enabled | default(true) + changed_when: false + +- name: Configure Collabora WOPI URL + shell: | + docker exec -u www-data nextcloud php occ config:app:set richdocuments wopi_url --value="https://{{ collabora_domain }}" + when: collabora_enabled | default(true) + changed_when: true + +- name: Get Nextcloud internal network info + shell: docker inspect nextcloud-internal -f '{{{{ .IPAM.Config }}}}' + register: nextcloud_network + changed_when: false + when: collabora_enabled | default(true) + +- name: Configure Collabora WOPI allowlist + shell: | + docker exec -u www-data nextcloud php occ config:app:set richdocuments wopi_allowlist --value="172.18.0.0/16,172.21.0.0/16" + when: collabora_enabled | default(true) + changed_when: true + +- name: Install two-factor authentication apps + shell: docker exec -u www-data nextcloud php occ app:install {{ item }} + loop: + - twofactor_totp + - twofactor_admin + - twofactor_backupcodes + register: twofactor_install + changed_when: "'installed' in twofactor_install.stdout" + failed_when: twofactor_install.rc != 0 and 'already installed' not in twofactor_install.stderr + +- name: Enable two-factor authentication apps + shell: docker exec -u www-data nextcloud php occ app:enable {{ item }} + loop: + - twofactor_totp + - twofactor_admin + - twofactor_backupcodes + changed_when: false + +- name: Enforce two-factor authentication + shell: | + docker exec -u www-data nextcloud php occ config:system:set twofactor_enforced --value="true" --type=boolean + when: twofactor_enforced | default(true) + changed_when: true + +- name: Configure APCu for local caching + shell: | + docker exec -u www-data nextcloud php occ config:system:set memcache.local --value="\\OC\\Memcache\\APCu" + changed_when: true + +- name: Configure maintenance window + shell: | + docker exec -u www-data nextcloud php occ config:system:set maintenance_window_start --value=2 --type=integer + changed_when: true + +- name: Display apps configuration summary + debug: + msg: | + Nextcloud Apps Configured: + - Collabora Office: {{ 'Enabled' if collabora_enabled else 'Disabled' }} + WOPI URL: https://{{ collabora_domain if collabora_enabled else 'N/A' }} + - Two-Factor Auth: {{ 'Enforced' if twofactor_enforced else 'Optional' }} + - TOTP (Authenticator apps) + - Admin enforcement + - Backup codes + - Caching: + - Local: APCu + - Distributed: Redis + - Locking: Redis + - Maintenance window: 2:00 AM diff --git a/ansible/roles/nextcloud/tasks/main.yml b/ansible/roles/nextcloud/tasks/main.yml index e6aed24..2feb4fe 100644 --- a/ansible/roles/nextcloud/tasks/main.yml +++ b/ansible/roles/nextcloud/tasks/main.yml @@ -19,3 +19,9 @@ tags: - nextcloud - oidc + +- name: Include apps installation and configuration + include_tasks: apps.yml + tags: + - nextcloud + - apps diff --git a/ansible/roles/nextcloud/templates/docker-compose.nextcloud.yml.j2 b/ansible/roles/nextcloud/templates/docker-compose.nextcloud.yml.j2 index 390a99c..1c7a216 100644 --- a/ansible/roles/nextcloud/templates/docker-compose.nextcloud.yml.j2 +++ b/ansible/roles/nextcloud/templates/docker-compose.nextcloud.yml.j2 @@ -26,6 +26,20 @@ services: networks: - nextcloud-internal + # Nextcloud cron (separate container for background jobs) + nextcloud-cron: + image: nextcloud:{{ nextcloud_version }} + container_name: nextcloud-cron + restart: unless-stopped + depends_on: + - nextcloud-db + - nextcloud-redis + volumes: + - nextcloud-data:/var/www/html + entrypoint: /cron.sh + networks: + - nextcloud-internal + # Nextcloud application nextcloud: image: nextcloud:{{ nextcloud_version }} @@ -96,6 +110,42 @@ services: # Service - "traefik.http.services.nextcloud.loadbalancer.server.port=80" + # Collabora Office (online document editing) + collabora: + image: collabora/code:latest + container_name: collabora + restart: unless-stopped + environment: + - domain={{ nextcloud_domain | regex_replace('\.', '\\.') }} + - username={{ collabora_admin_user }} + - password={{ client_secrets.collabora_admin_password }} + - extra_params=--o:ssl.enable=false --o:ssl.termination=true + - MEMPROPORTION=60.0 + - MAX_DOCUMENTS=10 + - MAX_CONNECTIONS=20 + deploy: + resources: + limits: + memory: 1g + cpus: '2' + reservations: + memory: 512m + networks: + - traefik + - nextcloud-internal + labels: + - "traefik.enable=true" + - "traefik.docker.network=traefik" + + # HTTP Router + - "traefik.http.routers.collabora.rule=Host(`{{ collabora_domain }}`)" + - "traefik.http.routers.collabora.entrypoints=websecure" + - "traefik.http.routers.collabora.tls=true" + - "traefik.http.routers.collabora.tls.certresolver=letsencrypt" + + # Service + - "traefik.http.services.collabora.loadbalancer.server.port=9980" + networks: traefik: external: true diff --git a/docs/COLLABORA_SETUP.md b/docs/COLLABORA_SETUP.md new file mode 100644 index 0000000..41040c5 --- /dev/null +++ b/docs/COLLABORA_SETUP.md @@ -0,0 +1,218 @@ +# Collabora Office Setup + +## Password Configuration + +Add the following to `secrets/clients/test.sops.yaml`: + +```bash +cd infrastructure +export SOPS_AGE_KEY_FILE="$PWD/keys/age-key.txt" +sops secrets/clients/test.sops.yaml +``` + +Then add this line: + +```yaml +collabora_admin_password: 7ju5h70L47xJMCoADgKiZIhSak4cwq0B +``` + +Save and exit. SOPS will automatically re-encrypt the file. + +## Features Added + +### 1. Collabora Office Container +- Online document editing (Word, Excel, PowerPoint) +- Integrated with Nextcloud via WOPI protocol +- Accessible at: https://office.{client}.vrije.cloud +- Resource limits: 1GB RAM, 2 CPUs + +### 2. Separate Cron Container +- Dedicated container for background jobs +- Uses same image as Nextcloud +- Shares data volume +- Runs `/cron.sh` entrypoint + +### 3. Two-Factor Authentication +Apps installed: +- `twofactor_totp` - TOTP authenticator apps (Google Authenticator, Authy, etc.) +- `twofactor_admin` - Admin enforcement +- `twofactor_backupcodes` - Backup codes for account recovery + +Configuration: +- 2FA enforced for all users +- Users must set up 2FA on first login (after SSO) + +### 4. Dual-Cache Strategy +- **APCu**: Local in-memory cache (fast, single-server) +- **Redis**: Distributed cache and file locking (shared across containers) + +Configuration: +```php +'memcache.local' => '\\OC\\Memcache\\APCu', +'memcache.distributed' => '\\OC\\Memcache\\Redis', +'memcache.locking' => '\\OC\\Memcache\\Redis', +``` + +### 5. Maintenance Window +- Set to 2:00 AM for automatic maintenance tasks +- Minimizes user disruption + +## Deployment + +After adding the Collabora password, redeploy: + +```bash +cd infrastructure/ansible +export SOPS_AGE_KEY_FILE="../keys/age-key.txt" +export HCLOUD_TOKEN="..." + +ansible-playbook -i hcloud.yml playbooks/deploy.yml +``` + +## Collabora Configuration in Nextcloud + +The automation configures: +- WOPI URL: `https://office.{client}.vrije.cloud` +- WOPI Allowlist: Docker internal networks (172.18.0.0/16, 172.21.0.0/16) +- SSL termination: Handled by Traefik + +## Testing + +### 1. Test Collabora Office + +1. Login to Nextcloud +2. Create a new document (File → New → Document) +3. Should open Collabora Online editor +4. If it doesn't load, check: + - Collabora container is running: `docker ps | grep collabora` + - WOPI URL is configured: `docker exec -u www-data nextcloud php occ config:app:get richdocuments wopi_url` + - Network connectivity between containers + +### 2. Test Two-Factor Authentication + +1. Login to Nextcloud (via SSO or direct) +2. Should be prompted to set up 2FA +3. Use authenticator app to scan QR code +4. Enter TOTP code to verify +5. Save backup codes + +### 3. Test Cron Jobs + +Check if cron is running: +```bash +docker logs nextcloud-cron +``` + +Should see periodic job execution logs. + +### 4. Test Caching + +Check configuration: +```bash +docker exec -u www-data nextcloud php occ config:list system +``` + +Should show APCu and Redis configuration. + +## Troubleshooting + +### Collabora Not Loading + +**Symptom**: Blank page or "Failed to load" when creating documents + +**Solutions**: +1. Check Collabora is running: `docker ps | grep collabora` +2. Check Collabora logs: `docker logs collabora` +3. Verify WOPI URL: Should be `https://office.{client}.vrije.cloud` +4. Check network allowlist includes Nextcloud container IP +5. Test Collabora directly: Visit `https://office.{client}.vrije.cloud` (should show Collabora page) + +### 2FA Not Enforcing + +**Symptom**: Users can skip 2FA setup + +**Solution**: +```bash +docker exec -u www-data nextcloud php occ config:system:set twofactor_enforced --value="true" --type=boolean +``` + +### Cron Not Running + +**Symptom**: Background jobs not executing + +**Solutions**: +1. Check container: `docker ps | grep nextcloud-cron` +2. Check logs: `docker logs nextcloud-cron` +3. Restart: `docker restart nextcloud-cron` + +### Cache Not Working + +**Symptom**: Slow performance + +**Solutions**: +1. Verify APCu is installed: `docker exec nextcloud php -m | grep apcu` +2. Verify Redis connection: `docker exec nextcloud-redis redis-cli ping` +3. Check config: `docker exec -u www-data nextcloud php occ config:list system` + +## Security Considerations + +### Collabora Admin Password + +The Collabora admin interface is protected by username/password: +- Username: `admin` +- Password: Stored in secrets (SOPS encrypted) +- Access: https://office.{client}.vrije.cloud/browser/dist/admin/admin.html + +**Recommendation**: Change password after first deployment. + +### 2FA Backup Codes + +Users receive backup codes when setting up 2FA. These should be: +- Stored securely (password manager or printed) +- Used only if TOTP device is lost +- Regenerated after use + +### Network Isolation + +Collabora and Nextcloud communicate over Docker internal network: +- Not exposed to public internet +- WOPI protocol secured by allowlist +- SSL termination at Traefik edge + +## Performance Tuning + +### Collabora Resource Limits + +Default: 1GB RAM, 2 CPUs + +Adjust in `docker-compose.nextcloud.yml.j2`: +```yaml +deploy: + resources: + limits: + memory: 2g # Increase for heavy usage + cpus: '4' # More CPUs for concurrent users +``` + +### Nextcloud PHP Memory + +Default: 512M + +Increase in `defaults/main.yml`: +```yaml +nextcloud_php_memory_limit: "1G" +``` + +### Redis Memory + +Redis uses system memory dynamically. Monitor with: +```bash +docker exec nextcloud-redis redis-cli INFO memory +``` + +## References + +- [Collabora Online Documentation](https://www.collaboraoffice.com/code/) +- [Nextcloud WOPI Integration](https://docs.nextcloud.com/server/latest/admin_manual/office/configuration.html) +- [Nextcloud Two-Factor Auth](https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/two_factor-auth.html) +- [Nextcloud Caching](https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/caching_configuration.html)