Compare commits

...

8 Commits

Author SHA1 Message Date
ce3fe1cd51 Nextcloud: integrate Talk & Whiteboard; adjust ports & healthchecks
- Enable Spreed (Talk); signaling via /standalone-signaling/
- STUN/TURN: move STUN to 3480 (3479 occupied by BBB), keep TURN 5350 reserved
- docker-compose: expose internal WS ports; explicit TURN port mapping
- Healthchecks: add nc-based TCP checks (roles/docker-container/templates/healthcheck/nc.yml.j2)
- Nginx: location proxy to talk:8081
- Schema: add talk_* secrets (turn/signaling/internal)
- Plugins: configure spreed/whiteboard via vars/*; remove old task files
- Ports matrix (group_vars/all/09_ports.yml) updated/commented

Conversation: https://chatgpt.com/share/68b61a6a-e1dc-800f-b793-4aa600bc0166
2025-09-02 00:13:23 +02:00
7ca8b7c71d feat(nextcloud): integrate Talk & Whiteboard; refactor to NEXTCLOUD_* vars; full-stack setup
config(ports): add Nextcloud websocket port (4003); canonical domains (nextcloud/talk/whiteboard)

refactor: unify get_app_conf usage & Jinja spacing; migrate paths/handlers to new NEXTCLOUD_* vars

feat(plugins): split plugin routines; configure Whiteboard via occ (URL + JWT)

fix(oidc): use NEXTCLOUD_URL for logout; correct LDAP attribute mappings; add OIDC flavor switch

feat: Whiteboard container & reverse-proxy location; Talk STUN/WS ports; Redis URL for Whiteboard

chore: drop obsolete TODO; minor cleanups in oauth2-proxy, matrix, peertube, pgadmin, phpldapadmin, pixelfed, phpmyadmin

security(schema): Bluesky jwt_secret now base64_prefixed_32; add Nextcloud whiteboard_jwt_secret

db: normalize postgres image tag templating; central DB host checks spacing fixes

ops: add full-stack bootstrap (certs, proxy, volumes); internal nginx config reload handler update

refs: https://chatgpt.com/share/68b5f5b7-8d64-800f-b001-1241f818dc0e
2025-09-01 21:37:02 +02:00
110381e80c Refactored peertube role and implemented config volume 2025-09-01 18:19:50 +02:00
b02d88adc0 Refactored server roles for better readability 2025-09-01 18:08:35 +02:00
b7065837df MediaWiki: switch feature.css to false and add custom Vector 2022 override stylesheet
See: https://chatgpt.com/share/68b5b925-f418-800f-8f84-de744dd2d093
2025-09-01 17:18:12 +02:00
c98a2378c4 Added is defined condition 2025-09-01 17:05:30 +02:00
4ae3cee36c web-svc-logout: merge logout domains into CSP connect-src and refactor task flow
• Add tasks/01_core.yml to set applications[application_id].server.csp.whitelist['connect-src'] = LOGOUT_CONNECT_SRC_NEW.

• Switch tasks/main.yml to include 01_core.yml (run-once guard preserved).

• Update templates/env.j2 to emit LOGOUT_DOMAINS as a comma-separated list.

• Rework vars/main.yml: compute LOGOUT_DOMAINS, derive LOGOUT_ORIGINS with WEB_PROTOCOL, read connect-src via the get_app_conf filter, and merge/dedupe (unique).

Rationale: ensure CSP allows cross-domain logout requests for all configured services.

Conversation: https://chatgpt.com/share/68b5b07d-b208-800f-b6b2-f26934607c8a
2025-09-01 16:41:33 +02:00
b834f0c95c Implemented config image for pretix 2025-09-01 16:20:04 +02:00
142 changed files with 795 additions and 389 deletions

View File

@@ -2,12 +2,12 @@ ports:
# Ports which are exposed to localhost
localhost:
database:
svc-db-postgres: 5432
svc-db-mariadb: 3306
svc-db-postgres: 5432
svc-db-mariadb: 3306
# https://developer.mozilla.org/de/docs/Web/API/WebSockets_API
websocket:
web-app-mastodon: 4001
web-app-espocrm: 4002
web-app-mastodon: 4001
web-app-espocrm: 4002
oauth2_proxy:
web-app-phpmyadmin: 4181
web-app-lam: 4182
@@ -26,7 +26,7 @@ ports:
web-app-gitea: 8002
web-app-wordpress: 8003
web-app-mediawiki: 8004
# Free: 8005
# Free : 8005
web-app-yourls: 8006
web-app-mailu: 8007
web-app-elk: 8008
@@ -80,9 +80,10 @@ ports:
svc-db-openldap: 636
stun:
web-app-bigbluebutton: 3478 # Not sure if it's right placed here or if it should be moved to localhost section
web-app-nextcloud: 3479
# Occupied by BBB: 3479
web-app-nextcloud: 3480
turn:
web-app-bigbluebutton: 5349 # Not sure if it's right placed here or if it should be moved to localhost section
web-app-nextcloud: 5350 # Not used yet
web-app-nextcloud: 5350 # Not used yet
federation:
web-app-matrix_synapse: 8448

View File

@@ -111,16 +111,6 @@ roles:
description: "Developer-centric server utilities and admin toolkits."
icon: "fas fa-code"
invokable: false
srv:
title: "Server"
description: "General server roles for provisioning and managing server infrastructure—covering web servers, proxy servers, network services, and other backend components."
icon: "fas fa-server"
invokable: false
proxy:
title: "Proxy Server"
description: "Proxy-server roles for virtual-host orchestration and reverse-proxy setups."
icon: "fas fa-project-diagram"
invokable: false
web:
title: "Web Infrastructure"
description: "Roles for managing web infrastructure—covering static content services and deployable web applications."

View File

@@ -20,7 +20,7 @@ To offer a centralized, extensible system for managing containerized application
- **Reset Logic:** Cleans previous Compose project files and data when `MODE_RESET` is enabled.
- **Handlers for Runtime Control:** Automatically builds, sets up, or restarts containers based on handlers.
- **Template-ready Service Files:** Predefined service base and health check templates.
- **Integration Support:** Compatible with `srv-proxy-core` and other Infinito.Nexus service roles.
- **Integration Support:** Compatible with `sys-svc-proxy` and other Infinito.Nexus service roles.
## Administration Tips

View File

@@ -3,7 +3,7 @@
- "CMD"
- "curl"
- "-f"
{% if container_hostname %}
{% if container_hostname is defined %}
- "-H"
- "Host: {{ container_hostname }}"
{% endif %}

View File

@@ -0,0 +1,7 @@
healthcheck:
test: ["CMD-SHELL", "nc -z localhost {{ container_port }} || exit 1"]
interval: 30s
timeout: 3s
retries: 3
start_period: 10s
{{ "\n" }}

View File

@@ -1,4 +0,0 @@
- block:
- include_tasks: 01_core.yml
- include_tasks: utils/run_once.yml
when: run_once_srv_letsencrypt is not defined

View File

@@ -2,5 +2,5 @@ server {
listen {{ ports.public.ldaps['svc-db-openldap'] }}ssl;
proxy_pass 127.0.0.1:{{ ports.localhost.ldap['svc-db-openldap'] }};
{% include 'roles/srv-letsencrypt/templates/ssl_credentials.j2' %}
{% include 'roles/sys-svc-letsencrypt/templates/ssl_credentials.j2' %}
}

View File

@@ -43,7 +43,7 @@ for filename in os.listdir(config_path):
url = f"{{ WEB_PROTOCOL }}://{domain}"
redirected_domains = [domain['source'] for domain in {{ redirect_domain_mappings }}]
redirected_domains.append("{{domains | get_domain('web-app-mailu')}}")
redirected_domains.append("{{domains | get_domain('web-app-mailu') }}")
expected_statuses = get_expected_statuses(domain, parts, redirected_domains)

View File

@@ -3,7 +3,7 @@
name: '{{ item }}'
loop:
- sys-svc-certbot
- srv-core
- sys-svc-webserver
- sys-ctl-alm-compose
- name: install certbot

View File

@@ -41,9 +41,9 @@
when: inj_enabled.logout
- block:
- name: Include dependency 'srv-core'
- name: Include dependency 'sys-svc-webserver'
include_role:
name: srv-core
when: run_once_srv_core is not defined
name: sys-svc-webserver
when: run_once_sys_svc_webserver is not defined
- include_tasks: utils/run_once.yml
when: run_once_sys_front_inj_all is not defined

View File

@@ -1,7 +1,7 @@
- name: Include dependency 'srv-core'
- name: Include dependency 'sys-svc-webserver'
include_role:
name: srv-core
when: run_once_srv_core is not defined
name: sys-svc-webserver
when: run_once_sys_svc_webserver is not defined
- name: Generate color palette with colorscheme-generator
set_fact:

View File

@@ -1,8 +1,8 @@
- block:
- name: Include dependency 'srv-core'
- name: Include dependency 'sys-svc-webserver'
include_role:
name: srv-core
when: run_once_srv_core is not defined
name: sys-svc-webserver
when: run_once_sys_svc_webserver is not defined
- include_tasks: 01_deploy.yml
- include_tasks: utils/run_once.yml
when: run_once_sys_front_inj_desktop is not defined

View File

@@ -1,9 +1,9 @@
- block:
- name: Include dependency 'srv-core'
- name: Include dependency 'sys-svc-webserver'
include_role:
name: srv-core
when: run_once_srv_core is not defined
name: sys-svc-webserver
when: run_once_sys_svc_webserver is not defined
- include_tasks: utils/run_once.yml
when: run_once_sys_front_inj_javascript is not defined

View File

@@ -1,8 +1,8 @@
- name: Include dependency 'srv-core'
- name: Include dependency 'sys-svc-webserver'
include_role:
name: srv-core
name: sys-svc-webserver
when:
- run_once_srv_core is not defined
- run_once_sys_svc_webserver is not defined
- name: "deploy the logout.js"
include_tasks: "02_deploy.yml"

View File

@@ -1,8 +1,8 @@
- block:
- name: Include dependency 'srv-core'
- name: Include dependency 'sys-svc-webserver'
include_role:
name: srv-core
when: run_once_srv_core is not defined
name: sys-svc-webserver
when: run_once_sys_svc_webserver is not defined
- include_tasks: utils/run_once.yml
when: run_once_sys_front_inj_matomo is not defined

View File

@@ -10,7 +10,7 @@ A higher-level orchestration wrapper, *sys-stk-front-proxy* ties together severa
1. **`sys-front-inj-all`** applies global tweaks and includes.
2. **`sys-svc-certs`** obtains Lets Encrypt certificates.
3. **Domain template deployment** copies a Jinja2 vHost from *srv-proxy-core*.
3. **Domain template deployment** copies a Jinja2 vHost from *sys-svc-proxy*.
4. **`web-app-oauth2-proxy`** *(optional)* protects the site with OAuth2.
The result is a complete, reproducible domain rollout in a single playbook task.

View File

@@ -2,4 +2,4 @@
vhost_flavour: "basic" # valid: basic, ws_generic
# build the full template path from the flavour
vhost_template_src: "roles/srv-proxy-core/templates/vhost/{{ vhost_flavour }}.conf.j2"
vhost_template_src: "roles/sys-svc-proxy/templates/vhost/{{ vhost_flavour }}.conf.j2"

View File

@@ -1,8 +1,8 @@
- block:
- name: Include dependency 'srv-proxy-core'
- name: Include dependency 'sys-svc-proxy'
include_role:
name: srv-proxy-core
when: run_once_srv_proxy_core is not defined
name: sys-svc-proxy
when: run_once_sys_svc_proxy is not defined
- include_tasks: utils/run_once.yml
when: run_once_sys_stk_front_proxy is not defined
@@ -15,7 +15,7 @@
- name: "include role for {{ domain }} to receive certificates and do the modification routines"
include_role:
name: srv-composer
name: sys-util-csp-cert
- name: "Copy nginx config to {{ configuration_destination }}"
template:

View File

@@ -1 +1 @@
configuration_destination: "{{ NGINX.DIRECTORIES.HTTP.SERVERS }}{{ domain }}.conf"
configuration_destination: "{{ [ NGINX.DIRECTORIES.HTTP.SERVERS, domain ~ '.conf'] | path_join }}"

View File

@@ -7,7 +7,7 @@ The **sys-stk-front-pure** role extends a basic Nginx installation by wiring in
2. Pulls in Lets Encrypt ACME challenge handling.
3. Applies global cleanup of unused domain configs.
This role is built on top of your existing `srv-core` role, and it automates the end-to-end process of turning HTTP sites into secure HTTPS sites.
This role is built on top of your existing `sys-svc-webserver` role, and it automates the end-to-end process of turning HTTP sites into secure HTTPS sites.
---
@@ -15,9 +15,9 @@ This role is built on top of your existing `srv-core` role, and it automates the
When you apply **sys-stk-front-pure**, it will:
1. **Include** the `srv-core` role to install and configure Nginx.
1. **Include** the `sys-svc-webserver` role to install and configure Nginx.
2. **Clean up** any stale vHost files under `sys-svc-cln-domains`.
3. **Deploy** the Lets Encrypt challenge-and-redirect snippet from `srv-letsencrypt`.
3. **Deploy** the Lets Encrypt challenge-and-redirect snippet from `sys-svc-letsencrypt`.
4. **Reload** Nginx automatically when any template changes.
All tasks are idempotent—once your certificates are in place and your configuration is set, Ansible will skip unchanged steps on subsequent runs.
@@ -42,7 +42,7 @@ All tasks are idempotent—once your certificates are in place and your configur
## Requirements
- A working `srv-core` setup.
- A working `sys-svc-webserver` setup.
- DNS managed via Cloudflare (for CAA record tasks) or equivalent ACME DNS flow.
- Variables:
- `LETSENCRYPT_WEBROOT_PATH`

View File

@@ -3,8 +3,8 @@
include_role:
name: '{{ item }}'
loop:
- srv-core
- sys-svc-webserver
- sys-svc-cln-domains
- srv-letsencrypt
- sys-svc-letsencrypt
- include_tasks: utils/run_once.yml
when: run_once_sys_stk_front_pure is not defined

View File

@@ -3,7 +3,7 @@
include_role:
name: '{{ item }}'
loop:
- srv-core
- sys-svc-webserver
- name: Include task to remove deprecated nginx configs
include_tasks: remove_deprecated_nginx_configs.yml

View File

@@ -15,6 +15,6 @@
- name: Remove exact nginx config for {{ domain }}
ansible.builtin.file:
path: "{{ NGINX.DIRECTORIES.HTTP.SERVERS }}{{ domain }}.conf"
path: "{{ [ NGINX.DIRECTORIES.HTTP.SERVERS, domain ~ '.conf'] | path_join }}"
state: absent
notify: restart openresty

View File

@@ -1,5 +1,4 @@
---
- block:
- include_tasks: 01_core.yml
- include_tasks: utils/run_once.yml
when: run_once_srv_core is not defined
when: run_once_sys_svc_letsencrypt is not defined

View File

@@ -12,4 +12,4 @@ ssl_session_tickets on;
add_header Strict-Transport-Security max-age=15768000;
ssl_stapling on;
ssl_stapling_verify on;
{% include 'roles/srv-letsencrypt/templates/ssl_credentials.j2' %}
{% include 'roles/sys-svc-letsencrypt/templates/ssl_credentials.j2' %}

View File

@@ -4,6 +4,6 @@
name: '{{ item }}'
loop:
- sys-stk-front-pure
- srv-core
- sys-svc-webserver
- include_tasks: utils/run_once.yml
when: run_once_srv_proxy_core is not defined
when: run_once_sys_svc_proxy is not defined

View File

@@ -1,6 +1,6 @@
# Nginx Location Templates
This directory contains Jinja2 templates for different Nginx `location` blocks, each designed to proxy and optimize different types of web traffic. These templates are used by the `srv-proxy-core` role to modularize and standardize reverse proxy configuration across a wide variety of applications.
This directory contains Jinja2 templates for different Nginx `location` blocks, each designed to proxy and optimize different types of web traffic. These templates are used by the `sys-svc-proxy` role to modularize and standardize reverse proxy configuration across a wide variety of applications.
---

View File

@@ -15,7 +15,7 @@ location {{location}}
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port {{ WEB_PORT }};
{% include 'roles/srv-proxy-core/templates/headers/content_security_policy.conf.j2' %}
{% include 'roles/sys-svc-proxy/templates/headers/content_security_policy.conf.j2' %}
# WebSocket specific header
proxy_http_version 1.1;

View File

@@ -1,7 +1,7 @@
server
{
server_name {{ domain }};
{% include 'roles/srv-proxy-core/templates/headers/buffers.conf.j2' %}
{% include 'roles/sys-svc-proxy/templates/headers/buffers.conf.j2' %}
{% if applications | get_app_conf(application_id, 'features.oauth2', False) %}
{% include 'roles/web-app-oauth2-proxy/templates/endpoint.conf.j2'%}
@@ -14,7 +14,7 @@ server
{{ proxy_extra_configuration }}
{% endif %}
{% include 'roles/srv-letsencrypt/templates/ssl_header.j2' %}
{% include 'roles/sys-svc-letsencrypt/templates/ssl_header.j2' %}
{% if applications | get_app_conf(application_id, 'features.oauth2', False) %}
{% set acl = applications | get_app_conf(application_id, 'oauth2_proxy.acl', False, {}) %}
@@ -23,38 +23,38 @@ server
{# 1. Expose everything by default, then protect blacklisted paths #}
{% set oauth2_proxy_enabled = false %}
{% set location = "/" %}
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
{% include 'roles/sys-svc-proxy/templates/location/html.conf.j2' %}
{% for loc in acl.blacklist %}
{% set oauth2_proxy_enabled = true %}
{% set location = loc %}
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
{% include 'roles/sys-svc-proxy/templates/location/html.conf.j2' %}
{% endfor %}
{% elif acl.whitelist is defined %}
{# 2. Protect everything by default, then expose whitelisted paths #}
{% set oauth2_proxy_enabled = true %}
{% set location = "/" %}
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
{% include 'roles/sys-svc-proxy/templates/location/html.conf.j2' %}
{% for loc in acl.whitelist %}
{% set oauth2_proxy_enabled = false %}
{% set location = loc %}
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
{% include 'roles/sys-svc-proxy/templates/location/html.conf.j2' %}
{% endfor %}
{% else %}
{# 3. OAuth2 enabled but no (or empty) ACL — protect all #}
{% set oauth2_proxy_enabled = true %}
{% set location = "/" %}
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
{% include 'roles/sys-svc-proxy/templates/location/html.conf.j2' %}
{% endif %}
{% else %}
{# 4. OAuth2 completely disabled — expose all #}
{% set oauth2_proxy_enabled = false %}
{% set location = "/" %}
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
{% include 'roles/sys-svc-proxy/templates/location/html.conf.j2' %}
{% endif %}
}

View File

@@ -6,7 +6,7 @@ map $http_upgrade $connection_upgrade {
server {
server_name {{ domain }};
{% include 'roles/srv-letsencrypt/templates/ssl_header.j2' %}
{% include 'roles/sys-svc-letsencrypt/templates/ssl_header.j2' %}
{% include 'roles/sys-front-inj-all/templates/server.conf.j2' %}
@@ -25,10 +25,10 @@ server {
add_header Strict-Transport-Security "max-age=31536000";
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
{% include 'roles/sys-svc-proxy/templates/location/html.conf.j2' %}
{% if location_ws is defined %}
{% include 'roles/srv-proxy-core/templates/location/ws.conf.j2' %}
{% include 'roles/sys-svc-proxy/templates/location/ws.conf.j2' %}
{% endif %}
error_page 500 501 502 503 504 /500.html;

View File

@@ -2,7 +2,7 @@
{% if not applications | get_app_conf(application_id, 'features.central_database', False) %}
{{ database_host }}:
image: postgres:{{applications['svc-db-postgres'].version}}-alpine
image: postgres:{{ applications['svc-db-postgres'].version}}-alpine
container_name: {{ application_id | get_entity_name }}-database
env_file:
- {{database_env}}

View File

@@ -18,4 +18,4 @@ galaxy_info:
- performance
repository: "https://s.infinito.nexus/code"
issue_tracker_url: "https://s.infinito.nexus/issues"
documentation: "https://s.infinito.nexus/code/roles/srv-core"
documentation: "https://s.infinito.nexus/code/roles/sys-svc-webserver"

View File

@@ -49,3 +49,5 @@
- sys-ctl-hlth-csp
vars:
flush_handlers: false
- include_tasks: utils/run_once.yml

View File

@@ -0,0 +1,4 @@
---
- block:
- include_tasks: 01_core.yml
when: run_once_sys_svc_webserver is not defined

View File

@@ -1,4 +1,4 @@
# Role: srv-composer
# Role: sys-util-csp-cert
This Ansible role composes and orchestrates all necessary HTTPS-layer tasks and HTML-content injections for your webserver domains. It integrates two key sub-roles into a unified workflow:

View File

@@ -27,4 +27,4 @@ galaxy_info:
- orchestration
repository: "https://s.infinito.nexus/code"
issue_tracker_url: "https://s.infinito.nexus/issues"
documentation: "https://s.infinito.nexus/code/roles/srv-composer"
documentation: "https://s.infinito.nexus/code/roles/sys-util-csp-cert"

View File

@@ -1,4 +1,4 @@
# run_once_srv_composer: deactivated
# run_once_sys_util_csp_cert: deactivated
- name: "include role sys-front-inj-all for '{{ domain }}'"
include_role:

View File

@@ -35,7 +35,7 @@ By default, BigBlueButton is deployed with best-practice hardening, modular secr
## System Requirements
- Arch Linux with Docker, Compose, and Nginx roles pre-installed
- DNS and reverse proxy configuration using `srv-proxy-core`
- DNS and reverse proxy configuration using `sys-svc-proxy`
- Functional email system for Greenlight SMTP
## Important Resources

View File

@@ -3,7 +3,7 @@
set_fact:
proxy_extra_configuration: >-
{{ lookup('ansible.builtin.template',
playbook_dir ~ '/roles/srv-proxy-core/templates/location/html.conf.j2') | trim }}
playbook_dir ~ '/roles/sys-svc-proxy/templates/location/html.conf.j2') | trim }}
vars:
location: '^~ /html5client'
oauth2_proxy_enabled: false

View File

@@ -1,8 +1,8 @@
credentials:
jwt_secret:
description: "Secret used for JWT signing (base64, 64 bytes)"
algorithm: "plain"
validation: "^[A-Za-z0-9+/=]{86,}$" # 64 bytes base64 = ~86 characters without newline
description: "Secret used for JWT signing"
algorithm: "base64_prefixed_32"
validation: "^base64:[A-Za-z0-9+/]{43}=$"
plc_rotation_key_k256_private_key_hex:
description: "PLC rotation key in hex format (32 bytes)"
algorithm: "sha256"

View File

@@ -1,5 +1,5 @@
PDS_HOSTNAME="{{domains[application_id].api}}"
PDS_ADMIN_EMAIL="{{applications.bluesky.users.administrator.email}}"
PDS_ADMIN_EMAIL="{{ applications.bluesky.users.administrator.email}}"
PDS_SERVICE_DID="did:web:{{domains[application_id].api}}"
# See https://mattdyson.org/blog/2024/11/self-hosting-bluesky-pds/

View File

@@ -97,7 +97,7 @@ STATIC_ROOT={{funkwhale_static_root}}
DJANGO_SETTINGS_MODULE=config.settings.production
# Generate one using `openssl rand -base64 45`, for example
DJANGO_SECRET_KEY={{applications | get_app_conf(application_id, 'credentials.django_secret', True)}}
DJANGO_SECRET_KEY={{ applications | get_app_conf(application_id, 'credentials.django_secret', True)}}
{% if applications | get_app_conf(application_id, 'features.ldap', False) %}
# LDAP settings

View File

@@ -41,7 +41,7 @@
"id.token.claim": "true",
"lightweight.claim": "false",
"access.token.claim": "true",
"claim.name": "{{LDAP.USER.ATTRIBUTES.ID}}",
"claim.name": "{{ LDAP.USER.ATTRIBUTES.ID }}",
"jsonType.label": "String"
}
}

View File

@@ -112,7 +112,7 @@
- name: create chatgpt bot
command:
cmd: docker compose exec -it synapse register_new_matrix_user -u chatgptbot -p {{applications | get_app_conf(application_id, 'credentials.chatgpt_bridge_user_password', True)}} -a -c {{ MATRIX_SYNAPSE_CONFIG_PATH_CONTAINER }} http://localhost:8008
cmd: docker compose exec -it synapse register_new_matrix_user -u chatgptbot -p {{ applications | get_app_conf(application_id, 'credentials.chatgpt_bridge_user_password', True)}} -a -c {{ MATRIX_SYNAPSE_CONFIG_PATH_CONTAINER }} http://localhost:8008
chdir: "{{ docker_compose.directories.instance }}"
ignore_errors: true
when: applications | get_app_conf(application_id, 'setup', True) | bool

View File

@@ -18,7 +18,7 @@
- name: "include role for {{ application_id }} to receive certs & do modification routines for {{ MATRIX_SYNAPSE_DOMAIN }}"
include_role:
name: srv-composer
name: sys-util-csp-cert
vars:
domain: "{{ MATRIX_SYNAPSE_DOMAIN }}"
http_port: "{{ MATRIX_SYNAPSE_PORT }}"

View File

@@ -62,7 +62,7 @@
volumes:
- chatgpt_data:/storage
environment:
OPENAI_API_KEY: '{{applications | get_app_conf(application_id, 'credentials.chatgpt_bridge_openai_api_key', True)}}'
OPENAI_API_KEY: '{{ applications | get_app_conf(application_id, 'credentials.chatgpt_bridge_openai_api_key', True)}}'
# Uncomment the next two lines if you are using Azure OpenAI API
# OPENAI_AZURE: 'false'
# CHATGPT_REVERSE_PROXY: 'your-completion-endpoint-here'

View File

@@ -39,7 +39,7 @@ appservice:
# Format examples:
# SQLite: sqlite:filename.db
# Postgres: postgres://username:password@hostname/dbname
database: postgres://mautrix_facebook_bridge:{{applications | get_app_conf(application_id, 'credentials.mautrix_facebook_bridge_database_password', True)}}@{{ database_host }}/mautrix_facebook_bridge
database: postgres://mautrix_facebook_bridge:{{ applications | get_app_conf(application_id, 'credentials.mautrix_facebook_bridge_database_password', True)}}@{{ database_host }}/mautrix_facebook_bridge
# Additional arguments for asyncpg.create_pool() or sqlite3.connect()
# https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.pool.create_pool
# https://docs.python.org/3/library/sqlite3.html#sqlite3.connect

View File

@@ -42,7 +42,7 @@ appservice:
# Format examples:
# SQLite: sqlite:filename.db
# Postgres: postgres://username:password@hostname/dbname
database: postgres://mautrix_instagram_bridge:{{applications | get_app_conf(application_id, 'credentials.mautrix_instagram_bridge_database_password', True)}}@{{ database_host }}/mautrix_instagram_bridge
database: postgres://mautrix_instagram_bridge:{{ applications | get_app_conf(application_id, 'credentials.mautrix_instagram_bridge_database_password', True)}}@{{ database_host }}/mautrix_instagram_bridge
# Additional arguments for asyncpg.create_pool() or sqlite3.connect()
# https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.pool.create_pool
# https://docs.python.org/3/library/sqlite3.html#sqlite3.connect

View File

@@ -43,7 +43,7 @@ appservice:
# https://github.com/mattn/go-sqlite3#connection-string
# Postgres: Connection string. For example, postgres://user:password@host/database?sslmode=disable
# To connect via Unix socket, use something like postgres:///dbname?host=/var/run/postgresql
uri: postgres://mautrix_signal_bridge:{{applications | get_app_conf(application_id, 'credentials.mautrix_signal_bridge_database_password', True)}}@{{ database_host }}/mautrix_signal_bridge?sslmode=disable
uri: postgres://mautrix_signal_bridge:{{ applications | get_app_conf(application_id, 'credentials.mautrix_signal_bridge_database_password', True)}}@{{ database_host }}/mautrix_signal_bridge?sslmode=disable
# Maximum number of connections. Mostly relevant for Postgres.
max_open_conns: 20
max_idle_conns: 2

View File

@@ -43,7 +43,7 @@ appservice:
# https://github.com/mattn/go-sqlite3#connection-string
# Postgres: Connection string. For example, postgres://user:password@host/database?sslmode=disable
# To connect via Unix socket, use something like postgres:///dbname?host=/var/run/postgresql
uri: postgres://mautrix_slack_bridge:{{applications | get_app_conf(application_id, 'credentials.mautrix_slack_bridge_database_password', True)}}@{{ database_host }}/mautrix_slack_bridge?sslmode=disable
uri: postgres://mautrix_slack_bridge:{{ applications | get_app_conf(application_id, 'credentials.mautrix_slack_bridge_database_password', True)}}@{{ database_host }}/mautrix_slack_bridge?sslmode=disable
# Maximum number of connections. Mostly relevant for Postgres.
max_open_conns: 20
max_idle_conns: 2

View File

@@ -42,7 +42,7 @@ appservice:
# Format examples:
# SQLite: sqlite:filename.db
# Postgres: postgres://username:password@hostname/dbname
database: postgres://mautrix_telegram_bridge:{{applications | get_app_conf(application_id, 'credentials.mautrix_telegram_bridge_database_password', True)}}@{{ database_host }}/mautrix_telegram_bridge
database: postgres://mautrix_telegram_bridge:{{ applications | get_app_conf(application_id, 'credentials.mautrix_telegram_bridge_database_password', True)}}@{{ database_host }}/mautrix_telegram_bridge
# Additional arguments for asyncpg.create_pool() or sqlite3.connect()
# https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.pool.create_pool
# https://docs.python.org/3/library/sqlite3.html#sqlite3.connect
@@ -564,8 +564,8 @@ bridge:
# Telegram config
telegram:
# Get your own API keys at https://my.telegram.org/apps
api_id: {{applications | get_app_conf(application_id, 'credentials.mautrix_telgegram_bridge_api_id', True)}}
api_hash: {{applications | get_app_conf(application_id, 'credentials.mautrix_telgegram_bridge_api_pin', True)}}
api_id: {{ applications | get_app_conf(application_id, 'credentials.mautrix_telgegram_bridge_api_id', True)}}
api_hash: {{ applications | get_app_conf(application_id, 'credentials.mautrix_telgegram_bridge_api_pin', True)}}
# (Optional) Create your own bot at https://t.me/BotFather
bot_token: disabled

View File

@@ -42,7 +42,7 @@ appservice:
# https://github.com/mattn/go-sqlite3#connection-string
# Postgres: Connection string. For example, postgres://user:password@host/database?sslmode=disable
# To connect via Unix socket, use something like postgres:///dbname?host=/var/run/postgresql
uri: postgres://mautrix_whatsapp_bridge:{{applications | get_app_conf(application_id, 'credentials.mautrix_whatsapp_bridge_database_password', True)}}@{{ database_host }}/mautrix_whatsapp_bridge?sslmode=disable
uri: postgres://mautrix_whatsapp_bridge:{{ applications | get_app_conf(application_id, 'credentials.mautrix_whatsapp_bridge_database_password', True)}}@{{ database_host }}/mautrix_whatsapp_bridge?sslmode=disable
# Maximum number of connections. Mostly relevant for Postgres.
max_open_conns: 20
max_idle_conns: 2

View File

@@ -1,6 +1,6 @@
server {
server_name {{ domain }};
{% include 'roles/srv-letsencrypt/templates/ssl_header.j2' %}
{% include 'roles/sys-svc-letsencrypt/templates/ssl_header.j2' %}
# For the federation port
listen {{ MATRIX_FEDERATION_PORT }} ssl default_server;
@@ -8,7 +8,7 @@ server {
{% include 'roles/sys-front-inj-all/templates/server.conf.j2'%}
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
{% include 'roles/sys-svc-proxy/templates/location/html.conf.j2' %}
{% include 'roles/srv-proxy-core/templates/location/upload.conf.j2' %}
{% include 'roles/sys-svc-proxy/templates/location/upload.conf.j2' %}
}

View File

@@ -18,6 +18,6 @@ docker:
features:
logout: true
central_database: true
css: true
css: false
desktop: true
oidc: true

View File

@@ -0,0 +1,256 @@
/* MediaWiki (Vector 2022 + OOUI) color remap via Infinito.Nexus palette
- Keep changes scoped and variable-driven
- Prefer variables over hard values
- Avoid !important unless an inline style or strong OOUI rule requires it
*/
/* ---------- App-scoped variables (derived from global color scale) ---------- */
:root {
/* Brand & accents */
--mw-primary: var(--color-01-60);
--mw-primary-contrast: var(--color-01-99);
--mw-secondary: var(--color-01-85);
--mw-accent: var(--color-01-50);
/* Surfaces */
--mw-surface: var(--color-01-92);
--mw-surface-variant: var(--color-01-90);
--mw-surface-muted: var(--color-01-95);
/* Text */
--mw-text: var(--color-01-20);
--mw-text-muted: var(--color-01-45);
--mw-heading: var(--color-01-15);
--mw-link: var(--color-01-55);
--mw-link-hover: var(--color-01-60);
--mw-link-visited: var(--color-01-45);
/* Lines / borders / focus */
--mw-border: var(--color-01-85);
--mw-divider: var(--color-01-87);
--mw-focus: rgba(var(--color-01-rgb-65), .35);
/* Status */
--mw-success: var(--bs-success);
--mw-warning: var(--bs-warning);
--mw-danger: var(--bs-danger);
}
/* ---------- Global shell ---------- */
body.skin-vector,
.skin-vector .mw-page-container {
background-color: var(--mw-surface);
background-image: linear-gradient({{ range(0, 361) | random }}deg,
var(--mw-surface),
var(--mw-surface-variant),
var(--mw-surface-muted),
var(--mw-surface)
);
color: var(--mw-text);
}
/* ---------- Header / site chrome ---------- */
.skin-vector .vector-header,
.skin-vector .vector-header-container,
.skin-vector .mw-header {
background-color: var(--color-01-80);
background-image: linear-gradient({{ range(0, 361) | random }}deg,
var(--color-01-75), var(--color-01-80), var(--color-01-81), var(--color-01-85)
);
color: var(--color-01-17);
border-bottom: 1px solid var(--mw-divider);
}
/* Logo & title area often inherits link styles—keep readable */
.skin-vector .mw-logo a,
.skin-vector .mw-logo svg,
.skin-vector .vector-header a {
color: var(--mw-heading);
fill: currentColor;
}
/* ---------- Sidebar / menus ---------- */
.skin-vector .vector-sidebar,
.skin-vector .mw-portlet,
.skin-vector .vector-menu-content {
background-color: var(--mw-surface-variant);
border-color: var(--mw-border);
}
.skin-vector .vector-sidebar .vector-menu-heading,
.skin-vector .vector-menu-heading {
color: var(--mw-heading);
border-bottom: 1px solid var(--mw-divider);
}
/* ---------- Table of Contents ---------- */
.skin-vector .vector-toc,
.skin-vector .vector-toc .vector-toc-contents {
background-color: var(--mw-surface-muted);
border: 1px solid var(--mw-border);
}
.skin-vector .vector-toc .vector-toc-text {
color: var(--mw-text);
}
/* ---------- Content area ---------- */
.skin-vector .mw-content-container,
.skin-vector .mw-content-ltr,
.skin-vector .mw-body,
.skin-vector .mw-parser-output {
color: var(--mw-text);
}
.skin-vector .mw-parser-output h1,
.skin-vector .mw-parser-output h2,
.skin-vector .mw-parser-output h3,
.skin-vector .mw-parser-output h4,
.skin-vector .mw-parser-output h5,
.skin-vector .mw-parser-output h6 {
color: var(--mw-heading);
}
/* Links */
.skin-vector .mw-parser-output a { color: var(--mw-link); }
.skin-vector .mw-parser-output a:visited { color: var(--mw-link-visited); }
.skin-vector .mw-parser-output a:hover,
.skin-vector .mw-parser-output a:focus { color: var(--mw-link-hover); }
/* ---------- Search ---------- */
.skin-vector .vector-search-box input,
.skin-vector .vector-search-box .vector-search-input {
background-color: var(--mw-surface);
border: 1px solid var(--mw-border);
color: var(--mw-text);
}
.skin-vector .vector-search-box input:focus {
outline: 0;
box-shadow: 0 0 0 3px var(--mw-focus);
border-color: var(--mw-link);
}
/* ---------- Buttons (MediaWiki UI + OOUI) ---------- */
/* MediaWiki UI */
.mw-ui-button,
.mw-ui-button:visited {
background-color: var(--mw-surface-muted);
color: var(--mw-text);
border: 1px solid var(--mw-border);
}
.mw-ui-button:hover,
.mw-ui-button:focus {
background-color: var(--mw-surface-variant);
color: var(--mw-text);
border-color: var(--mw-link);
box-shadow: 0 0 0 3px var(--mw-focus);
}
.mw-ui-progressive,
.mw-ui-primary {
background-color: var(--mw-primary);
color: var(--mw-primary-contrast);
border-color: var(--mw-primary);
}
.mw-ui-progressive:hover,
.mw-ui-primary:hover {
filter: brightness(0.95);
}
/* OOUI (covers most modern UI widgets) */
.oo-ui-buttonElement-button {
background-color: var(--mw-surface-muted);
color: var(--mw-text);
border: 1px solid var(--mw-border);
}
.oo-ui-buttonElement-button:focus-visible {
outline: 0;
box-shadow: 0 0 0 3px var(--mw-focus);
border-color: var(--mw-link);
}
.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button,
.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button {
background-color: var(--mw-primary);
color: var(--mw-primary-contrast);
border-color: var(--mw-primary);
}
/* Inputs */
.mw-ui-input,
.oo-ui-inputWidget-input {
background-color: var(--mw-surface);
color: var(--mw-text);
border: 1px solid var(--mw-border);
}
.oo-ui-inputWidget-input:focus,
.mw-ui-input:focus {
outline: 0;
box-shadow: 0 0 0 3px var(--mw-focus);
border-color: var(--mw-link);
}
/* ---------- Tables / infoboxes ---------- */
table.wikitable,
.mw-parser-output table.infobox,
.mw-parser-output table.prettytable {
background-color: var(--color-01-99);
border: 1px solid var(--mw-border);
color: var(--mw-text);
}
table.wikitable > * > tr > th,
table.wikitable > * > tr > td {
border: 1px solid var(--mw-border);
}
table.wikitable > * > tr > th {
background-color: var(--color-01-80);
background-image: linear-gradient({{ range(0, 361) | random }}deg,
var(--color-01-75), var(--color-01-80), var(--color-01-81), var(--color-01-85)
);
color: var(--mw-heading);
}
/* ---------- Notices / boxes ---------- */
.mw-notification,
.mw-message-box,
.mw-message-box-notice {
background-color: var(--mw-surface-muted);
border-color: var(--mw-border);
color: var(--mw-text);
}
.mw-message-box-warning {
border-left: 4px solid var(--mw-warning);
}
.mw-message-box-error {
border-left: 4px solid var(--mw-danger);
}
.mw-message-box-success {
border-left: 4px solid var(--mw-success);
}
/* ---------- Footer ---------- */
.skin-vector .mw-footer {
background-color: var(--mw-surface-variant);
border-top: 1px solid var(--mw-divider);
color: var(--mw-text-muted);
}
/* ---------- Dark-mode helpers (for browser extensions honoring vars) ---------- */
@media (prefers-color-scheme: dark) {
:root {
/* Nudge contrast a bit in dark environments */
--mw-text: var(--color-01-90);
--mw-text-muted: var(--color-01-80);
--mw-heading: var(--color-01-95);
}
}

View File

@@ -1,12 +1,12 @@
# General
MOODLE_SITE_NAME="{{applications | get_app_conf(application_id, 'site_titel', True)}}"
MOODLE_SITE_NAME="{{ applications | get_app_conf(application_id, 'site_titel', True) }}"
MOODLE_HOST="{{ domains | get_domain(application_id) }}"
MOODLE_SSLPROXY=yes
MOODLE_REVERSE_PROXY=yes
MOODLE_USERNAME={{ applications | get_app_conf(application_id, 'users.administrator.username') }}
MOODLE_PASSWORD={{applications | get_app_conf(application_id, 'credentials.user_password', True)}}
MOODLE_EMAIL={{applications | get_app_conf(application_id, 'users.administrator.email', True)}}
MOODLE_PASSWORD={{ applications | get_app_conf(application_id, 'credentials.user_password', True)}}
MOODLE_EMAIL={{ applications | get_app_conf(application_id, 'users.administrator.email', True)}}
BITNAMI_DEBUG={% if MODE_DEBUG | bool %}true{% else %}false{% endif %}
# Database

View File

@@ -1,2 +0,0 @@
# Todo
- Implement Collabora and Talk Supper . [See](https://www.youtube.com/watch?v=7cRmvTyt1ik)

View File

@@ -18,7 +18,6 @@ server:
domains:
canonical:
- "cloud.{{ PRIMARY_DOMAIN }}"
# talk: "talk.{{ PRIMARY_DOMAIN }}" @todo needs to be activated
docker:
volumes:
data: nextcloud_data
@@ -45,8 +44,14 @@ docker:
name: "nextcloud-talk"
image: "nextcloud/aio-talk"
version: "latest"
enabled: false # Not enabled yet, because just implemented during refactoring and not tested yet. if tested activate
oidc:
backup:
no_stop_required: false
whiteboard:
name: "nextcloud-whiteboard"
image: "ghcr.io/nextcloud-releases/whiteboard"
version: "latest"
backup:
no_stop_required: true
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
@@ -72,7 +77,8 @@ performance:
opcache_memory_consumption: "{{ ((ansible_memtotal_mb | int) / 30)|int }}M" # Dynamic set memory consumption
plugins_enabled: true # Implemented for speeding up testing and debugging process. For productive environments keep it true and steer the apps via the plugins config
oidc:
flavor: "{{ _applications_nextcloud_oidc_flavor }}"
plugins:
# List for Nextcloud Plugin Routine
# Decides if plugins should be activated or deactivated
@@ -234,7 +240,7 @@ plugins:
- oidc_login # Will be disabled
spreed:
# Nextcloud Spreed: offers video conferencing and chat functionalities (https://apps.nextcloud.com/apps/spreed)
enabled: false # @todo to activate it first implement web-svc-coturn and activate it
enabled: true
tables:
# Nextcloud tables: allows creation and editing of tables within the interface (https://apps.nextcloud.com/apps/tables)
enabled: true

View File

@@ -1,6 +1,6 @@
---
- name: restart nextcloud nginx service
command:
cmd: "docker exec {{ nextcloud_proxy_name }} nginx -s reload"
cmd: "docker exec {{ NEXTCLOUD_PROXY_CONTAINER }} nginx -s reload"
listen: restart nextcloud nginx service
ignore_errors: true # Ignoring if container is restarting

View File

@@ -1,6 +1,21 @@
credentials:
whiteboard_jwt_secret:
description: "Secret used for JWT signing"
algorithm: "base64_prefixed_32"
validation: "^base64:[A-Za-z0-9+/]{43}=$"
administrator_password:
description: "Initial password for the Nextcloud administrator (change immediately and enable 2FA)"
algorithm: "sha256"
validation: "^[a-f0-9]{64}$"
validation: "^[a-f0-9]{64}$"
talk_turn_secret:
description: "TURN REST secret for coturn"
algorithm: "base64_prefixed_32"
validation: "^base64:[A-Za-z0-9+/]{43}=$"
talk_signaling_secret:
description: "Secret for Talk signaling"
algorithm: "base64_prefixed_32"
validation: "^base64:[A-Za-z0-9+/]{43}=$"
talk_internal_secret:
description: "Internal secret for AIO Talk"
algorithm: "base64_prefixed_32"
validation: "^base64:[A-Za-z0-9+/]{43}=$"

View File

@@ -0,0 +1,37 @@
- name: "include role for {{ application_id }} to receive certs & do modification routines for '{{ domain }}:{{ port }}'"
include_role:
name: sys-util-csp-cert
- name: create nextcloud proxy configuration file
template:
src: "nginx/host.conf.j2"
dest: "{{ NEXTCLOUD_HOST_NGINX_PATH }}"
notify: restart openresty
- name: "load docker and db for {{ application_id }}"
include_role:
name: sys-stk-back-stateful
vars:
docker_compose_flush_handlers: false
- name: "create {{ NEXTCLOUD_HOST_CONF_ADD_PATH }}"
file:
path: "{{ NEXTCLOUD_HOST_CONF_ADD_PATH }}"
state: directory
mode: "0755"
- name: "Create config files at {{ NEXTCLOUD_HOST_CONF_ADD_PATH }}"
template:
src: "{{ item }}"
dest: "{{ NEXTCLOUD_HOST_CONF_ADD_PATH }}/{{ item | basename | regex_replace('\\.j2$', '') }}"
owner: "{{ NEXTCLOUD_DOCKER_USER_id }}"
group: "{{ NEXTCLOUD_DOCKER_USER_id }}"
loop: "{{ lookup('fileglob', role_path ~ '/templates/config/*.j2', wantlist=True) }}"
# Not all type of changes take instantly place. Due to this reason a rebuild is required.
notify: docker compose up
- name: create internal nextcloud nginx configuration
template:
src: "nginx/docker.conf.j2"
dest: "{{ [docker_compose.directories.volumes, 'nginx.conf'] | path_join }}"
notify: restart nextcloud nginx service

View File

@@ -3,7 +3,7 @@
- name: Add dynamic config merging from Jinja template
template:
src: include.php.j2
dest: "{{ nextcloud_host_include_instructions_file }}"
dest: "{{ NEXTCLOUD_HOST_INCL_PATH }}"
notify: docker compose restart
- name: Flush handlers so Nextcloud container is restarted and ready
@@ -19,11 +19,11 @@
- name: Copy include instructions to the container
command: >
docker cp {{ nextcloud_host_include_instructions_file }} {{ NEXTCLOUD_CONTAINER }}:{{ nextcloud_docker_include_instructions_file }}
docker cp {{ NEXTCLOUD_HOST_INCL_PATH }} {{ NEXTCLOUD_CONTAINER }}:{{ NEXTCLOUD_DOCKER_INCL_PATH }}
- name: Append generated config to config.php only if not present
command: >
docker exec -u {{ NEXTCLOUD_DOCKER_USER }} {{ NEXTCLOUD_CONTAINER }} sh -c "
grep -q '{{ nextcloud_docker_config_additives_directory }}' {{ nextcloud_docker_config_file }} ||
cat {{ nextcloud_docker_include_instructions_file }} >> {{ nextcloud_docker_config_file }}"
grep -q '{{ NEXTCLOUD_DOCKER_CONF_ADD_PATH }}' {{ NEXTCLOUD_DOCKER_CONFIG_FILE }} ||
cat {{ NEXTCLOUD_DOCKER_INCL_PATH }} >> {{ NEXTCLOUD_DOCKER_CONFIG_FILE }}"
notify: docker compose restart

View File

@@ -1,7 +1,7 @@
- name: Ensure Nextcloud administrator is in the 'admin' group
command: >
docker exec -u {{ NEXTCLOUD_DOCKER_USER }} {{ NEXTCLOUD_CONTAINER }}
php occ group:adduser admin {{ nextcloud_administrator_username }}
php occ group:adduser admin {{ NEXTCLOUD_ADMINISTRATOR_USERNAME }}
register: add_admin_to_group
changed_when: "not ASYNC_ENABLED and 'Added user' in (add_admin_to_group.stdout | default(''))"
failed_when: >

View File

@@ -1,5 +1,5 @@
- block:
- include_tasks: 06_plugin_routines.yml
- include_tasks: _plugin_a_routines.yml
when: plugin_value.enabled | bool
- name: disable {{ plugin_key }} nextcloud plugin

View File

@@ -35,9 +35,12 @@
and
("already installed" not in install_result.stdout)
- include_tasks: 07_plugin_enable_and_configure.yml
- include_tasks: _plugin_b_enable_and_configure.yml
when:
- install_result is defined
- >
install_result.rc == 0
or "already installed" in install_result.stdout
or "already installed" in install_result.stdout
vars:
plugin_task_path: "{{ NEXTCLOUD_CNODE_PLUGIN_TASKS_PATH }}{{ plugin_key }}.yml"
plugin_vars_path: "{{ NEXTCLOUD_CNODE_PLUGIN_VARS_PATH }}{{ plugin_key }}.yml"

View File

@@ -3,16 +3,16 @@
register: enable_result
changed_when: enable_result.rc == 0 and ("already enabled" not in enable_result.stdout)
- name: Check if {{ nextcloud_control_node_plugin_vars_directory }}{{ plugin_key }}.yml exists
- name: Check if {{ plugin_vars_path }} exists
stat:
path: "{{ nextcloud_control_node_plugin_vars_directory }}{{ plugin_key }}.yml"
path: "{{ plugin_vars_path }}"
delegate_to: localhost
become: false
register: plugin_vars_file
- name: "Load {{ plugin_key }} configuration variables"
include_vars:
file: "{{ nextcloud_control_node_plugin_vars_directory }}{{ plugin_key }}.yml"
file: "{{ plugin_vars_path }}"
when: plugin_vars_file.stat.exists
- name: "Set plugin configuration (batched shell, no async)"
@@ -34,14 +34,15 @@
failed_when: not ASYNC_ENABLED and config_set_shell.rc != 0
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | default(true) | bool }}"
- name: Check if {{ nextcloud_control_node_plugin_tasks_directory }}{{ plugin_key }}.yml exists
- name: Check if {{ plugin_task_path }} exists
stat:
path: "{{ nextcloud_control_node_plugin_tasks_directory }}{{ plugin_key }}.yml"
path: "{{ plugin_task_path }}"
delegate_to: localhost
become: false
register: plugin_tasks_file
- name: "include {{ nextcloud_control_node_plugin_tasks_directory }}{{ plugin_key }}.yml"
include_tasks: "{{ nextcloud_control_node_plugin_tasks_directory }}{{ plugin_key }}.yml"
- name: "include {{ plugin_task_path }}"
include_tasks: "{{ plugin_task_path }}"
when: plugin_tasks_file.stat.exists

View File

@@ -1,76 +1,39 @@
---
- name: "Install Collabora Dependency"
include_role:
name: web-svc-collabora
vars:
flush_handlers: true
when:
- run_once_web_svc_collabora is not defined
- NEXTCLOUD_COLLABORA_ENABLED | bool
- name: "include role for {{ application_id }} to receive certs & do modification routines"
include_role:
name: srv-composer
- name: create nextcloud proxy configuration file
template:
src: "nginx/host.conf.j2"
dest: "{{ nextcloud_host_nginx_path }}"
notify: restart openresty
- name: "load docker and db for {{ application_id }}"
- name: "load docker, db and proxy for {{ application_id }}"
include_role:
name: sys-stk-back-stateful
name: sys-stk-full-stateful
vars:
docker_compose_flush_handlers: false
- name: "create {{ nextcloud_host_config_additives_directory }}"
file:
path: "{{ nextcloud_host_config_additives_directory }}"
state: directory
mode: "0755"
- name: "Create config files at {{ nextcloud_host_config_additives_directory }}"
template:
src: "{{ item }}"
dest: "{{ nextcloud_host_config_additives_directory }}/{{ item | basename | regex_replace('\\.j2$', '') }}"
owner: "{{ NEXTCLOUD_DOCKER_USER_id }}"
group: "{{ NEXTCLOUD_DOCKER_USER_id }}"
loop: "{{ lookup('fileglob', role_path ~ '/templates/config/*.j2', wantlist=True) }}"
# Not all type of changes take instantly place. Due to this reason a rebuild is required.
notify: docker compose up
- name: create internal nextcloud nginx configuration
template:
src: "nginx/docker.conf.j2"
dest: "{{ docker_compose.directories.volumes }}nginx.conf"
notify: restart nextcloud nginx service
- name: Setup the full docker stack
include_tasks: 01_fullstack.yml
vars:
domain: "{{ NEXTCLOUD_DOMAIN }}"
http_port: "{{ NEXTCLOUD_PORT }}"
- name: Setup config.php
include_tasks: 01_config.yml
include_tasks: 02_config.yml
- name: Flush all handlers immediately so that occ can be used
meta: flush_handlers
- name: Update\Upgrade Nextcloud
include_tasks: 02_upgrade.yml
include_tasks: 03_upgrade.yml
when: MODE_UPDATE | bool
- name: Load system configuration steps
include_tasks: "{{ item }}"
loop:
- 03_admin.yml
- 04_system_config.yml
- 04_admin.yml
- 05_system_config.yml
- name: Setup Nextcloud Plugins
include_tasks: 05_plugin.yml
loop: "{{ applications | get_app_conf(application_id, 'plugins', True) | dict2items }}"
include_tasks: 06_setup_plugin.yml
loop: "{{ NEXTCLOUD_PLUGIN_ITEMS }}"
loop_control:
loop_var: plugin_item
vars:
plugin_key: "{{ plugin_item.key }}"
plugin_value: "{{ plugin_item.value }}"
when: nextcloud_plugins_enabled
when: NEXTCLOUD_PLUGINS_ENABLED

View File

@@ -0,0 +1,7 @@
- name: "Install Collabora Dependency"
include_role:
name: web-svc-collabora
vars:
flush_handlers: true
when:
- run_once_web_svc_collabora is not defined

View File

@@ -1,7 +1,7 @@
<?php
# Implementing OICD configuration
{% if applications | get_app_conf(application_id, 'oidc.flavor', True) == "oidc_login" %}
{% if applications | get_app_conf(application_id, 'oidc.flavor') == "oidc_login" %}
# Check out: https://github.com/pulsejet/nextcloud-oidc-login
@@ -21,7 +21,7 @@ return array (
'oidc_login_auto_redirect' => true,
// Redirect to this page after logging out the user
'oidc_login_logout_url' => 'https://{{ domains | get_domain(application_id) }}',
'oidc_login_logout_url' => '{{ NEXTCLOUD_URL }}',
// If set to true the user will be redirected to the
// logout endpoint of the OIDC provider after logout
@@ -33,7 +33,7 @@ return array (
//
// NOTE: If you want to allow NextCloud to manage quotas, omit this option. Do not set it to
// zero or -1 or ''.
'oidc_login_default_quota' => '{{applications | get_app_conf(application_id, 'default_quota', True)}}',
'oidc_login_default_quota' => '{{ applications | get_app_conf(application_id, 'default_quota', True)}}',
// Login button text
'oidc_login_button_text' => '{{ OIDC.BUTTON_TEXT }}',
@@ -97,7 +97,7 @@ return array (
// note: on Keycloak, OIDC name claim = "${given_name} ${family_name}" or one of them if any is missing
//
'oidc_login_attributes' => array (
'id' => '{{LDAP.USER.ATTRIBUTES.ID}}',
'id' => '{{ LDAP.USER.ATTRIBUTES.ID }}',
'name' => 'name',
'mail' => 'email',
'quota' => '{{ LDAP.USER.ATTRIBUTES.NEXTCLOUD_QUOTA }}',

View File

@@ -1,40 +1,8 @@
{% include 'roles/docker-compose/templates/base.yml.j2' %}
application:
image: "{{ nextcloud_image }}:{{ nextcloud_version }}"
container_name: {{ NEXTCLOUD_CONTAINER }}
volumes:
- 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"]
interval: 1m
timeout: 10s
retries: 3
{% include 'roles/docker-container/templates/base.yml.j2' %}
{% include 'roles/docker-container/templates/depends_on/dmbs_excl.yml.j2' %}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
ipv4_address: 192.168.102.69
{% if nextcloud_talk_enabled %}
talk:
{% include 'roles/docker-container/templates/base.yml.j2' %}
image: "{{ nextcloud_talk_image }}:{{ nextcloud_talk_version }}"
container_name: {{ nextcloud_talk_name }}
hostname: hpb_yt
init: true
ports:
- {{ networks.internet.ip4 }}:{{ nextcloud_talk_stun_port }}:3478/tcp #TURN TCP
- {{ networks.internet.ip4 }}:{{ nextcloud_talk_stun_port }}:3478/udp #TURN UDP
- {{ networks.internet.ip4 }}:8181:8081/tcp #Signaling @todo needs to be optimized
networks:
default:
ipv4_address: 192.168.102.68
{% endif %}
proxy:
image: "{{ nextcloud_proxy_image }}:{{ nextcloud_proxy_version }}"
container_name: "{{ nextcloud_proxy_name }}"
image: "{{ NEXTCLOUD_PROXY_IMAGE }}:{{ NEXTCLOUD_PROXY_VERSION }}"
container_name: "{{ NEXTCLOUD_PROXY_CONTAINER }}"
logging:
driver: journald
restart: {{ DOCKER_RESTART_POLICY }}
@@ -50,9 +18,57 @@
default:
ipv4_address: 192.168.102.67
application:
image: "{{ NEXTCLOUD_IMAGE }}:{{ NEXTCLOUD_VERSION }}"
container_name: {{ NEXTCLOUD_CONTAINER }}
volumes:
- data:{{ NEXTCLOUD_DOCKER_WORK_DIRECTORY }}
- {{ NEXTCLOUD_HOST_CONF_ADD_PATH }}:{{ NEXTCLOUD_DOCKER_CONF_ADD_PATH }}:ro
healthcheck:
test: ["CMD", "su", "www-data", "-s", "/bin/sh", "-c", "php {{ NEXTCLOUD_DOCKER_WORK_DIRECTORY }}occ status"]
interval: 1m
timeout: 10s
retries: 3
{% include 'roles/docker-container/templates/base.yml.j2' %}
{% include 'roles/docker-container/templates/depends_on/dmbs_excl.yml.j2' %}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
ipv4_address: 192.168.102.69
{% if NEXTCLOUD_TALK_ENABLED %}
talk:
{% set container_port = NEXTCLOUD_TALK_INTERNAL_PORT %}
{% include 'roles/docker-container/templates/base.yml.j2' %}
{% include 'roles/docker-container/templates/healthcheck/tcp.yml.j2' %}
image: "{{ NEXTCLOUD_TALK_IMAGE }}:{{ NEXTCLOUD_TALK_VERSION }}"
container_name: {{ NEXTCLOUD_TALK_CONTAINER }}
init: true
ports:
- {{ networks.internet.ip4 }}:{{ NEXTCLOUD_TALK_STUN_PORT }}:{{ NEXTCLOUD_TALK_INT_TURN_PORT }}/tcp #TURN TCP
- {{ networks.internet.ip4 }}:{{ NEXTCLOUD_TALK_STUN_PORT }}:{{ NEXTCLOUD_TALK_INT_TURN_PORT }}/udp #TURN UDP
expose:
- "{{ container_port }}"
networks:
default:
ipv4_address: 192.168.102.68
{% endif %}
{% if NEXTCLOUD_WHITEBOARD_ENABLED %}
whiteboard:
{% set container_port = NEXTCLOUD_WHITEBOARD_INTERNAL_PORT %}
{% include 'roles/docker-container/templates/base.yml.j2' %}
{% include 'roles/docker-container/templates/healthcheck/nc.yml.j2' %}
image: "{{ NEXTCLOUD_WHITEBOARD_IMAGE }}:{{ NEXTCLOUD_WHITEBOARD_VERSION }}"
container_name: {{ NEXTCLOUD_WHITEBOARD_CONTAINER }}
expose:
- "{{ container_port }}"
networks:
default:
ipv4_address: 192.168.102.71
{% endif %}
cron:
container_name: "{{ nextcloud_cron_name }}"
image: "{{ nextcloud_image }}:{{ nextcloud_version }}"
container_name: "{{ NEXTCLOUD_CRON_CONTAINER }}"
image: "{{ NEXTCLOUD_IMAGE }}:{{ NEXTCLOUD_VERSION }}"
restart: {{ DOCKER_RESTART_POLICY }}
logging:
driver: journald
@@ -70,6 +86,6 @@
{% include 'roles/docker-compose/templates/volumes.yml.j2' %}
data:
name: {{ nextcloud_volume }}
name: {{ NEXTCLOUD_VOLUME }}
{% include 'roles/docker-compose/templates/networks.yml.j2' %}

View File

@@ -8,9 +8,9 @@ MYSQL_PASSWORD= "{{ database_password }}"
MYSQL_HOST= "{{ database_host }}:{{ database_port }}"
# PHP
PHP_MEMORY_LIMIT= "{{applications | get_app_conf(application_id, 'performance.php.memory_limit')}}"
PHP_UPLOAD_LIMIT= "{{applications | get_app_conf(application_id, 'performance.php.upload_limit')}}"
PHP_OPCACHE_MEMORY_CONSUMPTION= "{{applications | get_app_conf(application_id, 'performance.php.opcache_memory_consumption')}}"
PHP_MEMORY_LIMIT= "{{ applications | get_app_conf(application_id, 'performance.php.memory_limit') }}"
PHP_UPLOAD_LIMIT= "{{ applications | get_app_conf(application_id, 'performance.php.upload_limit') }}"
PHP_OPCACHE_MEMORY_CONSUMPTION= "{{ applications | get_app_conf(application_id, 'performance.php.opcache_memory_consumption') }}"
# Email Configuration
SMTP_HOST= {{ SYSTEM_EMAIL.HOST }}
@@ -24,30 +24,37 @@ MAIL_FROM_ADDRESS= "{{ users['no-reply'].username }}"
MAIL_DOMAIN= "{{ SYSTEM_EMAIL.DOMAIN }}"
# Initial Admin Data
NEXTCLOUD_ADMIN_USER= "{{applications | get_app_conf(application_id, 'users.administrator.username')}}"
NEXTCLOUD_ADMIN_PASSWORD= "{{applications | get_app_conf(application_id, 'credentials.administrator_password')}}"
NEXTCLOUD_ADMIN_USER= "{{ NEXTCLOUD_ADMINISTRATOR_USER }}"
NEXTCLOUD_ADMIN_PASSWORD= "{{ NEXTCLOUD_ADMINISTRATOR_PASSWORD }}"
# Security
NEXTCLOUD_TRUSTED_DOMAINS= "{{ domains[application_id] | select | join(',') }}"
NEXTCLOUD_TRUSTED_DOMAINS= "{{ NEXTCLOUD_DOMAIN }}"
# Whitelist local docker gateway in Nextcloud to prevent brute-force throtteling
TRUSTED_PROXIES= "{{ networks.internet.values() | select | join(',') }}"
OVERWRITECLIURL= "{{ domains | get_url(application_id, WEB_PROTOCOL) }}"
OVERWRITEPROTOCOL= "https"
OVERWRITECLIURL= "{{ NEXTCLOUD_URL }}"
OVERWRITEPROTOCOL= "{{ WEB_PROTOCOL }}"
# Redis Configuration
REDIS_HOST= redis
REDIS_PORT= 6379
{% if nextcloud_talk_enabled %}
{% if NEXTCLOUD_TALK_ENABLED %}
# Talk Configuration
# This code was just moved here during refactoring and isn't tested yet.
# @todo move it to an own env file for encapsulation reasons
NC_DOMAIN=cloud.yourdomain.tld
TALK_HOST=signaling.yourdomain.tld
TURN_SECRET=${TURN_SECRET}
SIGNALING_SECRET=${SIGNALING_SECRET}
TZ=Europe/Berlin
NC_DOMAIN={{ NEXTCLOUD_DOMAIN }}
TALK_HOST={{ NEXTCLOUD_TALK_DOMAIN }}
TURN_SECRET={{ applications | get_app_conf(application_id, 'credentials.talk_turn_secret') }}
SIGNALING_SECRET={{ applications | get_app_conf(application_id, 'credentials.talk_signaling_secret') }}
INTERNAL_SECRET={{ applications | get_app_conf(application_id, 'credentials.talk_internal_secret') }}
TZ={{ HOST_TIMEZONE }}
TALK_PORT=3478
INTERNAL_SECRET=${INTERNAL_SECRET}
{% endif %}
{% if NEXTCLOUD_WHITEBOARD_ENABLED %}
# @todo move it to an own env file for encapsuling reasons
NEXTCLOUD_URL= "{{ NEXTCLOUD_URL }}"
JWT_SECRET_KEY= "{{ NEXTCLOUD_WHITEBOARD_JWT }}"
STORAGE_STRATEGY=redis
REDIS_URL=redis://redis:6379/0
{% endif %}

View File

@@ -3,7 +3,7 @@
$CONFIG_EXTRA = [];
foreach (glob("{% endraw %}{{ nextcloud_docker_config_additives_directory }}{% raw %}*.php") as $file) {
foreach (glob("{% endraw %}{{ NEXTCLOUD_DOCKER_CONF_ADD_PATH }}{% raw %}*.php") as $file) {
$CONFIG_EXTRA = array_merge($CONFIG_EXTRA, include $file);
}

View File

@@ -179,5 +179,24 @@ http {
location / {
try_files $uri $uri/ /index.php$request_uri;
}
location {{ NEXTCLOUD_WHITEBOARD_LOCATION }} {
proxy_pass http://whiteboard:{{ NEXTCLOUD_WHITEBOARD_INTERNAL_PORT }}/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600;
}
location {{ NEXTCLOUD_TALK_LOCATION }} {
proxy_pass http://talk:{{ NEXTCLOUD_TALK_INTERNAL_PORT }}/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600;
}
}
}

View File

@@ -2,7 +2,7 @@ server
{
server_name {{ domain }};
{% include 'roles/srv-letsencrypt/templates/ssl_header.j2' %}
{% include 'roles/sys-svc-letsencrypt/templates/ssl_header.j2' %}
{% include 'roles/sys-front-inj-all/templates/server.conf.j2'%}
@@ -17,7 +17,7 @@ server
client_body_buffer_size 400M;
fastcgi_buffers 64 4K;
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
{% include 'roles/sys-svc-proxy/templates/location/html.conf.j2' %}
location ^~ /.well-known {
rewrite ^/\.well-known/host-meta\.json /public.php?service=host-meta-json last;

Some files were not shown because too many files have changed in this diff Show More