From 8b1e05ed20dad8ce80f034f0f68b35b154a3bb02 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Fischer?= <a.fischer@opentalk.eu>
Date: Thu, 7 Nov 2024 14:44:05 +0100
Subject: [PATCH] add livekit service add livekit init script add livekit
 config remove redis ENV var from controller service update sample config
 align example domain update README add docker extra host remove livekit
 section change PRODUCT_VERSION

---
 README.md                                     |  30 ++-
 docker-compose.yaml                           |  26 +-
 env.sample                                    |   2 +-
 extras/nginx-samples/livekit.conf.sample      |  53 ++++
 .../opentalk-samples/controller.toml.sample   |  42 +---
 .../controller_oidc.toml.sample               | 228 ++++++++++++++++++
 extras/opentalk-samples/obelisk.toml.sample   |   8 +-
 extras/opentalk-samples/recorder.toml.sample  |  10 +-
 .../opentalk-samples/smtp-mailer.toml.sample  |   6 +-
 init/livekit-init.sh                          |  34 +++
 10 files changed, 373 insertions(+), 66 deletions(-)
 create mode 100644 extras/nginx-samples/livekit.conf.sample
 create mode 100644 extras/opentalk-samples/controller_oidc.toml.sample
 create mode 100755 init/livekit-init.sh

diff --git a/README.md b/README.md
index de24205..8e73c68 100644
--- a/README.md
+++ b/README.md
@@ -44,11 +44,11 @@ In the current state, the configuration that is ready to use out-of-the-box, cov
 | postgresql   | X         |
 | autoheal     | X         |
 | rabbitmq     | X         |
-| redis        | X         |
+| redis        |           |
 | web-frontend | X         |
 | controller   | X         |
 | minio        | X         |
-| janus-gateway| X         |
+| livekit      | X         |
 | obelisk      |           |
 | smtp-mailer  |           |
 | spacedeck    |           |
@@ -69,6 +69,8 @@ If your domain is for example `example.com`, you have to create the following DN
 - example.com (OpenTalk Web-UI)
 - accounts.example.com (Keycloak instance)
 - controller.example.com (OpenTalk controller service)
+- livekit.example.com (LiveKit server)
+- optional: turn.example.com (if you plan to use the TURN support in LiveKit server)
 
 ### Reverse-Proxy and SSL certificates
 
@@ -80,6 +82,7 @@ When you use the default ports, the services listen on the following ports on th
 - frontend:    localhost:8080
 - controller:  localhost:8090
 - keycloak:    localhost:8087
+- livekit:     localhost:7880
 
 We recommend using nginx as reverse-proxy. Please refer the [official nginx documentation](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) for further information.
 
@@ -94,7 +97,7 @@ Clone the git repository to a location of your choice. Since we are using direct
 Specify a release tag when you clone the git repository. Pick the current stable version from our [release page](https://docs.opentalk.eu/releases).
 
 ```bash
-git clone --branch v24.10.0 https://gitlab.opencode.de/opentalk/ot-setup.git /opt/opentalk
+git clone --branch v24.20.0 https://gitlab.opencode.de/opentalk/ot-setup.git /opt/opentalk
 ```
 
 Change to the root of this repository, and use it as base directory for the next steps.
@@ -123,7 +126,7 @@ cp extras/opentalk-samples/controller.toml.sample config/controller.toml
 
 Customize the variables in `.env` according to your needs. In most cases, it is sufficient to adjust the values listed under `common variables`. You should always leave the `docker-compose.yaml` file unchanged to have an easier update process in future.
 
-You absolutely *have to* set `OT_DOMAIN` yourself to a domain you or your organization control.
+You absolutely _have to_ set `OT_DOMAIN` yourself to a domain you or your organization control.
 
 You can generate the secrets with the `gen-secrets.sh` helper script and simply copy + paste the secrets into the `.env` file.
 
@@ -147,6 +150,7 @@ KEYCLOAK_CLIENT_SECRET_RECORDER=itoo2pieyohh6Aighiebietee7iefae7
 SPACEDECK_API_TOKEN=ohP2AeBirineimohS6Pha1oaphoapoM2
 SPACEDECK_INVITE_CODE=eij9weipaxohYiexoh1loo5zae8ic2ah
 ETHERPAD_API_KEY=iethae9aulo0ung6Tida6uquahmahphi
+LIVEKIT_KEYS_API_SECRET=QEHNPlkZ4sIWecuB4rZQVtTWMire3ZbI
 ```
 
 #### Add the secretes to the `config/controller.toml`
@@ -157,8 +161,9 @@ Use the following sed snippets or as an alternative you can also edit the `confi
 ```bash
 source .env; sed -i "s/postgrespw/$POSTGRES_PASSWORD/g" config/controller.toml 
 source .env; sed -i "s/keycloakclientsecretforcontroller/$KEYCLOAK_CLIENT_SECRET_CONTROLLER/g" config/controller.toml 
+source .env; sed -i "s/livekitapisecret/$LIVEKIT_KEYS_API_SECRET/g" config/controller.toml 
 source .env; sed -i "s/spacedeckapitoken/$SPACEDECK_API_TOKEN/g" config/controller.toml 
-source .env; sed -i "s/etherpadapikey/$ETHERPAD_API_KEY/g" config/controller.toml 
+source .env; sed -i "s/etherpadapikey/$ETHERPAD_API_KEY/g" config/controller.toml
 ```
 
 #### Final adjustments to the `config/controller.toml`
@@ -171,12 +176,21 @@ vi config/controller.toml
 
 Change the following values to fit your needs:
 
-```txt
+```toml
 [http]
-cors.allowed_origin = ["https://example.org"]
+cors.allowed_origin = ["https://example.com"]
 
 [keycloak]
-base_url = "https://accounts.example.org/auth"
+base_url = "https://accounts.example.com/auth"
+
+[livekit]
+public_url = "https://livekit.example.com"
+```
+
+If your domain is set with the variable OT_DOMAIN in the .env file, you can replace it with the following snippet, or edit it manually.
+
+```bash
+source .env; sed -i "s/example.com/$OT_DOMAIN/g" config/controller.toml 
 ```
 
 #### Optional: Advanced configuration method using environment variables
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 9449903..6cd7cfc 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -32,7 +32,6 @@ services:
       WAITING_ROOM_DEFAULT_VALUE: ${WAITING_ROOM_DEFAULT_VALUE:-false}
       PRODUCT_VERSION: "v24.20.0-rc.1"
 
-
   # *** controller ***
   controller:
     image: ${OPENTALK_CONTROLLER_IMAGE_SRC:-registry.opencode.de/opentalk/controller}:${OPENTALK_CONTROLLER_IMAGE_TAG:-v0.25.0}
@@ -40,6 +39,8 @@ services:
     restart: always
     ports:
       - ${OPENTALK_CONTROLLER_EXP_PORT:-8090}:11311
+    extra_hosts:
+      - host.docker.internal:host-gateway
     environment:
       RUST_LOG: info,k3k=debug,janus_client=info,k3k_janus_media::mcu=OFF
       OPENTALK_CTRL_DATABASE__URL: "postgres://${POSTGRES_USER:-ot}:${POSTGRES_PASSWORD}@${POSTGRES_HOST:-postgres}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-opentalk}"
@@ -58,7 +59,6 @@ services:
       OPENTALK_CTRL_RABBIT_MQ__URL: "${OPENTALK_CTRL_RABBIT_MQ__URL:-amqp://guest:guest@rabbit/%2F}"
       OPENTALK_CTRL_RABBIT_MQ__MAIL_TASK_QUEUE: "${OPENTALK_CTRL_RABBIT_MQ__MAIL_TASK_QUEUE:-opentalk_mailer}"
       OPENTALK_CTRL_RABBIT_MQ__RECORDING_TASK_QUEUE: "${OPENTALK_CTRL_RABBIT_MQ__RECORDING_TASK_QUEUE:-opentalk_recorder}"
-      OPENTALK_CTRL_REDIS__URL: "${OPENTALK_CTRL_REDIS__URL:-redis://redis:6379/}"
       OPENTALK_CTRL_MINIO__URI: "${OPENTALK_CTRL_MINIO__URI:-http://minio:9000}"
       OPENTALK_CTRL_MINIO__BUCKET: "${OPENTALK_CTRL_MINIO__BUCKET:-s3_bucket}"
       OPENTALK_CTRL_MINIO__ACCESS_KEY: "${OPENTALK_CTRL_MINIO__ACCESS_KEY:-minioadmin}"
@@ -81,6 +81,8 @@ services:
     image: ${OT_OBELISK_IMAGE_SRC:-registry.opencode.de/opentalk/obelisk}:${OT_OBELISK_IMAGE_TAG:-v0.15.0}
     profiles: ["obelisk"]
     network_mode: host
+    extra_hosts:
+      - host.docker.internal:host-gateway
     restart: always
     environment:
       RUST_LOG: ${RUST_LOG:-info}
@@ -101,6 +103,8 @@ services:
   recorder:
     image: ${RECORDER_IMAGE_SRC:-registry.opencode.de/opentalk/recorder}:${RECORDER_IMAGE_TAG:-v0.10.1}
     profiles: ["recorder"]
+    extra_hosts:
+      - host.docker.internal:host-gateway
     restart: always
     network_mode: host
     environment:
@@ -116,7 +120,7 @@ services:
 
   # *** livekit ***
   livekit:
-    image: livekit/livekit-server:v1.8
+    image: livekit/livekit-server:v1.7.2
     profiles: ["core", "livekit"]
     network_mode: host
     restart: always
@@ -125,8 +129,8 @@ services:
       LIVEKIT_HTTP_PORT: "${LIVEKIT_HTTP_PORT:-7880}"
       LIVEKIT_HTTP_BIND_ADDRESS: "${LIVEKIT_HTTP_BIND_ADDRESS:-}"
       LIVEKIT_TCP_PORT: "${LIVEKIT_TCP_PORT:-7881}"
-      LIVEKIT_RTC_PORT_RANGE_START: "${LIVEKIT_RTC_PORT_RANGE_START:-50000}"
-      LIVEKIT_RTC_PORT_RANGE_END: "${LIVEKIT_RTC_PORT_RANGE_END:-60000}"
+      LIVEKIT_RTC_PORT_RANGE_START: "${LIVEKIT_RTC_PORT_RANGE_START:-20000}"
+      LIVEKIT_RTC_PORT_RANGE_END: "${LIVEKIT_RTC_PORT_RANGE_END:-39999}"
       LIVEKIT_RTC_USE_EXTERNAL_IP: "${LIVEKIT_RTC_USE_EXTERNAL_IP:-true}"
       LIVEKIT_RTC_ENABLE_LOOPBACK_CANDIDATE: "${LIVEKIT_RTC_ENABLE_LOOPBACK_CANDIDATE:-false}"
       LIVEKIT_TURN_ENABLED: "${LIVEKIT_TURN_ENABLED:-false}"
@@ -134,8 +138,8 @@ services:
       LIVEKIT_TURN_TLS_PORT: "${LIVEKIT_TURN_TLS_PORT:-5349}"
       LIVEKIT_TURN_UDP_PORT: "${LIVEKIT_TURN_UDP_PORT:-3478}"
       LIVEKIT_TURN_EXTERNAL_TLS: "${LIVEKIT_TURN_EXTERNAL_TLS:-true}"
-      LIVEKIT_KEYS_API_KEY: "${LIVEKIT_KEYS_API_KEY:-opentalk}"
-      LIVEKIT_KEYS_API_SECRET: "${LIVEKIT_KEYS_API_SECRET:-secret}"
+      LIVEKIT_KEYS_API_KEY: "${LIVEKIT_KEYS_API_KEY:-controller}"
+      LIVEKIT_KEYS_API_SECRET: "${LIVEKIT_KEYS_API_SECRET:-}"
       LIVEKIT_LOGGING_JSON: "${LIVEKIT_LOGGING_JSON:-false}"
       LIVEKIT_LOGGING_LEVEL: "${LIVEKIT_LOGGING_LEVEL:-info}"
     command:
@@ -143,8 +147,6 @@ services:
     volumes:
       - ./init/livekit-init.sh:/livekit-init.sh
 
-
-
   # *** spacedeck ***
   whiteboard:
     image: ${SD_IMAGE_SRC:-registry.opencode.de/opentalk/spacedeck}:${SD_IMAGE_TAG:-v1.0.2}
@@ -257,15 +259,15 @@ services:
       interval: 10s
       timeout: 15s
       retries: 5
- 
+
   # *** Redis ***
   redis:
     image: redis:${REDIS_IMAGE_TAG:-7-alpine}
-    profiles: ["core", "redis"]
+    profiles: ["redis"]
     restart: always
     ports:
       - ${REDIS_EXP_PORT:-127.0.0.1:6379}:${REDIS_EXP_PORT:-6379}
-
+ 
   # *** minio ***
   minio:
     image: minio/minio:${MINIO_IMAGE_TAG:-RELEASE.2023-07-21T21-12-44Z}
diff --git a/env.sample b/env.sample
index d114384..651fda9 100644
--- a/env.sample
+++ b/env.sample
@@ -114,7 +114,7 @@ OPENTALK_CTRL_KEYCLOAK__CLIENT_SECRET="$KEYCLOAK_CLIENT_SECRET_CONTROLLER"
 # OPENTALK_CTRL_SPACEDECK__URL="http://localhost:9666"
 # OPENTALK_CTRL_SPACEDECK__API_KEY="secret"
 # OPENTALK_CTRL_SHARED_FOLDER__PROVIDER="nextcloud"
-# OPENTALK_CTRL_SHARED_FOLDER__URL="https://nextcloud.example.org/"
+# OPENTALK_CTRL_SHARED_FOLDER__URL="https://nextcloud.example.com/"
 # OPENTALK_CTRL_SHARED_FOLDER__USERNAME="ncuser"
 # OPENTALK_CTRL_SHARED_FOLDER__PASSWORD="v3rys3cr3t"
 # OPENTALK_CTRL_SHARED_FOLDER__DIRECTORY="opentalk/meetings"
diff --git a/extras/nginx-samples/livekit.conf.sample b/extras/nginx-samples/livekit.conf.sample
new file mode 100644
index 0000000..3b6d125
--- /dev/null
+++ b/extras/nginx-samples/livekit.conf.sample
@@ -0,0 +1,53 @@
+upstream livekit_backend {
+    server localhost:7880;
+}
+
+map $http_upgrade $connection_upgrade {
+        default upgrade;
+        ''      close;
+}
+
+server {
+    listen       80;
+    listen       [::]:80;
+    server_name  livekit.example.com;
+
+    # include snippets/letsencrypt.conf;
+
+    location / {
+        access_log off;
+        return 301 https://$server_name$request_uri;
+    }
+}
+
+server {
+    listen       443 ssl http2;
+    listen       [::]:443 ssl http2;
+    server_name  livekit.example.com;
+
+    ssl_certificate         /etc/letsencrypt/live/example.com/fullchain.pem;
+    ssl_certificate_key     /etc/letsencrypt/live/example.com/privkey.pem;
+
+    root livekit.example.com;
+
+    include snippets/sslsettings.conf;
+
+    access_log  /var/log/nginx/https-access_livekit.example.com.log;
+    error_log  /var/log/nginx/https-error_livekit.example.com.log;
+
+   location / {
+      proxy_set_header Host               $host;
+      proxy_set_header X-Real-IP          $remote_addr;
+      proxy_set_header X-Forwarded-Proto  $scheme;
+      proxy_set_header X-Forwarded-For    $remote_addr;
+      proxy_set_header Upgrade            $http_upgrade;
+      proxy_set_header Connection         $connection_upgrade;
+
+      client_max_body_size 100M;
+      proxy_read_timeout 300;
+      proxy_buffers                       8 8k;
+      proxy_buffer_size                   8k;
+
+      proxy_pass http://livekit_backend;
+   }
+}
diff --git a/extras/opentalk-samples/controller.toml.sample b/extras/opentalk-samples/controller.toml.sample
index 91dc952..baac599 100644
--- a/extras/opentalk-samples/controller.toml.sample
+++ b/extras/opentalk-samples/controller.toml.sample
@@ -38,13 +38,13 @@ url = "postgres://ot:postgrespw@postgres:5432/opentalk"
 # The port to bind the HTTP Server to (defaults to 11311).
 port = 11311
 # URLs that requests are allowed from. Leave empty to allow all.
-cors.allowed_origin = ["https://example.org"]
+cors.allowed_origin = ["https://example.com"]
 
 # Settings for the keycloak which is the user provider
 # and allows authentication via OIDC
 [keycloak]
 # URL to the keycloak
-base_url = "https://accounts.example.org/auth"
+base_url = "https://accounts.example.com/auth"
 # Name of the keycloak realm
 realm = "opentalk"
 # Client ID
@@ -52,34 +52,11 @@ client_id = "OtBackend"
 # Client secret (application requires confidential client).
 client_secret = "keycloakclientsecretforcontroller"
 
-[room_server]
-# Maximum bitrate allowed for media sessions that will be used to transmit webcam video/audio
-max_video_bitrate = "800000"
-
-# Maximum bitrate allowed for media sessions used for screen share
-max_screen_bitrate = "1200000"
-
-# Number of packets with with given `speaker_focus_level`
-# needed to detect a speaking participant. 
-# 
-# Default: 50 packets (1 second of audio)
-#speaker_focus_packets = "50"
-
-# Average value of audio level needed per packet.
-# 
-# min: 127 (muted)  
-# max: 0   (loud)  
-# default: 50  
-#speaker_focus_level = "50"
-
-# Connection settings for the channel used to talk to the room server.
-# Currently these should be equal to the settings in janus.transport.rabbitmq.jcfg
-# of the respective janus instance.
-[[room_server.connections]]
-to_routing_key = "to-janus"
-exchange = "janus-exchange"
-from_routing_key = "from-janus"
-
+[livekit]
+public_url = "https://livekit.example.com"
+service_url = "http://host.docker.internal:7880"
+api_key = "controller"
+api_secret = "livekitapisecret"
 
 [rabbit_mq]
 # The URL to use to connect to the rabbit mq broker
@@ -102,9 +79,7 @@ url = "amqp://rabbit/%2F"
 mail_task_queue = "opentalk_mailer"
 recording_task_queue = "opentalk_recorder"
 
-[redis]
-# Redis URL used to connect the redis server
-url = "redis://redis:6379/"
+
 
 #[turn]
 # Lifetime of the generated credentials (in seconds)
@@ -189,3 +164,4 @@ secret_key = "minioadmin"
 #
 # Example: Allow all traffic from localhost
 #allowlist = ["127.0.0.0/24", "::ffff:0:0/96"]
+
diff --git a/extras/opentalk-samples/controller_oidc.toml.sample b/extras/opentalk-samples/controller_oidc.toml.sample
new file mode 100644
index 0000000..98b3b4d
--- /dev/null
+++ b/extras/opentalk-samples/controller_oidc.toml.sample
@@ -0,0 +1,228 @@
+# SPDX-FileCopyrightText: OpenTalk GmbH <mail@opentalk.eu>
+#
+# SPDX-License-Identifier: EUPL-1.2
+
+[logging]
+# Default tracing directives that will always be applied after RUST_LOG's directives.
+# Each array entry may contain a single directive.
+# Below are some example directives which are used by default to reduce the amount of spamming some crates do by default.
+# The defaults will always apply, but they can be explicitly overwritten with this config or the RUST_LOG environment
+# variable. The priority of the different configuration options is: RUST_LOG > config file > defaults
+#default_directives = [
+#   "ERROR",
+#   "opentalk=INFO",
+#   "pinky_swear=OFF",
+#   "rustls=WARN",
+#   "mio=ERROR",
+#   "lapin=WARN",
+#   "execution_id=trace"
+#]
+
+# Specify an optional OTLP tracing endpoint to export traces to
+#otlp_tracing_endpoint = "http://localhost:4317"
+
+# Service name when using opentelemetry
+#service_name = "controller"
+# Service namespace when using opentelemetry
+#service_namespace = "opentalk"
+# Service instance id when using opentelemetry. A random UUID will be generated at runtime if not set here.
+#service_instance_id = "627cc493-f310-47de-96bd-71410b7dec09"
+
+[database]
+# URL used to connect to a postgres.
+url = "postgres://ot:postgrespw@postgres:5432/opentalk"
+
+# Maximum number of connections allowed to the server.
+# Defaults to 100 which is the default of postgres.
+#max_connections = 100
+
+[http]
+# The port to bind the HTTP Server to (defaults to 11311).
+port = 11311
+# URLs that requests are allowed from. Leave empty to allow all.
+#cors.allowed_origin = ["https://example.com"]
+
+# Settings for the keycloak which is the user provider and allows authentication via OIDC.
+# This is deprecated, replace with [oidc] and [user_search] sections.
+#[keycloak]
+# URL to the keycloak
+#base_url = "http://accounts.example.com/auth"
+# Name of the keycloak realm
+#realm = "opentalk"
+# Client ID
+#client_id = "OtBackend"
+# Client secret (application requires confidential client).
+#client_secret = "keycloakclientsecretforcontroller"
+
+# Configure how Keycloak users resulting from a search and registered Opentalk users are assigned to each other
+# The following assignment strategies are available:
+#   - by Keycloak id (default): Keycloak users are assigned to Opentalk users using Keycloak's id field.
+#   - by user attribute: Keycloak must provide a user attribute holding the user IDs. The name of this user
+#                        attribute must be set here in external_id_user_attribute_name.
+#external_id_user_attribute_name = "my_user_attribute_name"
+
+# OIDC configuration.
+# Currently only Keycloak is supported. Full compliance with other OIDC providers is not guaranteed.
+[oidc]
+# URL to the keycloak
+authority = "https://accounts.example.com/auth/realms/opentalk"
+
+[oidc.frontend]
+# OIDC authority base url for the frontend.
+# Optional, if not set, the value from `oidc.authority` is used.
+# Will be made available to the frontend via the `GET /v1/auth/login` endpoint.
+authority = "https://accounts.example.com/auth/realms/opentalk"
+
+# Client id that will be used by the frontend when connecting to the oidc provider.
+client_id = "OtFrontend"
+
+[oidc.controller]
+# OIDC authority base url for the controller.
+# Optional, if not set, the value from `oidc.authority` is used.
+#authority = "https://accounts.example.com/auth/realms/opentalk"
+
+# Client id that will be used by the controller when connecting to the oidc provider.
+client_id = "OtBackend"
+
+# Client secret that will be used by the controller when connecting to the oidc provider.
+client_secret = "keycloakclientsecretforcontroller"
+
+[user_search]
+# Defines which backend to use for user search. Only `keycloak_webapi` is currently available.
+backend = "keycloak_webapi"
+
+# Base URL of the Keycloak web api.
+api_base_url = "https://accounts.example.com/auth/realms/opentalk"
+
+# Client id that is used to authenticate against the user search API.
+# Optional, if not set, the value from `oidc.controller.client_id` is used.
+client_id = "OtBackend"
+
+# Client secret that is used to authenticate against the user search API.
+# Optional, if not set, the value from `oidc.controller.client_secret` is used.
+client_secret = "keycloakclientsecretforcontroller"
+
+# Configure how Keycloak users resulting from a search and registered Opentalk users are assigned to each other
+# The following assignment strategies are available:
+#   - by Keycloak id (default): Keycloak users are assigned to Opentalk users using Keycloak's id field.
+#   - by user attribute: Keycloak must provide a user attribute holding the user IDs. The name of this user
+#                        attribute must be set here in external_id_user_attribute_name.
+#external_id_user_attribute_name = "my_user_attribute_name"
+
+# Set the behaviour of the `/users/find` endpoint.
+# This allows searching for users who have not yet logged into the controller.
+# You can choose where to search for users or disable the endpoint completely for performance or privacy reasons.
+# Possible values are "disabled", "from_database" and "from_user_search_backend".
+#users_find_behavior = "from_user_search_backend"
+users_find_behavior = "from_user_search_backend"
+
+[livekit]
+public_url = "https://livekit.example.com"
+service_url = "http://host.docker.internal:7880"
+api_key = "controller"
+api_secret = "livekitapisecret"
+
+[rabbit_mq]
+# The URL to use to connect to the rabbit mq broker
+#url = "amqp://username:password@host/%2F"
+
+# The rabbitmq queue name for the mail worker,
+# mailing is disabled when this is not set.
+#mail_task_queue = "opentalk_mailer"
+
+# The rabbitmq queue name for the recorder,
+# recording is disabled when this is not set.
+#recording_task_queue = "opentalk_recorder"
+
+# Minimum amount of connections to retain when removing stale connections
+#min_connections = 10
+
+# Maximum number of amqp channels per connection
+#max_channels_per_connection = 100
+url = "amqp://rabbit/%2F"
+mail_task_queue = "opentalk_mailer"
+recording_task_queue = "opentalk_recorder"
+
+#[turn]
+# Lifetime of the generated credentials (in seconds)
+#lifetime = 86400
+
+#[[turn.servers]]
+# URIS of this Turn Server following rfc7065
+#uris = [
+#    "turn:127.0.0.1:3478?transport=udp",
+#    "turn:127.0.0.1:3478?transport=tcp",
+#    "turns:127.0.0.1:5349?transport=tcp"
+#]
+# The Pre Shared Key set with --static-auth-secret=...
+#pre_shared_key = "MyS3cr37"
+
+#[stun]
+#uris = ["stun:127.0.0.1:3478"]
+
+#[authz]
+# The reload interval of the permissions in seconds.
+# Used to propagate updates from one controller to the other.
+# reload_interval = 10
+
+#[call_in]
+# Set a phone number which will be displayed to the user
+# for the call-in service
+#tel="03012345678"
+# Enable the mapping of user names to their phone number. This requires
+# the OIDC provider to have a phone number field configured for their users.
+#enable_phone_mapping=false
+# The default country code for call in numbers. Notated in Alpha-2 code (ISO 3166)
+# Phone numbers that do not fall in the category of the default country must be notated
+# in the international format.
+#default_country_code="DE"
+
+# MinIO configuration
+[minio]
+# The URI to the MinIO instance
+uri = "http://minio:9000"
+# Name of the bucket
+bucket = "s3_bucket"
+# Access key for the MinIO bucket
+access_key = "minioadmin"
+# Secret key for the MinIO bucket
+secret_key = "minioadmin"
+
+# The etherpad configuration for the protocol module
+#[etherpad]
+#url = "http://etherpad:9001"
+# Etherpads api key
+#api_key = "etherpadapikey"
+
+# Spacedeck configuration
+#[spacedeck]
+#url = "http://spacedeck:9666"
+#api_key = "spacedeckapitoken"
+
+# Default/fallback values
+#[defaults]
+# Default language of a new user
+#user_language = "en-US"
+# Default presenter role for all users (defaults to false if not set)
+#participants_have_presenter_role = true
+
+# Settings for endpoints
+[endpoints]
+# Disable the /users/find endpoint for performance or privacy reasons
+disable_users_find = false
+
+# Enable user-searching using keycloak's admin API
+# This allows for finding users which have not yet
+# logged into the controller
+users_find_use_kc = false
+
+# Allow inviting any unchecked email address.
+# Not recommended without proper outgoing anti-spam protection
+event_invite_external_email_address = true
+
+# Configuration for the /metric HTTP endpoint
+#[metrics]
+# Allowlist for the /metrics endpoint
+#
+# Example: Allow all traffic from localhost
+#allowlist = ["127.0.0.0/24", "::ffff:0:0/96"]
\ No newline at end of file
diff --git a/extras/opentalk-samples/obelisk.toml.sample b/extras/opentalk-samples/obelisk.toml.sample
index 269ae82..e725134 100644
--- a/extras/opentalk-samples/obelisk.toml.sample
+++ b/extras/opentalk-samples/obelisk.toml.sample
@@ -31,7 +31,7 @@ port = 5060
 # ID of this SIP endpoint
 # When not set, it is generated as sip:<username>@<addr> where `addr` may be replaced by the
 # public address discovered using the stun-server
-#id = "sip:alice@example.org"
+#id = "sip:alice@example.com"
 
 # Username/Password pair.
 # Usually provided by the SIP provider
@@ -39,16 +39,16 @@ username = "alice"
 password = "mysecurepassword"
 
 # Realm of the given username/password pair
-realm = "example.org"
+realm = "example.com"
 
 # SIP URI of the registrar 
-registrar = "sip:example.org"
+registrar = "sip:example.com"
 
 # Seconds between ping/pong to keep NAT binding alive
 #nat_ping_delta = 30
 
 # Host-port of the stun server used for SIP
-stun_server = "stun.example.org:3478"
+stun_server = "stun.example.com:3478"
 
 # Enforce quality of protection on SIP authentication
 # (reuse of nonce + nonce-count instead of
diff --git a/extras/opentalk-samples/recorder.toml.sample b/extras/opentalk-samples/recorder.toml.sample
index 30bfe88..861ccc5 100644
--- a/extras/opentalk-samples/recorder.toml.sample
+++ b/extras/opentalk-samples/recorder.toml.sample
@@ -1,12 +1,12 @@
+[controller]
+domain = "controller.example.com"
+insecure = false
+
 [auth]
-issuer = "https://accounts.example.org/auth/realms/MyRealm"
+issuer = "https://accounts.example.com/auth/realms/MyRealm"
 client_id = "Recorder"
 client_secret = "INSERT_KEY"
 
-[controller]
-domain = "controller.example.org"
-insecure = false
-
 [rabbitmq]
 uri = "amqp://guest:guest@localhost/%2F"
 queue = "opentalk_recorder"
diff --git a/extras/opentalk-samples/smtp-mailer.toml.sample b/extras/opentalk-samples/smtp-mailer.toml.sample
index 5a815b8..8595b87 100644
--- a/extras/opentalk-samples/smtp-mailer.toml.sample
+++ b/extras/opentalk-samples/smtp-mailer.toml.sample
@@ -12,7 +12,7 @@ mail_task_queue = "opentalk_mailer"
 #smtp_server = "smtp://localhost:1025?disable_starttls=true"
 # Set the From email address according to the requirements of your SMTP server.
 #from_name = "OpenTalk"
-#from_email = "no-reply@example.org"
+#from_email = "no-reply@example.com"
 
 [template_builder]
 # Link builder templates. `base_url` and `x_id` will be replaced. Need when the frontend uses different paths.
@@ -21,8 +21,8 @@ mail_task_queue = "opentalk_mailer"
 #dashboard_event_link_builder = "{base_url}/dashboard/meetings/{event_id}"
 
 [frontend]
-#base_url = "https://opentalk.example.org"
-#data_protection_url = "https://opentalk.example.org/dataprotection"
+#base_url = "https://opentalk.example.com"
+#data_protection_url = "https://opentalk.example.com/dataprotection"
 
 [templates]
 # Path to templates. These are loaded at runtime and are not compiled in.
diff --git a/init/livekit-init.sh b/init/livekit-init.sh
new file mode 100755
index 0000000..2d6f172
--- /dev/null
+++ b/init/livekit-init.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+if [ -f /livekit.yaml ]; then
+  echo "[INIT] livekit.yaml config present. Skip writing config."
+else
+  echo "[INIT] Write livekit.yaml."
+cat << EOF > /livekit.yaml
+---
+port: $LIVEKIT_HTTP_PORT
+rtc:
+    tcp_port: $LIVEKIT_TCP_PORT
+    port_range_start: $LIVEKIT_RTC_PORT_RANGE_START
+    port_range_end: $LIVEKIT_RTC_PORT_RANGE_END
+    use_external_ip: $LIVEKIT_RTC_USE_EXTERNAL_IP
+    enable_loopback_candidate: $LIVEKIT_RTC_ENABLE_LOOPBACK_CANDIDATE
+turn: 
+    enabled: $LIVEKIT_TURN_ENABLED
+#    domain: "$LIVEKIT_TURN_DOMAIN"
+#    tls_port: $LIVEKIT_TURN_TLS_PORT
+#    udp_port: $LIVEKIT_TURN_UDP_PORT
+#    external_tls: $LIVEKIT_TURN_EXTERNAL_TLS
+keys:
+    $LIVEKIT_KEYS_API_KEY: $LIVEKIT_KEYS_API_SECRET
+logging:
+    json: $LIVEKIT_LOGGING_JSON
+    level: $LIVEKIT_LOGGING_LEVEL
+EOF
+fi
+
+echo "Print /livekit.yaml"
+cat /livekit.yaml
+
+
+/livekit-server --config /livekit.yaml
\ No newline at end of file
-- 
GitLab