Need to log IP addresses

As far as I can tell, there is no way to associate Jitsi occupants with IP addresses and/or ports. This is a must-have for auditing. Also, it can be used along with fail2ban to ban badly-behaved users.

Without this, a badly behaved user can flood the server with connection requests, potentially causing a DoS.

Ideally, there should be a data structure, such as ‘occupants’, that not only lists the user’s role and associates the user with a conference, but that also has a field that stores the user’s IP address. If we had this, the we could create mod_muc_audit.lua that would record each time an IP attempts to connect to the server and/or gets kicked from a conference. fail2ban can watch the logs and ban based on too many connection attempts or too many kicks.

1 Like

I second this request.

fail2ban is a MUST! We’ve had many attacks over the last couple of weeks and I fear without proper security we’re going to have to stop using this platform.

We’ve tried numerous modifications to nginx in order to pass the appropriate client IP , but the only IP passed is that of the local host. Which, renders $remote_addr and $proxy_add_x_forwarded_for useless as they always gather “”

1 Like

Has anyone tried using the nginx proxy_protocol to forward the client’s ip from the web server:443 to the web server on 4444?

The default ubuntu nginx server has proxy_protocol available for http but not for stream. (Enabling for stream requires recompiling nginx.)

I figured out how to get nginx to log the clients IP address to access.log (rather than logging

  1. Edit /etc/nginx/modules-enabled/60-jitsi-meet.conf
    Add to the server {…} section: proxy_protocol on

  2. Add a logging format to /etc/nginx/nginx/conf.
    In the http {…} section, add:
    log_format proxycombined '$proxy_protocol_addr - $remote_user [$time_local] ’ '"$request" $status $body_bytes_sent ’ ‘"$http_referer" “$http_user_agent”’;

This defines the format to be written to the log file and names this format “proxycombined”. (The default logging format is called “combined”.)

  1. Edit /etc/nginx/sites-enabled/mydomain.conf (whatever your domain is called).
    Add to the server {…} section for the server on port 4444:
    listen 4444 ssl http2 proxy_protocol;
    listen [::]:4444 ssl http2 proxy_protocol;
    access_log /var/log/nginx/access.log proxycombined;

Also, this section of code has a couple of lines that say “proxy_set_header X-Forwarded-For $remote_addr” Change each one to use $proxy_protocol_addr.

Now the client’s IP address is passed all the way down the chain and it gets logged to access.log.

I’m not too familiar with lua; how do I access the “X-Forwarded-For” header from my new module: /usr/share/jitsi-meet/prosody-plugins/mod_muc_audit.lua?

Edit: Added in the proxy_protocol on the listen lines. (Forgot those in the first write of these instructions.)


I wrote about this in another thread:

Hi @plokta,

I’m not a lua expert, so I’m going to need some step-by-step help here.

My nginx server is currently sending the user’s IP in the HTTP X-Forwarded-For header.

I see your example that uses: get_ip_from_request. Does this use X-Forwarded-For?

I added to my code: local ip = get_ip_from_request(event.request);
Unfortunately, now I’m getting errors about using an undefined global “get_ip_from_request”. How do I define this global?

My sample code:

module:log("info", "loading audit")
local is_healthcheck_room = module:require "util".is_healthcheck_room;

function audit_joined(event)
    module:log("info", "audit joined")
    local room =;
    if is_healthcheck_room(room) then
    local occupant = event.occupant;
    local jid_resource = require "util.jid".resource;
    local nick = jid_resource(occupant.nick);
    local ip = get_ip_from_request(event.request);
    local role = '';
    if occupant.role then
        role = occupant.role
    module:log("info", "room %s: join %s, role %s, ip %s", room, nick, role, ip);
module:hook("muc-occupant-joined", audit_joined, 150);

I mirrored your config, steps 1 through 3 , but main URL stops loading when when Proxy_protocol is enabled.
@Neal , Any thoughts on that?

On an up note, I do see the client IP logged :slight_smile: , just need to figure out why it breaks web access.

The error I see in /var/log/nginx/error.log , is:

upstream timed out (110: Connection timed out) while reading response header from upstream

My /etc/nginx/modules-enabled/60-jitsi-meet.conf is as follows (only change being that I added “proxy_protocol on;”)

stream {
    upstream web {
    upstream turn {
    # since 1.13.10
    map $ssl_preread_alpn_protocols $upstream {
        ~\bh2\b         web;
        ~\bhttp/1\.     web;
        default         turn;

    server {
        listen 443;
        listen [::]:443;

        proxy_protocol on;
         # since 1.11.5
        ssl_preread on;
        proxy_pass $upstream;

        # Increase buffer to serve video
        proxy_buffer_size 10m;


If you set the trusted_proxies in your prosody config, event.request.ip should contain the correct external client IP. get_ip_from_request() is a function that is declared in prosody’s http module to determine the actual client IP by means of the configured list of trusted proxies.

Your code snipped from /etc/nginx/modules-enabled/60-jitsi-meet.conf – with proxy_protocol on – looks correct. This tells nginx to not use the regular TCP+HTTP protocol when forwarding packets to the upstream web service. Instead, it will wrap it in a proxy header. In this case, the upstream web server is on

The next thing you need to do is edit /etc/nginx/sites-enabled/[yourdomain].conf. There are two “server” definitions in this file. The first one is for port 80 ( service { listen:80; … } ) – don’t touch this one.

The second one is for port 4444 ( service { listen:4444; … } ). This is where you need to add proxy_protocol to both of the listen lines.

server {
    listen 4444 ssl http2 proxy_protocol;
    listen [::]:4444 ssl http2 proxy_protocol;
    server_name mydomain;
    access_log /var/log/nginx/access.log proxycombined;

The “proxy_protocol” on the listen line will unwrap the proxy header. Otherwise, you’ll see errors in /var/log/nginx/error.log (and the errors may contain binary garbage) and the server won’t be able to decode the network traffic, resulting in the error you see.

Hi @plokta,

jitsi has WAY too many configuration files spread all over the place.

If you set the trusted_proxies in your prosody config

Can you be more specific? Which prosody config file? (Please provide the full path on the server.) And where do I set this? (Please give me a line number or sample code or something that tells me what to type and where to type it.)

Sweet! it works!
I was missing “proxy_protocol” in the listen lines for port 4444

I’ve been at this for hours, you are a life saver, thanks!

1 Like

Hi @Neal. Thank-you for this!

For the log_format code - I think it’s got those weird quote coding issue there so if a newbie did a cut and paste - an error would occur when restarting the Nginx service.

log_format proxycombined '$proxy_protocol_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"';
1 Like

Thanks a lot, this works perfectly!

To get the IP logging in prosody (/var/log/prosody/prosody.log), I had to add (line was not present) proxy_set_header X-Forwarded-For $proxy_protocol_addr; into the xmpp websockets location block:

location = /xmpp-websocket {
        proxy_http_version 1.1;
        # 2020-08-12
        proxy_set_header X-Forwarded-For $proxy_protocol_addr;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        tcp_nodelay on;

I thought it was worth mentioning it for others, since this is most likely were you would want to set your fail2ban on when you do LDAP-based authentication.