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



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}') 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:


  • 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 ( 56 data bytes
64 bytes from seq=0 ttl=64 time=0.194 ms
64 bytes from seq=1 ttl=64 time=0.220 ms
64 bytes from 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

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}') prosody:5280/room-census | jq .
  "room_census": [
      "room_name": "",
      "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

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