10 Commits

Author SHA1 Message Date
7405883b48 BigBlueButton & Nextcloud:
- Switch to custom BBB Docker repository
- Externalize Coturn and Collabora by default
- Add dedicated 03_dependencies.yml for dependency handling
- Improve env templating with lowercased feature flags
- Add conditional healthcheck for Greenlight
- Refactor TURN/STUN/relay handling with role variable _BBB_COTURN_ROLE
- Extend Collabora/Greenlight dependency wiring in override file
- Nextcloud Talk: refine vars and enable/disable logic with separate plugin/service flags, add network_mode support and conditional nginx proxy block

Ref: https://chatgpt.com/share/68d741ff-a544-800f-9e81-a565e0bab0eb
2025-09-27 03:46:57 +02:00
85db0a40db Refactor Coturn port configuration: unify STUN and TURN into stun_turn and stun_turn_tls, update vars, docker-compose template, and add robust healthcheck [https://chatgpt.com/share/68d73a2d-ef34-800f-90d2-1628822ca541] 2025-09-27 03:14:53 +02:00
8af39c32ec Override docker conf variables from parents 2025-09-27 02:41:13 +02:00
31e86ac0fc Optimized networks 2025-09-27 02:21:19 +02:00
4d223f1784 feat(web-svc-coturn): add configurable network_mode (default host) and adjust credential generation
- Introduced `COTURN_NETWORK_MODE` to support both host and bridge modes
- Updated docker-compose template to skip port publishing in host mode
- Changed user_password credential algorithm to random_hex for stronger randomness
- Set default network_mode: host in config

Ref: https://chatgpt.com/share/68d72a50-c36c-800f-9367-32c4ae520000
2025-09-27 02:05:48 +02:00
926def3d01 web-svc-coturn: Add resource limits and fix docker-compose template
- Set CPU, memory reservation/limit, and PID limit for coturn
- Ensure docker_compose_file_creation_enabled and disable git repo pulling
- Move certificate mounts to volumes and fix env var interpolation in command
- Correct realm and user formatting

See: https://chatgpt.com/share/66f65f18-799c-800a-95f4-b6b26511e9cb
2025-09-27 01:40:37 +02:00
083b7d2914 Refactor relay port ranges: set coturn to 20000–39999, BigBlueButton to 40000–49999, and Nextcloud to 50000–59999
See: https://chatgpt.com/share/68d6f6c2-f7c0-800f-bc2e-10876afff4a8
2025-09-26 22:26:44 +02:00
73a38e0b2b Refactor TURN/STUN handling:
- Split internal/external Coturn for BBB and Nextcloud
- Added dedicated relay port ranges per app
- Updated env and compose overrides for coturn
- Ensure coturn role is loaded conditionally
- Standardize credential/env passing for coturn
@See https://chatgpt.com/share/68d6f376-4878-800f-b4f7-62822caa49ea
2025-09-26 22:11:55 +02:00
e3c0880e98 Fix semi-stateless run_once label and load both docker-compose & openresty handlers
See: https://chatgpt.com/share/68d6f2f3-59a4-800f-b20e-ed1c7df9e2ff
2025-09-26 22:09:39 +02:00
a817d964e4 refactor(front-stack): introduce sys-stk-front-base and semi-stateless stack; improve coturn role docs
- Extract common HTTPS + Cloudflare + handler bootstrap into new role sys-stk-front-base
- Update sys-stk-front-proxy, web-svc-cdn, web-svc-file, web-svc-html to depend on sys-stk-front-base
- Add new sys-stk-semi-stateless role combining front-base + back-stateless
- Update web-svc-coturn to use sys-stk-semi-stateless and rewrite README/meta with detailed Coturn description
- Unify sys-util-csp-cert README heading

Ref: ChatGPT conversation https://chatgpt.com/share/68d6cea2-3570-800f-acb3-c3277317f17b
2025-09-26 20:25:53 +02:00
40 changed files with 382 additions and 110 deletions

View File

@@ -88,18 +88,21 @@ ports:
web-app-gitlab: 2202
ldaps:
svc-db-openldap: 636
stun:
stun_turn:
web-app-bigbluebutton: 3478 # Not sure if it's right placed here or if it should be moved to localhost section
# Occupied by BBB: 3479
web-app-nextcloud: 3480
web-app-coturn: 3481
turn:
web-svc-coturn: 3481
stun_turn_tls:
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-coturn: 5351
web-svc-coturn: 5351
federation:
web-app-matrix_synapse: 8448
relay_port_ranges:
web-app-coturn_start: 49152
web-app-coturn_end: 65535
web-svc-coturn_start: 20000
web-svc-coturn_end: 39999
web-app-bigbluebutton_start: 40000
web-app-bigbluebutton_end: 49999
web-app-nextcloud_start: 50000
web-app-nextcloud_end: 59999

View File

@@ -0,0 +1,21 @@
# Front Base (HTTPS + Cloudflare + Handlers) 🚀
## Description
**sys-stk-front-base** bootstraps the front layer that most web-facing apps need:
- Ensures the HTTPS base via `sys-svc-webserver-https`
- (Optional) Cloudflare bootstrap (zone lookup, dev mode, purge)
- Wires OpenResty/Nginx handlers
- Leaves per-domain certificate issuance to consumer roles (or pass-through vars to `sys-util-csp-cert` if needed)
> This role is intentionally small and reusable. It prepares the ground so app roles can just render their vHost.
## Responsibilities
- Include `sys-svc-webserver-https` (once per host)
- Include Cloudflare tasks when `DNS_PROVIDER == "cloudflare"`
- Load handler utilities (e.g., `svc-prx-openresty`)
- Stay domain-agnostic: expect `domain` to be provided by the consumer
## Outputs
- Handler wiring completed
- HTTPS base ready (Nginx, ACME webroot)
- Cloudflare prepared (optional)

View File

@@ -0,0 +1,24 @@
galaxy_info:
author: "Kevin Veen-Birkenbach"
description: "Front bootstrap for web apps: HTTPS base, optional Cloudflare setup, and handler wiring."
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: Archlinux
versions:
- rolling
galaxy_tags:
- nginx
- https
- cloudflare
- automation
- web
repository: "https://s.infinito.nexus/code"
issue_tracker_url: "https://s.infinito.nexus/issues"
documentation: "https://docs.infinito.nexus/"
dependencies: []

View File

@@ -0,0 +1,14 @@
- block:
- name: Include dependency 'sys-svc-webserver-https'
include_role:
name: sys-svc-webserver-https
when: run_once_sys_svc_webserver_https is not defined
- include_tasks: utils/run_once.yml
when: run_once_sys_stk_front_base is not defined
- include_tasks: "01_cloudflare.yml"
when: DNS_PROVIDER == "cloudflare"
- include_tasks: "{{ [ playbook_dir, 'tasks/utils/load_handlers.yml' ] | path_join }}"
vars:
handler_role_name: "svc-prx-openresty"

View File

@@ -1,17 +1,6 @@
- block:
- name: Include dependency 'sys-svc-webserver-https'
include_role:
name: sys-svc-webserver-https
when: run_once_sys_svc_webserver_https is not defined
- include_tasks: utils/run_once.yml
when: run_once_sys_stk_front_proxy is not defined
- include_tasks: "02_cloudflare.yml"
when: DNS_PROVIDER == "cloudflare"
- include_tasks: "{{ [ playbook_dir, 'tasks/utils/load_handlers.yml' ] | path_join }}"
vars:
handler_role_name: "svc-prx-openresty"
- name: Front bootstrap
include_role:
name: sys-stk-front-base
- name: "include role for '{{ domain }}' to receive certificates and do the modification routines"
include_role:

View File

@@ -0,0 +1,13 @@
# Semi-Stateless Stack (Front + Back) ⚡
## Description
**sys-stk-semi-stateless** combines the front and back layer into a lightweight, mostly stateless web service stack:
- Front bootstrap via `sys-stk-front-base` (HTTPS base, optional Cloudflare, handlers)
- Backend via `sys-stk-back-stateless` (no persistent volumes/DB)
Ideal for services that need TLS/front glue but no database (e.g., TURN/STUN, gateways, simple APIs).
## Responsibilities
- Prepare the front layer (HTTPS / handlers / optional Cloudflare)
- Deploy the stateless backend (typically via Docker Compose)
- Keep domain variables (`domain`) and app-scoped variables (`application_id`) clearly separated

View File

@@ -0,0 +1,24 @@
galaxy_info:
author: "Kevin Veen-Birkenbach"
description: "Combined semi-stateless app stack: front bootstrap + stateless backend."
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: Archlinux
versions:
- rolling
galaxy_tags:
- nginx
- https
- stateless
- backend
- cloudflare
- automation
repository: "https://s.infinito.nexus/code"
issue_tracker_url: "https://s.infinito.nexus/issues"
documentation: "https://docs.infinito.nexus/"

View File

@@ -0,0 +1,11 @@
# run_once_sys_stk_semi_stateless: deactivated
- name: "sys-stk-front-base"
include_role:
name: sys-stk-front-base
vars:
domain: "{{ domains | get_domain(application_id) }}"
- name: "For '{{ application_id }}': Load sys-stk-back-stateless"
include_role:
name: sys-stk-back-stateless

View File

@@ -11,10 +11,13 @@
- name: "Load variables from {{ DOCKER_VARS_FILE }} for {{ role_name }}/{{ application_id }}"
include_vars: "{{ DOCKER_VARS_FILE }}"
- name: "Load docker compose handlers"
- name: "Load docker compose & openresty handlers"
include_tasks: "{{ [ playbook_dir, 'tasks/utils/load_handlers.yml' ] | path_join }}"
vars:
handler_role_name: "docker-compose"
loop:
- docker-compose
- svc-prx-openresty
loop_control:
loop_var: handler_role_name
- name: "Include tasks to create directories"
include_tasks: 04_directories.yml
@@ -23,7 +26,7 @@
template:
src: nginx.conf.j2
dest: "{{ NGINX.FILES.CONFIGURATION }}"
notify: docker compose up
notify: restart openresty
- name: Include openresty
# Outside of run_once block is necessary for handler loading

View File

@@ -1,4 +1,4 @@
# Role: sys-util-csp-cert
# 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

@@ -24,7 +24,7 @@ credentials: {}
docker:
services:
bigbluebutton:
repository: "https://github.com/bigbluebutton/docker.git"
repository: "https://github.com/kevinveenbirkenbach/bigbluebutton-docker.git"
version: "bbb3.0"
database:
# This is set to true to pass integration test, doesn't have any other function
@@ -32,4 +32,6 @@ docker:
greenlight:
enabled: true
coturn:
enabled: true
internal: false
collabora:
internal: false

View File

@@ -17,7 +17,7 @@ credentials:
validation: "^[a-zA-Z0-9]{32}$"
fsesl_password:
description: "Password for FreeSWITCH ESL connection"
algorithm: "alphanumeric_32"
algorithm: "random_hex"
validation: "^.{8,}$"
turn_secret:
description: "TURN server shared secret"

View File

@@ -0,0 +1,17 @@
- name: "Load Coturn Role for '{{ application_id }}'"
include_role:
name: web-svc-coturn
vars:
flush_handlers: true
when:
- run_once_web_svc_coturn is not defined
- not BBB_COTURN_ENABLED
- name: "Install Collabora Dependency"
include_role:
name: web-svc-collabora
vars:
flush_handlers: true
when:
- run_once_web_svc_collabora is not defined
- not BBB_COLLABORA_ENABLED

View File

@@ -67,4 +67,5 @@
- name: "Setup administrator"
include_tasks: "02_administrator.yml"
- name: "Load '{{ application_id }}' dependencies"
include_tasks: "03_dependencies.yml"

View File

@@ -5,3 +5,42 @@ services:
MS_ENABLE_IPV6: "false"
MS_WEBRTC_LISTEN_IPS: >-
[{"ip":"0.0.0.0","announcedIp":"${EXTERNAL_IPv4}"}]
{% if BBB_COTURN_ENABLED | bool %}
coturn:
ports:
- "{{ BBB_TURN_PORT }}:{{ BBB_TURN_PORT }}/udp"
- "{{ BBB_TURN_PORT }}:{{ BBB_TURN_PORT }}/tcp"
- "{{ BBB_STUN_PORT }}:{{ BBB_STUN_PORT }}/udp"
- "{{ BBB_STUN_PORT }}:{{ BBB_STUN_PORT }}/tcp"
- "{{ BBB_RELAY_PORT_RANGE }}/udp"
command: >-
--use-auth-secret
--static-auth-secret=${TURN_SECRET}
--lt-cred-mech
--realm=${DOMAIN}
--fingerprint
--no-multicast-peers
--no-cli
--no-tcp-relay
--min-port={{ BBB_RELAY_PORT_START }}
--max-port={{ BBB_RELAY_PORT_END }}
--external-ip=${EXTERNAL_IPv4}
{% if BBB_IP6_ENABLED %}--external-ip=${EXTERNAL_IPv6}{% endif %}
--cert=${COTURN_TLS_CERT_PATH}
--pkey=${COTURN_TLS_KEY_PATH}
{% endif %}
{% if BBB_GREENLIGHT_ENABLED | bool %}
greenlight:
{% set container_port = 3000 %}
{% include 'roles/docker-container/templates/healthcheck/nc.yml.j2' %}
{% endif %}
{% if BBB_COLLABORA_ENABLED | bool %}
bbb-web:
depends_on:
- redis
- etherpad
- bbb-pads
etherpad:
depends_on:
- redis
{% endif %}

View File

@@ -1,11 +1,15 @@
# Coturn
ENABLE_COTURN={{ BBB_COTURN_ENABLED }}
ENABLE_COTURN={{ BBB_COTURN_ENABLED | lower }}
# Credentials
# Collabora
ENABLE_COLLABORA={{ BBB_COLLABORA_ENABLED | lower }}
COLLABORA_URL={{ BBB_COLLABORA_URL }}
## Credentials
COTURN_TLS_CERT_PATH={{ BBB_COTURN_TLS_CERT_PATH }}
COTURN_TLS_KEY_PATH={{ BBB_COTURN_TLS_KEY_PATH }}
ENABLE_GREENLIGHT={{ BBB_GREENLIGHT_ENABLED }}
ENABLE_GREENLIGHT={{ BBB_GREENLIGHT_ENABLED | lower }}
# Enable Webhooks
# used by some integrations

View File

@@ -14,12 +14,13 @@ domain: "{{ domains | get_domain(application_id) }
http_port: "{{ ports.localhost.http[application_id] }}"
# Docker
docker_compose_file_creation_enabled: false # Handled in this role
docker_compose_file_creation_enabled: false
docker_pull_git_repository: true
docker_repository_address: "{{ applications | get_app_conf(application_id, 'docker.services.' ~ entity_name ~ '.repository') }}"
docker_repository_branch: "{{ applications | get_app_conf(application_id, 'docker.services.' ~ entity_name ~ '.version') }}"
docker_pull_git_repository: true
# BigBlueButton
_BBB_COTURN_ROLE: 'web-svc-coturn'
## Credentials
BBB_SHARED_SECRET: "{{ applications | get_app_conf(application_id, 'credentials.shared_secret') }}"
@@ -27,16 +28,24 @@ BBB_ETHERPAD_API_KEY: "{{ applications | get_app_conf(applicatio
BBB_RAILS_SECRET: "{{ applications | get_app_conf(application_id, 'credentials.rails_secret') }}"
BBB_POSTGRESQL_SECRET: "{{ applications | get_app_conf(application_id, 'credentials.postgresql_secret') }}"
BBB_FSESL_PASSWORD: "{{ applications | get_app_conf(application_id, 'credentials.fsesl_password') }}"
BBB_TURN_SECRET: "{{ applications | get_app_conf(application_id, 'credentials.turn_secret') }}"
BBB_TURN_SECRET: "{{ applications | get_app_conf(application_id, 'credentials.turn_secret') if BBB_COTURN_ENABLED else applications | get_app_conf(_BBB_COTURN_ROLE, 'credentials.auth_secret') }}"
## TLS
BBB_COTURN_TLS_CERT_PATH: "{{ [ LETSENCRYPT_LIVE_PATH, ssl_cert_folder, 'fullchain.pem'] | path_join }}"
BBB_COTURN_TLS_KEY_PATH: "{{ [ LETSENCRYPT_LIVE_PATH, ssl_cert_folder, 'privkey.pem'] | path_join }}"
## Turn
BBB_TURN_DOMAIN: "{{ networks.internet.ip4 if BBB_COTURN_ENABLED else domains | get_domain('web-svc-coturn') }}"
BBB_TURN_PORT: "{{ ports.public.turn[application_id] if BBB_COTURN_ENABLED else ports.public.turn['web-svc-coturn'] }}"
BBB_STUN_PORT: "{{ ports.public.turn[application_id] if BBB_COTURN_ENABLED else ports.public.stun['web-svc-coturn'] }}"
BBB_COTURN_ENABLED: "{{ applications | get_app_conf(application_id, 'docker.services.coturn.internal') }}"
BBB_TURN_DOMAIN: "{{ networks.internet.ip4 if BBB_COTURN_ENABLED else domains | get_domain(_BBB_COTURN_ROLE) }}"
BBB_TURN_PORT: "{{ ports.public.stun_turn[application_id] if BBB_COTURN_ENABLED else ports.public.stun_turn[_BBB_COTURN_ROLE] }}"
BBB_STUN_PORT: "{{ ports.public.stun_turn[application_id] if BBB_COTURN_ENABLED else ports.public.stun_turn_tls[_BBB_COTURN_ROLE] }}"
BBB_RELAY_PORT_START: "{{ ports.public.relay_port_ranges[application_id ~ '_start'] }}"
BBB_RELAY_PORT_END: "{{ ports.public.relay_port_ranges[application_id ~ '_end'] }}"
BBB_RELAY_PORT_RANGE: "{{ BBB_RELAY_PORT_START }}-{{ BBB_RELAY_PORT_END }}"
# Collabora
BBB_COLLABORA_ENABLED: "{{ applications | get_app_conf(application_id, 'docker.services.collabora.internal') }}"
BBB_COLLABORA_URL: "{{ 'https://collabora:9980/cool' if BBB_COLLABORA_ENABLED else (domains | get_url('web-svc-collabora', WEB_PROTOCOL)) }}"
## Switchs
@@ -45,7 +54,6 @@ BBB_IP6_ENABLED: "{{ applications | get_app_conf(applicatio
### Container
BBB_GREENLIGHT_ENABLED: "{{ applications | get_app_conf(application_id, 'docker.services.greenlight.enabled') }}"
BBB_COTURN_ENABLED: "{{ applications | get_app_conf(application_id, 'docker.services.coturn.enabled') }}"
### SSO
BBB_LDAP_ENABLED: "{{ applications | get_app_conf(application_id, 'features.ldap') }}"

View File

@@ -28,9 +28,9 @@ docker:
database:
enabled: true
nextcloud:
name: "nextcloud"
image: "nextcloud"
version: "production-fpm-alpine"
name: "nextcloud"
image: "nextcloud"
version: "production-fpm-alpine"
backup:
no_stop_required: true
cpus: "2.0"
@@ -38,26 +38,28 @@ docker:
mem_limit: "3g"
pids_limit: 512
proxy:
name: "nextcloud-proxy"
image: "nginx"
version: "alpine"
name: "nextcloud-proxy"
image: "nginx"
version: "alpine"
backup:
no_stop_required: true
cron:
name: "nextcloud-cron"
name: "nextcloud-cron"
talk:
name: "nextcloud-talk"
image: "nextcloud/aio-talk"
version: "latest"
name: "nextcloud-talk"
image: "nextcloud/aio-talk"
version: "latest"
backup:
no_stop_required: false
internal: false
network_mode: host
whiteboard:
name: "nextcloud-whiteboard"
image: "ghcr.io/nextcloud-releases/whiteboard"
version: "latest"
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
enabled: "{{ applications | get_app_conf('web-app-nextcloud', 'features.oidc', False) }}" # 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

View File

@@ -0,0 +1,7 @@
- name: "Load Coturn Role for '{{ application_id }}'"
include_role:
name: web-svc-coturn
vars:
flush_handlers: true
when:
- run_once_web_svc_coturn is not defined

View File

@@ -34,7 +34,7 @@
{% include 'roles/docker-container/templates/networks.yml.j2' %}
ipv4_address: 192.168.102.69
{% if NEXTCLOUD_TALK_ENABLED %}
{% if NEXTCLOUD_TALK_SERVICE_ENABLED %}
talk:
{% set container_port = NEXTCLOUD_TALK_PORT_INTERNAL %}
{% include 'roles/docker-container/templates/base.yml.j2' %}
@@ -42,15 +42,19 @@
image: "{{ NEXTCLOUD_TALK_IMAGE }}:{{ NEXTCLOUD_TALK_VERSION }}"
container_name: {{ NEXTCLOUD_TALK_CONTAINER }}
init: true
network_mode: {{ COTURN_NETWORK_MODE }}
{% if NEXTCLOUD_TALK_NETWORK_MODE == 'bridge' %}
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
- {{ networks.internet.ip4 }}:{{ NEXTCLOUD_TALK_STUN_PORT }}:{{ NEXTCLOUD_TALK_INT_TURN_PORT }}/tcp
- {{ networks.internet.ip4 }}:{{ NEXTCLOUD_TALK_STUN_PORT }}:{{ NEXTCLOUD_TALK_INT_TURN_PORT }}/udp
- {{ NEXTCLOUD_TALK_RELAY_PORT_RANGE }}:{{ NEXTCLOUD_TALK_RELAY_PORT_RANGE }}/udp
expose:
- "{{ container_port }}"
networks:
default:
ipv4_address: 192.168.102.68
{% endif %}
{% endif %}
{% if NEXTCLOUD_WHITEBOARD_ENABLED %}
whiteboard:

View File

@@ -39,7 +39,7 @@ OVERWRITEPROTOCOL= "{{ WEB_PROTOCOL }}"
REDIS_HOST= redis
REDIS_PORT= 6379
{% if NEXTCLOUD_TALK_ENABLED %}
{% if NEXTCLOUD_TALK_PLUGIN_ENABLED %}
# Talk Configuration
# @todo move it to an own env file for encapsulation reasons
NC_DOMAIN={{ NEXTCLOUD_DOMAIN }}
@@ -49,6 +49,10 @@ SIGNALING_SECRET={{ applications | get_app_conf(application_id, 'credentials.tal
INTERNAL_SECRET={{ applications | get_app_conf(application_id, 'credentials.talk_internal_secret') }}
TZ={{ HOST_TIMEZONE }}
TALK_PORT={{ NEXTCLOUD_TALK_INT_TURN_PORT }}
TURN_MIN_PORT={{ NEXTCLOUD_TALK_RELAY_PORT_START }}
TURN_MAX_PORT={{ NEXTCLOUD_TALK_RELAY_PORT_END }}
COTURN_MIN_PORT={{ NEXTCLOUD_TALK_RELAY_PORT_START }}
COTURN_MAX_PORT={{ NEXTCLOUD_TALK_RELAY_PORT_END }}
{% endif %}
{% if NEXTCLOUD_WHITEBOARD_ENABLED %}

View File

@@ -190,6 +190,7 @@ http {
proxy_read_timeout 3600;
}
{% if NEXTCLOUD_TALK_SERVICE_ENABLED %}
location {{ NEXTCLOUD_TALK_LOCATION }} {
proxy_pass http://talk:{{ NEXTCLOUD_TALK_PORT_INTERNAL }}/;
proxy_http_version 1.1;
@@ -198,5 +199,7 @@ http {
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600;
}
{% endif %}
}
}

View File

@@ -58,16 +58,24 @@ NEXTCLOUD_PROXY_VERSION: "{{ applications | get_app_conf(application_
NEXTCLOUD_CRON_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.cron.name') }}"
### Talk
#### Service
NEXTCLOUD_TALK_CONTAINER: "{{ 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 | get_app_conf(application_id, 'plugins.spreed.enabled') }}"
NEXTCLOUD_TALK_STUN_PORT: "{{ ports.public.stun[application_id] }}"
NEXTCLOUD_TALK_DOMAIN: "{{ NEXTCLOUD_DOMAIN }}"
NEXTCLOUD_TALK_PLUGIN_ENABLED: "{{ applications | get_app_conf(application_id, 'plugins.spreed.enabled') }}"
NEXTCLOUD_TALK_SERVICE_ENABLED: "{{ applications | get_app_conf(application_id, 'docker.services.talk.internal') if NEXTCLOUD_TALK_PLUGIN_ENABLED else false }}"
NEXTCLOUD_TALK_LOCATION: "/standalone-signaling/"
NEXTCLOUD_TALK_URL: "{{ [ NEXTCLOUD_URL, NEXTCLOUD_TALK_LOCATION ] | url_join }}"
NEXTCLOUD_TALK_PORT_INTERNAL: "8081"
NEXTCLOUD_TALK_INT_TURN_PORT: "3478"
NEXTCLOUD_TALK_RELAY_PORT_START: "{{ ports.public.relay_port_ranges[application_id ~ '_start'] }}"
NEXTCLOUD_TALK_RELAY_PORT_END: "{{ ports.public.relay_port_ranges[application_id ~ '_end' ] }}"
NEXTCLOUD_TALK_RELAY_PORT_RANGE: "{{ NEXTCLOUD_TALK_RELAY_PORT_START }}-{{ NEXTCLOUD_TALK_RELAY_PORT_END }}"
NEXTCLOUD_TALK_NETWORK_MODE: "{{ applications | get_app_conf(application_id, 'docker.services.talk.network_mode') }}"
# Connection
NEXTCLOUD_TALK_STUN_PORT: "{{ ports.public.stun_turn_tls[application_id] }}"
NEXTCLOUD_TALK_DOMAIN: "{{ NEXTCLOUD_DOMAIN }}"
NEXTCLOUD_TALK_URL: "{{ [ NEXTCLOUD_URL, NEXTCLOUD_TALK_LOCATION ] | url_join }}"
### Whiteboard
NEXTCLOUD_WHITEBOARD_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.whiteboard.name') }}"

View File

@@ -2,7 +2,7 @@
include_role:
name: '{{ item }}'
loop:
- sys-svc-webserver-https
- sys-stk-front-base
- dev-git
- name: "include role for {{ application_id }} to receive certs & do modification routines"

View File

@@ -3,7 +3,9 @@
name: sys-stk-full-stateless
public: true
vars:
docker_compose_flush_handlers: true
docker_compose_flush_handlers: true
docker_compose_file_creation_enabled: true
docker_pull_git_repository: false
- name: "generate {{ domain }}.conf"
template:

View File

@@ -1,9 +1,46 @@
# Coturn Server (DRAFT)
setup an coturn server based on https://hub.docker.com/r/coturn/coturn
# Coturn
## todo
This folder contains the role to deploy and manage a [Coturn](https://github.com/coturn/coturn) service.
Needs to be implemented so that Nextcloud Talk works
## Description
## author
[Kevin Veen-Birkenbach](https://www.veen.world)
[Coturn](https://github.com/coturn/coturn) is a free and open-source **TURN (Traversal Using Relays around NAT)** and **STUN (Session Traversal Utilities for NAT)** server.
It enables real-time communication (RTC) applications such as **WebRTC** to work reliably across NATs and firewalls.
Without TURN/STUN, video calls, conferencing, and peer-to-peer connections often fail due to NAT traversal issues.
Coturn solves this by acting as a **relay server** and/or **discovery service** for public IP addresses.
More background:
* Wikipedia: [Traversal Using Relays around NAT](https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT)
* Wikipedia: [Session Traversal Utilities for NAT](https://en.wikipedia.org/wiki/STUN)
* Official Coturn Docs: [https://github.com/coturn/coturn/wiki](https://github.com/coturn/coturn/wiki)
## Overview
This role deploys Coturn via Docker Compose using the `sys-stk-semi-stateless` stack.
It automatically configures:
- TURN and STUN listening ports
- Relay port ranges
- TLS certificates (via Lets Encrypt integration)
- Long-term credentials and/or REST API secrets
Typical use cases:
- Nextcloud Talk
- Jitsi
- BigBlueButton
- Any WebRTC-based application
## Features
* Stateless container deployment (no database or persistent volume required)
* Automatic TLS handling via `sys-stk-front-base`
* TURN and STUN support over TCP and UDP
* Configurable relay port ranges for scaling
* Integration into Infinito.Nexus inventory/variable system
## Further Resources
* Coturn Project — [https://github.com/coturn/coturn](https://github.com/coturn/coturn)
* Coturn Wiki — [https://github.com/coturn/coturn/wiki](https://github.com/coturn/coturn/wiki)
* TURN on Wikipedia — [https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT](https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT)
* STUN on Wikipedia — [https://en.wikipedia.org/wiki/STUN](https://en.wikipedia.org/wiki/STUN)

View File

@@ -0,0 +1,19 @@
username: coturnconsumer
server:
domains:
canonical:
- "coturn.{{ PRIMARY_DOMAIN }}"
docker:
services:
coturn:
image: "coturn/coturn"
version: "latest"
cpus: 1.0
mem_reservation: 512m
mem_limit: 1g
pids_limit: 256
network_mode: host
redis:
enabled: false
database:
enabled: false

View File

@@ -1,13 +0,0 @@
server:
domains:
canonical:
- "coturn.{{ PRIMARY_DOMAIN }}"
docker:
services:
coturn:
image: "coturn/coturn"
version: "latest"
redis:
enabled: false
database:
enabled: false

View File

@@ -1,7 +1,7 @@
---
galaxy_info:
author: "Kevin Veen-Birkenbach"
description: "Deploys a Coturn TURN/STUN server via Docker Compose, with automatic domain and port configuration for Nextcloud Talk."
description: "Deploys Coturn, a free and open-source TURN/STUN server"
license: "Infinito.Nexus NonCommercial License"
license_url: "https://s.infinito.nexus/license"
company: |
@@ -12,12 +12,13 @@ galaxy_info:
- coturn
- turn
- stun
- webrtc
- docker
- stateless
- realtime
repository: "https://s.infinito.nexus/code"
issue_tracker_url: "https://s.infinito.nexus/issues"
documentation: "https://s.infinito.nexus/code/tree/main/roles/web-svc-coturn"
min_ansible_version: "2.9"
platforms:
- name: Any
versions:
- all
documentation: "https://github.com/coturn/coturn/wiki"
logo:
class: "webrtc"
run_after: []

View File

@@ -1,7 +1,7 @@
credentials:
user_password:
description: "Long-Term Credential password for clients"
algorithm: "alphanumeric_32"
algorithm: "random_hex"
validation: "^[A-Za-z0-9]{32}$"
auth_secret:
description: "TURN-REST static auth secret"

View File

@@ -0,0 +1,6 @@
- name: "Load 'sys-stk-semi-stateless' for '{{ application_id }}'"
include_role:
name: sys-stk-semi-stateless
vars:
docker_compose_file_creation_enabled: true
docker_pull_git_repository: false

View File

@@ -1,4 +1,6 @@
---
- name: "For '{{ application_id }}': Load sys-stk-back-stateless"
include_role:
name: sys-stk-back-stateless
- block:
- name: "Load core functions for '{{ application_id }}'"
include_tasks: 01_core.yml
- include_tasks: utils/run_once.yml
when: run_once_web_svc_coturn is not defined

View File

@@ -4,36 +4,48 @@
{% include 'roles/docker-container/templates/base.yml.j2' %}
image: {{ COTURN_IMAGE }}:{{ COTURN_VERSION }}
container_name: {{ COTURN_VOLUME }}
{% include 'roles/docker-container/templates/base.yml.j2' %}
network_mode: {{ COTURN_NETWORK_MODE }}
{% if COTURN_NETWORK_MODE == 'bridge' %}
ports:
- "{{ COTURN_TURN_PORT }}:{{ COTURN_TURN_PORT }}/udp"
- "{{ COTURN_TURN_PORT }}:{{ COTURN_TURN_PORT }}/tcp"
- "{{ COTURN_STUN_PORT }}:{{ COTURN_STUN_PORT }}/tcp"
- "{{ COTURN_STUN_PORT }}:{{ COTURN_STUN_PORT }}/udp"
- "{{ COTURN_STUN_TURN_PORT }}:{{ COTURN_STUN_TURN_PORT }}/udp"
- "{{ COTURN_STUN_TURN_PORT }}:{{ COTURN_STUN_TURN_PORT }}/tcp"
- "{{ COTURN_STUN_TURN_PORT_TLS }}:{{ COTURN_STUN_TURN_PORT_TLS }}/tcp"
- "{{ COTURN_STUN_TURN_PORT_TLS }}:{{ COTURN_STUN_TURN_PORT_TLS }}/udp"
- "{{ COTURN_RELAY_PORT_RANGE }}/udp"
{% include 'roles/docker-container/templates/networks.yml.j2' %}
{% endif %}
volumes:
- "{{ COTURN_TLS_CERT_PATH }}:{{ COTURN_TLS_CERT_PATH }}:ro"
- "{{ COTURN_TLS_KEY_PATH }}:{{ COTURN_TLS_KEY_PATH }}:ro"
command: >
--use-auth-secret
--static-auth-secret={{ COTURN_STATIC_AUTH_SECRET }}
--static-auth-secret="${COTURN_STATIC_AUTH_SECRET}"
--lt-cred-mech
--user={{ COTURN_USER_NAME }}:{{ COTURN_USER_PASSWORD }}
--user="${COTURN_USER_NAME}:${COTURN_USER_PASSWORD}"
--log-file=stdout
--external-ip={{ networks.internet.ip4 }}
{% if networks.internet.ip6|default('') %}
--external-ip={{ networks.internet.ip6 }}
{% endif %}
--realm={{ COTURN_REALM }}
--realm="${COTURN_REALM}"
--fingerprint
--total-quota=100
--stale-nonce
--no-multicast-peers
--no-cli
--no-tcp-relay
--listening-port={{ COTURN_STUN_TURN_PORT }}
--tls-listening-port={{ COTURN_STUN_TURN_PORT_TLS }}
--min-port={{ COTURN_RELAY_PORT_START }}
--max-port={{ COTURN_RELAY_PORT_END }}
--cert={{ COTURN_TLS_CERT_PATH }}
--pkey={{ COTURN_TLS_KEY_PATH }}
--cipher-list=DEFAULT
--dh2066
{% include 'roles/docker-container/templates/networks.yml.j2' %}
healthcheck:
test: ["CMD", "sh", "-c", "command -v turnutils_stunclient >/dev/null && turnutils_stunclient -p {{ COTURN_STUN_TURN_PORT }} 127.0.0.1 || nc -z 127.0.0.1 {{ COTURN_STUN_TURN_PORT }}"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
{% include 'roles/docker-compose/templates/networks.yml.j2' %}

View File

@@ -0,0 +1,4 @@
COTURN_STATIC_AUTH_SECRET={{ COTURN_STATIC_AUTH_SECRET }}
COTURN_USER_NAME={{ COTURN_USER_NAME }}
COTURN_USER_PASSWORD={{ COTURN_USER_PASSWORD }}
COTURN_REALM={{ COTURN_REALM }}

View File

@@ -10,16 +10,17 @@ COTURN_VERSION: "{{ applications | get_app_conf(application_id, 'doc
COTURN_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.' ~ entity_name ~ '.image') }}"
COTURN_VOLUME: "{{ entity_name }}"
COTURN_REALM: "{{ domain }}"
COTURN_NETWORK_MODE: "{{ applications | get_app_conf(application_id, 'docker.services.' ~ entity_name ~ '.network_mode') }}"
## Ports
COTURN_TURN_PORT: "{{ ports.public.turn[application_id] }}"
COTURN_STUN_PORT: "{{ ports.public.stun[application_id] }}"
COTURN_STUN_TURN_PORT: "{{ ports.public.stun_turn[application_id] }}"
COTURN_STUN_TURN_PORT_TLS: "{{ ports.public.stun_turn_tls[application_id] }}"
COTURN_RELAY_PORT_START: "{{ ports.public.relay_port_ranges[application_id ~ '_start'] }}"
COTURN_RELAY_PORT_END: "{{ ports.public.relay_port_ranges[application_id ~ '_end' ] }}"
COTURN_RELAY_PORT_RANGE: "{{ COTURN_RELAY_PORT_START }}-{{ COTURN_RELAY_PORT_END }}"
## Credentials
COTURN_USER_NAME: "{{ applications | get_app_conf(application_id, 'credentials.user_name') }}"
COTURN_USER_NAME: "{{ applications | get_app_conf(application_id, 'username') }}"
COTURN_USER_PASSWORD: "{{ applications | get_app_conf(application_id, 'credentials.user_password') }}"
COTURN_STATIC_AUTH_SECRET: "{{ applications | get_app_conf(application_id, 'credentials.auth_secret') }}"

View File

@@ -3,7 +3,7 @@
include_role:
name: '{{ item }}'
loop:
- sys-svc-webserver-https
- sys-stk-front-base
- dev-git
- include_tasks: utils/run_once.yml
when: run_once_web_svc_file is not defined

View File

@@ -3,7 +3,7 @@
include_role:
name: '{{ item }}'
loop:
- sys-svc-webserver-https
- sys-stk-front-base
- dev-git
- include_tasks: utils/run_once.yml
when: run_once_web_svc_html is not defined