Installing OpenTalk on Debian 12

OpenTalk is a video conferencing solution prioritizing productivity, digital sovereignty, and privacy. It is tailored to support moderators and ensure a good user experience with scalable performance during video conferences.

First, set up a Debian server with firewall ufw.

Reverse Proxy

Firewall

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
sudo ufw status

Domain/DNS

Go to your domain provider and point your domain at your server's IP 4 and IP 6 adresses.

Create configuration files (see appendix):

  • sudo vi /etc/nginx/sites-available/controller.conf

  • sudo vi /etc/nginx/sites-available/frontend.conf

  • sudo vi /etc/nginx/sites-available/keycloak.conf

Certificates

sudo certbot certonly --standalone -d talk.example.com
sudo certbot certonly --standalone -d accounts.talk.example.com
sudo certbot certonly --standalone -d controller.talk.example.com

Install Nginx

sudo apt-get install nginx
sudo systemctl start nginx
sudo systemctl enable nginx

Generate a DH parameter file:

sudo openssl dhparam -out /etc/ssl/dhparam.pem 4096
sudo systemctl restart nginx

Copy sslsettings.conf:

sudo cp extras/nginx-samples/snippets/sslsettings.conf.sample /etc/nginx/snippets/sslsettings.conf
sudo rm /etc/nginx/sites-enabled/default

Configure Nginx

sudo vi /etc/nginx/sites-available/controller.conf
sudo vi /etc/nginx/sites-available/frontend.conf
sudo vi /etc/nginx/sites-available/keycloak.conf
sudo ln -s /etc/nginx/sites-available/controller.conf /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/frontend.conf /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/keycloak.conf /etc/nginx/sites-enabled/

sudo systemctl restart nginx

Test Nginx configuration:

sudo nginx -t

OpenTalk

Install Docker

From their homepage (https://docs.docker.com/engine/install/debian/#install-using-the-repository):

sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
    https://download.docker.com/linux/debian \
    $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
    sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo docker run hello-world
sudo apt-get update
sudo apt-get install docker-compose-plugin
docker compose version

Firewall

sudo ufw allow 20000:25000/udp
sudo ufw reload
sudo ufw status

Container stack

git clone https://gitlab.opencode.de/opentalk/ot-setup.git /opt/opentalk
cd /opt/opentalk
cp env.sample .env
cp extras/opentalk-samples/controller.toml.sample config/controller.toml
sudo apt-get install pwgen
bash extras/gen-secrets.sh

The last command produces an output that you can use to replace the header area in the .env file. Note that the OT_DOMAIN must be set manually.

vi .env:

OT_DOMAIN="talk.example.com"

POSTGRES_PASSWORD=paiquohlai9eQueih0Aiki3ror9chuyu
KEYCLOAK_ADMIN_PASSWORD=Aelai3ucu2aewoo7couth9Afiezeeyai
KEYCLOAK_CLIENT_SECRET_CONTROLLER=iengoo5Ohhaog3ig9piogooh6phouluM
KEYCLOAK_CLIENT_SECRET_OBELISK=Pai9juem8ha2iiKaovai0veofaeTheeL
KEYCLOAK_CLIENT_SECRET_RECORDER=heus6aiJoh5eu3oofairo1oovahwau5U
SPACEDECK_API_TOKEN=dae6ein6ootuang3aihaebenu0Oixuit
SPACEDECK_INVITE_CODE=thoo0ne4ooGhaichinie3ohpouZoht7e
ETHERPAD_API_KEY=jaisaephaico1Ohz3maaGh9quocuNg3i

Replace the placeholders in vi config/controller.toml:

# ``POSTGRES_PASSWORD`` from ``.env.``
url = "postgres://ot:<POSTGRES_PASSWORD>@postgres:5432/opentalk"

cors.allowed_origin = ['talk.example.com']

base_url = "https://accounts.talk.example.com/auth"

# ``KEYCLOAK_CLIENT_SECRET_RECORDER`` from ``.env.``
client_secret = "<KEYCLOAK_CLIENT_SECRET_CONTROLLER>"

Run the OpenTalk stack

docker compose up -d

Post installation tasks

Point your web browser to https://accounts.talk.example.com/auth.

user

admin

password

KEYCLOAK_CLIENT_SECRET_CONTROLLER from env..

After login to Keycloak administration, switch to the realm opentalk and create a new user with the default role default-roles-opentalk. As reference you can refer the testuser provided for demo purposes. You can also enable the testuser and reset the password for testing OpenTalk.

Log in to your OpenTalk instance

If you have successfully created an OpenTalk user, you can now use it to log in to your new OpenTalk installation. By default, the OpenTalk web interface is available at the root of your domain e.g. https://talk.example.com.

Trouble Shooting

ancestor violates the following Content Security Policy directive: "frame-ancestors 'self'"

Set the Content-Security-Policy on the Keycloak webinterface at Keycloak -> reaml "opentalk" (Dropdown) -> Realm settings -> Security defenses Content-Security-Policy:

frame-ancestors 'self' https://talk.example.com https://accounts.talk.example.com https://controller.talk.example.com; default-src 'self' https://talk.example.com https://accounts.talk.example.com https://controller.talk.example.com; frame-src 'unsafe-inline' 'self' https://talk.example.com https://accounts.talk.example.com https://controller.talk.example.com; style-src 'unsafe-inline' 'self'; connect-src 'unsafe-inline' 'self' https://talk.example.com https://accounts.talk.example.com https://controller.talk.example.com

Access to fetch at 'https://controller.talk.suredigital.de/v1/auth/login' from origin 'https://talk.suredigital.de' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

TODO

"``Invalid parameter: redirect_uri`` und Bad Request"

The bad request is triggered by the URL-Paratemer redirect_uri. The error message should be correctly: "Invalid value for parameter: redirect_uri". The value of that parameter needs to correspond an URL set in Keycloak.

To fix the "Bad Request": in the Admin-Panel of Keycloak go to -> realm "opentalk" (Dropdown) -> Clients ->

  • OtBackend -> Valid redirect URL -> Add valid redirect URIs: change all entries from talk.example.com to subdomain.foo.com.

  • OtFrontend -> Valid redirect URL -> Add valid redirect URIs: change all entries from talk.example.com to subdomain.foo.com.

Note this happens when changing domains after setting up the Docker container for the first time, as while some values get updated on later configuration changes, those values won't be updated.

Appendix

/etc/nginx/sites-available/controller.conf

upstream controller {
    server localhost:8090;
}

map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
}

server {
    listen       80;
    listen       [::]:80;
    server_name  controller.talk.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  controller.talk.example.com;

    ssl_certificate         /etc/letsencrypt/live/controller.talk.example.com/fullchain.pem;
    ssl_certificate_key     /etc/letsencrypt/live/controller.talk.example.com/privkey.pem;

    # NOTE: ChatGPT says this is not needed for a reverse proxy
    # root controller.talk.example.com;

    include /etc/nginx/snippets/sslsettings.conf;

    access_log  /var/log/nginx/https-access_controller.talk.example.com.log;
    error_log  /var/log/nginx/https-error_controller.talk.example.com.log;

    client_max_body_size 1G;

    location / {
        proxy_set_header X-Forwarded-For    $remote_addr;
        proxy_set_header Upgrade            $http_upgrade;
        proxy_set_header Connection         $connection_upgrade;
        proxy_buffers                       8 8k;
        proxy_buffer_size                   8k;

        proxy_pass                          http://controller;
    }
}

/etc/nginx/sites-available/frontend.conf

upstream web-frontend {
    server localhost:8080;
}

map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
}

server {
    listen       80;
    listen       [::]:80;
    server_name  talk.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  talk.example.com;

    ssl_certificate         /etc/letsencrypt/live/talk.example.com/fullchain.pem;
    ssl_certificate_key     /etc/letsencrypt/live/talk.example.com/privkey.pem;

    # NOTE: ChatGPT says, this is not needed for a reverse proxy:
    # root talk.example.com;

    include /etc/nginx/snippets/sslsettings.conf;

    access_log  /var/log/nginx/https-access_talk.example.com.log;
    error_log  /var/log/nginx/https-error_talk.example.com.log;


    location / {
        proxy_set_header X-Forwarded-For    $remote_addr;
        proxy_set_header Upgrade            $http_upgrade;
        proxy_set_header Connection         $connection_upgrade;
        proxy_buffers                       8 8k;
        proxy_buffer_size                   8k;

        proxy_pass                          http://web-frontend;
    }
}

/etc/nginx/sites-available/keycloak.conf

upstream keycloak {
    server localhost:8087;
}

map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
}

server {
    listen       80;
    listen       [::]:80;
    server_name  accounts.talk.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  accounts.talk.example.com;

    ssl_certificate         /etc/letsencrypt/live/accounts.talk.example.com/fullchain.pem;
    ssl_certificate_key     /etc/letsencrypt/live/accounts.talk.example.com/privkey.pem;

    # NOTE: ChatGPT says, this is not needed for a remote proxy setup:
    # root accounts.talk.example.com;

    include /etc/nginx/snippets/sslsettings.conf;

    access_log  /var/log/nginx/https-access_accounts.talk.example.com.log;
    error_log  /var/log/nginx/https-error_accounts.talk.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;
        proxy_buffers                       8 8k;
        proxy_buffer_size                   8k;

        proxy_pass                          http://keycloak;
    }
}

Changing domain

sed -i 's^old.com^new.com^g' /opt/opentalk/.env
find /opt/opentalk/config/ -name "*.toml" -exec sed -i 's^old.com^new.com^g' '{}' \;
sudo find /etc/nginx/sites-available/ -name "*.conf" -exec sed -i 's^old.com^new.com^g' '{}' \;

Create certificates for the new domain und sub domains, if not existened yet.