Version: 25.09.16
Video conferences are part of everyday life—whether working from home, in online courses, or chatting privately. With Jitsi Meet, you can run a completely self-hosted video conferencing platform—independent of external services and with full control over data and features. 🛡️
A self-hosted Jitsi server is suitable for, e.g.:
📚 Training and online courses
👥 Team meetings in a company
🔒 Secure, private conversations without third-party providers
To get started successfully, you should bring a few basics and prerequisites:
🐧 Linux basics (server administration, SSH, installing packages)
🐳 Experience working with Docker and Docker Compose (already installed)
🌐 Basic knowledge of networks and domains (DNS, ports, SSL certificates)
⚠️ !! your own TURN / Coturn server so you can accept connections from outside! Basic prerequisite—see point 1 !! 🔥🔥
In this tutorial, I’ll show you step by step how to set up your own Jitsi Meet server—from the prerequisites all the way to a working video conferencing platform.
For this, we’ll draw on several elements taken from the official Jitsi Meet configuration page:
https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker
1. Turn / Coturn Server
🔥 Jitsi Meet requires a working TURN / Coturn server so that external connections via WebRTC can be accepted. ‼️ Port forwarding for Coturn (UDP port 3478, 40000–41000 and TCP 3478, and additionally 5349 for TLS) must be enabled in the firewall / VPS.
Coturn is installed on the Linux server as follows:
sudo apt update
sudo apt install coturn
Afterwards, activate the corresponding service:
sudo systemctl enable coturn
Then run: nano /etc/turnserver.conf
lt-cred-mech
realm=yourturnserver.com
listening-port=3478
listening-ip=IP-ADRESS-YOUR-VPS
min-port=40000
max-port=41000
# DB-Directory
userdb=/var/lib/turn/turndb
# LOGS
log-file=/var/log/turnserver.log
simple-log
Assign permissions for the database (userdb):
sudo mkdir -p /var/lib/turn
sudo rm -f /var/lib/turn/turndb #remove old DB
sudo -u turnserver touch /var/lib/turn/turndb
sudo chown -R turnserver:turnserver /var/lib/turn
sudo chmod 750 /var/lib/turn
sudo chmod 660 /var/lib/turn/turndb
After that, start the service:
sudo systemctl start coturn
Now we still need to create the users in Coturn—especially one user that Jitsi Meet will later use in the .env
config file.
sudo turnadmin -a -u user -p ultrastrongpassword -r yourturnserver.com -b /var/lib/turn/turndb
With this, you can display the Coturn users stored in the database:
sudo turnadmin -l -b /var/lib/turn/turndb
Such messages in the terminal can be ignored (everything is running smoothly):
0: : log file opened: /var/log/turn_2255621_2025-09-15.log 0: : SQLite connection was closed.
You can test your own TURN server with the following command:
turnutils_uclient -u user -w password -r yourturnserver.com -p 3478 -y turn.yourturnserver.com
If something like this is displayed, everything worked correctly:
: : Total connect time is 1 0: : Total connect time is 1 0: : start_mclient: msz=4, tot_send_msgs=0, tot_recv_msgs=0, tot_send_bytes ~ 0, tot_recv_bytes ~ 0 1: : start_mclient: msz=4, tot_send_msgs=0, tot_recv_msgs=0, tot_send_bytes ~ 0, tot_recv_bytes ~ 0 2: : start_mclient: msz=4, tot_send_msgs=5, tot_recv_msgs=5, tot_send_bytes ~ 500, tot_recv_bytes ~ 500 3: : start_mclient: msz=4, tot_send_msgs=5, tot_recv_msgs=5, tot_send_bytes ~ 500, tot_recv_bytes ~ 500 4: : start_mclient: msz=4, tot_send_msgs=5, tot_recv_msgs=5, tot_send_bytes ~ 500, tot_recv_bytes ~ 500 4: : start_mclient: tot_send_msgs=20, tot_recv_msgs=20 4: : start_mclient: tot_send_bytes ~ 2000, tot_recv_bytes ~ 2000 4: : Total transmit time is 4 4: : Total lost packets 0 (0.000000%), total send dropped 0 (0.000000%) 4: : Average round trip delay 0.000000 ms; min = 0 ms, max = 0 ms 4: : Average jitter 0.100000 ms; min = 0 ms, max = 1 ms
Done! Don’t forget to open the corresponding ports mentioned above in the UFW firewall or VPS firewall!
2. Installation of Jitsi Meet:
To do this, log in to your server (Linux Ubuntu / VPS), create a new folder called “jitsi” in your project directory, and then navigate into it.
cd /home/
mkdir jitsi
cd jitsi
Inside the jitsi folder, run the following command:
wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4)
Then, in that folder, we use ls
to check the name of the file we downloaded and run the following command:
unzip <filename>
3. Configuration:
After that:
cp env.example .env
With the cp env
command to .env
, we copy the sample configuration file from Jitsi Meet into our own .env
file, where we will later add our configuration.
Now we still need to generate strong passwords for the .env
file, which will then be entered directly there. Simply run the following command inside the “jitsi” folder:
./gen-passwords.sh
Now we create the remaining configuration files:
mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri}
After all config files have been created, we start the Docker project briefly and then shut it down again:
docker compose up -d
docker compose down
Now let’s take a closer look at the .env
configuration file and add the corresponding entries:
nano .env
The following content (adjusted to your setup!) should be in the .env
file to make everything work:
# All config files into jitsi folder:
CONFIG=./config
HTTP_PORT=8000
HTTPS_PORT=8443
#Timezone
TZ=UTC
PUBLIC_URL=https://meeting.yourdomain.com
# Reachable IP from Outside the docker container:
JVB_ADVERTISE_IPS=128.XXX.XXX.XXX
# 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
# XMPP password for Jicofo client connections
JICOFO_AUTH_PASSWORD=GENERATEDWITHGENPASSWORDSHFILEABOVE
# XMPP password for JVB client connections
JVB_AUTH_PASSWORD=GENERATEDWITHGENPASSWORDSHFILEABOVE
# XMPP password for Jigasi MUC client connections
JIGASI_XMPP_PASSWORD=GENERATEDWITHGENPASSWORDSHFILEABOVE
# XMPP password for Jigasi transcriber client connections
JIGASI_TRANSCRIBER_PASSWORD=GENERATEDWITHGENPASSWORDSHFILEABOVE
# XMPP recorder password for Jibri client connections
JIBRI_RECORDER_PASSWORD=GENERATEDWITHGENPASSWORDSHFILEABOVE
# XMPP password for Jibri client connections
JIBRI_XMPP_PASSWORD=GENERATEDWITHGENPASSWORDSHFILEABOVE
# Container restart policy
RESTART_POLICY=unless-stopped
# Jitsi image version (useful for local development)
#JITSI_IMAGE_VERSION=latest
ENABLE_XMPP_WEBSOCKET=1
ENABLE_COLIBRI_WEBSOCKET=1
#TURN SERVER CONFIGURATION:
# TURN-Server Configuration
TURN_HOST=yourturnserver.com
TURN_PORT=3478
TURN_TRANSPORT=udp,tcp
# If used TLS TURN SERVER
#TURNS_HOST=yourturnserver.com
#TURNS_PORT=443
# Login Data Turnserver (username:password)
TURN_CREDENTIALS=username:password
# Turn TTL in Seconds, let it so
TURN_TTL=86400
We now need to assign the corresponding users, since we configured Jitsi Meet so that not just anyone who knows the URL can start a video conference.
The Docker project is started with:
docker compose up -d
Now we switch into the “prosody” Jitsi container.
docker compose exec prosody /bin/bash
After that, we can create users (conference hosts) with the following command:
Note: Conference hosts can later be, for example, company accounts that can be issued for a fee.
prosodyctl --config /config/prosody.cfg.lua register TheDesiredUsername meet.jitsi TheDesiredPassword
To delete a user again, use the following command:
prosodyctl --config /config/prosody.cfg.lua unregister TheDesiredUsername meet.jitsi
And to display all users:
find /config/data/meet%2ejitsi/accounts -type f -exec basename {} .dat \;
We then exit the “prosody” container with:
exit
4. Port forwarding and NPM:
‼️ Jitsi Meet urgently requires UDP port 10000 to be opened! ‼️ (also allow it in the firewall)
Before moving on to NPM, you must first create a corresponding subdomain for your video conferencing server with your provider (DNS record pointing to the server’s IP address):
meeting.yourdomain.com
In NPM (Nginx Proxy Manager), create a new domain (Proxy Host), for example: meeting.yourdomain.com

Intern, we point this to HTTP port 8000, and NPM takes care of the SSL certificate and external encryption. With a click on “Save”, everything is stored, and the configuration of our own Jitsi Meet server for external access is complete.
5. Optional: your own “Branding”
Now we want to apply custom branding, so that on the start page of our meeting.yourdomain.com URL it no longer says “Jitsi Meet” but, for example, “IT-Service-Commander”:

For this, the relevant language file needs to be patched. You can do this inside the Docker Compose container:
docker-compose exec web bash
Install the Nano editor, since the container does not have it by default:
apt-get update
apt-get install -y nano
Edit the file:
nano /usr/share/jitsi-meet/lang/main-de.json
Search for the following section and modify it:
"headerTitle": "Jitsi Meet",
"headerSubtitle": "Sichere und hochqualitative Konferenzen",
Save the file and restart the container:
docker-compose restart web
If you want to make the change permanent, you need to proceed as follows (better approach):
In the “jitsi” folder (Docker project folder), create the following file:
nano docker-compose.override.yml
The following content:
services:
web:
volumes:
- ./overrides/lang/main-de.json:/usr/share/jitsi-meet/lang/main-de.json:ro
On the host, create the directory structure:
mkdir -p ./overrides/lang
Extract the language file from the container:
docker cp jitsi-web-1:/usr/share/jitsi-meet/lang/main-de.json ./overrides/lang/main-de.json
And then edit the file on the host (as mentioned above, change the passage with Jitsi Meet accordingly):
nano ./overrides/lang/main-de.json
Finally, restart everything once more:
docker-compose up -d --force-recreate web
Done — the Jitsi Meet branding should now be replaced with your own custom branding.
6. Completion
✅ We’re done and have set up the following:
🔗 Coturn / TURN server to ensure accessibility (not just internal but also external connections)
🖥️ Jitsi Meet server
🌐 TCP and UDP ports opened in the firewall
🏷️ Access via a subdomain for our Jitsi Meet server
🔒 SSL certificates assigned in NPM Manager
🎨 Optional: custom branding applied
✨ Finished – a fully operational Jitsi Meet server!
![]() | ![]() | ![]() |
bc1q8dxp9mlt3mkvaklu2vn8j6jteqyv53kschc90v | Lightning: itsc@strike.me | https://paypal.me/TomC777 |
![]() | ![]() | ![]() |