Persistent Passwords on Self Hosted Rooms

Using the muc_room_default_persistent = true method I now have a different error: connection.GET_SESSION_ID_ERROR
I just closed the browser and joined in a private tab.

Folks, I’ve finally made it working by updating to the freshest version of Prosody

Prosody 0.11.5

# Lua environment
Lua version:                    Lua 5.2
LuaRocks:               Not installed

# Network

Backend: select

# Lua module versions
DBI:            0.7
lfs:            LuaFileSystem 1.6.3
lxp:            LuaExpat 1.3.0
socket:         LuaSocket 3.0-rc1
ssl:            0.6

You can try to adjust the module posted above to fit your needs, that is do not allow to delete the password and don’t let rooms go stale (perhaps just remove the muc-room-destroyed hook.
Restart prosody to enable the module.

Now create a room, set a password and leave the room. Check that a plaintext file has been created in prosody’s data folder in a folder called <your-muc-component>/persistent_muc_passwords/<urlencoded_muc_name>.dat

Then also enable the prosody module described here: and add the muc#roomconfig_roomsecret option. Restart prosody again. For each room you want to setup, create a file similar to the file you checked in the last step. Make sure these are only readable by the prosody user.

This is still just a workaround, as anybody who joins a room first (i.e. the moderator) will see the Remove Password button. However, clicking this button shows an error message stating that passwords were not supported.

Hope this helps!


I am using docker as well and would to have this setup. Is it possible for you to layout in a more detailed guide? I am struggling on where the modules locations are and if we need to turn that on in the docker-compose.yml file (via .env).

1 Like

I am using docker too in a test system.

If you do not change CONFIG in .env, file location in a standard configuration are

In docker-compose.yml you have a add a line for a prosody module

    image: jitsi/prosody
        - '5222'
        - '5347'
        - '5280'
        - ${CONFIG}/prosody:/config
        - ${CONFIG}/prosody-plugins-custom:/prosody-plugins-custom

And you have to create the directory ~/.jitsi-meet-cfg/prosody-plugins-custom/

1 Like

Alternatively, if you don’t want to change the docker-compose.yml, just change the plugin_paths option in ~/.jitsi-meet-cfg/prosody/conf.d/jitsi-meet.cfg.lua to include "/config/prosody-plugins-custom". Then put the module in ~/.jitsi-meet-cfg/prosody/prosody-plugins-custom/mod_persist_muc_passwords.lua

1 Like

Thanks a lot for your script! I managed to install it and it works - half-way:

  • It still asks for the operator’s password. Am I supposed to turn the restrict_create_room(?) off again?
  • It’s still possible to delete the password.

Sorry if I misunderstood any of the above instructions. I came from a “quick install” and didn’t expect to deep dive into the system just to set up a password.

(edit: found some details I have to re-read)

To prevent the password from being deleted, you can enable the mod_muc_config_restrict.lua module mentioned above.

You are asked to provide the operator’s password because you setup a secure domain - if everybody should be able to create a room try to undo the respective configuration. Note that in this case whoever joins the room first will be the room’s moderator which is likely not what you want.

Thanks for everyone that’s helped as well, and I think it is working as intended.

  • I have authentication turned on (internal)
  • When I “create” a room and set the password, that password carries over from session to session (i.e. I close out the window completely and go back in), so that is working as intended
  • However, because I have authentication on, when a room does not have a participant anymore (everyone left) and then join back in, it requires someone to authenticate first, and then the room password kicks in; is there a way to not have authentication on a room that had been created?

I’m stuck on the very same problem right now.
I wonder if it makes sense to remove the authentication and just use the room’s password. Using any unknown room would require a password nobody knows.
As soon as I figured out why my settings don’t apply, I’ll start tinkering with the script @plokta provided.

My concern is that I have this running on a public-facing VPS and I don’t want anyone and everyone to use up my bandwidth. With my scenario, ideally I would like to only let authenticated users create persistent rooms that require passwords.

That being said, I think @plokta solution is the best workaround. I have authentication so not everyone can just create a room, and passwords are persistent.

I have an almost working version for my needs (only pre-configured rooms with passwords - no accounts):

I’m not using any secure domain.


Component "conference.domain.tld" "muc"
    modules_enabled = {
    admins = { "focus@auth.domain.tld" }
    default_storage = "memory";
    storage = {
	persistent_muc_passwds = "internal";
    muc_config_restricted = {

/usr/lib/prosody/modules/mod_persist_muc_passwords.lua (modified script of @plokta )

local store = module:open_store("persistent_muc_passwds", "map");
if not store then
    module:log("error","Failed to open storage.");
    return nil;

module:hook("muc-room-created", function (event)    
    local room =;
    module:log("debug","hooked room create for %s", room);

    local old_pass = store:get(room.jid, "password");
    if not old_pass then
        -- default password for unknown rooms; not to be shared with anyone
	old_pass = "some-admin-password" -- should be moved into some config file
        module:log("debug", "No password to restore for room %s", room);

    module:log("debug", "Loaded old password '%s' for room %s", old_pass, room);

    -- restore old pass for the mucroom
    local success = room:set_password(old_pass);
    if not success then 
        module:log("warn", "Failed to set old password %s for restored room %s.", old_pass, room);
    module:log("debug", "Set password '%s' for restored room %s.", old_pass, room);
    return nil;
end, 0);

For each room: /var/lib/prosody/conference%2edomain%2etld/persistent_muc_passwds/name_of_the_room%40conference%2edomain%2etld.dat

return {
	["password"] = "shared room password";

Current issues:

  • It’s still possible to delete the password when entering the room. But that has only temporary effect. @plokta any idea why my configuration of mod_muc_config_restrict doesn’t work? Is muc#roomconfig_roomsecret available on secured domains only?

My setup is somewhat different but I can confirm that mod_muc_config_restrict also works without secured domain: The Remove Password button is visible but an error message pops up when the button is clicked.

Did you check the prosody logs to see whether the module was loaded successfully? Also, in my config the focus user is only set as admin in the global section and not in the muc component. And I don’t have the modules muc_meeting_id and muc_domain_mapper enabled but to be honest, I don’t know if this could affect the muc_config_restrict module.


@plokta Couldn’t you remove the Remove Password button from the react template?

Thanks for the thread, this has been a super helpful discussion.

To remove the password button or to change some other css, i use this trick:

In the start of file config.js some lines can be added;

<style type="text/css">
.remove-password {
        display: none;




I have followed the working version of @fyl2xp1 but with the secure domain enabled.

  • modify: /etc/prosody/conf.d/domain.tld.cfg.lua
  • create: /usr/lib/prosody/modules/mod_persist_muc_passwords.lua

I have an error that @fyl2xp1 already solved, maybe I’ve missing something, when I try to open/create a conference, Jitsi asks the login/password for the host, but after the credentials validation I have the following error:
Oops, Something went wrong and we couldn’t connect to the conference: connection.GET_SESSION_ID_ERROR.

Maybe I have miss to configure something ?

1 Like

I have the same problem.

After allowing access to microphone and camera, the “Something went wrong” error appears.
Very rarely I am asked for the password first, but then the same error pops up.

It happens only if I call…).

I’m running Prosody 0.10.0 on Ubuntu 18.04.4 LTS.

I only added this simple module:

module:hook("muc-room-created", function (event)
    local room =;

    local pass = "test-pass";

and enabled it like this:

Component "conference.domain…" "muc"
    storage = "none";
    modules_enabled = {
        "my_muc_passwords"; -- ←
    admins = { "focus@auth.domain…" }
    muc_room_locking = false
    muc_room_default_public_jids = true

Here are the JavaScript console errors:

2020-04-09T15:51:32.339Z [JitsiMeetJS.js] <getGlobalOnErrorHandler>:  UnhandledError: null Script: null Line: null Column: null StackTrace:  Error: "Focus error, retry after 1000"
    _allocateConferenceFocusError moderator.js:446
    allocateConferenceFocus moderator.js:373
    s strophe.umd.js:2716
    run strophe.umd.js:1875
    _dataRecv strophe.umd.js:3157
    forEachChild strophe.umd.js:830
    _dataRecv strophe.umd.js:3146
    _onRequestStateChange strophe.umd.js:5012
    o Logger.js:154
    getGlobalOnErrorHandler JitsiMeetJS.js:612
    onerror middleware.js:100
    callErrorHandler GlobalOnErrorHandler.js:61
    _allocateConferenceFocusError moderator.js:446
    allocateConferenceFocus moderator.js:373
    s strophe.umd.js:2716
    run strophe.umd.js:1875
    _dataRecv strophe.umd.js:3157
    forEachChild strophe.umd.js:830
    _dataRecv strophe.umd.js:3146
    _onRequestStateChange strophe.umd.js:5012
2020-04-09T15:51:32.341Z [modules/xmpp/moderator.js] <l.prototype._allocateConferenceFocusError>:  Focus error, retry after 1000 
<iq id="09f539c6-43b7-4b5a-b9bf-b48aaa7bd48f:sendIQ" type="error" to="78aed5e5-92d8-4844-b698-…-455f-a0fd-859b404d375a" from="focus.domain…" xmlns="jabber:client">
    o Logger.js:154
    _allocateConferenceFocusError moderator.js:447
    allocateConferenceFocus moderator.js:373
    s strophe.umd.js:2716
    run strophe.umd.js:1875
    _dataRecv strophe.umd.js:3157
    forEachChild strophe.umd.js:830
    _dataRecv strophe.umd.js:3146
    _onRequestStateChange strophe.umd.js:5012
2020-04-09T15:51:32.359Z [features/overlay] <componentDidMount>:  The conference will be reloaded after 26 seconds. Logger.js:154:22
2020-04-09T15:51:32.373Z [conference.js] <_onConferenceFailed>:  CONFERENCE FAILED: conference.focusDisconnected focus.domain… 1

Looks like there is still a problem with jicofo to my untrained eye, even though I use the muc-room-created hook instead of muc-room-pre-create.

I would be very grateful for any hints.

IIRC, this approach has only been verified to work with Prosody >= 0.11 so if you use Prosody 0.10 you may need to check the respective Prosody API and adjust the module accordingly, or upgrade your Prosody to version 0.11 (not sure how complicated an upgrade would be).

1 Like

Due to a storage crash I had to start over with jitsi yesterday, so I pulled the latest docker for jitsi. I re-followed the steps I took in my first install - mostly slight changes to the module you proposed. But somehow I now get:

prosody_1   | modulemanager       error Unable to load module 'muc_config_restrict': /usr/lib/prosody/modules/mod_muc_config_restrict.lua: No such file or directory

When I check the prosody container it is missing. I am not even sure if that file was present in my last jitsi. Am I misunderstanding something?

never mind, i obviously just had to pull muc_config_restrict from prosody. Must have done that late night last time.

This is very good.

It would be preferable, although we cant complain too much, if we could have administrative users create rooms within jitsi itself. But we can manage this easily enough (larger organizations will find this not scaling very well)

For other peoples sake Ill put clear notes on the mod_muc_config_restrict/mod_muc_config_restrict.lua module:

You can find the most recent version here. Put that script under /usr/lib/prosody/modules/mod_muc_config_restrict.lua