FICUSONLINE F9E
Video Conference with Jitsi Meet on Docker (+ Podman)
In addition to operating the latest version of the open-source video conferencing system Jitsi Meet using Docker containers, we are also exploring a transition to a rootless container and pod-based deployment using Podman. The traditional Docker Compose-based setup often requires root privileges, which poses security risks to the host system. Podman, on the other hand, is an OCI (Open Container Initiative)-compliant container runtime that enables production-level environments to be built and run by non-privileged users. By integrating each Jitsi Meet component—web, prosody, jicofo, and jvb—within a single Pod, internal communication can be confined to a local network, minimizing unnecessary external connections and optimizing both security and performance. This Podman-based deployment is intended as a foundation for future system architecture that includes Kubernetes integration and automated scaling.
Takanobu FuseAdministrator

5 days ago

Cloud / Server

This is a summary of a forum article. For details (modifications, additions, troubleshooting), please refer to here (Japanese only).


Added a SIP gateway Jigasi container (audio only) and rebuilt as the latest stable version. The system is configured to access the Jitsi Meet system via Nginx reverse proxy.

Jitsi Meet

Latest Stable 10078-1

Jitsi Docker Install Guide


Download Latest Stable Version

Download the latest package, then expand it.

$ wget $(curl -s https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep 'zip' | cut -d\" -f4)

Expand Command

$ unzip stable-10078-1

Move to the directory including the file named env.example, then copy it as .env.

$ cp env.example .env

Executed a script to set the required security passwords for each container in the .env file at startup.

$ ./gen-passwords.sh

Created the necessary configuration file directories for each container within the extracted directory.

$ mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri}

Note) This directory is specified in the .env file as CONFIG=./.jitsi-meet-cfg.

The list of configuration directories and files is as follows.

$ tree -aL 1 ../jitsi-docker-jitsi-meet-10078-1
../jitsi-docker-jitsi-meet-10078-1
├── .env
├── .env.bak
├── .github
├── .gitignore
├── .jitsi-meet-cfg
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── README.md
├── base
├── base-java
├── docker-compose.yml
├── env.example
├── etherpad.yml
├── examples
├── gen-passwords.sh
├── grafana.yml
├── jibri
├── jibri.yml
├── jicofo
├── jigasi
├── jigasi.yml
├── jvb
├── log-analyser
├── log-analyser.yml
├── nginx
├── prometheus
├── prometheus.yml
├── prosody
├── release.sh
├── resources
├── transcriber.yml
├── web
└── whiteboard.yml

Create the config file for Nginx Reverse Proxy

Access to Jitsi Meet is routed through an Nginx reverse proxy. By handling TLS authentication at the reverse proxy, TLS authentication within Jitsi Meet becomes unnecessary, making certificate management and renewal easier.

Reverse proxy configuration

To obtain TLS certificates via the reverse proxy, the following settings in the WEB container are disabled.

  • .env
DISABLE_HTTPS=1
ENABLE_HTTP_REDIRECT=0
ENABLE_LETS_ENCRYPT=0

Please also make the following necessary configurations in the .env file.

  • .env
#
# Basic configuration options
#

# Directory where all configuration will be stored
CONFIG=./.jitsi-meet-cfg

# Exposed HTTP port (will redirect to HTTPS port)
HTTP_PORT=8000

# Exposed HTTPS port
HTTPS_PORT=8443

# System time zone
TZ=JST

# Public URL for the web service (required)
# Keep in mind that if you use a non-standard HTTPS port, it has to appear in the public URL
#PUBLIC_URL=https://test.ficusonline.com:${HTTPS_PORT}
PUBLIC_URL=https://test.ficusonline.com

# Media IP addresses to advertise by the JVB
# This setting deprecates DOCKER_HOST_ADDRESS, and supports a comma separated list of IPs
# See the "Running behind NAT or on a LAN environment" section in the Handbook:
# https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker#running-behind-nat-or-on-a-lan-environment
JVB_ADVERTISE_IPS=192.168.1.1,1.2.3.4

# Enable authentication (will ask for login and password to join the meeting)
ENABLE_AUTH=1

# Enable guest access (if authentication is enabled, this allows for users to be held in lobby until registered user lets them in)
ENABLE_GUESTS=1

# Select authentication type: internal, jwt, ldap or matrix
AUTH_TYPE=internal

To enable TLS connections via the reverse proxy, connections to the Jitsi WEB container are made over HTTP. As a result, a WebSocket (wss) connection error occurs. To address this, WebSocket connections within the container are configured to use ws instead. The Nginx configuration is updated by adding location /xmpp-websocket and location /colibri-ws.

The final configuration file is as follows:

  • nginx/default.conf
server {
    server_name test.ficusonline.com;

    server_tokens off;
    # access_log  /var/log/nginx/test.ficusonline.com.access.log;
    # error_log   /var/log/nginx/test.ficusonline.com.error.log error;

	location / {
		proxy_pass http://web:80;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
	}
    
	location /xmpp-websocket {
		proxy_pass http://prosody:5280/xmpp-websocket;
		proxy_http_version 1.1;
		proxy_set_header Upgrade $http_upgrade;
		proxy_set_header Connection "upgrade";
	}

	location /colibri-ws {
		proxy_pass http://jvb:8080/colibri-ws;
		proxy_http_version 1.1;
		proxy_set_header Upgrade $http_upgrade;
		proxy_set_header Connection "upgrade";
	}

    listen 443 ssl; # managed by Certbot
    listen [::]:443 ssl;
    ssl_certificate /etc/letsencrypt/live/ficusonline.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ficusonline.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

}
server {
    if ($host = test.ficusonline.com) {
        return 301 https://$host$request_uri;
    } 

    server_name test.ficusonline.com;
    listen [::]:80;
    listen 80;
    return 404; 
}

Create the dedicated docker-compose file for Nginx

To operate the system using Podman in a pod-based setup, a dedicated docker-compose file for Nginx is created, independent from the Jitsi Meet system.

Since Podman, for security reasons, does not allow access to ports below 1000 at the user level, access to ports 80 and 443 is redirected to ports 8080 and 8443 using iptables. To make this redirection persistent, it must be registered with the system daemon. For more details, please refer to here (Japanese only).

$ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
$ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
$ sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443
$ sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443
  • docker-compose-nginx.yml
    nginx:
        container_name: nginx
        image: nginx:alpine
        tty: true
        ports:
            - "8080:80"
            - "8443:443"
        volumes:
            # nginx config
            - ./nginx:/etc/nginx/conf.d
            - /etc/letsencrypt:/etc/letsencrypt
        restart: always
        networks:
            meet.jitsi:

Start Containers

Start by specifying both the Jitsi and Nginx docker-compose files.

$ docker compose -f docker-compose.yml -f docker-compose-nginx.yml up -d

Register The Admin User

The registration of meeting administrator users will be done inside the Prosody container.

$ docker compose exec prosody bash
# prosodyctl --config /config/prosody.cfg.lua register USER_NAME meet.jitsi PASSWORD

Check Admin User

# find /config/data/meet%2ejitsi/accounts -type f -exec basename {} .dat \;

Jitsi Main Screen Jitsi Meet Main

Meeting Screen


Run with Pods

The Nginx pod and the group of containers that configure Jitsi Meet will be operated as a packaged pod.

Jitsi Meet on Pod

The proxy_pass setting in Nginx will be rewritten to match the Podman network configuration.

  • nginx/default.conf
server {
    server_name test.ficusonline.com;

    server_tokens off;
    # access_log  /var/log/nginx/test.ficusonline.com.access.log;
    # error_log   /var/log/nginx/test.ficusonline.com.error.log error;

	location / {
		# jitsi-meet network 172.18.0.0/16
		# web container
#		proxy_pass http://web:80/;		
		proxy_pass http://meet.jitsi:80/;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
	}
    
	location /xmpp-websocket {
	    # prosody ws
#	    proxy_pass http://prosody:5280/xmpp-websocket;
		proxy_pass http://meet.jitsi:5280/xmpp-websocket;
		proxy_http_version 1.1;
		proxy_set_header Upgrade $http_upgrade;
		proxy_set_header Connection "upgrade";
	}

	location /colibri-ws {
	    # jvb ws
#		proxy_pass http://jvb:8080/colibri-ws;
		proxy_pass http://meet.jitsi:8080/colibri-ws;
		proxy_http_version 1.1;
		proxy_set_header Upgrade $http_upgrade;
		proxy_set_header Connection "upgrade";
	}

    listen 443 ssl; # managed by Certbot
    listen [::]:443 ssl;
    ssl_certificate /etc/letsencrypt/live/ficusonline.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ficusonline.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

}
server {
    if ($host = test.ficusonline.com) {
        return 301 https://$host$request_uri;
    } 

    server_name test.ficusonline.com;
    listen [::]:80;
    listen 80;
    return 404; 
}

The series of commands for creating a network with Podman, creating a pod, and placing containers within the pod are as follows:

$ JITSI_IMAGE_VERSION=stable-10078-1

$ podman network create meet-jitsi

$ podman pod create --name pod-nginx --hostname host-nginx --network meet-jitsi -p 8080:80 -p 8443:443

$ podman pod create --name pod-jitsi --hostname meet.jitsi --network meet-jitsi -p 10000:10000/udp -p 20000-20050:20000-20050/udp \
    --add-host=xmpp.meet.jitsi:127.0.0.1

$ podman create \
    --pod pod-nginx \
    --name nginx \
    -v ./nginx:/etc/nginx/conf.d \
    -v ./letsencrypt:/etc/letsencrypt \
    nginx:alpine
    
$ podman create \
    --name web \
    --pod pod-jitsi \
    --env-file .env \
    -v .jitsi-meet-cfg/web:/config:Z \
    -v .jitsi-meet-cfg/web/crontabs:/var/spool/cron/crontabs:Z \
    -v .jitsi-meet-cfg/transcripts:/usr/share/jitsi-meet/transcripts:Z \
    -v .jitsi-meet-cfg/web/load-test:/usr/share/jitsi-meet/load-test:Z \
    --label service=jitsi-web \
    jitsi/web:${JITSI_IMAGE_VERSION}
    
$ podman create \
  --name prosody \
  --pod pod-jitsi \
  --env-file .env \
  -v .jitsi-meet-cfg/prosody/config:/config:Z \
  -v .jitsi-meet-cfg/prosody/prosody-plugins-custom:/prosody-plugins-custom:Z \
  --label service="jitsi-prosody" \
  jitsi/prosody:${JITSI_IMAGE_VERSION}
  
$ podman create \
  --name jicofo \
  --pod pod-jitsi \
  --env-file .env \
  -v .jitsi-meet-cfg/jicofo:/config:Z \
  --label service="jitsi-jicofo" \
  jitsi/jicofo:${JITSI_IMAGE_VERSION}
  
$ podman create \
  --name jvb \
  --pod pod-jitsi \
  --env-file .env \
  -v .jitsi-meet-cfg/jvb:/config:Z \
  --label service="jitsi-jvb" \
  jitsi/jvb:${JITSI_IMAGE_VERSION}
  
$ podman create \
  --name jigasi \
  --pod pod-jitsi \
  --env-file .env \
  -v .jitsi-meet-cfg/jigasi:/config:Z \
  --label service="jitsi-jigasi" \
  jitsi/jigasi:${JITSI_IMAGE_VERSION}

By installing Podman Desktop, you will be able to manage the pods and containers created with the above command. You can start and stop each pod either from Podman Desktop or by using the command “$ podman pod start POD_NAME” .

Podman Conteiners


Run under Kubernetes environment

Create a Kubernetes YAML file from a Pod created with Podman.

$ podman generate kube pod-nginx >> pod-nginx.yaml
$ podman generate kube pod-jitsi >> pod-jitsi.yaml

From pod-jitsi.yaml

Delete : metadata -> annotations

https://github.com/containers/podman/issues/17761#issuecomment-1845394695

  • pod-jitsi.yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2025-03-27T14:17:48Z"
  labels:
    app: pod-jitsi
  name: pod-jitsi
.....
.....

Launch the following Pods from the created Kubernetes YAML file.

$ podman play kube pod-jitsi.yaml
$ podman play kube pod-nginx.yaml

To check the logs until the pod starts.

$ podman --log-level=debug play kube pod-jitsi.yaml
$ podman --log-level=debug play kube pod-nginx.yaml

Managed by System Daemon (Automatic Startup)

Since Podman does not run as a system daemon, processes remain stopped after a host reboot. However, by registering the pod as a system daemon service, it can be set to automatically start either upon user login or when the host machine boots up.

Two methods are available for using a system daemon:

1) $ podman generate systemd ~

This generates a systemd unit file from an existing pod or container. However, it is only a service to start and stop the pod or container, so if the pod or container is deleted, the service will become inactive. Functionally, this is equivalent to docker-compose stop and docker-compose start.

2) Quadlet (Recommended)

This method generates a systemd unit file to start a new container from an image based on an existing container definition (without relying on existing containers). When the service is stopped, the container is removed. Functionally, this is equivalent to docker-compose up and docker-compose down. Note: As of Podman v4.9.3, pod-container linkage functionality is not implemented (it will be supported in v5 and later).


1) $ podman generate systemd ~

Check Pods

$ podman pod ps
POD ID        NAME        STATUS      CREATED      INFRA ID      # OF CONTAINERS
8479ea3524b9  pod-jitsi   Exited      4 hours ago  de6fb0a4d245  5
7787d93bd426  pod-nginx   Exited      4 hours ago  20552d55e11c  2

The management of each pod will be handed over to the system daemon. A service file for this will be created using the podman generate command.

$ podman generate systemd --name pod-nginx --files

The following 2 files will be created.

  • pod-pod-nginx.service
  • container-nginx.service
$ podman generate systemd --name pod-jitsi --files

The following 6 files will be created.

  • pod-pod-jitsi.service
  • container-web.service
  • container-prosody.service
  • container-jicofo.service
  • container-jvb.service
  • container-jigasi.service

Please copy the above-created file to the ~/.config/systemd/user directory to manage it as a system daemon at the user level.

$ cp *.service ~/.config/systemd/user 

Activation of each service.

$ systemctl --user daemon-reload
$ systemctl --user enable pod-pod-jitsi
$ systemctl --user enable pod-pod-nginx

Launch each Pod

$ systemctl --user start pod-pod-jitsi
$ systemctl --user start pod-pod-nginx

The above method is only effective when the user logs in, so to ensure it works regardless of user login, the following configuration is required.

$ sudo loginctl enable-linger $(whoami)

Activation of Systend Service