What you will set up
Jitsi Meet is a video meeting service, like Zoom or Google Meet, that runs on your own server. People join in the browser from a link, with nothing to install.
A Jitsi server is several programs working together: a web server, nginx, serves the page; Prosody passes messages between participants; the videobridge carries the sound and video of every meeting; and coturn helps people on networks that block the videobridge. This guide uses Jitsi's own Debian packages, which install cleanly on Debian 13 with Debian's own Prosody and Java and run as ordinary system services. Jitsi's Docker setup needs root Docker, which opens ports past ufw. Give Jitsi a server of its own: it takes over ports 80 and 443 for nginx.
Out of the box, anyone who finds your server can start a meeting on it. Step 4 changes that, so only accounts you create can start one, and anyone with the link can join once it has started.
Every step below was run on a fresh Melonslab VC-P Alloy (2 vCPU, 8 GB) with Debian 13:
- Jitsi Meet installed in about 90 seconds and got a Let's Encrypt certificate for its name by itself.
- A guest who opened a meeting alone was told to wait for a moderator. Once a user had logged in and started the meeting, the guest joined it. A wrong password was refused.
- Two participants in Chromium, with test camera and microphone, sent and received video through the videobridge on UDP port 10000, and also directly to each other, and through coturn.
- The page made no requests to other sites, and the server no longer asks Jitsi's own STUN server for its address (step 6).
- An upgrade from the previous Jitsi release kept every change, and everything came back by itself after a reboot.
With two people in a meeting, Jitsi's programs used about 700 MB of memory together, most of it in the two Java services.
Before you start
You need:
- a fresh Melonslab server with Debian 13 and nothing else installed;
- a name for it, such as
meet.example.com, with an A record and an AAAA record pointing at the server. Create them first: the installer asks Let's Encrypt for a certificate straight away.
Set up SSH keys, automatic security updates and ufw as in steps 1 to 4 of the security guide, including the rule for HTTP and HTTPS.
The examples use meet.example.com, 203.0.113.10 for the server's IPv4 address and 2001:db8::10 for its IPv6 address. Replace them throughout.
1. Open the ports
As root:
ufw allow 10000/udp
ufw allow 3478/udp
ufw allow 5349/tcp
The videobridge carries meetings on UDP port 10000. coturn listens on UDP port 3478, and on TCP port 5349 with TLS, for people whose network blocks UDP port 10000. The rules cover IPv4 and IPv6.
2. Add Jitsi's package repository
apt update
apt install -y curl gnupg
curl -fsSL https://download.jitsi.org/jitsi-key.gpg.key | gpg --dearmor -o /usr/share/keyrings/jitsi-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/jitsi-keyring.gpg] https://download.jitsi.org stable/" > /etc/apt/sources.list.d/jitsi-stable.list
apt update
The repository is the same for every Debian release. On Debian 13 Jitsi uses Debian's own Prosody 13 and Java 21.
3. Install Jitsi Meet
The installer asks for the server's name, which certificate to use and an email address for Let's Encrypt. Give the answers first, with your own name and address:
cat <<'EOF' | debconf-set-selections
jitsi-videobridge2 jitsi-videobridge/jvb-hostname string meet.example.com
jitsi-meet-web-config jitsi-meet/cert-choice select Let's Encrypt certificates
jitsi-meet-web-config jitsi-meet/email string anna@example.com
jitsi-meet-web-config jitsi-meet/jaas-choice boolean false
EOF
DEBIAN_FRONTEND=noninteractive apt install -y jitsi-meet
The last answer declines a free account on JaaS, 8x8's hosted Jitsi service. The installer downloads acme.sh from GitHub, gets the certificate with it, and adds a cron job that renews it. It ends with an advert for JaaS, which you can ignore. Warnings about the hostname or Could not get FQDN are about a spare self-signed certificate, and are harmless.
Open https://meet.example.com. The page offers to start a meeting, and at this point anyone can.
4. Let only your users start meetings
Jitsi calls this a secure domain. Jitsi's documentation now points to signed tokens instead, which need a login service of your own. A secure domain needs nothing else, and works as described here.
Open /etc/prosody/conf.avail/meet.example.com.cfg.lua. Under VirtualHost "meet.example.com", change the line
authentication = "jitsi-anonymous" -- do not delete me
to:
authentication = "internal_hashed"
And add this to the end of the file:
VirtualHost "guest.meet.example.com"
authentication = "jitsi-anonymous"
c2s_require_encryption = false
Guests connect to guest.meet.example.com. It is a name inside Prosody only, and needs no DNS record.
Open /etc/jitsi/meet/meet.example.com-config.js. Under hosts:, below the line domain: 'meet.example.com',, add:
anonymousdomain: 'guest.meet.example.com',
Open /etc/jitsi/jicofo/jicofo.conf, and below the first line, jicofo {, add:
authentication: {
enabled: true
type: XMPP
login-url: meet.example.com
}
Restart the services, and create an account for each person who should be able to start meetings. prosodyctl asks for the password twice:
systemctl restart prosody jicofo jitsi-videobridge2
prosodyctl adduser anna@meet.example.com
prosodyctl passwd anna@meet.example.com sets a new password, and prosodyctl deluser anna@meet.example.com removes the account.
5. Hold a meeting
Open https://meet.example.com, enter a name for the meeting and choose Start meeting, then Join meeting. A dialog says Waiting for a moderator…. Choose Log-in, and enter the user name, anna, and the password under User and User password. Choose Login. The meeting starts, and you are its moderator.
Send the address in your browser to the others. They choose Join meeting and are let straight in, without an account. If a guest arrives before you, they see Waiting for a moderator… until you have logged in.
Meetings with two people go directly between the two browsers when they can reach each other. From three people, or when they cannot, everything goes through the videobridge.
6. Keep outside services out
Two settings send something to other services by default:
- The videobridge asks a STUN server run by Jitsi,
meet-jit-si-turnrelay.jitsi.net, for its public address at every start. A Melonslab server has its public addresses on its own network card, so it does not need to ask. - Browsers ask the same server for their address in meetings between two people. Your coturn can answer instead.
In /etc/jitsi/videobridge/jvb.conf, delete the three lines of the stun block, so that the end of the file reads:
ice4j {
harvest {
mapping {
aws {
enabled = false
}
}
}
}
In /etc/jitsi/meet/meet.example.com-config.js, find the line { urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' }, under p2p: and change it to:
{ urls: 'stun:meet.example.com:3478' },
Jitsi also shows people's pictures from Gravatar, a public service, when they enter an email address in their settings, which sends a code made from the address to Gravatar. To switch that off, add this line just below var config = { at the top of the same file:
gravatar: { disabled: true },
Then restart the videobridge:
systemctl restart jitsi-videobridge2
Changes to config.js reach each browser when it next loads the page.
7. Close the settings files to other users
Several settings files hold the passwords the Jitsi services use with each other, and every user on the server can read them. Make them readable only to root and the service that needs each one:
chmod o-r /etc/jitsi/jicofo/jicofo.conf /etc/jitsi/videobridge/jvb.conf
chgrp prosody /etc/prosody/conf.avail/meet.example.com.cfg.lua
chgrp turnserver /etc/turnserver.conf
chmod 640 /etc/prosody/conf.avail/meet.example.com.cfg.lua /etc/turnserver.conf
systemctl restart prosody coturn jicofo jitsi-videobridge2
8. What is open to the internet
ss -tulpn lists more than you allowed, but ufw keeps the rest closed. From outside, only these answer:
| Port | For |
|---|---|
| 22/tcp | SSH |
| 80/tcp | Redirects to HTTPS, and Let's Encrypt |
| 443/tcp | The meeting page, and the connection each browser keeps to Prosody |
| 10000/udp | Sound and video through the videobridge |
| 3478/udp, 5349/tcp | coturn, for networks that block UDP port 10000 |
Prosody's ports 5222, 5269 and 5281 listen on every address but stay closed. The videobridge's own interface on port 8080 listens only on 127.0.0.1. curl -s localhost:8080/metrics | grep sending_video on the server shows how many participants are sending video right now.
Everything works over IPv6 as well: nginx and coturn listen on both addresses, and the videobridge offers browsers both. The meeting page was tested over IPv6 from the server itself; meetings were tested over IPv4.
9. Updates
The automatic updates from the security guide install Debian's security updates, which include nginx, Prosody, Java and coturn. They do not install Jitsi's own packages. Update those yourself, at a time when nobody is in a meeting, as the services restart:
apt update
apt upgrade
An upgrade keeps your changes to the settings files. The certificate renews by itself: /opt/acmesh/.acme.sh/acme.sh --list --home /opt/acmesh/.acme.sh shows when it renews next.
Troubleshooting
Guests see "Waiting for a moderator…" and never get in. Nobody with an account has started the meeting yet. It starts when someone chooses Log-in in the same meeting and logs in.
Logging in says "Incorrect username or password". Enter the name without @meet.example.com. Set a new password with prosodyctl passwd anna@meet.example.com.
You can join a meeting, but nobody sees or hears anyone. UDP port 10000 cannot be reached. Check ufw status for the rules from step 1, and that ss -ulpn | grep 10000 shows the videobridge's java process. With only two people, the meeting may be going directly between the browsers, so try with a third.
The browser warns about the certificate. Let's Encrypt could not reach the server when you installed, usually because the A or AAAA record was missing. Once both point at the server, run /usr/share/jitsi-meet/scripts/install-letsencrypt-cert.sh anna@example.com meet.example.com.
Nothing works after editing a settings file. A typing error stops a service from starting. systemctl status prosody jicofo jitsi-videobridge2 shows which one. Prosody's log is in /var/log/prosody, and those of jicofo and the videobridge are in /var/log/jitsi.