[{"data":1,"prerenderedAt":151},["ShallowReactive",2],{"seo-verification":3,"blog-host-jitsi-on-your-own-vps-ma-en":6,"promo-bar-likely":150},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-host-jitsi-on-your-own-vps-ma-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"noindex":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":30,"intro":33,"sections":34,"ctaTitle":90,"ctaBody":91,"ctaButton":92,"ctaUrl":93,"relatedPosts":94},78,"host-jitsi-on-your-own-vps",{"fr":12,"en":10,"ar":13,"es":14},"heberger-jitsi","استضافة-jitsi-على-خادم-vps-الخاص-بك","alojar-jitsi-meet-en-un-vps","Host Jitsi on your own VPS","Deploy Jitsi Meet on your VPS with Docker, coturn TURN server and SSL. Full guide: .env config, troubleshooting ICE failed, missing audio and screen sharing.",11,3,false,"2026-04-03T00:00:00+00:00","2026-11-08T01:13:14+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},7,"Self-hosting","self-hosting","bg-indigo-500\u002F10 text-indigo-400","cloud",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fheberger-jitsi-poster.svg","Jitsi Meet is an open source video conferencing solution that works directly in the browser, with no installation on the participant's side. Self-hosting it on a VPS gives you as many rooms as you need, with no time limit and no data collection. The deployment itself is quick — configuring the TURN server (coturn) is what causes most installations to fail: without it, video works on a local network but stops as soon as a participant is behind a corporate NAT or a carrier-grade NAT provider. This guide covers the full installation, advanced coturn configuration, video bridge monitoring, and troubleshooting of the most common errors.",[35,39,49,52,74,77,81,84,87],{"type":36,"title":37,"body":38},"h2","Jitsi self-hosted vs Zoom: what actually changes","Consumer video conferencing services (Zoom, Google Meet, Teams) impose time limits on free plans, participant quotas, and keep your recordings on their servers. Self-hosted Jitsi Meet removes these constraints: rooms with no cap on participants, no meeting time limit, no account required to join a meeting, and video streams that stay on your infrastructure. This is particularly relevant for an organization concerned about the confidentiality of its meetings, a firm handling sensitive data, or anyone who wants to embed video calling in a third-party application (Jitsi provides a stable **iframe API**). Running costs come down to the VPS bill — no per-seat subscription, no software surcharge.",{"type":40,"title":41,"items":42},"ul","Concrete benefits of self-hosted Jitsi",[43,44,45,46,47,48],"Meetings with no time limit and no cap on the number of rooms — no timer cutting the call.","No account required for participants: a link is enough to join.","iframe API to embed video calling directly in your application or website.","Transport encryption (DTLS-SRTP) and full control over any recordings.","Complete customization: logo, colors, room domain name.","No telemetry sent to a third party — video streams never leave your VPS.",{"type":36,"title":50,"body":51},"Concrete prerequisites before you start","Jitsi is sized by **bandwidth**, not CPU. The Jitsi documentation recommends **8 GB of RAM** (4 GB is enough for small meetings), around 4 dedicated cores for a basic server, and above all a reliable network link: a 720p stream uses about 2.5 Mbit\u002Fs, and a 100 Mbit\u002Fs link will not carry twenty participants in high definition. Monitor JVB network load. Three ports must be reachable from the internet: **TCP 443** (HTTPS), **TCP 80** (Let's Encrypt challenge and redirect to HTTPS), **UDP 10000** (JVB media). TCP port 4443, mentioned in older guides, is no longer on the official list. If coturn runs on the same VPS, add its ports: **3478** over UDP and TCP, **5349** for TLS (443 is already taken by the web container). You need Docker with Compose V2 (the `docker compose` command), a domain name `meet.yourdomain.com` with an A record pointing to the VPS public IP, and a **dedicated, stable public IP** — a shared IP makes coturn configuration significantly harder.",{"type":53,"title":54,"steps":55},"steps","Step-by-step deployment: Docker, .env, coturn and first test",[56,59,62,65,68,71],{"title":57,"body":58},"Fetch docker-jitsi-meet","Download the latest release from the releases page of `github.com\u002Fjitsi\u002Fdocker-jitsi-meet` and unzip it: the official guide advises against cloning the repository, whose main branch pulls the `unstable` images. Create the configuration folders listed in the guide (`~\u002F.jitsi-meet-cfg\u002F…`, including `storage` and `tmp`, writable by uid 1000): the containers run rootless and refuse to start otherwise. Copy `env.example` to `.env`, then run `.\u002Fgen-passwords.sh` — this script generates all internal secrets (Prosody, Jicofo, JVB). Do not skip this step: default values are not secrets. The `stable-11248-3` release (November 2026) is the latest stable; avoid `master` and the `unstable` images in production — internal components change without notice.",{"title":60,"body":61},"Set PUBLIC_URL, the ports and JVB_ADVERTISE_IPS","In `.env`, first set `HTTP_PORT=80` and `HTTPS_PORT=443` (8000 and 8443 by default). Two variables are then critical: `PUBLIC_URL=https:\u002F\u002Fmeet.yourdomain.com` (used by the web client to build room URLs) and `JVB_ADVERTISE_IPS=\u003CVPS_PUBLIC_IP>` (the address JVB announces to clients to establish the direct media connection; it replaces the former `DOCKER_HOST_ADDRESS`). Without `JVB_ADVERTISE_IPS`, JVB tries to discover its public IP via STUN; if the announced address is wrong, calls fail as soon as more than two participants join the meeting.",{"title":63,"body":64},"Enable Let's Encrypt in .env","Add to `.env`: `ENABLE_LETSENCRYPT=1`, `LETSENCRYPT_DOMAIN=meet.yourdomain.com`, `LETSENCRYPT_EMAIL=admin@yourdomain.com`. Verify that port 80 is open before starting — Let's Encrypt uses an HTTP-01 challenge that requires a response on that port. The web container obtains and renews the certificate with acme.sh (an internal renewal service) and keeps it in `~\u002F.jitsi-meet-cfg\u002Fstorage\u002Fweb`: keep that folder across restarts. Also add `LETSENCRYPT_ACME_SERVER=letsencrypt`: without it, acme.sh uses ZeroSSL by default.",{"title":66,"body":67},"Configure coturn (TURN server)","This is the step most guides skim over and that causes installations to fail. docker-jitsi-meet does not ship coturn: install it separately (package or container), then declare it in `.env` so that Prosody hands clients temporary credentials: `TURNS_HOST=turn.yourdomain.com` and `TURNS_PORT` for TLS, plus `TURN_HOST=turn.yourdomain.com`, `TURN_PORT=3478` and `TURN_TRANSPORT=udp,tcp`. Port 443 over TLS crosses the most restrictive firewalls, which block non-standard ports but let through anything resembling HTTPS; it needs an IP the web container does not already use, otherwise keep 5349.\n\nThen generate a shared secret (`openssl rand -hex 32`) and put it in `TURN_CREDENTIALS` in `.env` and in coturn (`use-auth-secret` and `static-auth-secret=\u003Cthe same secret>`); never `no-auth`, which would turn your server into a relay open to anyone. The TLS certificate is declared in the coturn configuration (`cert=` and `pkey=`), not in `.env`. If coturn runs in a separate container, mount these files as volumes.\n\nOne often-missed detail: coturn does not block RFC1918 ranges (192.168.x.x, 10.x.x.x, 172.16.x.x) by default: only loopback is refused. An authenticated client can therefore relay traffic into your internal network. Add `no-multicast-peers` and `denied-peer-ip` lines for those ranges, then, if JVB has an internal address, allow only that one with `allowed-peer-ip`.",{"title":69,"body":70},"Start the stack and check the JVB","Run `docker compose up -d`. Wait 30 seconds, then: `docker compose logs jvb 2>&1 | grep -E 'register|connected|error'`. You should see a line showing that JVB registered with Jicofo. If you see `Failed to register` or `Connection refused`, Prosody is not ready yet — retry after a minute. Then verify the ports respond: `nc -zv meet.yourdomain.com 443` (web, TCP), `nc -zv turn.yourdomain.com 3478` (coturn, TCP) and `nc -zvu meet.yourdomain.com 10000` (JVB, UDP; a UDP success is only indicative).",{"title":72,"body":73},"First video test from two different networks","Open `https:\u002F\u002Fmeet.yourdomain.com` from your usual machine and a second device on a different network (a phone on mobile data, for example). If both participants see and hear each other, TURN is working. A test between two machines on the same local network **does not validate coturn** — it succeeds peer-to-peer without ever using the relay.",{"type":36,"title":75,"body":76},"Advanced configuration: recording, authentication and limits","**Meeting recording.** Jitsi includes Jibri for local recording or RTMP streaming. Jibri captures a browser render in real time: one instance records only one meeting at a time, and the Jitsi documentation asks for at least 8 GB of RAM per instance at 720p, preferably on a separate server. Enable `ENABLE_RECORDING=1` in `.env` and start the bundled Jibri container: `docker compose -f docker-compose.yml -f jibri.yml up -d`. **Organizer authentication.** By default, anyone can create a room: a public instance left that way becomes free video calling for strangers, on your bandwidth. Enable `ENABLE_AUTH=1`, `AUTH_TYPE=internal` and `ENABLE_GUESTS=1` to require an account on the organizer's side while letting guests join freely. Create host accounts with `docker compose exec prosody prosodyctl --config \u002Frun\u002Fprosody\u002Fconfig\u002Fprosody.cfg.lua register admin meet.jitsi \u003Cpassword>`: `meet.jitsi` is the internal XMPP domain, not your public name, and the password should be generated (`openssl rand -base64 18`) rather than reused. **Limiting anonymous participants.** `ENABLE_LOBBY=1` makes the lobby available: once the moderator turns it on, each entry must be approved before accessing the room. Combined with `ENABLE_AUTH=1`, this gives full control over who accesses what.",{"type":78,"title":79,"body":80},"tip","Hardening: fail2ban on the TURN service","coturn exposes a service reachable from the internet. Install fail2ban and create a filter on failed TURN authentication attempts: failures show up in the coturn log with a 401 code; check the exact format of your version before writing the filter regex. A fail2ban jail with `maxretry=10` and `bantime=600` is enough to deter automated scans without affecting your legitimate users. Pin the log with `log-file=\u002Fvar\u002Flog\u002Fturnserver.log` in the coturn configuration (without this option, coturn picks a file itself in \u002Fvar\u002Flog, \u002Fvar\u002Ftmp or \u002Ftmp), have fail2ban watch that path, or mount that file from the container.",{"type":36,"title":82,"body":83},"Troubleshooting: the four most common errors","**Missing audio or video stuck on 'connecting' — coturn + UDP 10000.** This is the most frequent failure. Check in this order: (1) `ufw status` — are TCP 443 and UDP 10000 open? (2) the coturn logs (`journalctl -u coturn` when native, `docker logs \u003Ccoturn-container>` otherwise) — does coturn start without certificate errors? (3) From an external machine: `curl -v telnet:\u002F\u002Fmeet.yourdomain.com:3478` — does coturn respond? (4) In browser logs (F12 → Console): do you see `ICE failed` or `failed to gather candidates`? If so, coturn is not reachable from outside. Check that `TURN_HOST` and `TURNS_HOST` in `.env` resolve to the actual IP of the coturn server. **Connection refused on TCP 443.** If Let's Encrypt could not issue a certificate (port 80 was closed on first start), the web container stops after the message `Failed to obtain a certificate from the Let's Encrypt CA` and nothing answers on 443 any more. Fix: open port 80, check `HTTP_PORT=80` and re-run `docker compose up -d`; there is no need to delete the configuration, and every new attempt counts against Let's Encrypt's limits. **Screen sharing refused by the browser.** Screen sharing requires a secure context (valid HTTPS). If you see `getUserMedia is not supported`, the certificate is invalid or the domain is not on HTTPS. Check `PUBLIC_URL` — it must start with `https:\u002F\u002F` with a domain whose certificate is valid, not a raw IP. **Persistent 'ICE failed' error despite a working coturn.** Check the `JVB_ADVERTISE_IPS` variable (formerly `DOCKER_HOST_ADDRESS`): it must contain the VPS public IP, not the internal Docker container IP (172.17.x.x). If your VPS sits behind cloud NAT (rare but possible), you need the external NAT IP, not the network interface IP.",{"type":36,"title":85,"body":86},"Monitoring: tracking bandwidth and participants","The JVB video bridge exposes a real-time statistics API at `http:\u002F\u002Flocalhost:8080\u002Fcolibri\u002Fstats`. This JSON endpoint reports the number of active conferences, participants, inbound and outbound bandwidth in kbit\u002Fs, and the average RTT (`rtt_aggregate`). Port 8080 is only published on `127.0.0.1`: keep it that way. For continuous monitoring, JVB already exposes its metrics in Prometheus format at `\u002Fmetrics` (same private port); on the Prosody side, enable `PROSODY_ENABLE_METRICS=1` in `.env`. Then connect a Prometheus + Grafana stack: the repository ships `prometheus.yml` and `grafana.yml`, which publish ports 9090 and 3000 on all interfaces. Restrict them to `127.0.0.1` or a VPN, because ports published by Docker bypass ufw rules.\n\nWithout Prometheus, minimal monitoring is achieved with a cron that queries `\u002Fcolibri\u002Fstats` and alerts when throughput exceeds a threshold: `curl -s http:\u002F\u002F127.0.0.1:8080\u002Fcolibri\u002Fstats | python3 -c \"import json,sys; s=json.load(sys.stdin); print(s.get('bit_rate_download',0), s.get('bit_rate_upload',0))\"`.\n\nTo estimate capacity before saturation: a JVB's capacity depends first on the network link and the resolutions being sent; measure it on your own load rather than relying on a generic figure. As the limit approaches, `rtt_aggregate` climbs and perceived quality drops before the CPU saturates — that is the signal to add another JVB instance.",{"type":36,"title":88,"body":89},"Your Jitsi is running — manage bandwidth","Jitsi runs in SFU mode: the video bridge (JVB) relays each stream to each participant, so outbound bandwidth scales with the number of participants multiplied by the number of streams. A 720p stream weighs about 2.5 Mbit\u002Fs according to the Jitsi documentation: multiply by the number of streams actually sent to each participant to estimate outbound throughput. Set `channelLastN: 5` in `custom-config.js` (the `web` folder of the configuration) to receive only the last N active videos to cap client-side streams in large meetings, and watch `docker stats jvb` to anticipate saturation. Above about twenty regular simultaneous participants, deploy several JVB instances on separate VPSes behind a single Jicofo: that is Jitsi's native horizontal scaling architecture. For multi-organization or multi-domain deployments, keep in mind that a docker-jitsi-meet installation has a single `PUBLIC_URL`: if each organization needs its own accounts and an isolated room namespace, plan one instance per organization, on its own subdomain.","Launch your Jitsi server on a ServOrbit Cloud VPS","A Cloud VPS with a dedicated public IP, generous bandwidth and root access lets you deploy Jitsi Meet, coturn and Jibri with no meeting limit. Your video calls stay on your infrastructure.","Launch my Cloud VPS","\u002Fvps-cloud",[95,114,132],{"id":96,"slug":97,"slugs":98,"title":102,"excerpt":103,"readTime":104,"views":105,"isPinned":19,"noindex":19,"publishedAt":106,"updatedAt":107,"category":108,"categories":109,"featuredImage":30,"bgImage":31,"posterImage":111,"relatedSolution":112},71,"hosting-nextcloud-on-your-own-vps",{"fr":99,"en":97,"ar":100,"es":101},"heberger-nextcloud","استضافة-nextcloud-على-خادمك-الـvps-الخاص","alojar-nextcloud-en-su-propio-vps","Self-Host Nextcloud on VPS: NC 35, PHP 8.3 and MariaDB 11 Guide","Host Nextcloud on a VPS: Docker Compose, Redis, MariaDB backup, uploads over 40 GB behind Cloudflare and an alternative to Office 2021.",20,1,"2026-04-10T00:00:00+00:00","2026-11-08T16:32:50+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[110],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fheberger-nextcloud-poster.svg",{"categorySlug":25,"appSlug":113},"nextcloud",{"id":115,"slug":116,"slugs":117,"title":121,"excerpt":122,"readTime":123,"views":105,"isPinned":19,"noindex":19,"publishedAt":124,"updatedAt":125,"category":126,"categories":127,"featuredImage":30,"bgImage":31,"posterImage":129,"relatedSolution":130},72,"hosting-ghost-on-your-own-vps",{"fr":118,"en":116,"ar":119,"es":120},"heberger-ghost","استضافة-ghost-على-خادمك-الـvps-الخاص","alojar-ghost-en-un-vps","Hosting Ghost on your own VPS: complete 2026 guide","Deploy Ghost v6 on your VPS with Caddy, MySQL, Ghost CLI and Stripe Tax: installation, TLS reverse proxy, updates and troubleshooting common startup errors.",10,"2026-04-09T00:00:00+00:00","2026-11-04T16:30:25+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[128],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fheberger-ghost-poster.svg",{"categorySlug":25,"appSlug":131},"ghost",{"id":133,"slug":134,"slugs":135,"title":139,"excerpt":140,"readTime":23,"views":141,"isPinned":19,"noindex":19,"publishedAt":142,"updatedAt":143,"category":144,"categories":145,"featuredImage":30,"bgImage":31,"posterImage":147,"relatedSolution":148},73,"host-wordpress-on-your-own-vps",{"fr":136,"en":134,"ar":137,"es":138},"heberger-wordpress","استضافة-wordpress-على-خادم-vps-الخاص-بك","alojar-wordpress-en-un-vps","Host WordPress on your own VPS","Host WordPress on your VPS for maximum performance and control: Docker, MariaDB, caching, reverse proxy and SSL.",0,"2026-04-08T00:00:00+00:00","2026-11-09T20:55:18+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[146],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fheberger-wordpress-poster.svg",{"categorySlug":25,"appSlug":149},"wordpress",true,1794270412758]