_______ ____ ____ __ __ ____ __ ______ ______ /_ __// __// __// /_/ // _ / / / / __ // ____/ / / / __// /_ / __ // _ < / /_ / /_/ // /_ / /_/ /___//___//_/ /_//____//___//_____//_____/ techblog.koponen.se [ / ] [ howto ] [ reviews ] [ webapps ] [ youtube ] [ links ] [ about ] -------------------------------------------------------------------------
techblog.koponen.se [ / ] [ howto ] [ reviews ] [ webapps ] [ youtube ] [ about ] [ links ] -------------------------------------
HOWTO
VIDEOCHAT
INSTALL JITSI SERVER WITH DOCKER COMPOSE
Published: 20221023
Tested on:
-
Preparations
These are just some quick notes on how I got it working
Required:
A 64-bit PC architecture machine, baremetal or virtual
I used a 64-bit VM with: 1 vCPU, 1GB ram, 16GB disk space
A public IPv4 address with these ports open: TCP 80, TCP 443, UDP 10000
Technically you can use other ports, but it wont be as easy to setup
A public A record (or CNAME) pointing to your public IPv4 address
In this example I will use these values:
A (or CNAME) record jitsi5.example.com pointing to public IPv4 address: 192.0.2.5
OK, let's get on with the actual installation!
Install the docker environment and docker-compose
~$ sudo apt -y install docker-compose
Download jitsi
On the jitsi account at github there's a repo for installing jitsi with docker-compose. Under the releases section you can download the latest "Source code tarball". Under the latest release, under Assets, download the file called "Source code (tar.gz)"
~$ wget https://github.com/jitsi/docker-jitsi-meet/archive/refs/tags/stable-7830.tar.gz
unpack it:
~$ tar zxvf stable-7830.tar.gz
~$ cd docker-jitsi-meet-stable-7830/
Configuring the server
As mentioned in the repo page: "The installation manual is available here"
I followed the manual and it went like this:
~/docker-jitsi-meet-stable-7830$ cp env.example .env
~/docker-jitsi-meet-stable-7830$ ./gen-passwords.sh
~/docker-jitsi-meet-stable-7830$ sudo mkdir -p /root/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri}
~/docker-jitsi-meet-stable-7830$ vi .env
Inside this .env file I made sure these values were set:
CONFIG=/root/.jitsi-meet-cfg
HTTP_PORT=80
HTTPS_PORT=443
JVB_PORT=10000
PUBLIC_URL=https://jitsi5.example.com
JVB_ADVERTISE_IPS=192.0.2.5
ENABLE_LETSENCRYPT=1
LETSENCRYPT_DOMAIN=jitsi5.example.com
LETSENCRYPT_EMAIL=webmaster@example.com
LETSENCRYPT_USE_STAGING=1
ENABLE_HTTP_REDIRECT=1
ENABLE_HSTS=1
Configuring the server: JVB_ADVERTISE_IPS
This setting was previously known as: DOCKER_HOST_ADDRESS
The value of JVB_ADVERTISE_IPS depends on how your network is setup. There are basically four network scenarios when you setup jitsi on IPv4.
Scenario A - Public IPv4 on the VM
This scenario is typical if you install jitsi on a VM in a cloud. Make sure the firewall ports are open.
You can click on this SVG picture if you want to view it closer
In this case you don't really need to set JVB_ADVERTISE_IPS:
#JVB_ADVERTISE_IPS=
If you want to have it set anyway, you can set it to the public IPv4 address of your VM:
JVB_ADVERTISE_IPS=192.0.2.5
Scenario B - Public IPv4 network and public IPv4 address on the VM
If you do have an IPv4 subnet (of public addresses), you might want other machines on your network be able to reach your jitsi server.
You can click on this SVG picture if you want to view it closer
Settings:
JVB_ADVERTISE_IPS=192.0.2.5
Scenario C - Public IPv4 on the router, jitsi server on a private RFC 1918 network
Therefore my IPv4 router needs to have these port forwards set.
I can verify that running port 80 and port 443 (by using the proxy
protocol, aka SNI routing) through HAProxy works.
192.0.2.5 TCP port 80 --port-forward--> 10.0.0.2 TCP 80
192.0.2.5 TCP port 443 --port-forward--> 10.0.0.2 TCP 443
192.0.2.5 UDP port 10000 --port-forward--> 10.0.0.2 UDP 10000
You can click on this SVG picture if you want to view it closer
Settings:
JVB_ADVERTISE_IPS=10.0.0.2
Scenario D - Public IPv4 on the router, jitsi server on a private RFC 1918 network with a Split-horizon DNS
You can click on this SVG picture if you want to view it closer
I don't really know what to say.
These kind of setups are really the deep end of IPv4 NAT.
On top of that, the official documentation isn't very clear.
Nor are the discussions around this, that you can read about here or here.
I think the idea is JVB_ADVERTISE_IPS (which now can be several IP-addresses) means that you can and should advertise both addresses:
JVB_ADVERTISE_IPS=10.0.0.2,192.0.2.5
My recommendation is that while NAT is stupid enough, try to stay away from NAT with Split-horizon DNS, because you will have a lot of problems.
Anyway... Let's continue.
Configuring the server: LETSENCRYPT_USE_STAGING=1
Let's launch the service with the settings we already have:
~/docker-jitsi-meet-stable-7830$ sudo docker-compose up -d
Creating network "docker-jitsi-meet-stable-7830_meet.jitsi" with the default driver
Pulling web (jitsi/web:stable-7830)...
stable-7830: Pulling from jitsi/web
31b3f1ad4ce1: Pull complete
6020084f933f: Pull complete
ee1eaad5280a: Pull complete
4f4fb700ef54: Pull complete
3819e3283aee: Pull complete
820d6d377523: Pull complete
c3b22928936c: Pull complete
Digest: sha256:5209d42b08c1330472a6f1af5674a44901228022a9bb95c472043db76fdc3567
Status: Downloaded newer image for jitsi/web:stable-7830
Pulling prosody (jitsi/prosody:stable-7830)...
stable-7830: Pulling from jitsi/prosody
31b3f1ad4ce1: Already exists
6020084f933f: Already exists
ee1eaad5280a: Already exists
4f4fb700ef54: Already exists
7a2424ecf957: Pull complete
0c37992c8287: Pull complete
8ec5fdfe8d5f: Pull complete
a802456bd2fb: Pull complete
Digest: sha256:5e3050d5c5e47cbb542f03cd9b8f4fd33a9b9888ffd5cec4219497a6115f2552
Status: Downloaded newer image for jitsi/prosody:stable-7830
Pulling jicofo (jitsi/jicofo:stable-7830)...
stable-7830: Pulling from jitsi/jicofo
31b3f1ad4ce1: Already exists
6020084f933f: Already exists
ee1eaad5280a: Already exists
4f4fb700ef54: Already exists
bc9d3bc2c78e: Pull complete
1a207e87fa86: Pull complete
3f43ac9e7c10: Pull complete
Digest: sha256:f108b9b23d40743e02193d880d6cb6568d09405aeac7dbac3f61f5046aa13c93
Status: Downloaded newer image for jitsi/jicofo:stable-7830
Pulling jvb (jitsi/jvb:stable-7830)...
stable-7830: Pulling from jitsi/jvb
31b3f1ad4ce1: Already exists
6020084f933f: Already exists
ee1eaad5280a: Already exists
4f4fb700ef54: Already exists
bc9d3bc2c78e: Already exists
8e8f21dd7dc4: Pull complete
2b9d1507078a: Pull complete
Digest: sha256:d30f7675eb8b7b834a48c86262816aac3c18c1c202ac26ebeb8705774feaa74d
Status: Downloaded newer image for jitsi/jvb:stable-7830
Creating docker-jitsi-meet-stable-7830_prosody_1 ... done
Creating docker-jitsi-meet-stable-7830_web_1 ... done
Creating docker-jitsi-meet-stable-7830_jvb_1 ... done
Creating docker-jitsi-meet-stable-7830_jicofo_1 ... done
~/docker-jitsi-meet-stable-7830$
Check that the containers are running:
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
08c2368c2a22 jitsi/jvb:stable-7830 "/init" About a minute ago Up About a minute 127.0.0.1:8080->8080/tcp, 0.0.0.0:10000->10000/udp, :::10000->10000/udp docker-jitsi-meet-stable-7830_jvb_1
b57cea77b093 jitsi/jicofo:stable-7830 "/init" About a minute ago Up About a minute docker-jitsi-meet-stable-7830_jicofo_1
c724c67b3bf8 jitsi/web:stable-7830 "/init" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp docker-jitsi-meet-stable-7830_web_1
fd83ef2522b2 jitsi/prosody:stable-7830 "/init" About a minute ago Up About a minute 5222/tcp, 5280/tcp, 5347/tcp docker-jitsi-meet-stable-7830_prosody_1
$
Now the service should be up and it should have a "red certificate" (meaning you have an invalid certificate).
If you look at the certificate (via a web browser) it has these values:
Issued By:
CN = (STAGING) Artificial Apricot R3
O = (STAGING) Let's Encrypt
You can also verify these values in the terminal:
$ sudo openssl x509 -in /root/.jitsi-meet-cfg/web/acme.sh/jitsi5.example.com/jitsi5.example.com.cer -text -noout
This is because we launched the service with:
LETSENCRYPT_USE_STAGING=1
When you're using Let's Encrypt, it's always good practise to start with the Staging Environment.
There are many things that could go wrong (you could even be unlucky and run a bad release of Jitsi) and you don't want to get rate limited for trying too many times, so you'd have to wait until you could deploy again.
However, now when things are running smoothly, you can just disable the staging environment and redeploy.
First, undeploy the containers:
~/docker-jitsi-meet-stable-7830$ sudo docker-compose down
Stopping docker-jitsi-meet-stable-7830_jvb_1 ... done
Stopping docker-jitsi-meet-stable-7830_jicofo_1 ... done
Stopping docker-jitsi-meet-stable-7830_web_1 ... done
Stopping docker-jitsi-meet-stable-7830_prosody_1 ... done
Removing docker-jitsi-meet-stable-7830_jvb_1 ... done
Removing docker-jitsi-meet-stable-7830_jicofo_1 ... done
Removing docker-jitsi-meet-stable-7830_web_1 ... done
Removing docker-jitsi-meet-stable-7830_prosody_1 ... done
Removing network docker-jitsi-meet-stable-7830_meet.jitsi
~/docker-jitsi-meet-stable-7830$
Secondly, edit ~/docker-jitsi-meet-stable-7830/.env and make sure this row is commented:
#LETSENCRYPT_USE_STAGING=1
Thirdly, delete the old (staging environment) certificate files or the next time you deploy the containers, they will prevent the containers to ask for new ones (since they're not outdated yet).
$ sudo rm -rf /root/.jitsi-meet-cfg
Lastly, don't forget to recreate the required directories:
$ sudo mkdir -p /root/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri}
Now, redeploy:
~/docker-jitsi-meet-stable-7830$ sudo docker-compose up -d
Creating network "docker-jitsi-meet-stable-7830_meet.jitsi" with the default driver
Creating docker-jitsi-meet-stable-7830_web_1 ... done
Creating docker-jitsi-meet-stable-7830_prosody_1 ... done
Creating docker-jitsi-meet-stable-7830_jicofo_1 ... done
Creating docker-jitsi-meet-stable-7830_jvb_1 ... done
~/docker-jitsi-meet-stable-7830$
And if all goes well, that's it. Jitsi is installed!
If you run into troubles...
There are many things that can go wrong, but the two most commons problems I run into are either: rate limiting or jitsi is starting to get buggy.
Rate limiting - jitsi wont start
I'm often tempted to set:
RESTART_POLICY=unless-stopped
This setting isn't wrong but it can cause a lot of problems.
The idea is that if the containers are having some kind of trouble starting, they will just restart themselves, about once a minute.
If the "web container" is the one restarting and is having troubles with the certificate signing request, it can within minutes hit the Let's Encrypt rate limits and then there's nothing you can do but shutdown the container and wait.
So the good idea is to disable this setting:
#RESTART_POLICY=unless-stopped
at least until things are stable and everything is setup against the staging environment. Even when I've done this a couple of times and feel that I know how jitsi works and could skip the staging evinronment, that is usually when I miss something.
It happened when I wrote this article. But it wasn't obvious at first.
The web container was restarting, so I started tracking the docker logs:
Find out the docker container id:
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ac52a8511e05 jitsi/web:stable-7882 "/init" 22 seconds ago Up 21 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp docker-jitsi-meet-stable-7882_web_1
8f8de7c103ff jitsi/jicofo:stable-7882 "/init" 15 minutes ago Up 15 minutes docker-jitsi-meet-stable-7882_jicofo_1
d75ee6f262f1 jitsi/jvb:stable-7882 "/init" 15 minutes ago Up 15 minutes 127.0.0.1:8080->8080/tcp, 0.0.0.0:10000->10000/udp, :::10000->10000/udp docker-jitsi-meet-stable-7882_jvb_1
8cd8f2d2cfba jitsi/prosody:stable-7882 "/init" 15 minutes ago Up 15 minutes 5222/tcp, 5280/tcp, 5347/tcp docker-jitsi-meet-stable-7882_prosody_1
$
Read the logs of the container that has troubles: ac52a8511e05
$ sudo docker logs ac52a8511e05 -f
[s6-init] making user provided files available at /var/run/s6/etc...exited 0.
[s6-init] ensuring user provided files have correct perms...exited 0.
[fix-attrs.d] applying ownership & permissions fixes...
[fix-attrs.d] done.
[cont-init.d] executing container initialization scripts...
[cont-init.d] 01-set-timezone: executing...
[cont-init.d] 01-set-timezone: exited 0.
[cont-init.d] 10-config: executing...
/opt /
[Sat Oct 22 22:22:47 UTC 2022] Installing to /config/acme.sh
[Sat Oct 22 22:22:47 UTC 2022] Installed to /config/acme.sh/acme.sh
[Sat Oct 22 22:22:47 UTC 2022] Installing alias to '/root/.profile'
[Sat Oct 22 22:22:47 UTC 2022] OK, Close and reopen your terminal to start using acme.sh
[Sat Oct 22 22:22:47 UTC 2022] Installing cron job
no crontab for root
no crontab for root
[Sat Oct 22 22:22:47 UTC 2022] Good, bash is found, so change the shebang to use bash as preferred.
[Sat Oct 22 22:22:47 UTC 2022] OK
/
[Sat Oct 22 22:22:49 UTC 2022] Using CA: https://acme-v02.api.letsencrypt.org/directory
[Sat Oct 22 22:22:49 UTC 2022] Run pre hook:'if [[ -d /var/run/s6/services/nginx ]]; then s6-svc -d /var/run/s6/services/nginx; fi'
[Sat Oct 22 22:22:50 UTC 2022] Standalone mode.
[Sat Oct 22 22:22:50 UTC 2022] Create account key ok.
[Sat Oct 22 22:22:50 UTC 2022] Registering account: https://acme-v02.api.letsencrypt.org/directory
[Sat Oct 22 22:22:52 UTC 2022] Registered
[Sat Oct 22 22:22:52 UTC 2022] ACCOUNT_THUMBPRINT='PqWbqYUoy4QRiQZM5lI1tp7ToZmvcFORhR3VZZAEuPQ'
[Sat Oct 22 22:22:52 UTC 2022] Creating domain key
[Sat Oct 22 22:22:53 UTC 2022] The domain key is here: /config/acme.sh/jitsi5.example.com/jitsi5.example.com.key
[Sat Oct 22 22:22:53 UTC 2022] Single domain='jitsi5.example.com'
[Sat Oct 22 22:22:53 UTC 2022] Getting domain auth token for each domain
[Sat Oct 22 22:22:56 UTC 2022] Getting webroot for domain='jitsi5.example.com'
[Sat Oct 22 22:22:56 UTC 2022] Verifying: jitsi5.example.com
[Sat Oct 22 22:22:56 UTC 2022] Standalone mode server
[Sat Oct 22 22:23:01 UTC 2022] jitsi5.example.com:Verify error:During secondary validation: 192.0.2.5: Invalid response from http://jitsi5.example.com/.well-known/acme-challenge/KXixVGSQ04LgCTNa9CqB9t8gNdXAq456kbI76ezG7ug: 503
[Sat Oct 22 22:23:01 UTC 2022] Please add '--debug' or '--log' to check more details.
[Sat Oct 22 22:23:01 UTC 2022] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
[Sat Oct 22 22:23:01 UTC 2022] Run post hook:'if [[ -d /var/run/s6/services/nginx ]]; then s6-svc -u /var/run/s6/services/nginx; fi'
Failed to obtain a certificate from the Let's Encrypt CA.
Exiting.
[cont-init.d] 10-config: exited 1.
[cont-finish.d] executing container finish scripts...
[cont-finish.d] done.
[s6-finish] waiting for services.
[s6-finish] sending all processes the TERM signal.
[s6-finish] sending all processes the KILL signal and exiting.
$
So it looks like there's some kind of trouble with the nginx web server, but in reality it worked much better after a couple of hours.
I'm posting this as an example how often rate limiting is the real issue.
When the jitsi experience starts to get buggy
If you don't update your jitsi server regularly you will eventually find that it works less and less well. This is because all the web browsers have auto update, meaning that their way of parsing web code changes over the time.
When you notice video working (or not working) in weird ways...
When you notice audio is not working properly...
When you can join meetings but there are glitches...
When it works for some but not for others...
When the app works but the browser doesn't work...
Then ask yourself: When was the last time you updated the server?
So, if you use jitsi for a longer period of time, upgrading the jitsi server will become a regular task.
Updating the jitsi server
Upgrading is actually quite simple.
First, download the new release:
~$ wget https://github.com/jitsi/docker-jitsi-meet/archive/refs/tags/stable-7882.tar.gz
Secondly, take down the current containers:
~$ cd docker-jitsi-meet-stable-7830
~/docker-jitsi-meet-stable-7830$ sudo docker-compose down
Stopping docker-jitsi-meet-stable-7830_jvb_1 ... done
Stopping docker-jitsi-meet-stable-7830_jicofo_1 ... done
Stopping docker-jitsi-meet-stable-7830_prosody_1 ... done
Stopping docker-jitsi-meet-stable-7830_web_1 ... done
Removing docker-jitsi-meet-stable-7830_jvb_1 ... done
Removing docker-jitsi-meet-stable-7830_jicofo_1 ... done
Removing docker-jitsi-meet-stable-7830_prosody_1 ... done
Removing docker-jitsi-meet-stable-7830_web_1 ... done
Removing network docker-jitsi-meet-stable-7830_meet.jitsi
~/docker-jitsi-meet-stable-7830$
Copy the configuration to the new release:
~/docker-jitsi-meet-stable-7830$ cd
~$ tar zxvf stable-7882.tar.gz
~$ cp docker-jitsi-meet-stable-7830/.env docker-jitsi-meet-stable-7882/
~$ cd docker-jitsi-meet-stable-7882
Deploy the new release:
~/docker-jitsi-meet-stable-7882$ sudo docker-compose up -d
Creating network "docker-jitsi-meet-stable-7882_meet.jitsi" with the default driver
Pulling web (jitsi/web:stable-7882)...
stable-7882: Pulling from jitsi/web
bd159e379b3b: Pull complete
41b5f31c8065: Pull complete
8582d050995d: Pull complete
4f4fb700ef54: Pull complete
1130e8313dbf: Pull complete
63dd5eda0e26: Pull complete
bd645286c2d9: Pull complete
Digest: sha256:7f755b130d95d48f8ea1568ba9848e9c9574ae89b73170b869b73697b5f70b48
Status: Downloaded newer image for jitsi/web:stable-7882
Pulling prosody (jitsi/prosody:stable-7882)...
stable-7882: Pulling from jitsi/prosody
bd159e379b3b: Already exists
41b5f31c8065: Already exists
8582d050995d: Already exists
4f4fb700ef54: Already exists
1a800766f078: Pull complete
a8dba1d9ad1e: Pull complete
156ba1c18fd5: Pull complete
b4c7f5a50d7d: Pull complete
Digest: sha256:df473674f47c45b97f1e3063a613e9a8ca1e143b5456f7268594aadae6066689
Status: Downloaded newer image for jitsi/prosody:stable-7882
Pulling jicofo (jitsi/jicofo:stable-7882)...
stable-7882: Pulling from jitsi/jicofo
bd159e379b3b: Already exists
41b5f31c8065: Already exists
8582d050995d: Already exists
4f4fb700ef54: Already exists
909201c50280: Pull complete
28d3f309146c: Pull complete
9129d06cfa66: Pull complete
Digest: sha256:b9324e367c601b58dfe90dfdeba77fbd065ae36a583d351aae8d1668fa650e0a
Status: Downloaded newer image for jitsi/jicofo:stable-7882
Pulling jvb (jitsi/jvb:stable-7882)...
stable-7882: Pulling from jitsi/jvb
bd159e379b3b: Already exists
41b5f31c8065: Already exists
8582d050995d: Already exists
4f4fb700ef54: Already exists
909201c50280: Already exists
1d42c90453ff: Pull complete
890370b0ccb8: Pull complete
Digest: sha256:97582ef359bd82b40c8d4d9eb71f5eed8ed7926a35fd19c3420213531a260ecb
Status: Downloaded newer image for jitsi/jvb:stable-7882
Creating docker-jitsi-meet-stable-7882_prosody_1 ... done
Creating docker-jitsi-meet-stable-7882_web_1 ... done
Creating docker-jitsi-meet-stable-7882_jicofo_1 ... done
Creating docker-jitsi-meet-stable-7882_jvb_1 ... done
~/docker-jitsi-meet-stable-7830$
That's it!
However...
If you find yourself with a non-working jitsi service, it could very well be that the latest release has bugs. It happens every now and then.
You can usually find information about this on the github issues page.
The solution then is usually to just run the second latest release.
Jitsi, IPv6 problems and the woes of IPv4 NAT
Yeah, I need to tell you something about JVB_ADVERTISE_IPS and IPv4 NAT...
I do understand that writing a HOWTO in 2022 which not only implies an IPv4-only install but also includes "port forwarding" is quite disturbing. Let me explain myself. Now and then the jitsi and/or ubuntu distribution of the docker environment has had problems with IPv6, breaking jitsi for dual stack users. It was a while ago I had these problems, so the dual stack and/or IPv6-only setups might be more stable now, I don't know, I haven't tried in a while. The reason for sticking to IPv4 is not because IPv4 is a good idea, but because the jitsi developers have historically kept the IPv4 support much more stable than the IPv6 support. If you set this up dual stack just be prepared that a regular "apt update/upgrade" or an update of the docker-compose can break this and the only solution is to remove the AAAA record and wait for the settings to take globally. I'm not making this up, it happened to me. So by writing a tutorial aimed for IPv4, I at least know it'll work for us who still have access to the IPv4 Internet...