Manage Jitsi through Ansible using custom role #172

Open
stb wants to merge 5 commits from jitsi-docker-compose-role into main
21 changed files with 691 additions and 2 deletions

View file

@ -1,4 +1,7 @@
ansible_pull__age_private_key: ENC[AES256_GCM,data:8PCkZx76R5aWPITn5MCZCMckXvaLfVvnDgO70XmF/eeH5xLVOVx+EC3DZjmHxEoW7Kn4LAJTR4mWl/xP+p++elRvTMcHltV+vBQ=,iv:jKq07NLM84MSGU4CCyUS9ODmwiUMhlDONkKJ7P9P2DM=,tag:95yBZlwYdSNeX2O4t/h9kw==,type:str] ansible_pull__age_private_key: ENC[AES256_GCM,data:8PCkZx76R5aWPITn5MCZCMckXvaLfVvnDgO70XmF/eeH5xLVOVx+EC3DZjmHxEoW7Kn4LAJTR4mWl/xP+p++elRvTMcHltV+vBQ=,iv:jKq07NLM84MSGU4CCyUS9ODmwiUMhlDONkKJ7P9P2DM=,tag:95yBZlwYdSNeX2O4t/h9kw==,type:str]
jitsi__jicofo_auth_password: ENC[AES256_GCM,data:a7y36RJUR4OBtVNzgmqlGEsg1hNRGgsuwG2YFJrDlMI=,iv:mnGlKOXtNltNe3wY34BnVCJ9CtLQ7aksr4xXbrTOnJg=,tag:j1N7MUTJG8K0JW/a6YESFg==,type:str]
jitsi__jvb_auth_password: ENC[AES256_GCM,data:xUFiIXAzY4pEpwgL/5LPBlhkx73RX6VFT3QJlG5QbFo=,iv:/XqENztrrpj1h3lBhEtJJo78lCrxrMWxRszNjSwx+KQ=,tag:+LRYmv9Tvt0muR47QTd6HA==,type:str]
jitsi__turn_secret: ENC[AES256_GCM,data:UPev9ND9Mf2gGK28huQuuxRyUZvPPCmFL9rU1f0zndSPPBMspSsnlgtMy0+VY/CsGEIEcWsy3eYDPcAW/EKFtA==,iv:ew0MKP5zdQvqfla2y7xkcXLm3qSMlf5sucn8Qu3G3Zs=,tag:dqe239LD+wPVqLQFF+nz2A==,type:str]
sops: sops:
age: age:
- enc: | - enc: |
@ -30,8 +33,8 @@ sops:
QzBBdJ6TiDwJ1rwwM211smfIbcYhWX6C/EfitI5XoIW8aS4ln1g1Ww== QzBBdJ6TiDwJ1rwwM211smfIbcYhWX6C/EfitI5XoIW8aS4ln1g1Ww==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
recipient: age187zdk64205lx7r83a4m26pfa8hq6khc8sf83k266jasngeq08v3sfqswfg recipient: age187zdk64205lx7r83a4m26pfa8hq6khc8sf83k266jasngeq08v3sfqswfg
lastmodified: "2026-07-29T20:26:44Z" lastmodified: "2026-10-08T07:56:43Z"
mac: ENC[AES256_GCM,data:dHiB768SBppBrjNoSpgDvriCgrSNzIkpSYzm9REx4otbnvNjHYPhP9OdsZ6zTcoFoX+41/zE13r4EoAz4F++jdJidv1+7DMFvVUKMuFNzp2VjDfB1ZNzzyM+px7l83L5eNhgNPp26mweOVMEz92NgB916KMY+5e3uUeSR+iIdho=,iv:7k8rugBXULjPSOZukQiufNn9Vs5uWVhcvFKIhD1o7so=,tag:IE+2uhzGS2xJJgFHuc94CA==,type:str] mac: ENC[AES256_GCM,data:CgD19xHN5nEg9TMQq/c4Xpv1LH0LfcXrkfBMUcbJiIn4FsSzQetLYxueeDXUVOujOb9ZSEin1nR+OZwa/nuwN9mTg37c0XZ6HV0UvNNEIrN/o4doUCQa2jLmbX8etxeNhF7oWJ84OgQIhPLvLwp3Z0A/+kPKbmtz3znQNgKoHQY=,iv:6Dt7z55az2SJovJ7ozG35Q99a08kOrKl/uQCUVcbq8c=,tag:M6p0ZJzoFnWgspnGknq7SQ==,type:str]
pgp: pgp:
- created_at: "2026-09-24T19:54:13Z" - created_at: "2026-09-24T19:54:13Z"
enc: |- enc: |-

View file

@ -0,0 +1,33 @@
nftables__config: "{{ lookup('ansible.builtin.file', 'resources/chaosknoten/jitsi/nftables/nftables.conf') }}"
# renovate: datasource=github-releases depName=jitsi/docker-jitsi-meet versioning=regex:^stable-(?<major>\d+)$
jitsi__version: stable-11248
jitsi__domain: jitsi.hamburg.ccc.de
jitsi__letsencrypt_email: le-admin@hamburg.ccc.de
jitsi__jvb_advertise_ips:
- 212.12.51.139
- 2a00:14b0:f000:23:51:139:0:1
jitsi__whiteboard: true
jitsi__turn: true
jitsi__prometheus_exporter: true
# jitsi__jicofo_auth_password, jitsi__jvb_auth_password and jitsi__turn_secret are defined in jitsi.sops.yaml.
# Branding
jitsi__env:
DYNAMIC_BRANDING_URL: https://jitsi.hamburg.ccc.de/static/ccchh-branding.json
jitsi__custom_interface_config_js: |
// Replace the footer with app store links with our own in welcomePageAdditionalContent.html.
interfaceConfig.DISPLAY_WELCOME_FOOTER = false;
interfaceConfig.DISPLAY_WELCOME_PAGE_CONTENT = true;
interfaceConfig.JITSI_WATERMARK_LINK = 'https://hamburg.ccc.de/';
jitsi__web_files:
- path: images/watermark.svg
content: "{{ lookup('ansible.builtin.file', 'resources/chaosknoten/jitsi/web/ccchh-logo.svg') }}"
- path: images/favicon.svg
content: "{{ lookup('ansible.builtin.file', 'resources/chaosknoten/jitsi/web/round-logo.svg') }}"
- path: images/ccchh-background.svg
content: "{{ lookup('ansible.builtin.file', 'resources/chaosknoten/jitsi/web/background.svg') }}"
- path: static/ccchh-branding.json
content: "{{ lookup('ansible.builtin.file', 'resources/chaosknoten/jitsi/web/branding.json') }}"
- path: static/welcomePageAdditionalContent.html
content: "{{ lookup('ansible.builtin.file', 'resources/chaosknoten/jitsi/web/welcomePageAdditionalContent.html') }}"

View file

@ -141,6 +141,7 @@ systemd_networkd_hosts:
router: router:
nftables_hosts: nftables_hosts:
hosts: hosts:
jitsi:
router: router:
docker_compose_hosts: docker_compose_hosts:
hosts: hosts:
@ -258,6 +259,9 @@ wiki_hosts:
netbox_hosts: netbox_hosts:
hosts: hosts:
netbox: netbox:
jitsi_hosts:
hosts:
jitsi:
proxmox_vm_template_hosts: proxmox_vm_template_hosts:
hosts: hosts:
chaosknoten: chaosknoten:

View file

@ -110,6 +110,13 @@
tags: tags:
- docker_compose - docker_compose
- name: Ensure Jitsi deployment on jitsi_hosts
hosts: jitsi_hosts
roles:
- jitsi
tags:
- jitsi
- name: Ensure NGINX deployment on nginx_hosts - name: Ensure NGINX deployment on nginx_hosts
hosts: nginx_hosts:!public_reverse_proxy_hosts hosts: nginx_hosts:!public_reverse_proxy_hosts
roles: roles:

View file

@ -0,0 +1,65 @@
#!/usr/sbin/nft -f
# Docker manages its own tables (via iptables-nft), so don't use "flush ruleset" here,
# but only replace our own table. This also means that a reload is fine, but stopping
# or restarting nftables.service (which flushes the whole ruleset) requires restarting
# Docker afterwards.
# Traffic to ports published by Docker containers (web, JVB, exporter) gets DNATed in
# prerouting and therefore passes the forward hook instead of the input hook.
## Variables
define if_wan = "ens18"
# Prometheus on grafana (IPv4 via the NAT of router)
define prometheus_v4 = { 212.12.48.123 }
define prometheus_v6 = { 2a00:14b0:42:102::e }
## Rules
table inet host_filter
delete table inet host_filter
table inet host_filter {
# Runs before Docker's DNAT, so this also applies to ports published by containers.
chain prerouting {
type filter hook prerouting priority dstnat - 10; policy accept;
iifname $if_wan tcp dport 9888 ip saddr $prometheus_v4 accept comment "jitsi exporter (container)"
iifname $if_wan tcp dport 9888 ip6 saddr $prometheus_v6 accept comment "jitsi exporter (container)"
iifname $if_wan tcp dport 9888 drop
}
chain input {
type filter hook input priority filter; policy drop;
iifname "lo" accept
ct state invalid drop
ct state established,related accept
# ICMPv6 is needed for neighbour discovery etc.
meta l4proto ipv6-icmp accept
meta l4proto icmp accept
# Docker networks
iifname { "docker0", "br-*" } accept
tcp dport 22 accept comment "ssh"
# Ports published by containers normally get DNATed and never reach the input
# hook, but they do when handled by docker-proxy (e.g. for IPv6 without IPv6
# enabled on the Docker network).
tcp dport { 80, 443 } accept comment "jitsi web (container)"
udp dport 10000 accept comment "jitsi jvb (container)"
# coturn (runs in the host network namespace)
udp dport 3478 accept comment "turn"
tcp dport 3478 accept comment "turn"
tcp dport 5349 accept comment "turns"
udp dport 5349 accept comment "turns (dtls)"
udp dport 49152-65535 accept comment "turn relay ports"
tcp dport { 9100, 9888 } ip saddr $prometheus_v4 accept comment "node exporter, jitsi exporter (container)"
tcp dport { 9100, 9888 } ip6 saddr $prometheus_v6 accept comment "node exporter, jitsi exporter (container)"
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.8 KiB

View file

@ -0,0 +1,5 @@
{
"logoImageUrl": "https://jitsi.hamburg.ccc.de/images/watermark.svg",
"logoClickUrl": "https://hamburg.ccc.de/",
"backgroundImageUrl": "https://jitsi.hamburg.ccc.de/images/ccchh-background.svg"
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 84 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.3 KiB

View file

@ -0,0 +1,13 @@
<template id = "welcome-page-additional-content-template">
<footer class = "welcome-footer">
<div class = "welcome-footer-centered">
<div class = "welcome-footer-padded">
<div class = "welcome-footer-row-block welcome-footer--row-1" style = "flex-wrap: wrap; gap: 16px;">
<a href = "https://wiki.hamburg.ccc.de/infrastructure:services:jitsi" style = "color: #fff;">Technical Information for CCCHH Jitsi</a>
<a href = "https://hamburg.ccc.de/imprint/" style = "color: #fff;">Imprint and Contact</a>
<a href = "https://hamburg.ccc.de/privacy-notice/" style = "color: #fff;">Privacy Policy</a>
</div>
</div>
</div>
</footer>
</template>

64
roles/jitsi/README.md Normal file
View file

@ -0,0 +1,64 @@
# Role `jitsi`
A role for deploying [Jitsi Meet](https://jitsi.org/) using the official [docker-jitsi-meet](https://github.com/jitsi/docker-jitsi-meet) release.
The given release is downloaded and unpacked unmodified to `/opt/jitsi/releases/` and `/opt/jitsi/release` is pointed to it.
The `.env` file at `/opt/jitsi/.env` is fully managed by this role; `env.example` and `gen-passwords.sh` of the release are not used.
The `.env` also sets `COMPOSE_PROJECT_NAME` and `COMPOSE_FILE`, so `docker compose` can be run by hand in `/opt/jitsi`.
The Jitsi configuration directory (`CONFIG`) is `/opt/jitsi/config`, with persistent state in `/opt/jitsi/config/storage/`.
The image version (`JITSI_IMAGE_VERSION`) always equals the release version, so upgrading means bumping `jitsi__version`.
Releases other than the configured one are removed.
TLS certificates are obtained by the web container itself using Let's Encrypt, so ports 80/tcp and 443/tcp as well as 10000/udp (media) must be reachable.
Optionally, a [coturn](https://github.com/coturn/coturn) TURN server and the [Prometheus Jitsi Meet exporter](https://github.com/systemli/prometheus-jitsi-meet-exporter) are deployed as additional services of the same Compose project, defined in `/opt/jitsi/compose.override.yaml`.
coturn uses the certificate obtained by the web container and is restarted weekly to pick up renewals.
It needs 3478/udp+tcp, 5349/tcp and the relay port range 49152-65535/udp to be reachable.
The exporter scrapes the JVB statistics and listens on port 9888.
Files can be added to or replaced in the Jitsi Meet web root (`/usr/share/jitsi-meet` in the web container) using `jitsi__web_files`, e.g. for branding.
They are deployed to `/opt/jitsi/web-files/` and bind-mounted into the web container.
## Supported Distributions
Should work on Debian-based distributions.
## Required Arguments
- `jitsi__version`: The docker-jitsi-meet release to deploy, e.g. `stable-11248`.
- `jitsi__domain`: The domain Jitsi is served on. Used for `PUBLIC_URL` and the Let's Encrypt certificate.
- `jitsi__letsencrypt_email`: The e-mail address for the Let's Encrypt account.
- `jitsi__jicofo_auth_password`: XMPP password for Jicofo. Generate using `openssl rand -hex 16`.
- `jitsi__jvb_auth_password`: XMPP password for the JVB. Generate using `openssl rand -hex 16`.
## Optional Arguments
- `jitsi__timezone`: The time zone for the containers.
Defaults to `Europe/Berlin`.
- `jitsi__jvb_advertise_ips`: List of IP addresses the JVB should advertise for media (`JVB_ADVERTISE_IPS`).
Defaults to `[ ]`.
- `jitsi__whiteboard`: Whether to deploy the Excalidraw whiteboard backend (`whiteboard.yml`).
Defaults to `false`.
- `jitsi__turn`: Whether to deploy coturn and configure Jitsi to use it.
Defaults to `false`.
- `jitsi__turn_secret`: The shared secret between Prosody and coturn. Required if `jitsi__turn` is `true`.
Generate using `openssl rand -hex 32`.
- `jitsi__prometheus_exporter`: Whether to deploy the Prometheus Jitsi Meet exporter on port 9888.
Defaults to `false`.
- `jitsi__env`: Dictionary of additional variables to put into the `.env` file.
See `env.example` of the release and the handbook for available variables.
Defaults to `{ }`.
- `jitsi__custom_config_js`: Content of `custom-config.js`, which gets appended to the generated `config.js`.
Defaults to `""` (no file).
- `jitsi__custom_interface_config_js`: Content of `custom-interface_config.js`, which gets appended to the generated `interface_config.js`.
Defaults to `""` (no file).
- `jitsi__web_files`: List of files to mount into the Jitsi Meet web root.
Defaults to `[ ]`.
- `jitsi__web_files.*.path`: Path relative to the web root, e.g. `images/watermark.svg` or `static/welcomePageAdditionalContent.html`.
- `jitsi__web_files.*.content`: The content of the file.
## Links & Resources
- <https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker/>
- <https://github.com/jitsi/docker-jitsi-meet>
- <https://github.com/jitsi/docker-jitsi-meet/releases>

View file

@ -0,0 +1,9 @@
jitsi__timezone: Europe/Berlin
jitsi__jvb_advertise_ips: [ ]
jitsi__whiteboard: false
jitsi__turn: false
jitsi__prometheus_exporter: false
jitsi__env: { }
jitsi__custom_config_js: ""
jitsi__custom_interface_config_js: ""
jitsi__web_files: [ ]

View file

@ -0,0 +1,19 @@
- name: restart jitsi web
community.docker.docker_compose_v2:
project_src: "{{ jitsi__base_dir }}"
project_name: jitsi
files: "{{ jitsi__compose_files }}"
services:
- web
state: restarted
become: true
- name: restart jitsi coturn
community.docker.docker_compose_v2:
project_src: "{{ jitsi__base_dir }}"
project_name: jitsi
files: "{{ jitsi__compose_files }}"
services:
- coturn
state: restarted
become: true

View file

@ -0,0 +1,69 @@
argument_specs:
main:
options:
jitsi__version:
type: str
required: true
jitsi__domain:
type: str
required: true
jitsi__letsencrypt_email:
type: str
required: true
jitsi__jicofo_auth_password:
type: str
required: true
no_log: true
jitsi__jvb_auth_password:
type: str
required: true
no_log: true
jitsi__timezone:
type: str
required: false
default: Europe/Berlin
jitsi__jvb_advertise_ips:
type: list
elements: str
required: false
default: [ ]
jitsi__whiteboard:
type: bool
required: false
default: false
jitsi__turn:
type: bool
required: false
default: false
jitsi__turn_secret:
type: str
required: false
no_log: true
jitsi__prometheus_exporter:
type: bool
required: false
default: false
jitsi__env:
type: dict
required: false
default: { }
jitsi__custom_config_js:
type: str
required: false
default: ""
jitsi__custom_interface_config_js:
type: str
required: false
default: ""
jitsi__web_files:
type: list
elements: dict
required: false
default: [ ]
options:
path:
type: str
required: true
content:
type: str
required: true

View file

@ -0,0 +1,4 @@
---
allow_duplicates: false
dependencies:
- role: docker

226
roles/jitsi/tasks/main.yaml Normal file
View file

@ -0,0 +1,226 @@
- name: make sure a TURN secret is given, if TURN is enabled
ansible.builtin.assert:
that:
- jitsi__turn_secret is defined
- jitsi__turn_secret | length > 0
quiet: true
when: jitsi__turn
- name: make sure the Jitsi base directories exist
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: "0755"
owner: root
group: root
become: true
loop:
- "{{ jitsi__base_dir }}"
- "{{ jitsi__base_dir }}/releases"
- name: make sure the docker-jitsi-meet release is present
ansible.builtin.unarchive:
src: "https://github.com/jitsi/docker-jitsi-meet/archive/refs/tags/{{ jitsi__version }}.tar.gz"
remote_src: true
dest: "{{ jitsi__base_dir }}/releases"
creates: "{{ jitsi__release_dir }}/docker-compose.yml"
owner: root
group: root
become: true
- name: point the `release` symlink to the configured release
ansible.builtin.file:
src: "{{ jitsi__release_dir }}"
dest: "{{ jitsi__base_dir }}/release"
state: link
owner: root
group: root
become: true
# Configuration read by the containers at startup; managed by Ansible.
- name: make sure the configuration input directories exist
ansible.builtin.file:
path: "{{ jitsi__config_dir }}/{{ item }}"
state: directory
mode: "0755"
owner: root
group: root
become: true
loop:
- ""
- web
- prosody
- prosody/config
- prosody/prosody-plugins-custom
- jicofo
- jvb
- storage
- tmp
# State written by the containers, which run as uid/gid 1000.
# The certificate directory is created here, as Docker would otherwise create it owned by
# root for the coturn bind mount, before the web container gets to write the certificate.
- name: make sure the storage and tmp directories exist and are writable by the containers
ansible.builtin.file:
path: "{{ jitsi__config_dir }}/{{ item }}"
state: directory
mode: "0750"
owner: "1000"
group: "1000"
become: true
loop:
- storage/prosody
- storage/web
- storage/web/acme-certs
- "storage/web/acme-certs/{{ jitsi__domain }}"
- storage/transcripts
- tmp/web-crontabs
- tmp/web-load-test
- name: deploy custom web configuration
ansible.builtin.copy:
content: "{{ item.content }}"
dest: "{{ jitsi__config_dir }}/web/{{ item.name }}"
mode: "0644"
owner: root
group: root
become: true
when: item.content != ""
loop:
- name: custom-config.js
content: "{{ jitsi__custom_config_js }}"
- name: custom-interface_config.js
content: "{{ jitsi__custom_interface_config_js }}"
loop_control:
label: "{{ item.name }}"
notify: restart jitsi web
- name: remove unconfigured custom web configuration
ansible.builtin.file:
path: "{{ jitsi__config_dir }}/web/{{ item.name }}"
state: absent
become: true
when: item.content == ""
loop:
- name: custom-config.js
content: "{{ jitsi__custom_config_js }}"
- name: custom-interface_config.js
content: "{{ jitsi__custom_interface_config_js }}"
loop_control:
label: "{{ item.name }}"
notify: restart jitsi web
- name: make sure the coturn directory exists
ansible.builtin.file:
path: "{{ jitsi__base_dir }}/coturn"
state: "{{ 'directory' if jitsi__turn else 'absent' }}"
mode: "0755"
owner: root
group: root
become: true
# Readable by uid 1000, which coturn runs as.
- name: deploy the coturn configuration
ansible.builtin.template:
src: turnserver.conf.j2
dest: "{{ jitsi__base_dir }}/coturn/turnserver.conf"
mode: "0640"
owner: root
group: "1000"
become: true
when: jitsi__turn
notify: restart jitsi coturn
# coturn doesn't notice the certificate renewed by the web container on its own.
- name: ensure the weekly coturn restart cron job is present
ansible.builtin.cron:
name: "jitsi coturn restart for certificate renewal"
special_time: weekly
job: "cd {{ jitsi__base_dir }} && docker compose restart coturn >/dev/null"
state: "{{ 'present' if jitsi__turn else 'absent' }}"
become: true
# Files mounted into the web container, replacing or adding to the files of Jitsi Meet.
- name: make sure the directories for the web files exist
ansible.builtin.file:
path: "{{ jitsi__base_dir }}/web-files/{{ item }}"
state: directory
mode: "0755"
owner: root
group: root
become: true
loop: "{{ [''] + (jitsi__web_files | map(attribute='path') | map('dirname') | unique | reject('equalto', '') | list) }}"
- name: deploy the web files
ansible.builtin.copy:
content: "{{ item.content }}"
dest: "{{ jitsi__base_dir }}/web-files/{{ item.path }}"
mode: "0644"
owner: root
group: root
become: true
loop: "{{ jitsi__web_files }}"
loop_control:
label: "{{ item.path }}"
# Single file bind mounts keep pointing to the replaced file until the container is restarted.
notify: restart jitsi web
- name: find web files to remove
ansible.builtin.find:
paths: "{{ jitsi__base_dir }}/web-files"
recurse: true
register: jitsi__web_files_found
- name: remove web files, which should be removed
ansible.builtin.file:
path: "{{ item }}"
state: absent
become: true
loop: "{{ jitsi__web_files_found.files | map(attribute='path') | reject('in', jitsi__web_files_paths) | list }}"
vars:
jitsi__web_files_paths: "{{ jitsi__web_files | map(attribute='path') | map('regex_replace', '^', jitsi__base_dir ~ '/web-files/') | list }}"
# Changes to these make `docker compose up` below recreate the affected containers.
- name: deploy the compose override file
ansible.builtin.template:
src: compose.override.yaml.j2
dest: "{{ jitsi__base_dir }}/compose.override.yaml"
mode: "0644"
owner: root
group: root
become: true
- name: deploy the .env file
ansible.builtin.template:
src: jitsi.env.j2
dest: "{{ jitsi__base_dir }}/.env"
mode: "0600"
owner: root
group: root
become: true
- name: docker compose up
community.docker.docker_compose_v2:
project_src: "{{ jitsi__base_dir }}"
project_name: jitsi
files: "{{ jitsi__compose_files }}"
state: present
pull: missing
remove_orphans: true
become: true
- name: find old releases
ansible.builtin.find:
paths: "{{ jitsi__base_dir }}/releases"
file_type: directory
excludes: "docker-jitsi-meet-{{ jitsi__version }}"
register: jitsi__old_releases
- name: remove old releases
ansible.builtin.file:
path: "{{ item.path }}"
state: absent
become: true
loop: "{{ jitsi__old_releases.files }}"
loop_control:
label: "{{ item.path }}"

View file

@ -0,0 +1,47 @@
# {{ ansible_managed }}
# Services in addition to the ones of the docker-jitsi-meet release.
# Docker Compose explicitly disables IPv6 for networks not enabling it, overriding the
# daemon's default-network-opts.
networks:
meet.jitsi:
enable_ipv6: true
services:
{% if jitsi__web_files | length > 0 %}
web:
volumes:
{% for file in jitsi__web_files %}
- {{ jitsi__base_dir }}/web-files/{{ file.path }}:/usr/share/jitsi-meet/{{ file.path }}:ro
{% endfor %}
{% endif %}
{% if jitsi__turn %}
coturn:
image: docker.io/coturn/coturn:4.18.0
restart: unless-stopped
# Recommended by coturn, as Docker performs badly with large port ranges.
network_mode: host
# Needs to be able to read the certificate obtained by the web container.
user: "1000:1000"
command: ["-c", "/etc/coturn/turnserver.conf"]
volumes:
- {{ jitsi__base_dir }}/coturn/turnserver.conf:/etc/coturn/turnserver.conf:ro
- {{ jitsi__config_dir }}/storage/web/acme-certs/{{ jitsi__domain }}:/certs:ro
tmpfs:
- /var/lib/coturn
{% endif %}
{% if jitsi__prometheus_exporter %}
prometheus-jitsi-meet-exporter:
image: docker.io/systemli/prometheus-jitsi-meet-exporter:1.4.2
restart: unless-stopped
command: ["-videobridge-url", "http://jvb:8080/colibri/stats"]
ports:
- "9888:9888"
depends_on:
- jvb
networks:
meet.jitsi:
{% endif %}
{% if not (jitsi__web_files or jitsi__turn or jitsi__prometheus_exporter) %}
{}
{% endif %}

View file

@ -0,0 +1,46 @@
# {{ ansible_managed }}
# Only the settings differing from the defaults are set here.
# Reference: {{ jitsi__base_dir }}/release/env.example and
# https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker
# Allow running `docker compose` by hand in {{ jitsi__base_dir }}.
COMPOSE_PROJECT_NAME=jitsi
COMPOSE_FILE={{ jitsi__compose_files | join(':') }}
CONFIG={{ jitsi__config_dir }}
JITSI_IMAGE_VERSION={{ jitsi__version }}
TZ={{ jitsi__timezone }}
PUBLIC_URL=https://{{ jitsi__domain }}
HTTP_PORT=80
HTTPS_PORT=443
ENABLE_HTTP_REDIRECT=1
ENABLE_LETSENCRYPT=1
LETSENCRYPT_DOMAIN={{ jitsi__domain }}
LETSENCRYPT_EMAIL={{ jitsi__letsencrypt_email }}
LETSENCRYPT_ACME_SERVER=letsencrypt
{% if jitsi__jvb_advertise_ips | length > 0 %}
JVB_ADVERTISE_IPS={{ jitsi__jvb_advertise_ips | join(',') }}
{% endif %}
{% if jitsi__whiteboard %}
WHITEBOARD_COLLAB_SERVER_URL_BASE=http://whiteboard.meet.jitsi
{% endif %}
{% if jitsi__turn %}
TURN_CREDENTIALS={{ jitsi__turn_secret }}
TURN_HOST={{ jitsi__domain }}
TURN_PORT=3478
TURN_TRANSPORT=udp,tcp
TURNS_HOST={{ jitsi__domain }}
TURNS_PORT=5349
{% endif %}
{% if jitsi__env | length > 0 %}
{% for key, value in jitsi__env.items() %}
{{ key }}={{ value }}
{% endfor %}
{% endif %}
JICOFO_AUTH_PASSWORD={{ jitsi__jicofo_auth_password }}
JVB_AUTH_PASSWORD={{ jitsi__jvb_auth_password }}

View file

@ -0,0 +1,34 @@
# {{ ansible_managed }}
listening-port=3478
tls-listening-port=5349
realm={{ jitsi__domain }}
use-auth-secret
static-auth-secret={{ jitsi__turn_secret }}
cert=/certs/fullchain.pem
pkey=/certs/key.pem
no-tlsv1
no-tlsv1_1
no-cli
no-multicast-peers
no-loopback-peers
log-file=stdout
# Don't relay to private and otherwise special addresses.
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.0.0.0-192.0.0.255
denied-peer-ip=192.0.2.0-192.0.2.255
denied-peer-ip=192.88.99.0-192.88.99.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=198.51.100.0-198.51.100.255
denied-peer-ip=203.0.113.0-203.0.113.255
denied-peer-ip=240.0.0.0-255.255.255.255
denied-peer-ip=::1
denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff

View file

@ -0,0 +1,4 @@
jitsi__base_dir: /opt/jitsi
jitsi__config_dir: "{{ jitsi__base_dir }}/config"
jitsi__release_dir: "{{ jitsi__base_dir }}/releases/docker-jitsi-meet-{{ jitsi__version }}"
jitsi__compose_files: "{{ ['release/docker-compose.yml'] + (['release/whiteboard.yml'] if jitsi__whiteboard else []) + ['compose.override.yaml'] }}"

View file

@ -13,3 +13,10 @@
group: root group: root
become: true become: true
notify: Reload nftables service notify: Reload nftables service
- name: ensure nftables service is enabled and started
ansible.builtin.systemd_service:
name: nftables
enabled: true
state: started
become: true