Deploy Nextcloud file sync/share with automated installation (#4)
This commit implements a complete Nextcloud deployment with PostgreSQL, Redis, automated installation, and preparation for OIDC/SSO integration with Zitadel. ## Nextcloud Deployment ### New Ansible Role (ansible/roles/nextcloud/) - Complete Nextcloud v30 deployment with Docker Compose - PostgreSQL 16 backend with persistent volumes - Redis 7 for caching and file locking - Automated installation via Docker environment variables - Post-installation configuration via occ commands ### Features Implemented - **Database**: PostgreSQL with proper credentials and persistence - **Caching**: Redis for memory caching and file locking - **HTTPS**: Traefik integration with Let's Encrypt SSL - **Security**: Proper security headers and HSTS - **WebDAV**: CalDAV/CardDAV redirect middleware - **Configuration**: Automated trusted domain, reverse proxy, and Redis setup - **OIDC Preparation**: user_oidc app installed and enabled ### Traefik Updates - Added Nextcloud routing to dynamic.yml (static file-based config) - Configured CalDAV/CardDAV redirect middleware - Added Nextcloud-specific security headers ### Configuration Tasks - Automated trusted domain configuration for nextcloud.test.vrije.cloud - Reverse proxy overwrite settings (protocol, host, CLI URL) - Redis cache and locking configuration - Default phone region (NL) - Background jobs via cron ## Deployment Status ✅ Successfully deployed and tested: - Nextcloud: https://nextcloud.test.vrije.cloud/ - Admin login working - PostgreSQL database initialized - Redis caching operational - HTTPS with Let's Encrypt SSL - user_oidc app installed (ready for Zitadel integration) ## Next Steps To complete OIDC/SSO integration: 1. Create OIDC application in Zitadel console 2. Use redirect URI: https://nextcloud.test.vrije.cloud/apps/user_oidc/code 3. Configure provider in Nextcloud with Zitadel credentials Partially addresses #4 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
054e0e1e87
commit
93ce586b94
9 changed files with 327 additions and 2 deletions
|
|
@ -26,8 +26,14 @@
|
|||
zitadel_domain: "{{ client_secrets.zitadel_domain }}"
|
||||
when: client_secrets.zitadel_domain is defined
|
||||
|
||||
- name: Set client domain from secrets
|
||||
set_fact:
|
||||
client_domain: "{{ client_secrets.client_domain }}"
|
||||
when: client_secrets.client_domain is defined
|
||||
|
||||
roles:
|
||||
- role: zitadel
|
||||
- role: nextcloud
|
||||
|
||||
post_tasks:
|
||||
- name: Display deployment summary
|
||||
|
|
@ -36,8 +42,11 @@
|
|||
Deployment complete for client: {{ client_name }}
|
||||
|
||||
Zitadel: https://{{ zitadel_domain }}
|
||||
Nextcloud: https://nextcloud.{{ client_domain }}
|
||||
|
||||
Next steps:
|
||||
1. Login to Zitadel with the admin credentials
|
||||
2. Change the admin password
|
||||
3. Configure OIDC applications for Nextcloud (when deployed)
|
||||
2. Create OIDC application in Zitadel for Nextcloud
|
||||
- Client name: Nextcloud
|
||||
- Redirect URI: https://nextcloud.{{ client_domain }}/apps/user_oidc/code
|
||||
3. Configure OIDC in Nextcloud using the client ID and secret from Zitadel
|
||||
|
|
|
|||
36
ansible/roles/nextcloud/defaults/main.yml
Normal file
36
ansible/roles/nextcloud/defaults/main.yml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
# Default variables for nextcloud role
|
||||
|
||||
# Nextcloud version
|
||||
nextcloud_version: "30" # Latest stable version (uses major version tag)
|
||||
|
||||
# Database configuration
|
||||
nextcloud_db_type: "pgsql"
|
||||
nextcloud_db_host: "nextcloud-db"
|
||||
nextcloud_db_port: "5432"
|
||||
nextcloud_db_name: "nextcloud"
|
||||
nextcloud_db_user: "nextcloud"
|
||||
|
||||
# Admin user configuration
|
||||
nextcloud_admin_user: "admin"
|
||||
|
||||
# Nextcloud domain (will be set from client_domain variable)
|
||||
nextcloud_domain: "nextcloud.{{ client_domain }}"
|
||||
|
||||
# Redis configuration for caching and file locking
|
||||
nextcloud_redis_host: "nextcloud-redis"
|
||||
nextcloud_redis_port: "6379"
|
||||
|
||||
# OIDC configuration
|
||||
nextcloud_oidc_enabled: true
|
||||
nextcloud_oidc_provider_url: "https://{{ zitadel_domain }}"
|
||||
nextcloud_oidc_client_id: "" # Will be set after creating app in Zitadel
|
||||
nextcloud_oidc_client_secret: "" # Will be set after creating app in Zitadel
|
||||
|
||||
# Trusted domains (for Nextcloud config)
|
||||
nextcloud_trusted_domains:
|
||||
- "{{ nextcloud_domain }}"
|
||||
|
||||
# PHP memory limit
|
||||
nextcloud_php_memory_limit: "512M"
|
||||
nextcloud_php_upload_limit: "16G"
|
||||
7
ansible/roles/nextcloud/handlers/main.yml
Normal file
7
ansible/roles/nextcloud/handlers/main.yml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
# Handlers for Nextcloud role
|
||||
|
||||
- name: Restart Nextcloud
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: /opt/nextcloud
|
||||
state: restarted
|
||||
29
ansible/roles/nextcloud/tasks/docker.yml
Normal file
29
ansible/roles/nextcloud/tasks/docker.yml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
# Docker deployment tasks for Nextcloud
|
||||
|
||||
- name: Create Nextcloud directory
|
||||
file:
|
||||
path: /opt/nextcloud
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Deploy Nextcloud Docker Compose file
|
||||
template:
|
||||
src: docker-compose.nextcloud.yml.j2
|
||||
dest: /opt/nextcloud/docker-compose.yml
|
||||
mode: '0600'
|
||||
notify: Restart Nextcloud
|
||||
|
||||
- name: Start Nextcloud services
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: /opt/nextcloud
|
||||
state: present
|
||||
register: nextcloud_deploy
|
||||
|
||||
- name: Wait for Nextcloud to be ready
|
||||
wait_for:
|
||||
host: localhost
|
||||
port: 80
|
||||
delay: 10
|
||||
timeout: 120
|
||||
when: nextcloud_deploy.changed
|
||||
43
ansible/roles/nextcloud/tasks/install.yml
Normal file
43
ansible/roles/nextcloud/tasks/install.yml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
# Automated Nextcloud installation tasks using occ commands
|
||||
|
||||
- name: Wait for Nextcloud container to be healthy
|
||||
shell: docker exec -u www-data nextcloud php -v
|
||||
register: nextcloud_health
|
||||
retries: 30
|
||||
delay: 10
|
||||
until: nextcloud_health.rc == 0
|
||||
changed_when: false
|
||||
|
||||
- name: Wait for Nextcloud auto-installation to complete
|
||||
shell: "docker exec -u www-data nextcloud php occ status 2>&1 | grep -q 'installed: true'"
|
||||
register: nextcloud_status
|
||||
retries: 60
|
||||
delay: 5
|
||||
until: nextcloud_status.rc == 0
|
||||
changed_when: false
|
||||
|
||||
- name: Configure trusted domains
|
||||
shell: |
|
||||
docker exec -u www-data nextcloud php occ config:system:set trusted_domains 0 --value="{{ nextcloud_domain }}"
|
||||
|
||||
- name: Configure overwrite settings for reverse proxy
|
||||
shell: |
|
||||
docker exec -u www-data nextcloud php occ config:system:set overwriteprotocol --value="https"
|
||||
docker exec -u www-data nextcloud php occ config:system:set overwritehost --value="{{ nextcloud_domain }}"
|
||||
docker exec -u www-data nextcloud php occ config:system:set overwrite.cli.url --value="https://{{ nextcloud_domain }}"
|
||||
|
||||
- name: Configure Redis for caching
|
||||
shell: |
|
||||
docker exec -u www-data nextcloud php occ config:system:set redis host --value="{{ nextcloud_redis_host }}"
|
||||
docker exec -u www-data nextcloud php occ config:system:set redis port --value="{{ nextcloud_redis_port }}"
|
||||
docker exec -u www-data nextcloud php occ config:system:set memcache.local --value="\OC\Memcache\Redis"
|
||||
docker exec -u www-data nextcloud php occ config:system:set memcache.locking --value="\OC\Memcache\Redis"
|
||||
|
||||
- name: Set default phone region
|
||||
shell: |
|
||||
docker exec -u www-data nextcloud php occ config:system:set default_phone_region --value="NL"
|
||||
|
||||
- name: Run background jobs via cron
|
||||
shell: |
|
||||
docker exec -u www-data nextcloud php occ background:cron
|
||||
21
ansible/roles/nextcloud/tasks/main.yml
Normal file
21
ansible/roles/nextcloud/tasks/main.yml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
# Main tasks for Nextcloud deployment
|
||||
|
||||
- name: Include Docker deployment tasks
|
||||
include_tasks: docker.yml
|
||||
tags:
|
||||
- nextcloud
|
||||
- docker
|
||||
|
||||
- name: Include installation tasks
|
||||
include_tasks: install.yml
|
||||
tags:
|
||||
- nextcloud
|
||||
- install
|
||||
|
||||
- name: Include OIDC configuration tasks
|
||||
include_tasks: oidc.yml
|
||||
when: nextcloud_oidc_enabled | default(true)
|
||||
tags:
|
||||
- nextcloud
|
||||
- oidc
|
||||
36
ansible/roles/nextcloud/tasks/oidc.yml
Normal file
36
ansible/roles/nextcloud/tasks/oidc.yml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
# OIDC/SSO integration tasks for Nextcloud with Zitadel
|
||||
|
||||
- name: Check if user_oidc app is installed
|
||||
shell: docker exec -u www-data nextcloud php occ app:list --output=json
|
||||
register: nextcloud_apps
|
||||
changed_when: false
|
||||
|
||||
- name: Parse installed apps
|
||||
set_fact:
|
||||
user_oidc_installed: "{{ 'user_oidc' in (nextcloud_apps.stdout | from_json).enabled }}"
|
||||
|
||||
- name: Install user_oidc app
|
||||
shell: docker exec -u www-data nextcloud php occ app:install user_oidc
|
||||
when: not user_oidc_installed
|
||||
register: oidc_install
|
||||
changed_when: "'installed' in oidc_install.stdout"
|
||||
|
||||
- name: Enable user_oidc app
|
||||
shell: docker exec -u www-data nextcloud php occ app:enable user_oidc
|
||||
when: not user_oidc_installed
|
||||
|
||||
# Note: OIDC provider configuration requires the Zitadel application to be created first
|
||||
# This will be configured manually or via Zitadel API in a follow-up task
|
||||
- name: Display OIDC configuration instructions
|
||||
debug:
|
||||
msg: |
|
||||
To complete OIDC setup:
|
||||
1. Create an OIDC application in Zitadel console at https://{{ zitadel_domain }}
|
||||
2. Use redirect URI: https://{{ nextcloud_domain }}/apps/user_oidc/code
|
||||
3. Configure the provider in Nextcloud using:
|
||||
docker exec -u www-data nextcloud php occ user_oidc:provider:add \
|
||||
--clientid="<client_id>" \
|
||||
--clientsecret="<client_secret>" \
|
||||
--discoveryuri="https://{{ zitadel_domain }}/.well-known/openid-configuration" \
|
||||
"Zitadel"
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
services:
|
||||
# PostgreSQL Database for Nextcloud
|
||||
nextcloud-db:
|
||||
image: postgres:16-alpine
|
||||
container_name: nextcloud-db
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- nextcloud-db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_DB: {{ nextcloud_db_name }}
|
||||
POSTGRES_USER: {{ nextcloud_db_user }}
|
||||
POSTGRES_PASSWORD: {{ client_secrets.nextcloud_db_password }}
|
||||
# Grant full privileges to the user
|
||||
POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256"
|
||||
networks:
|
||||
- nextcloud-internal
|
||||
|
||||
# Redis for caching and file locking
|
||||
nextcloud-redis:
|
||||
image: redis:7-alpine
|
||||
container_name: nextcloud-redis
|
||||
restart: unless-stopped
|
||||
command: redis-server --save 60 1 --loglevel warning
|
||||
volumes:
|
||||
- nextcloud-redis-data:/data
|
||||
networks:
|
||||
- nextcloud-internal
|
||||
|
||||
# Nextcloud application
|
||||
nextcloud:
|
||||
image: nextcloud:{{ nextcloud_version }}
|
||||
container_name: nextcloud
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- nextcloud-db
|
||||
- nextcloud-redis
|
||||
volumes:
|
||||
- nextcloud-data:/var/www/html
|
||||
environment:
|
||||
# Database configuration
|
||||
POSTGRES_HOST: {{ nextcloud_db_host }}
|
||||
POSTGRES_DB: {{ nextcloud_db_name }}
|
||||
POSTGRES_USER: {{ nextcloud_db_user }}
|
||||
POSTGRES_PASSWORD: {{ client_secrets.nextcloud_db_password }}
|
||||
|
||||
# Redis configuration
|
||||
REDIS_HOST: {{ nextcloud_redis_host }}
|
||||
REDIS_HOST_PORT: {{ nextcloud_redis_port }}
|
||||
|
||||
# Nextcloud configuration
|
||||
NEXTCLOUD_ADMIN_USER: {{ nextcloud_admin_user }}
|
||||
NEXTCLOUD_ADMIN_PASSWORD: {{ client_secrets.nextcloud_admin_password }}
|
||||
NEXTCLOUD_TRUSTED_DOMAINS: {{ nextcloud_domain }}
|
||||
OVERWRITEPROTOCOL: https
|
||||
OVERWRITEHOST: {{ nextcloud_domain }}
|
||||
OVERWRITECLIURL: https://{{ nextcloud_domain }}
|
||||
|
||||
# PHP configuration
|
||||
PHP_MEMORY_LIMIT: {{ nextcloud_php_memory_limit }}
|
||||
PHP_UPLOAD_LIMIT: {{ nextcloud_php_upload_limit }}
|
||||
|
||||
# SMTP configuration (optional, can be configured via OIDC later)
|
||||
# SMTP_HOST:
|
||||
# SMTP_SECURE:
|
||||
# SMTP_PORT:
|
||||
# SMTP_NAME:
|
||||
# SMTP_PASSWORD:
|
||||
# MAIL_FROM_ADDRESS:
|
||||
# MAIL_DOMAIN:
|
||||
networks:
|
||||
- traefik
|
||||
- nextcloud-internal
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik"
|
||||
|
||||
# HTTP Router
|
||||
- "traefik.http.routers.nextcloud.rule=Host(`{{ nextcloud_domain }}`)"
|
||||
- "traefik.http.routers.nextcloud.entrypoints=websecure"
|
||||
- "traefik.http.routers.nextcloud.tls=true"
|
||||
- "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
|
||||
|
||||
# Middleware for Nextcloud
|
||||
- "traefik.http.routers.nextcloud.middlewares=nextcloud-headers,nextcloud-redirectregex"
|
||||
|
||||
# Security headers
|
||||
- "traefik.http.middlewares.nextcloud-headers.headers.stsSeconds=31536000"
|
||||
- "traefik.http.middlewares.nextcloud-headers.headers.stsIncludeSubdomains=true"
|
||||
- "traefik.http.middlewares.nextcloud-headers.headers.stsPreload=true"
|
||||
|
||||
# CalDAV/CardDAV redirect
|
||||
- "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.permanent=true"
|
||||
- "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.regex=https://(.*)/.well-known/(card|cal)dav"
|
||||
- "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.replacement=https://$$1/remote.php/dav/"
|
||||
|
||||
# Service
|
||||
- "traefik.http.services.nextcloud.loadbalancer.server.port=80"
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
nextcloud-internal:
|
||||
name: nextcloud-internal
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
nextcloud-db-data:
|
||||
name: nextcloud-db-data
|
||||
nextcloud-redis-data:
|
||||
name: nextcloud-redis-data
|
||||
nextcloud-data:
|
||||
name: nextcloud-data
|
||||
|
|
@ -14,6 +14,18 @@ http:
|
|||
middlewares:
|
||||
- zitadel-headers
|
||||
|
||||
# Nextcloud file sync/share
|
||||
nextcloud:
|
||||
rule: "Host(`nextcloud.test.vrije.cloud`)"
|
||||
service: nextcloud
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
middlewares:
|
||||
- nextcloud-headers
|
||||
- nextcloud-redirectregex
|
||||
|
||||
services:
|
||||
# Zitadel service
|
||||
zitadel:
|
||||
|
|
@ -21,6 +33,12 @@ http:
|
|||
servers:
|
||||
- url: "h2c://zitadel:8080"
|
||||
|
||||
# Nextcloud service
|
||||
nextcloud:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://nextcloud:80"
|
||||
|
||||
middlewares:
|
||||
# Zitadel-specific headers
|
||||
zitadel-headers:
|
||||
|
|
@ -29,6 +47,20 @@ http:
|
|||
stsIncludeSubdomains: true
|
||||
stsPreload: true
|
||||
|
||||
# Nextcloud-specific headers
|
||||
nextcloud-headers:
|
||||
headers:
|
||||
stsSeconds: 31536000
|
||||
stsIncludeSubdomains: true
|
||||
stsPreload: true
|
||||
|
||||
# CalDAV/CardDAV redirect for Nextcloud
|
||||
nextcloud-redirectregex:
|
||||
redirectRegex:
|
||||
permanent: true
|
||||
regex: "https://(.*)/.well-known/(card|cal)dav"
|
||||
replacement: "https://$1/remote.php/dav/"
|
||||
|
||||
# Security headers
|
||||
security-headers:
|
||||
headers:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue