Docker: curl to exposed container port which is not published to the outside (Jitsi endpoint for counting sessions)

Introduction

TL/DR:

I just wanted to figure out how many current users I have on our Jitsi instance, in the random case that I would need to restart it. Nobody is happy when their conference room disappears in the middle of a call.

docker run --rm -it --network=$(docker network list | grep jitsi | awk '{print $2}') quay.io/curl/curl prosody:5280/room-census | jq .

I found the plugin mod_muc_census.lus for the Jitsi Prosody component, which would help me do that by just issuing a curl localhost:5280/room-census. Sounds almost too easy (it was).

There is a fundamental difference between expose and publish a TCP/UDP port in a docker environment/container. Here is a good explanation of the difference: https://www.mend.io/free-developer-tools/blog/docker-expose-port/

TL/DR:

  • expose: Other containers on the same docker network may connect to an exposed port
  • publish: the docker host may connect to the published port

Hence, in my Jitsi environment, where I would like to access an exposed, but not published, port, this does not work:

docker ps

$ curl localhost:5280
curl: (7) Failed to connect to localhost port 5280 after 0 ms: Connection refused

This is expected, and I don’t really want to publish that port either, as the docker-compose.yml file comes pre-baked from the Docker Jitsi Meet project. I am happy with it as it is, and I don’t want to make any changes to it, as I do any configuration changes that I need to do in the .env file.

But, I still want to access the information through an endpoint behind that port.

Since our Jitsi is running in docker containers managed through a docker-compose.yml file, the containers will automatically connect to a docker network bridge called jitsi_meet.jitsi:

$ docker network list | grep jitsi
aa203101c7bd   jitsi_meet.jitsi   bridge    local

I can easily connect a new container to this bridge and run a command, accessing other container using the service names defined in the docker-compose.yml file:

$ docker run --rm -it --network=jitsi_meet.jitsi alpine ping prosody
PING prosody (172.23.0.2): 56 data bytes
64 bytes from 172.23.0.2: seq=0 ttl=64 time=0.194 ms
64 bytes from 172.23.0.2: seq=1 ttl=64 time=0.220 ms
64 bytes from 172.23.0.2: seq=2 ttl=64 time=0.199 ms

With that I have almost all I need to access, although the alpine container does not have the curl command. You can use wget instead:

$ docker run --rm -it --network=jitsi_meet.jitsi alpine wget -q -O - prosody:5280/room-census
{"room_census":[{"room_name":"coffeemeeting@muc.meet.jitsi","participants":1,"leaked":false,"created_time":1708950454000}]}

And if you would like to use curl anyways, there is a curl container available, and here I go a bit fancy to dynamically figuring out the network name and filtering the json output through jq .:

$ docker run --rm -it --network=$(docker network list | grep jitsi | awk '{print $2}') quay.io/curl/curl prosody:5280/room-census | jq .
{
  "room_census": [
    {
      "room_name": "coffeemeeting@muc.meet.jitsi",
      "participants": 1,
      "leaked": false,
      "created_time": 1708950454000
    }
  ]
}


Extra credit

Since the /room-census does not come out of the box, this is how I installed it. The docker-compose.yml file from the dockerized Jitsi project points to ~/.jitsi-meet-cfg for persistent and shared files, you can download the plugin like this:

wget -O ~/.jitsi-meet-cfg/prosody/prosody-plugins-custom/mod_muc_census.lua https://github.com/jitsi/jitsi-meet/blob/master/resources/prosody-plugins/mod_muc_census.lua

Then you activate it by adding GLOBAL_MODULES=muc_census to the .env file, then restart jitsi. This will enable the path /room-census to prosody.

$ grep GLOBAL_MODULES .env
GLOBAL_MODULES=muc_census

References: