From 7019b307c5eac42493e1ddcaec13a27c26321145 Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Wed, 20 Aug 2025 01:00:20 +0200 Subject: [PATCH] Optimized collabora draft --- roles/web-app-nextcloud/config/main.yml | 16 +++---- roles/web-app-nextcloud/meta/main.yml | 1 - roles/web-app-nextcloud/tasks/01_config.yml | 4 +- roles/web-app-nextcloud/tasks/main.yml | 7 +++ .../templates/docker-compose.yml.j2 | 10 ++--- roles/web-app-nextcloud/vars/main.yml | 43 +++++++++++-------- .../vars/plugins/richdocuments.yml | 15 +++++++ roles/web-svc-collabora/README.md | 30 +++++++++++++ roles/web-svc-collabora/config/main.yml | 16 +++++++ roles/web-svc-collabora/meta/main.yml | 27 ++++++++++++ roles/web-svc-collabora/tasks/main.yml | 6 +++ .../templates/docker-compose.yml.j2 | 18 ++++++++ roles/web-svc-collabora/templates/env.j2 | 4 ++ .../web-svc-collabora/templates/nginx.conf.j2 | 22 ++++++++++ roles/web-svc-collabora/vars/main.yml | 11 +++++ 15 files changed, 195 insertions(+), 35 deletions(-) create mode 100644 roles/web-app-nextcloud/vars/plugins/richdocuments.yml create mode 100644 roles/web-svc-collabora/README.md create mode 100644 roles/web-svc-collabora/config/main.yml create mode 100644 roles/web-svc-collabora/meta/main.yml create mode 100644 roles/web-svc-collabora/tasks/main.yml create mode 100644 roles/web-svc-collabora/templates/docker-compose.yml.j2 create mode 100644 roles/web-svc-collabora/templates/env.j2 create mode 100644 roles/web-svc-collabora/templates/nginx.conf.j2 create mode 100644 roles/web-svc-collabora/vars/main.yml diff --git a/roles/web-app-nextcloud/config/main.yml b/roles/web-app-nextcloud/config/main.yml index 524ccb86..d948c739 100644 --- a/roles/web-app-nextcloud/config/main.yml +++ b/roles/web-app-nextcloud/config/main.yml @@ -9,11 +9,14 @@ server: whitelist: font-src: - "data:" + #frame-src: + # - "" domains: canonical: - "cloud.{{ PRIMARY_DOMAIN }}" - # nextcloud: "cloud.{{ PRIMARY_DOMAIN }}" # talk: "talk.{{ PRIMARY_DOMAIN }}" @todo needs to be activated + helpers: + collabora: "{{ WEB_PROTOCOL ~ '://' ~ applications | get_app_conf('web-svc-collabora','server.domains.canonical[0]',False,'<< defaults_applications[web-svc-collabora].server.domains.canonical[0]>>') }}" docker: volumes: data: nextcloud_data @@ -41,13 +44,8 @@ docker: image: "nextcloud/aio-talk" version: "latest" enabled: false # Not enabled yet, because just implemented during refactoring and not tested yet. if tested activate - # Its in a own role. @todo remove it if it gets implemented via the other role - #collabora: - # name: "nextcloud-collabora" - # image: "nextcloud-collabora" - # version: "latest" oidc: - enabled: " {{ applications | get_app_conf('web-app-nextcloud', 'features.oidc', False, True) }}" # Activate OIDC for Nextcloud + enabled: "{{ applications | get_app_conf('web-app-nextcloud', 'features.oidc', False, True) }}" # Activate OIDC for Nextcloud # floavor decides which OICD plugin should be used. # Available options: oidc_login, sociallogin # @see https://apps.nextcloud.com/apps/oidc_login @@ -149,7 +147,7 @@ plugins: enabled: false fileslibreofficeedit: # Nextcloud LibreOffice integration: allows online editing of documents with LibreOffice (https://apps.nextcloud.com/apps/fileslibreofficeedit) - enabled: true + enabled: "{{ not (applications | get_app_conf('web-app-nextcloud', 'plugins.richdocuments.enabled', False, True)) }}" forms: # Nextcloud forms: facilitates creation of forms and surveys (https://apps.nextcloud.com/apps/forms) enabled: true @@ -225,7 +223,7 @@ plugins: enabled: false # Deactivated because it let to bugs richdocuments: # Nextcloud Rich Documents: provides collaborative document editing capabilities (https://apps.nextcloud.com/apps/richdocuments) - enabled: false # @todo To set it default to true activate https://hub.docker.com/r/collabora/code before + enabled: true # @todo To set it default to true activate https://hub.docker.com/r/collabora/code before sociallogin: # Nextcloud social login: allows authentication using social networks (https://apps.nextcloud.com/apps/sociallogin) enabled: "{{ _applications_nextcloud_oidc_flavor=='sociallogin' | lower }}" diff --git a/roles/web-app-nextcloud/meta/main.yml b/roles/web-app-nextcloud/meta/main.yml index c0b5ca15..68d63ba4 100644 --- a/roles/web-app-nextcloud/meta/main.yml +++ b/roles/web-app-nextcloud/meta/main.yml @@ -29,6 +29,5 @@ galaxy_info: logo: class: "fa-solid fa-cloud" run_after: - - web-app-collabora - web-app-keycloak - web-app-mastodon diff --git a/roles/web-app-nextcloud/tasks/01_config.yml b/roles/web-app-nextcloud/tasks/01_config.yml index d49518a3..ce6e748c 100644 --- a/roles/web-app-nextcloud/tasks/01_config.yml +++ b/roles/web-app-nextcloud/tasks/01_config.yml @@ -9,10 +9,10 @@ - name: Flush handlers so Nextcloud container is restarted and ready meta: flush_handlers - - name: "Wait until Nextcloud is reachable on port {{ports.localhost.http[application_id]}}" + - name: "Wait until Nextcloud is reachable on port {{ ports.localhost.http[application_id] }}" wait_for: host: 127.0.0.1 - port: "{{ports.localhost.http[application_id]}}" + port: "{{ ports.localhost.http[application_id] }}" timeout: 120 delay: 2 state: started diff --git a/roles/web-app-nextcloud/tasks/main.yml b/roles/web-app-nextcloud/tasks/main.yml index c310d8eb..41caed74 100644 --- a/roles/web-app-nextcloud/tasks/main.yml +++ b/roles/web-app-nextcloud/tasks/main.yml @@ -1,4 +1,11 @@ --- +#- name: "Install Collabora Dependency" +# include_role: +# name: web-svc-collabora +# vars: +# flush_handlers: true +# when: NEXTCLOUD_COLLABORA_ENABLED + - name: "include role for {{ application_id }} to receive certs & do modification routines" include_role: name: srv-web-7-6-composer diff --git a/roles/web-app-nextcloud/templates/docker-compose.yml.j2 b/roles/web-app-nextcloud/templates/docker-compose.yml.j2 index d11cee41..1f8bb894 100644 --- a/roles/web-app-nextcloud/templates/docker-compose.yml.j2 +++ b/roles/web-app-nextcloud/templates/docker-compose.yml.j2 @@ -4,10 +4,10 @@ image: "{{ nextcloud_image }}:{{ nextcloud_version }}" container_name: {{ nextcloud_container }} volumes: - - data:{{nextcloud_docker_work_directory}} + - data:{{ NEXTCLOUD_DOCKER_WORK_DIRECTORY }} - {{nextcloud_host_config_additives_directory}}:{{nextcloud_docker_config_additives_directory}}:ro healthcheck: - test: ["CMD", "su", "www-data", "-s", "/bin/sh", "-c", "php {{nextcloud_docker_work_directory}}occ status"] + test: ["CMD", "su", "www-data", "-s", "/bin/sh", "-c", "php {{ NEXTCLOUD_DOCKER_WORK_DIRECTORY }}occ status"] interval: 1m timeout: 10s retries: 3 @@ -39,7 +39,7 @@ driver: journald restart: {{ DOCKER_RESTART_POLICY }} ports: - - "127.0.0.1:{{ports.localhost.http[application_id]}}:{{ container_port }}" + - "127.0.0.1:{{ ports.localhost.http[application_id] }}:{{ container_port }}" volumes: - "{{ docker_compose.directories.volumes }}nginx.conf:/etc/nginx/nginx.conf:ro" volumes_from: @@ -57,10 +57,10 @@ logging: driver: journald volumes: - - data:{{nextcloud_docker_work_directory}} + - data:{{ NEXTCLOUD_DOCKER_WORK_DIRECTORY }} entrypoint: /cron.sh healthcheck: - test: ["CMD", "su", "www-data", "-s", "/bin/sh", "-c", "php {{nextcloud_docker_work_directory}}occ status"] + test: ["CMD", "su", "www-data", "-s", "/bin/sh", "-c", "php {{ NEXTCLOUD_DOCKER_WORK_DIRECTORY }}occ status"] interval: 1m timeout: 10s retries: 3 diff --git a/roles/web-app-nextcloud/vars/main.yml b/roles/web-app-nextcloud/vars/main.yml index aa62bfcd..9088a320 100644 --- a/roles/web-app-nextcloud/vars/main.yml +++ b/roles/web-app-nextcloud/vars/main.yml @@ -11,7 +11,7 @@ http_port: "{{ ports.localhost.http[applica database_password: "{{ applications | get_app_conf(application_id, 'credentials.database_password', True)}}" database_type: "mariadb" # Database flavor -nextcloud_plugins_enabled: "{{ applications | get_app_conf(application_id, 'plugins_enabled', True) }}" +nextcloud_plugins_enabled: "{{ applications | get_app_conf(application_id, 'plugins_enabled') }}" nextcloud_administrator_username: "{{ applications | get_app_conf(application_id, 'users.administrator.username') }}" # Control Node @@ -27,38 +27,45 @@ nextcloud_host_nginx_path: "{{ NGINX.DIRECTORIES.HTTP.SERVE # Docker -nextcloud_volume: "{{ applications | get_app_conf(application_id, 'docker.volumes.data', True) }}" +nextcloud_volume: "{{ applications | get_app_conf(application_id, 'docker.volumes.data') }}" -nextcloud_version: "{{ applications | get_app_conf(application_id, 'docker.services.nextcloud.version', True) }}" -nextcloud_image: "{{ applications | get_app_conf(application_id, 'docker.services.nextcloud.image', True) }}" -nextcloud_container: "{{ applications | get_app_conf(application_id, 'docker.services.nextcloud.name', True) }}" +nextcloud_version: "{{ applications | get_app_conf(application_id, 'docker.services.nextcloud.version') }}" +nextcloud_image: "{{ applications | get_app_conf(application_id, 'docker.services.nextcloud.image') }}" +nextcloud_container: "{{ applications | get_app_conf(application_id, 'docker.services.nextcloud.name') }}" -nextcloud_proxy_name: "{{ applications | get_app_conf(application_id, 'docker.services.proxy.name', True) }}" -nextcloud_proxy_image: "{{ applications | get_app_conf(application_id, 'docker.services.proxy.image', True) }}" -nextcloud_proxy_version: "{{ applications | get_app_conf(application_id, 'docker.services.proxy.version', True) }}" +nextcloud_proxy_name: "{{ applications | get_app_conf(application_id, 'docker.services.proxy.name') }}" +nextcloud_proxy_image: "{{ applications | get_app_conf(application_id, 'docker.services.proxy.image') }}" +nextcloud_proxy_version: "{{ applications | get_app_conf(application_id, 'docker.services.proxy.version') }}" -nextcloud_cron_name: "{{ applications | get_app_conf(application_id, 'docker.services.cron.name', True) }}" +nextcloud_cron_name: "{{ applications | get_app_conf(application_id, 'docker.services.cron.name') }}" -nextcloud_talk_name: "{{ applications | get_app_conf(application_id, 'docker.services.talk.name', True) }}" -nextcloud_talk_image: "{{ applications | get_app_conf(application_id, 'docker.services.talk.image', True) }}" -nextcloud_talk_version: "{{ applications | get_app_conf(application_id, 'docker.services.talk.version', True) }}" +# Plugins + +## Talk +nextcloud_talk_name: "{{ applications | get_app_conf(application_id, 'docker.services.talk.name') }}" +nextcloud_talk_image: "{{ applications | get_app_conf(application_id, 'docker.services.talk.image') }}" +nextcloud_talk_version: "{{ applications | get_app_conf(application_id, 'docker.services.talk.version') }}" nextcloud_talk_enabled: "{{ applications | is_docker_service_enabled(application_id, 'talk') }}" nextcloud_talk_stun_port: "{{ ports.public.stun[application_id] }}" # nextcloud_talk_domain: "{{ domains[application_id].talk }}" -#nextcloud_collabora_name: "{{ applications | get_app_conf(application_id, 'docker.services.collabora.name', True) }}" +# Collabora +#nextcloud_collabora_name: "{{ applications | get_app_conf(application_id, 'docker.services.collabora.name') }}" +NEXTCLOUD_COLLABORA_URL: "{{ domains | get_url('web-svc-collabora', WEB_PROTOCOL) }}" +#NEXTCLOUD_COLLABORA_DOMAIN: "{{ domains | get_domain('web-svc-collabora') }}" +NEXTCLOUD_COLLABORA_ENABLED: "{{ applications | get_app_conf(application_id, 'plugins.richdocuments.enabled') }}" ## User Configuration nextcloud_docker_user_id: 82 # UID of the www-data user nextcloud_docker_user: "www-data" # Name of the www-data user (Set here to easy change it in the future) ## Internal Paths -nextcloud_docker_work_directory: "/var/www/html/" # Name of the workdir in which the application is stored -nextcloud_docker_config_directory: "{{nextcloud_docker_work_directory}}config/" # Folder in which the Nextcloud configurations are stored -nextcloud_docker_config_file: "{{nextcloud_docker_config_directory}}config.php" # Path to the Nextcloud configuration file -nextcloud_docker_config_additives_directory: "{{nextcloud_docker_config_directory}}infinito/" # Path to the folder which contains additional configurations +NEXTCLOUD_DOCKER_WORK_DIRECTORY: "/var/www/html/" # Name of the workdir in which the application is stored +NEXTCLOUD_DOCKER_CONFIG_DIRECTORY: "{{ NEXTCLOUD_DOCKER_WORK_DIRECTORY }}config/" # Folder in which the Nextcloud configurations are stored +nextcloud_docker_config_file: "{{ NEXTCLOUD_DOCKER_CONFIG_DIRECTORY }}config.php" # Path to the Nextcloud configuration file +nextcloud_docker_config_additives_directory: "{{ NEXTCLOUD_DOCKER_CONFIG_DIRECTORY }}infinito/" # Path to the folder which contains additional configurations nextcloud_docker_include_instructions_file: "/tmp/includes.php" # Path to the temporary file which will be included to the config.php to load the additional configurations ## Execution nextcloud_docker_exec: "docker exec -u {{ nextcloud_docker_user }} {{ nextcloud_container }}" # General execute composition -nextcloud_docker_exec_occ: "{{nextcloud_docker_exec}} {{ nextcloud_docker_work_directory }}occ" # Execute docker occ command \ No newline at end of file +nextcloud_docker_exec_occ: "{{nextcloud_docker_exec}} {{ NEXTCLOUD_DOCKER_WORK_DIRECTORY }}occ" # Execute docker occ command \ No newline at end of file diff --git a/roles/web-app-nextcloud/vars/plugins/richdocuments.yml b/roles/web-app-nextcloud/vars/plugins/richdocuments.yml new file mode 100644 index 00000000..96ec35e8 --- /dev/null +++ b/roles/web-app-nextcloud/vars/plugins/richdocuments.yml @@ -0,0 +1,15 @@ +plugin_configuration: + - appid: "richdocuments" + configkey: "wopi_url" + configvalue: "{{ NEXTCLOUD_COLLABORA_URL }}" + + # Optional, but helpful if you ever front Collabora by a CDN: + - appid: "richdocuments" + configkey: "public_wopi_url" + configvalue: "{{ NEXTCLOUD_COLLABORA_URL }}" + + # Only use this if you terminate TLS in front and run CODE plain HTTP behind it. + # 0 = verify certs (recommended), 1 = skip verification + - appid: "richdocuments" + configkey: "disable_certificate_verification" + configvalue: 0 diff --git a/roles/web-svc-collabora/README.md b/roles/web-svc-collabora/README.md new file mode 100644 index 00000000..852870c6 --- /dev/null +++ b/roles/web-svc-collabora/README.md @@ -0,0 +1,30 @@ +# Docker Collabora (DRAFT) + +## Description + +This Ansible role deploys Collabora Online (CODE) in Docker to enable real-time, in-browser document editing for Nextcloud. It automates the setup of the Collabora CODE container, Nginx reverse proxy configuration, network isolation via Docker networks, and environment variable management. + +## Overview + +* **Dockerized Collabora CODE:** Uses the official `collabora/code` image. +* **Nginx Reverse Proxy:** Configures a public-facing proxy with TLS termination and WebSocket support for `/cool/` paths. +* **Docker Network Management:** Creates an isolated `/28` subnet for Collabora and connects containers securely. +* **Environment Configuration:** Generates a `.env` file with domain, credentials, and extra parameters for Collabora's WOPI server. + +## Features + +* Automatic creation of a dedicated Docker network for Collabora. +* Proxy configuration template for Nginx with long timeouts and WebSocket upgrades. +* Customizable domain names and ports via Ansible variables. +* Support for SSL termination at the proxy level. +* Integration hooks to restart Nginx and recreate Docker Compose stacks on changes. + +## Documentation + +See the role’s `README.md`, task files, and Jinja2 templates in the `roles/web-svc-collabora` directory for usage examples and variable definitions. + +## Further Resources + +* [Collabora & Talk Super integration demo](https://www.youtube.com/watch?v=7cRmvTyt1ik) +* [Collabora configuration examples archive](https://cloud.thesysadminhub.com/s/FNKyP43y35HGDTJ?dir=/&openfile=true) +* [Official Collabora CODE website](https://www.collaboraoffice.com/code/) diff --git a/roles/web-svc-collabora/config/main.yml b/roles/web-svc-collabora/config/main.yml new file mode 100644 index 00000000..58d3c6a0 --- /dev/null +++ b/roles/web-svc-collabora/config/main.yml @@ -0,0 +1,16 @@ +server: + domains: + canonical: + - "collabora.{{ PRIMARY_DOMAIN }}" +docker: + services: + redis: + enabled: true + database: + enabled: false # May this is wrong. Just set during refactoring + collabora: + image: collabora/code + version: latest + name: collabora +features: + logout: false # I think collabora is more a service then a app. So no login neccessary Propably it makes sense to rename it ;) diff --git a/roles/web-svc-collabora/meta/main.yml b/roles/web-svc-collabora/meta/main.yml new file mode 100644 index 00000000..23e12b17 --- /dev/null +++ b/roles/web-svc-collabora/meta/main.yml @@ -0,0 +1,27 @@ +--- +galaxy_info: + author: "Kevin Veen-Birkenbach" + description: "Collabora Online CODE with automated proxy, networking, and environment configuration." + license: "Infinito.Nexus NonCommercial License" + license_url: "https://s.infinito.nexus/license" + company: | + Kevin Veen-Birkenbach + Consulting & Coaching Solutions + https://www.veen.world + min_ansible_version: "2.9" + platforms: + - name: Linux + versions: + - all + galaxy_tags: + - collabora + - docker + - nginx + - office + - wopi + - code + repository: "https://s.infinito.nexus/code" + issue_tracker_url: "https://s.infinito.nexus/issues" + documentation: "https://s.infinito.nexus/code/web-svc-collabora" + logo: + class: "fa-solid fa-file-code" diff --git a/roles/web-svc-collabora/tasks/main.yml b/roles/web-svc-collabora/tasks/main.yml new file mode 100644 index 00000000..f944d4f7 --- /dev/null +++ b/roles/web-svc-collabora/tasks/main.yml @@ -0,0 +1,6 @@ +- block: + - name: "load docker, proxy for '{{ application_id }}'" + include_role: + name: cmp-docker-proxy + - include_tasks: utils/run_once.yml + when: run_once_web_svc_collabora is not defined \ No newline at end of file diff --git a/roles/web-svc-collabora/templates/docker-compose.yml.j2 b/roles/web-svc-collabora/templates/docker-compose.yml.j2 new file mode 100644 index 00000000..efffcea7 --- /dev/null +++ b/roles/web-svc-collabora/templates/docker-compose.yml.j2 @@ -0,0 +1,18 @@ +{% include 'roles/docker-compose/templates/base.yml.j2' %} + + collabora: + {% include 'roles/docker-container/templates/base.yml.j2' %} + image: {{ COLLABORA_IMAGE }} + version: {{ COLLABORA_VERSION }} + container_name: {{ COLLABORA_CONTAINER }} + ports: + - "127.0.0.1:{{ ports.localhost.http[application_id] }}:{{ container_port }}" +{% include 'roles/docker-container/templates/healthcheck/curl.yml.j2' %} + healthcheck: + test: ["CMD", "curl", "-f", "http://127.0.0.1:9980/hosting/discovery"] + interval: 30s + timeout: 10s + retries: 5 +{% include 'roles/docker-container/templates/networks.yml.j2' %} + +{% include 'roles/docker-compose/templates/networks.yml.j2' %} diff --git a/roles/web-svc-collabora/templates/env.j2 b/roles/web-svc-collabora/templates/env.j2 new file mode 100644 index 00000000..101b20d0 --- /dev/null +++ b/roles/web-svc-collabora/templates/env.j2 @@ -0,0 +1,4 @@ +domain={{ (domains | get_domain('web-app-nextcloud')) | regex_replace('\\.', '\\\\.') }} +{# username=admin #} +{# password={{ applications | get_app_conf('web-svc-collabora', 'credentials.admin_password', False, 'ChangeMe!') }}" #} +extra_params=--o:ssl.enable=false --o:ssl.termination=true \ No newline at end of file diff --git a/roles/web-svc-collabora/templates/nginx.conf.j2 b/roles/web-svc-collabora/templates/nginx.conf.j2 new file mode 100644 index 00000000..70bae0c0 --- /dev/null +++ b/roles/web-svc-collabora/templates/nginx.conf.j2 @@ -0,0 +1,22 @@ +server { + server_name {{ domain }}; + + {% include 'roles/srv-web-7-7-letsencrypt/templates/ssl_header.j2' %} + {% include 'roles/sys-srv-web-inj-compose/templates/server.conf.j2'%} + + {% include 'roles/srv-proxy-7-4-core/templates/headers/content_security_policy.conf.j2' %} + + {# Normal HTTP routes (discovery, browser, assets) – no Lua injection #} + {% set proxy_lua_enabled = false %} + {% set location = "/" %} + {% include 'roles/srv-proxy-7-4-core/templates/location/html.conf.j2' %} + + {# Optional explicit fast path for discovery #} + {% set location = "= /hosting/discovery" %} + {% include 'roles/srv-proxy-7-4-core/templates/location/html.conf.j2' %} + + {# WebSocket handling for Collabora #} + {% set location_ws = '^~ /cool/' %} + {% set ws_port = http_port %} + {% include 'roles/srv-proxy-7-4-core/templates/location/ws.conf.j2' %} +} diff --git a/roles/web-svc-collabora/vars/main.yml b/roles/web-svc-collabora/vars/main.yml new file mode 100644 index 00000000..510f9109 --- /dev/null +++ b/roles/web-svc-collabora/vars/main.yml @@ -0,0 +1,11 @@ +--- +# General +application_id: web-svc-collabora +# Container +container_port: 9980 +container_healthcheck: "/hosting/discovery" + +# Collabora +COLLABORA_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.collabora.name') }}" +COLLABORA_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.collabora.image') }}" +COLLABORA_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.collabora.version') }}" \ No newline at end of file