Who this is for
You run Jitsi Meet with docker-jitsi-meet on stable-11031 or older and want to move to stable-11146 or newer. You want the same rooms, accounts, branding, certificate and recordings afterwards, plus a quick way back if something breaks. The latest release on 2026-10-05 is stable-11248 (2026-09-14).
How it works
stable-11146 was a large hardening release. A maintainer described it as one of the largest changes in the project’s lifetime. The parts that matter for an upgrade:
- Unprivileged user. Every service runs as user
s6with uid/gid 1000 and no Linux capabilities. Any host folder a container writes to must be writable by uid 1000. - Read-only root filesystem. Only
/runand/tmpare writable, astmpfsmounts./configis now input only. Each service renders its real config into/run/<service>/configat every start, so generated files such asconfig.jsno longer appear in${CONFIG}/web. - New storage and tmp folders. Persistent state moves to
${CONFIG}/storage/{jibri,prosody,transcripts,web}, and regenerable files to${CONFIG}/tmp. Prosody data and web TLS files are copied over on first start. Old folders are left untouched. - Ports 8000 and 8443 inside the web container.
HTTP_PORTandHTTPS_PORTstill set the host ports. The container side is fixed at 8000 and 8443. - Debian Trixie base. Images moved from Bookworm to Trixie, and Java images from OpenJDK 17 to 21.
- GHCR registry. Images are published only at
ghcr.io/jitsi. Docker Hubjitsi/*stopped at stable-11031. - Colibri websockets removed. The
/colibri-ws/proxy, the JVB websocket server on port 9090 and their variables are gone. SCTP data channels are always on.
Containers check that each storage folder is writable and refuse to start with a FATAL ERROR message if it is not.
Before you start
- Shell access to the Docker host, with Docker Compose v2 (
docker compose). - The value of
CONFIGin your.env. The handbook default is~/.jitsi-meet-cfg. The commands below use that path, so change it if yours is different. - A maintenance window. All containers are recreated.
- Free disk space for a backup of
CONFIG(recordings can be large). - Host ports do not change: whatever
HTTP_PORTandHTTPS_PORTsay (defaults 8000 and 8443), plus 10000/udp for media. - If you use Let’s Encrypt, DNS for meet.example.com must still point to 203.0.113.10, so a new certificate can be issued if needed.
Steps
Docker (docker-jitsi-meet)
Applies when moving from stable-11031 or older to stable-11146 or newer. The commands use the stable-11248 files.
-
Record what runs now. From your docker-jitsi-meet folder:
Terminaldocker compose images grep -E '^(CONFIG|JITSI_IMAGE_VERSION|JITSI_IMAGE_REPO|HTTP_PORT|HTTPS_PORT)=' .env -
Stop and back up. Old containers ran as root, so some files are root-owned. Use
sudo:Terminaldocker compose down sudo tar czf ~/jitsi-files-stable-11031.tgz .env *.yml sudo tar czf ~/jitsi-config-stable-11031.tgz -C ~ .jitsi-meet-cfgOn a cloud server, a disk snapshot is better still. Add
-f jibri.ymland your other overlays to everydocker composecommand if you use them. -
Download the new release files. Compose files and image tags must come from the same release:
TerminalNEW=stable-11248 BASE=https://raw.githubusercontent.com/jitsi/docker-jitsi-meet/$NEW curl -fsSLO $BASE/docker-compose.yml curl -fsSL -o env.example.new $BASE/env.example # only the overlays you use: curl -fsSLO $BASE/jibri.yml curl -fsSLO $BASE/jigasi.yml curl -fsSLO $BASE/transcriber.ymlThe handbook alternative is to download the latest release archive and unzip it over your folder. If you changed
docker-compose.ymlyourself, copy those changes into the new file by hand. -
Create the new folders and make them writable by uid 1000. These are the handbook commands for upgrades from releases older than stable-11146:
Terminalmkdir -p ~/.jitsi-meet-cfg/storage/{jibri,prosody,transcripts,web} mkdir -p ~/.jitsi-meet-cfg/tmp/{web-crontabs,web-load-test} chmod 777 ~/.jitsi-meet-cfg/storage/{jibri,prosody,transcripts,web} chmod 777 ~/.jitsi-meet-cfg/tmp/{web-crontabs,web-load-test}A tighter option is ownership instead of mode 777:
Terminalsudo chown -R 1000:1000 ~/.jitsi-meet-cfg/storage ~/.jitsi-meet-cfg/tmpWhen you can skip it: the handbook says the
chmodstep is not needed on Docker Desktop for Windows. The start check does a real write test, so folders already owned by uid 1000 also pass. Create the folders yourself either way: if Docker creates a missing bind mount source, it is owned by root and the container cannot write to it.tmp/web-crontabsis no longer mounted from stable-11146-2 on, because cron was replaced by anacme-renewalservice. Creating it does no harm. -
Update
.env. Compare the variable names:Terminaldiff <(grep -oE '^#?[A-Z_]+=' env.example.new | tr -d '#' | sort -u) \ <(grep -oE '^[A-Z_]+=' .env | sort -u)Then:
- Remove or comment out
JITSI_IMAGE_VERSIONso the compose file picks the tag. A maintainer gave this advice in issue #2336. A leftoverJITSI_IMAGE_VERSION=stable-11031makes the new compose file look forghcr.io/jitsi/web:stable-11031, which does not exist (manifest unknown). - Leave
JITSI_IMAGE_REPOunset. It defaults toghcr.io/jitsi. - Delete the removed colibri and SCTP variables (see the table below). They are ignored now.
- Remove or comment out
-
Fix your reverse proxy, if you have one. Point it at the host port (
HTTP_PORT, default 8000), or at container port 8000, never container port 80. Remove any/colibri-ws/and/colibri-relay-ws/locations and any proxy to JVB port 9090. Keep the/xmpp-websocketproxy. -
Pull and start:
Terminaldocker compose pull docker compose up -d docker compose ps -
Move optional data yourself. Recordings, Jibri logs and transcripts are not migrated automatically:
Terminalsudo cp -a ~/.jitsi-meet-cfg/jibri/recordings ~/.jitsi-meet-cfg/storage/jibri/ sudo cp -a ~/.jitsi-meet-cfg/transcripts/. ~/.jitsi-meet-cfg/storage/transcripts/ sudo chown -R 1000:1000 ~/.jitsi-meet-cfg/storage -
Update your admin habits. Create users with the explicit config path:
Terminaldocker compose exec prosody prosodyctl --config /run/prosody/config/prosody.cfg.lua register alice meet.jitsi CHANGE_MEBranding stays in
${CONFIG}/web/custom-config.jsandcustom-interface_config.js. Editing a generatedconfig.json the host has no effect.
Rollback (Docker)
stable-11031 images are still on Docker Hub as jitsi/<service>:stable-11031, and the old compose file pulls from there.
docker compose down
sudo tar xzf ~/jitsi-files-stable-11031.tgz
sudo tar xzf ~/jitsi-config-stable-11031.tgz -C ~
docker compose up -dRun it from your docker-jitsi-meet folder, so .env and the old compose files are restored there. The new storage and tmp folders stay behind and the old images ignore them. Old Prosody data in prosody/config/data was only copied, not moved, so accounts made before the upgrade are still there. Accounts created after the upgrade are lost.
Debian/Ubuntu packages
The rootless change, port change, Trixie base and GHCR move apply only to Docker images. Package installs follow the jitsi-meet releases (2.0.11248 is the counterpart of stable-11248). Supported systems are Debian 12 or newer and Ubuntu 24.04 or newer. Snapshot the server, then:
sudo apt update
sudo apt upgradeIn the package nginx example, the colibri websocket proxy is commented out by default. Remove it only if you turned it on yourself.
Configuration reference
| Name | Where | Default | What it does |
|---|---|---|---|
CONFIG |
.env |
~/.jitsi-meet-cfg (handbook) |
Host folder for config, storage and tmp |
JITSI_IMAGE_REPO |
.env (new) |
ghcr.io/jitsi |
Registry and namespace for images |
JITSI_IMAGE_VERSION |
.env |
tag set in compose file | Image tag. Leave unset after upgrading |
HTTP_PORT / HTTPS_PORT |
.env |
8000 / 8443 |
Host ports only. The container uses 8000/8443 |
JIBRI_RECORDING_DIR |
.env |
now /storage/recordings |
Recordings now under ${CONFIG}/storage/jibri |
ENABLE_COLIBRI_WEBSOCKET, ENABLE_COLIBRI_WEBSOCKET_UNSAFE_REGEX, COLIBRI_WEBSOCKET_PORT, COLIBRI_WEBSOCKET_REGEX, COLIBRI_WEBSOCKET_JVB_LOOKUP_NAME, DISABLE_COLIBRI_WEBSOCKET_JVB_LOOKUP, ENABLE_OCTO |
.env |
removed in 11146 | No longer honored |
ENABLE_SCTP, ENABLE_OCTO_SCTP |
.env |
removed in 11146 | SCTP is always on |
JVB_WS_DOMAIN, JVB_WS_SERVER_ID, JVB_WS_TLS |
.env |
removed in 11146 | JVB websocket server removed |
ENABLE_TRACING, TRACING_ENDPOINT, TRACING_PROTOCOL, TRACING_HTTP_ENDPOINT |
.env (new, 11248) |
unset | OpenTelemetry tracing for Jicofo, JVB, Prosody |
ENABLE_ICE_RESTART, ENABLE_ICE_RESTART_ON_NETWORK_CHANGE |
.env (new, 11248) |
unset | ICE restart behaviour |
ENABLE_AUDIO_TRANSLATION, AUDIO_TRANSLATION_DUCKED_VOLUME, JICOFO_TRANSLATION_URL_TEMPLATE, JICOFO_TRANSLATION_CF_ACCESS_CLIENT_ID, JICOFO_TRANSLATION_CF_ACCESS_CLIENT_SECRET |
.env (new) |
unset | Live audio translation |
ENABLE_ADVANCED_AUDIO_SETTINGS, ENABLE_THIRD_PARTY_REQUESTS, DISABLE_AV1_DECODE_FOR_FF, new VIDEOQUALITY_* keys |
.env (new, 11248) |
unset | Web client options |
JIBRI_CHROMEDRIVER_DEBUG, JIBRI_CHROMEDRIVER_DEBUG_LOG |
.env (new) |
unset | Jibri driver logging |
read_only, tmpfs (/run, /tmp) |
docker-compose.yml |
/run 16M web and prosody, 32M jicofo, jvb, jigasi, 256M jibri (11248) |
Read-only root, writable tmpfs |
No variable was renamed between stable-11031 and stable-11248. The changes are additions and removals.
Common mistakes
FATAL ERROR: directory '/storage' is not writable by the container user (uid 1000).(or'/var/lib/prosody'). The folder was created by Docker as root, or never made writable. Run thechmodorchownfrom step 4.manifest unknownon pull..envstill pins an old tag that GHCR never had. RemoveJITSI_IMAGE_VERSION.- Your reverse proxy can no longer reach Jitsi. It targets container port 80. Use 8000. Setting
HTTP_PORT=80does not change the container side. Prosody was unable to find the configuration file:/etc/prosody//config/prosody.cfg.lua. Add--config /run/prosody/config/prosody.cfg.luatoprosodyctl.- Branding looks ignored. Check the served file with
curl https://meet.example.com/interface_config.js. In issue #2291 the reporter fixed it by rebuilding the custom file from the current template. - Certificates never renew on 11146 or 11146-1. The web log repeats
seteuid: Operation not permitted. Upgrade to 11146-2 or newer. - Renewal fails with a 404 on
/.well-known/acme-challenge/. acme.sh state copied from the old image still uses the old port and hooks. A community workaround: stop web, movestorage/web/acme.sh,storage/web/acme-certs,web/acme.shandweb/acme-certsaside, start web so it issues a fresh certificate. Not fixed upstream as of 2026-10-05. - Nobody can join on 11146-2:
There are no operational bridges.JVB logsUnsatisfiedLinkErrorfordcsctp4j, because/runwas too small. Fixed in stable-11248 (PR #2325). Keep the 32M/runline if you maintain your own compose file. - LDAP:
could not open pid lock file: /var/run/saslauthd/saslauthd.pid.lock. Fixed in stable-11248 (PR #2312).
Verify
docker compose imagesEvery Jitsi service shows ghcr.io/jitsi/<service> with tag stable-11248.
docker compose exec web id -u
docker compose logs web | grep 'read-only root'The first prints 1000. The second contains info: read-only root.
docker compose logs | grep -E 'FATAL ERROR|no operational bridges|No stream features'No output means none of the known failure lines appeared.
If you use Let’s Encrypt:
docker compose exec web /storage/acme.sh/acme.sh --cron --home /storage/acme.sh
sudo grep Le_HTTPPort ~/.jitsi-meet-cfg/storage/web/acme.sh/meet.example.com*/meet.example.com.confA healthy cron run ends with Skip, Next renewal time is: for your domain, or with a successful renewal. Le_HTTPPort='8000' matches the port the new image uses.
Then do the post-upgrade checklist:
- Three people in one room with cameras on. Two people use peer-to-peer, so only three or more test the videobridge.
- Moderator login, if you use authentication or JWT.
- A short recording, and check it appears in
${CONFIG}/storage/jibri/recordings. - Certificate renewal, with the cron command above.
- Branding is still shown after a hard refresh.
If it still fails
docker compose logs -t -f prosody, thenjicofoandjvb. Look forFATAL ERRORlines, which name the folder at fault.jvbandjicofologNo stream features to proceed with: this is issue #2336, open as of 2026-10-05. Maintainers asked for three things: the compose file from the same release, the new folders, and noJITSI_IMAGE_VERSION=stablepin.- Check
docker compose exec web ls /run/web/configto see the rendered config, and confirm your custom files were appended. - If you run Podman or Kubernetes, check the volume ownership rules in PR #2304.
What we have not confirmed yet
We checked everything above against the handbook, release notes, pull requests, maintainer comments and the release source on 2026-10-05. We have not yet run this upgrade end to end on a test server. These points are still open:
- The handbook still lists
tmp/web-crontabs, but stable-11146-2 and later no longer mount it. Harmless, but unconfirmed whether the handbook will drop it. - Docker Desktop for macOS: the handbook only says the
chmodstep is not needed on Docker Desktop for Windows. Not confirmed for macOS. - Whether the container uid can be changed from 1000 was asked in issue #2291 and not answered.
ENABLE_VIRTUAL_BACKGROUND_V2andENABLE_MESSAGE_MODERATIONappear in the 11146 and 11248 notes and are read by the templates (both defaulttrue), but neither is listed in theenvironment:section of the stable-11248 compose files. A value set only in.envmay not reach the container. Needs a test.- The exact
docker compose pullerror text for a missing GHCR tag was not captured. The registry itself returnsmanifest unknown. - Issue #2336 (
No stream features to proceed with) has no confirmed cause yet. - The package quickstart still says “OpenJDK 17 must be used”, while Debian 13 Trixie dropped openjdk-17 and the Docker images moved to OpenJDK 21. Package installs on Debian 13 need checking.
- Whether the old-acme-state renewal problem in #2321 affects every Let’s Encrypt upgrade, or only some, is not known.
Sources
- docker-jitsi-meet release stable-11146, 2026-08-03, release note
- PR #2258 feat: Rootless containers, merged 2026-06-19, maintainer PR (backwards-incompatible changes section)
- PR #2261 refactor(web): use unprivileged ports 8000 and 8443, merged 2026-06-20, maintainer PR
- PR #2271 Migrate image publishing from DockerHub to GHCR, merged 2026-06-25, maintainer PR
- PR #2285 feat(web,jvb): remove deprecated colibri websocket support, merged 2026-07-29, maintainer PR
- PR #2257 base: update to Debian Trixie, merged 2026-06-15, maintainer PR
- docker-jitsi-meet release stable-11146-2, 2026-08-17, release note
- PR #2305 fix(web) replace cron with a rootless acme.sh renewal service, merged 2026-08-17, maintainer PR (fixes issue #2301)
- docker-jitsi-meet release stable-11248, 2026-09-14, release note
- Jitsi handbook, Self-Hosting Guide: Docker (Quick start, Updating from a release older than stable-11146, Rootless and read-only containers, Authentication, Accessing server logs), source last changed 2026-10-02, official doc
- Issue #2302 Prosody unable to find config file after updating to stable-11146-1, 2026-08-08 to 2026-08-22, maintainer comments (saghul, emrahcom)
- Issue #2291 custom-*.js files seems to be ignored in 11146, 2026-08-05, maintainer comments and user logs
- Issue #2336 jvb and jicofo crashing with XMPP error in stable-11248, opened 2026-10-01, open on 2026-10-05, maintainer comments
- Issue #2323 jitsi-videobridge2 on stable-11146-2 missing native dcsctp4j library, 2026-09-11, maintainer comments; fix PR #2325 in stable-11248
- Issue #2289 web container doesn’t seem to respect $HTTP_PORT, 2026-08-05, maintainer comment (saghul)
- Issue #2294 container images are not available on docker-hub, 2026-08-05, maintainer comments
- Issue #2321 acme.sh is not succeeding in renewing cert, 2026-09-08, community report (closed by reporter with workaround)
- docker-compose.yml, env.example, jibri.yml, jigasi.yml, transcriber.yml at tags stable-11031 and stable-11248, diffed 2026-10-05, source code
- base/rootfs/usr/bin/check-writable at stable-11248, source code
- Registry tag lists for ghcr.io/jitsi and Docker Hub jitsi/*, and https://hub.docker.com/r/jitsi/web/tags, queried 2026-10-05 (GHCR: no tags before 2026-06-25,
stabledigest equalsstable-11248,stable-11031returns MANIFEST_UNKNOWN; Docker Hub: stable-11031 present for web, prosody, jicofo, jvb, jibri, jigasi, last push 2026-06-25), registry data - Jitsi handbook, Self-Hosting Guide: Debian/Ubuntu server, official doc
- jitsi-meet doc/debian/jitsi-meet/jitsi-meet.example, source code
- PR #2304 fix(prosody) create the data folder at runtime to fix its ownership, merged 2026-08-10, maintainer PR
- jitsi-meet releases (2.0.11248, 2.0.11146, 2.0.11031), release note
- Docker docs, docker compose images, official doc (Docker)
- acme.sh source,
_savedomainconf "Le_HTTPPort", source code - web/rootfs/etc/s6-overlay/scripts/config at stable-11248 (
--httpport 8000, one-time TLS migration), source code
Need a hand?
If you would rather not do this on a production server, our support plans include upgrades done and verified for you. You can also contact our engineers with the output of docker compose logs --tail 200 prosody jicofo jvb.