Max_occupants and duration is ignored with reservation system

I have enabled reservations module in prosody and assigned a reservation service to it as well. Even reservations_enable_max_occupants property is set to true in prosody configuration file.

Prosody is making the appropriate POST /conference and DELETE /conference/{conferenceId} calls as well on the respective events from jitsi meet.

The reservations module in prosody also logs that it is correctly receiving the max_occupants and duration value from the reservation system API on POST /conference call and setting it within itself, but none of these values of max_occupants and duration is getting enforced when the corresponding meeting is in progress in jitsi meet.

Neither max_occupants nor duration is honoured as received by the reservations module. Kindly help me in resolving this.

Prosody version: 0.11.13

Thanks,
Anirban Das

Have you enabled the muc_max_occupants module?

Can you share your prosody config (and redact sensitive info)?

Also, what version of Jitsi Meet are you using?

muc_max_occupants is enabled and max_occupants attribute is also set.

jitsi meet version: 1.2.2

Main prosody configuration file:

-- Prosody Example Configuration File
--
-- Information on configuring Prosody can be found on our
-- website at http://prosody.im/doc/configure
--
-- Tip: You can check that the syntax of this file is correct
-- when you have finished by running: luac -p prosody.cfg.lua
-- If there are any errors, it will let you know what and where
-- they are, otherwise it will keep quiet.
--
-- The only thing left to do is rename this file to remove the .dist ending, and fill in the
-- blanks. Good luck, and happy Jabbering!


---------- Server-wide settings ----------
-- Settings in this section apply to the whole server and are the default settings
-- for any virtual hosts

-- This is a (by default, empty) list of accounts that are admins
-- for the server. Note that you must create the accounts separately
-- (see http://prosody.im/doc/creating_accounts for info)
-- Example: admins = { "user1@example.com", "user2@example.net" }
admins = { }

-- Enable use of libevent for better performance under high load
-- For more information see: http://prosody.im/doc/libevent
--use_libevent = true;

-- This is the list of modules Prosody will load on startup.
-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
-- Documentation on modules can be found at: http://prosody.im/doc/modules
modules_enabled = {

        -- Generally required
                "roster"; -- Allow users to have a roster. Recommended ;)
                "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
                "tls"; -- Add support for secure TLS on c2s/s2s connections
                "dialback"; -- s2s dialback support
                "disco"; -- Service discovery

        -- Not essential, but recommended
                "private"; -- Private XML storage (for room bookmarks, etc.)
                "vcard"; -- Allow users to set vCards
                "limits"; -- Enable bandwidth limiting for XMPP connections

        -- These are commented by default as they have a performance impact
                --"privacy"; -- Support privacy lists
                --"compression"; -- Stream compression (Debian: requires lua-zlib module to work)

        -- Nice to have
                "version"; -- Replies to server version requests
                "uptime"; -- Report how long server has been running
                "time"; -- Let others know the time here on this server
                "ping"; -- Replies to XMPP pings with pongs
                "pep"; -- Enables users to publish their mood, activity, playing music and more
                "register"; -- Allow users to register on this server using a client and change passwords

        -- Admin interfaces
                "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
                --"admin_telnet"; -- Opens telnet console interface on localhost port 5582

        -- HTTP modules
                --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
                --"http_files"; -- Serve static files from a directory over HTTP

        -- Other specific functionality
                "posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
                --"groups"; -- Shared roster support
                --"announce"; -- Send announcement to all online users
                --"welcome"; -- Welcome users who register accounts
                --"watchregistrations"; -- Alert admins of registrations
                --"motd"; -- Send a message to users when they log in
                --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
        
        "prometheus";
"measure_stanza_counts";
"measure_client_presence";
"reservations";
"data_access";
"muc_max_occupants";
        
};

https_ports = { }

-- These modules are auto-loaded, but should you want
-- to disable them then uncomment them here:
modules_disabled = {
        -- "offline"; -- Store offline messages
        -- "c2s"; -- Handle client connections
        "s2s"; -- Handle server-to-server connections
};

-- Disable account creation by default, for security
-- For more information see http://prosody.im/doc/creating_accounts
allow_registration = false;

daemonize = false;

-- Enable rate limits for incoming client and server connections
limits = {
  c2s = {
    rate = "10kb/s";
  };
  s2sin = {
    rate = "30kb/s";
  };
}

pidfile = "/config/data/prosody.pid";

-- Force clients to use encrypted connections? This option will
-- prevent clients from authenticating unless they are using encryption.

c2s_require_encryption = false

-- Force certificate authentication for server-to-server connections?
-- This provides ideal security, but requires servers you communicate
-- with to support encryption AND present valid, trusted certificates.
-- NOTE: Your version of LuaSec must support certificate verification!
-- For more information see http://prosody.im/doc/s2s#security

s2s_secure_auth = false

-- Many servers don't support encryption or have invalid or self-signed
-- certificates. You can list domains here that will not be required to
-- authenticate using certificates. They will be authenticated using DNS.

--s2s_insecure_domains = { "gmail.com" }

-- Even if you leave s2s_secure_auth disabled, you can still require valid
-- certificates for some domains by specifying a list here.

--s2s_secure_domains = { "jabber.org" }

-- Select the authentication backend to use. The 'internal' providers
-- use Prosody's configured data storage to store the authentication data.
-- To allow Prosody to offer secure authentication mechanisms to clients, the
-- default provider stores passwords in plaintext. If you do not trust your
-- server please see http://prosody.im/doc/modules/mod_auth_internal_hashed
-- for information about using the hashed backend.

authentication = "internal_hashed"

-- Select the storage backend to use. By default Prosody uses flat files
-- in its configured data directory, but it also supports more backends
-- through modules. An "sql" backend is included by default, but requires
-- additional dependencies. See http://prosody.im/doc/storage for more info.

--storage = "sql" -- Default is "internal" (Debian: "sql" requires one of the
-- lua-dbi-sqlite3, lua-dbi-mysql or lua-dbi-postgresql packages to work)

-- For the "sql" backend, you can uncomment *one* of the below to configure:
--sql = { driver = "SQLite3", database = "prosody.sqlite" } -- Default. 'database' is the filename.
--sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }
--sql = { driver = "PostgreSQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }

-- Logging configuration
-- For advanced logging see http://prosody.im/doc/logging
--
-- Debian:
--  Logs info and higher to /var/log
--  Logs errors to syslog also
log = {
        { levels = {min = "debug"}, to = "console"};
}


statistics = "internal";
statistics_interval = 15;
reservations_api_prefix = <reservation system base URL>
reservations_enable_max_occupants = true
reservations_api_timeout = 60000
reservations_api_headers = {
  ["Authorization"] = "Basic <token>";
}


-- Enable use of native prosody 0.11 support for epoll over select
network_backend = "epoll";
-- Set the TCP backlog to 511 since the kernel rounds it up to the next power of 2: 512.
network_settings = {
  tcp_backlog = 511;
}

component_interface = { "*" }

data_path = "/config/data"

smacks_max_unacked_stanzas = 5;
smacks_hibernation_time = 60;
smacks_max_hibernated_sessions = 1;
smacks_max_old_sessions = 1;

Include "conf.d/*.cfg.lua"

Additional prosody configuration file:

admins = {
    "focus@auth.meet.jitsi",
    "jvb@auth.meet.jitsi"
}

unlimited_jids = {
    "focus@auth.meet.jitsi",
    "jvb@auth.meet.jitsi"
}

plugin_paths = { "/prosody-plugins/", "/prosody-plugins-custom" }

muc_mapper_domain_base = "meet.jitsi";
muc_mapper_domain_prefix = "muc";

http_default_host = "meet.jitsi"


external_service_secret = <token>;



external_services = {
  
  
  
     { type = "turns", host = <turn server FQDN>, port = 443, transport = "tcp", secret = true, ttl = 86400, algorithm = "turn" }
  
};






consider_bosh_secure = true;

-- Deprecated in 0.12
-- https://github.com/bjc/prosody/commit/26542811eafd9c708a130272d7b7de77b92712de



cross_domain_websocket = true
cross_domain_bosh = true


VirtualHost "meet.jitsi"

    authentication = "jitsi-anonymous"

    ssl = {
        key = "/config/certs/meet.jitsi.key";
        certificate = "/config/certs/meet.jitsi.crt";
    }
    modules_enabled = {
        "bosh";
        
        "websocket";
        "smacks"; -- XEP-0198: Stream Management
        
        "pubsub";
        "ping";
        "speakerstats";
        "conference_duration";
        
        "external_services";
        
        
        "muc_lobby_rooms";
        
        
        
        "av_moderation";
        
        
        
    }

    main_muc = "muc.meet.jitsi"

    
    lobby_muc = "lobby.meet.jitsi"
    
    muc_lobby_whitelist = { "recorder.meet.jitsi" }
    
    

    

    speakerstats_component = "speakerstats.meet.jitsi"
    conference_duration_component = "conferenceduration.meet.jitsi"

    
    av_moderation_component = "avmoderation.meet.jitsi"
    

    c2s_require_encryption = false



VirtualHost "auth.meet.jitsi"
    ssl = {
        key = "/config/certs/auth.meet.jitsi.key";
        certificate = "/config/certs/auth.meet.jitsi.crt";
    }
    modules_enabled = {
        "limits_exception";
    }
    authentication = "internal_hashed"


VirtualHost "recorder.meet.jitsi"
    modules_enabled = {
      "ping";
    }
    authentication = "internal_hashed"


Component "internal-muc.meet.jitsi" "muc"
    storage = "memory"
    modules_enabled = {
        "ping";
        }
    restrict_room_creation = true
    muc_room_locking = false
    muc_room_default_public_jids = true

Component "muc.meet.jitsi" "muc"
    storage = "memory"
    modules_enabled = {
        "muc_meeting_id";
        "muc_domain_mapper";
"muc_max_occupants";
        "polls";
        }
    muc_room_cache_size = 1000
    muc_room_locking = false
    muc_room_default_public_jids = true

Component "focus.meet.jitsi" "client_proxy"
    target_address = "focus@auth.meet.jitsi"

Component "speakerstats.meet.jitsi" "speakerstats_component"
    muc_component = "muc.meet.jitsi"

Component "conferenceduration.meet.jitsi" "conference_duration_component"
    muc_component = "muc.meet.jitsi"


Component "avmoderation.meet.jitsi" "av_moderation_component"
    muc_component = "muc.meet.jitsi"



Component "lobby.meet.jitsi" "muc"
    storage = "memory"
    restrict_room_creation = true
    muc_room_locking = false
    muc_room_default_public_jids = true




consider_websocket_secure = true;
muc_max_occupants = "5"
muc_access_whitelist = {
  "focus@auth.meet.jitsi",
  "jvb@auth.meet.jitsi"
}

Hmm… you seem to have added both those modules and their settings in the global config.

AFAIK, muc_max_occupants should be added to your muc component instead, so under Component "muc.meet.jitsi" "muc". See: [Solved] Where to add the "muc_max_occupants" to limit participants in a meeting? - #2 by corby

The reservations module should be added to the main virtual host, so under VirtualHost "meet.jitsi". See: Reservation System setup | Jitsi Meet

I’m afraid I have no idea what that version number refers to.

For the record, the integration between reservations and muc_max_occupant was only added in jitsi-meet 1.0.6091 which was part of the 2.0.7210 release (April 2022).

You mentioned “prosody also logs that it is correctly receiving the max_occupants and duration value from the reservation system” so I’m assuming your version is reasonable new.

Our jitsi meet version is 2.0.6865-2

Then you need to upgrade to use that feature. If you are not in a position to upgrade, you might be able to get away with copying the mod_reservations.lua file from master and replacing in your deployment.

You will also need to fix your config to place them in the right place.

Is there a pre condition that only enforces duration for a reservation to take effect only when max_occupants is enabled properly or will it be considered irrespective of any other condition as long as the reservation service is in place properly?

Duration won’t be affected by max_occupant and should work in your version. You will however need to configure it in the correct place.

By correct place, do you mean the reservation system for jitsi sending out response containing the duration field in action against POST /conference by prosody?

I meant that the reservations module and settings should be added to the main virtual host section in prosody config and not in the global config.

We upgraded our jitsi meet to version: 1.0.6260-1 and modified the global and local prosody configuration files accordingly but still max_occupants doesn’t seem to have any effect along with the reservation system.

More users than the max occupants configured for a meeting is able to join that meeting.

Below are the new prosody configuration files that we are using:

Global prosody configuration file:


-- Prosody Example Configuration File
--
-- Information on configuring Prosody can be found on our
-- website at http://prosody.im/doc/configure
--
-- Tip: You can check that the syntax of this file is correct
-- when you have finished by running: luac -p prosody.cfg.lua
-- If there are any errors, it will let you know what and where
-- they are, otherwise it will keep quiet.
--
-- The only thing left to do is rename this file to remove the .dist ending, and fill in the
-- blanks. Good luck, and happy Jabbering!


---------- Server-wide settings ----------
-- Settings in this section apply to the whole server and are the default settings
-- for any virtual hosts

-- This is a (by default, empty) list of accounts that are admins
-- for the server. Note that you must create the accounts separately
-- (see http://prosody.im/doc/creating_accounts for info)
-- Example: admins = { "user1@example.com", "user2@example.net" }
admins = { }

-- Enable use of libevent for better performance under high load
-- For more information see: http://prosody.im/doc/libevent
--use_libevent = true;

-- This is the list of modules Prosody will load on startup.
-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
-- Documentation on modules can be found at: http://prosody.im/doc/modules
modules_enabled = {

        -- Generally required
                "roster"; -- Allow users to have a roster. Recommended ;)
                "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
                "tls"; -- Add support for secure TLS on c2s/s2s connections
                "dialback"; -- s2s dialback support
                "disco"; -- Service discovery

        -- Not essential, but recommended
                "private"; -- Private XML storage (for room bookmarks, etc.)
                "vcard"; -- Allow users to set vCards
                "limits"; -- Enable bandwidth limiting for XMPP connections

        -- These are commented by default as they have a performance impact
                --"privacy"; -- Support privacy lists
                --"compression"; -- Stream compression (Debian: requires lua-zlib module to work)

        -- Nice to have
                "version"; -- Replies to server version requests
                "uptime"; -- Report how long server has been running
                "time"; -- Let others know the time here on this server
                "ping"; -- Replies to XMPP pings with pongs
                "pep"; -- Enables users to publish their mood, activity, playing music and more
                "register"; -- Allow users to register on this server using a client and change passwords

        -- Admin interfaces
                "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
                --"admin_telnet"; -- Opens telnet console interface on localhost port 5582

        -- HTTP modules
                --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
                --"http_files"; -- Serve static files from a directory over HTTP

        -- Other specific functionality
                "posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
                --"groups"; -- Shared roster support
                --"announce"; -- Send announcement to all online users
                --"welcome"; -- Welcome users who register accounts
                --"watchregistrations"; -- Alert admins of registrations
                --"motd"; -- Send a message to users when they log in
                --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
        
        "prometheus";
"measure_stanza_counts";
"measure_client_presence";
"data_access";
        
};

component_ports = { }
https_ports = { }

-- These modules are auto-loaded, but should you want
-- to disable them then uncomment them here:
modules_disabled = {
        -- "offline"; -- Store offline messages
        -- "c2s"; -- Handle client connections
        "s2s"; -- Handle server-to-server connections
};

-- Disable account creation by default, for security
-- For more information see http://prosody.im/doc/creating_accounts
allow_registration = false;

-- Enable rate limits for incoming client and server connections
limits = {
  c2s = {
    rate = "10kb/s";
  };
  s2sin = {
    rate = "30kb/s";
  };
}

pidfile = "/config/data/prosody.pid";

-- Force clients to use encrypted connections? This option will
-- prevent clients from authenticating unless they are using encryption.

c2s_require_encryption = false

-- set c2s port
c2s_ports = { 5222 } -- Listen on specific c2s port

-- Force certificate authentication for server-to-server connections?
-- This provides ideal security, but requires servers you communicate
-- with to support encryption AND present valid, trusted certificates.
-- NOTE: Your version of LuaSec must support certificate verification!
-- For more information see http://prosody.im/doc/s2s#security

s2s_secure_auth = false

-- Many servers don't support encryption or have invalid or self-signed
-- certificates. You can list domains here that will not be required to
-- authenticate using certificates. They will be authenticated using DNS.

--s2s_insecure_domains = { "gmail.com" }

-- Even if you leave s2s_secure_auth disabled, you can still require valid
-- certificates for some domains by specifying a list here.

--s2s_secure_domains = { "jabber.org" }

-- Select the authentication backend to use. The 'internal' providers
-- use Prosody's configured data storage to store the authentication data.
-- To allow Prosody to offer secure authentication mechanisms to clients, the
-- default provider stores passwords in plaintext. If you do not trust your
-- server please see http://prosody.im/doc/modules/mod_auth_internal_hashed
-- for information about using the hashed backend.

authentication = "internal_hashed"

-- Select the storage backend to use. By default Prosody uses flat files
-- in its configured data directory, but it also supports more backends
-- through modules. An "sql" backend is included by default, but requires
-- additional dependencies. See http://prosody.im/doc/storage for more info.

--storage = "sql" -- Default is "internal" (Debian: "sql" requires one of the
-- lua-dbi-sqlite3, lua-dbi-mysql or lua-dbi-postgresql packages to work)

-- For the "sql" backend, you can uncomment *one* of the below to configure:
--sql = { driver = "SQLite3", database = "prosody.sqlite" } -- Default. 'database' is the filename.
--sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }
--sql = { driver = "PostgreSQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }

-- Logging configuration
-- For advanced logging see http://prosody.im/doc/logging
--
-- Debian:
--  Logs info and higher to /var/log
--  Logs errors to syslog also
log = {
        { levels = {min = "debug"}, to = "console"};
}


statistics = "internal";
statistics_interval = 15;


-- Enable use of native prosody 0.11 support for epoll over select
network_backend = "epoll";
-- Set the TCP backlog to 511 since the kernel rounds it up to the next power of 2: 512.
network_settings = {
  tcp_backlog = 511;
}
unbound = {
    resolvconf = true
}

http_ports = { 5280 }
http_interfaces = { "*", "::" }

data_path = "/config/data"

smacks_max_unacked_stanzas = 5;
smacks_hibernation_time = 60;
smacks_max_hibernated_sessions = 1;
smacks_max_old_sessions = 1;

Include "conf.d/*.cfg.lua"

Local prosody configuration file:

admins = { "focus@auth.meet.jitsi", "jvb@auth.meet.jitsi" }

unlimited_jids = { "focus@auth.meet.jitsi", "jvb@auth.meet.jitsi"}

plugin_paths = { "/prosody-plugins/", "/prosody-plugins-custom" }

muc_mapper_domain_base = "meet.jitsi";
muc_mapper_domain_prefix = "muc";
http_default_host = "meet.jitsi"

external_service_secret = "<token>";
external_services = {
  { type = "turns", host = "FQDN of turn", port = 443, transport = "tcp", secret = true, ttl = 86400, algorithm = "turn" }
};

consider_bosh_secure = true;
consider_websocket_secure = true;

VirtualHost "meet.jitsi"
  authentication = "jitsi-anonymous"

  ssl = { key = "/config/certs/meet.jitsi.key"; certificate = "/config/certs/meet.jitsi.crt"; }

  modules_enabled = {
    "bosh";
    "websocket";
    "smacks"; -- XEP-0198: Stream Management
    "pubsub";
    "ping";
    "speakerstats";
    "conference_duration";
    "external_services";
    "muc_lobby_rooms";
    "av_moderation";
    "reservations";
  }

  main_muc = "muc.meet.jitsi"
  lobby_muc = "lobby.meet.jitsi"
  speakerstats_component = "speakerstats.meet.jitsi"
  conference_duration_component = "conferenceduration.meet.jitsi"
  av_moderation_component = "avmoderation.meet.jitsi"
  c2s_require_encryption = false

  reservations_api_prefix = "FQDN reservation system"
  reservations_enable_max_occupants = true
  reservations_api_timeout = 60000
  reservations_api_headers = {
    ["Authorization"] = "Basic <token>";
  }

VirtualHost "auth.meet.jitsi"
  ssl = { key = "/config/certs/auth.meet.jitsi.key"; certificate = "/config/certs/auth.meet.jitsi.crt"; }
  modules_enabled = {
    "limits_exception";
  }
  authentication = "internal_hashed"

Component "internal-muc.meet.jitsi" "muc"
  storage = "memory"
  modules_enabled = {
    "ping";
  }
  restrict_room_creation = true
  muc_room_locking = false
  muc_room_default_public_jids = true

Component "muc.meet.jitsi" "muc"
  storage = "memory"
  modules_enabled = {
    "muc_meeting_id";
    "muc_domain_mapper";
    "muc_max_occupants";
    "polls";
    "muc_domain_mapper";
  }
  muc_room_cache_size = 1000
  muc_room_locking = false
  muc_room_default_public_jids = true

Component "focus.meet.jitsi" "client_proxy"
  target_address = "focus@auth.meet.jitsi"
  muc_max_occupants = "5"
  muc_access_whitelist = { "focus@auth.meet.jitsi", "jvb@auth.meet.jitsi" }

Component "speakerstats.meet.jitsi" "speakerstats_component"
  muc_component = "muc.meet.jitsi"

Component "conferenceduration.meet.jitsi" "conference_duration_component"
  muc_component = "muc.meet.jitsi"

Component "avmoderation.meet.jitsi" "av_moderation_component"
  muc_component = "muc.meet.jitsi"

Component "lobby.meet.jitsi" "muc"
  storage = "memory"
  restrict_room_creation = true
  muc_room_locking = false
  muc_room_default_public_jids = true

Try moving this to the muc component?

If muc_max_occupants is not set properly the module will not trigger. This would be the default max that would apply for rooms if not specified in reservations payload.

1 Like

Working. Thanks a lot @shawn