Jitsi Docker Compose gets you a running video conferencing stack in about ten minutes, and a stack that actually handles real calls in maybe thirty, once you've dealt with the one setting that trips up almost every first attempt. The gap between those two numbers is JVB_ADVERTISE_IPS, and skipping it is why so many people get a working login screen and then a black video tile the moment a second participant joins from another network.

This is the full setup using the official docker-jitsi-meet project: getting it, configuring it, enabling HTTPS, and the specific things that go wrong with docker jitsi meet deployments that don't show up in a five-minute quickstart.

Quick answer

Download the latest docker-jitsi-meet release (not a git clone, more on that below), copy env.example to .env, run ./gen-passwords.sh, set JVB_ADVERTISE_IPS to your server's public IP, and run docker compose up -d. That last env var is the one people skip, and it's the difference between a stack that looks fine and one that actually works for real calls.

Prerequisites

Before you start

  • Docker Engine and Docker Compose v2 on a Linux host with at least 2 vCPUs and 4GB RAM for light use, more if you expect concurrent large calls.
  • A public IP address and, ideally, a domain pointed at it. Jitsi works over plain IP, but HTTPS and mobile clients both expect a real domain.
  • Ports 80/tcp and 443/tcp open for the web interface, and 10000/udp open for JVB media, that last one is the port most tutorials forget to mention until calls fail.

Getting docker-jitsi-meet

The official docker-jitsi-meet repo is the one to use, not a random third-party image. One thing that surprises people who've done this before with other projects: the Jitsi team's own docs recommend downloading a tagged release archive for production, not git cloneing the repo directly.

wget $(wget -q -O - https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep zip | cut -d\" -f4)
unzip docker-jitsi-meet-*.zip
cd docker-jitsi-meet-*
cp env.example .env

Then create the config directories the containers mount their persistent state into:

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

Configuring the .env file

Generate strong passwords for the internal service accounts first, this rewrites .env in place and keeps a backup at .env.bak:

chmod +x gen-passwords.sh
./gen-passwords.sh

Then set the handful of variables that actually determine whether this deployment works outside your laptop:

VariableWhat it does
PUBLIC_URLThe domain participants use to join, e.g. https://meet.example.com
JVB_ADVERTISE_IPSThe public IP JVB tells clients to send media to. Wrong or missing, and calls with more than one participant on different networks fail silently.
TZYour server's timezone, affects log timestamps
HTTP_PORT / HTTPS_PORTHost ports the web container binds to, default 8000 and 8443

JVB_ADVERTISE_IPS is not optional

This is the setting behind almost every "I can join alone but calls don't connect with anyone else" report. Set it to your server's actual public IP, even if you're behind a reverse proxy, since it controls media routing, not HTTP traffic, so a proxy in front of the web container doesn't help it. Running on AWS or GCP specifically? Our Jitsi AWS guide and GCP guide cover the exact IP and security-group setup for each provider if you'd rather not piece it together from a generic Docker guide.

Enabling HTTPS

For a real deployment, let the stack handle Let's Encrypt itself rather than fronting it with your own reverse proxy, it's fewer moving parts to get wrong:

ENABLE_LETSENCRYPT=1
LETSENCRYPT_DOMAIN=meet.example.com
LETSENCRYPT_EMAIL=you@example.com

Let's Encrypt caps you at 5 certificates per exact domain per week, so don't loop docker compose up while debugging an unrelated issue, you'll burn through that limit fast and get locked out for days. If you're running Jitsi behind a Kubernetes ingress instead of plain Compose, certificate renewal works differently, our guide to updating SSL certs in Jitsi on Kubernetes covers that path specifically.

Starting the stack

docker compose up -d
docker compose ps

All four core containers, web, prosody, jicofo, jvb, should show as running. That's necessary but not sufficient: a healthy docker compose ps means the processes started, not that calls will actually connect once someone outside your local network joins. Test with two devices on two different networks (phone on mobile data, laptop on wifi) before calling it done.

If participants sit behind strict corporate firewalls or symmetric NAT, JVB alone won't always get media through, that's what a TURN server is for. Our TURN server setup guide for Jitsi Meet covers adding one alongside this stack.

Adding Jibri for recording

Jibri docker support is a one-line addition, an extra compose file layered on top of the base stack:

docker compose -f docker-compose.yml -f jibri.yml up -d

The container still needs the host's snd_aloop kernel module loaded, that part doesn't move inside Docker no matter which way you set it up. Our Jibri recording setup guide covers the full config, S3 upload setup, and troubleshooting in detail, worth reading in full rather than repeating here since it's genuinely its own topic once recording is involved.

Scaling and troubleshooting

A single JVB container handles a meaningful number of concurrent participants, but there's a ceiling, and past it you scale by adding more JVB instances behind Jicofo rather than resizing the one you have. That's a bigger architectural change than a docker-compose tweak, worth understanding the JVB/Jicofo/Prosody relationship first, our Jitsi architecture breakdown covers what each component actually does before you start adding more of them.

The failures that show up most with this stack, in rough order of how often they happen:

  • Calls work solo, fail with a second participant: JVB_ADVERTISE_IPS again. It's the answer to most "video doesn't connect" reports with this stack.
  • Let's Encrypt fails to issue: DNS for LETSENCRYPT_DOMAIN isn't actually pointing at the server yet, or port 80 is blocked at the firewall/security-group level during the initial challenge.
  • Audio works, video doesn't, or the reverse: usually 10000/udp blocked somewhere between the client and the server, a corporate firewall or a cloud security group that only opened 80/443.
  • Container restarts in a loop: check docker compose logs prosody first, a bad or regenerated password in .env after containers already have old credentials cached is a common cause.

Skipping the DIY setup

Docker Compose is the right call when you want to understand exactly what's running, you're already operating a Docker-based stack, or you're testing before committing to production infrastructure. It's also a stack you now own end to end: JVB capacity planning, cert renewal, container upgrades, and being the one debugging JVB_ADVERTISE_IPS at 11pm before a client demo.

If that's more than you want to take on yourself, Meetrix's pre-configured AMIs have the networking, TLS, and JVB sizing already handled, including a 500-user edition with Jibri recording built in.

Frequently Asked Questions

Is there an official Jitsi Docker image?

Yes, docker-jitsi-meet on GitHub, maintained by the Jitsi team. It's a full docker-compose stack, web, Prosody, Jicofo, and JVB as separate containers, not a single image, since Jitsi Meet itself isn't a single-process app.

What's the difference between Jitsi Docker Compose and a manual install?

Same components underneath, Prosody, Jicofo, JVB, just each one isolated in its own container instead of installed directly on the host. Docker Compose gets you a working stack faster and makes upgrades a version bump instead of an apt upgrade across four services, but you still need to understand JVB_ADVERTISE_IPS and port forwarding to get real calls working.

Does Jibri work in Docker?

Yes. docker-jitsi-meet ships a jibri.yml overlay you add to the base compose command, no separate manual Jibri install needed. It still needs the snd_aloop kernel module loaded on the host, that part doesn't move into the container.

Can I self-host Jitsi with Docker without a public IP?

Not for real multi-user calls. JVB needs to advertise a reachable address for media, set via JVB_ADVERTISE_IPS, so a fully private or CGNAT-only host will fail the moment two people join from different networks. Behind restrictive corporate firewalls, participants may also need a TURN relay even with a public IP.

How many containers does docker-jitsi-meet run?

Four in the base stack: web (nginx serving the frontend and running Coturn's little sibling for some deployments), prosody, jicofo, and jvb. Jibri and Jigasi are separate opt-in overlays, not part of the default docker compose up.

Why can't I connect to video after docker compose up finishes?

Almost always JVB_ADVERTISE_IPS, either unset or set to a private IP instead of the server's public one. The containers come up fine either way, since that's an application-layer problem, not a container health issue, so docker ps showing everything healthy doesn't mean calls will actually work.

Skip the Docker Setup Entirely

Launch a pre-configured Jitsi Meet server for up to 500 concurrent users with Jibri recording already wired up, no docker-compose.yml required.

Get Jitsi Meet 500-User with Recording