Question about Restricting Channel Visibility in Mumble #3092

Closed
opened 2026-02-20 22:17:56 -05:00 by deekerman · 7 comments
Owner

Originally created by @Nablusi on GitHub (Jan 10, 2026).

The issue

I am currently integrating Mumble with ICE for a multi-company setup. I want to ensure that users from one company can only see their own company channel and cannot see channels of other companies.

Could you please let me know if there is a way to restrict channel visibility so that a user only sees the channels assigned to their company?

I don't want the users to see the root channel or any other channel except their company channel

import { meta } from "../client.js";
import {
  checkServerConnection,
  findServerUniqueId,
  findServerInformation,
  editServerName,
  editServerPort,
  editServerMaxUsers,
  editServerWelcomeText,
  getServerChannels,
  getRegisteredUsersInformation,
  getAllRegisteredUsers,
  getAllRegisteredUsersForChannel,
} from "./serverFunctions.js";
import {
  deleteChannels,
  companyChannelsIsExist,
  createCompanyChannel,
  createServerCompanyChannels,
  getCompanyChannelId,
} from "./createChannels.js";
import {
  userExists,
  addUser,
  deleteUser,
  updateUserInformation,
  getUserId,
} from "./addUser.js";

// import { setSuperUserPassword } from "./superUserFunctions.js";

// import { lockCompaniesChannel } from "./setPermissions/lockCompaniesChannel.js";
import { lockRootChannel } from "./setPermissions/lockRootChannel.js";
import fs from "fs";
import { fileURLToPath } from "url";
import { dirname, join } from "path";

// Get current directory for ES modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// Read and parse JSON file
const data = JSON.parse(
  fs.readFileSync(join(__dirname, "..", "users.json"), "utf8")
);
const { company_list, companies, users } = data;

const server = await meta.getServer(1);

const serverConnection = server.ice_context(
  new Map([["secret", "iceSuperSecret123"]])
);

checkServerConnection(serverConnection);
// findServerUniqueId(serverConnection);
// editServerName(serverConnection, "Professional Mumble Server");
// editServerMaxUsers(serverConnection, 100);
// editServerWelcomeText(serverConnection, "Welcome to the Professional Server !");
// findServerInformation(serverConnection);
// getServerChannels(serverConnection);
// getRegisteredUsersInformation(serverConnection);
// getAllRegisteredUsers(serverConnection);
//getAllRegisteredUsersForChannel(serverConnection, 1);

/*
 Create the company channels on the server
*/

// 1️⃣ Create (or ensure) "companies" root channel
// await createCompanyChannel(serverConnection, "companies", 0);

// // 2️⃣ Get its REAL ID
// const companiesChannelId = await getCompanyChannelId(
//   serverConnection,
//   "companies"
// );

// 3️⃣ Create company sub-channels under "companies"
await createServerCompanyChannels(
  serverConnection,
  companies,
  0,
);

// 4️⃣ Lock the "companies" parent channel (visible but not directly joinable)
// This allows users to see the parent but forces them to enter specific company channels
// await lockCompaniesChannel(serverConnection, companiesChannelId);

/* 
Add all users from users.json to the server
*/

// Add all users from users.json to the server
// Map users to the correct format and pass as array
const usersToAdd = users
  .filter((user) => user.name && user.email && user.password)
  .map((user) => ({
    name: user.name,
    email: user.email,
    password: user.password,
    role: user.role,
    company_name: user.company_name,
    comment: `Role: ${user.role}, Company: ${user.company_name}`,
  }));

// // // addUser now accepts either a single user or an array of users
// // // Pass companies list so users can be assigned to their company channels
await addUser(serverConnection, usersToAdd, { companies });

// //Verify users were added and permissions were set
// console.log("\n🔍 Verifying permissions...");
// const company1ChannelId = await getCompanyChannelId(
//   serverConnection,
//   "Company 1"
// );
// if (company1ChannelId) {
//   await getAllRegisteredUsersForChannel(serverConnection, company1ChannelId);
// } else {
//   console.log("⚠️  Company 1 channel not found");
// }

// // Check if a specific user exists
// userExists(serverConnection, "Carol Williams");
// //delete user

// deleteUser(serverConnection, 4);

// update user information
// updateUserInformation(serverConnection, 4, { name: "Carol Williams", email: "carol@company1.com", password: "user123" });

// check the users on the server
// const usersOnServer = await serverConnection.getRegisteredUsers();
// console.log(usersOnServer);

// // Get user ID by username
// const userId = await getUserId(serverConnection, "Carol Williams");
// if (userId !== null) {
//   console.log(`User ID: ${userId}`);
// } else {
//   console.log("User not found");
// }

/*
 Set the super user password and name
*/

// set the super user password and name
// await setSuperUserPassword(serverConnection, "zaid");


await lockRootChannel(serverConnection, 0);

export { serverConnection };


import { MumbleServer } from "../../ICEBACKENDSERVER/MumbleServer.js";

export async function applyCompanyACL(
  serverConnection,
  channelId,
  companyId,
  companyUsers = [],
  companyAdmins = []
) {
  // Define basic permissions for regular company users using bitwise OR operations
  // Each permission is a bit flag, and | combines them into a single permission mask
  const allowBasic =
    MumbleServer.PermissionTraverse | // ⭐ CRITICAL: Controls channel VISIBILITY - users without this CANNOT SEE the channel at all
    MumbleServer.PermissionEnter | // Can enter/join the channel (requires Traverse to see it first)
    MumbleServer.PermissionSpeak | // Can speak (voice chat) in the channel
    MumbleServer.PermissionTextMessage; // Can send text messages in the channel

  // Admin permissions: include all basic permissions PLUS administrative capabilities
  const allowAdmin =
    allowBasic | // All basic permissions (inherit from allowBasic)
    MumbleServer.PermissionMove | // Can move users between channels
    MumbleServer.PermissionKick | // Can kick users from the server
    MumbleServer.PermissionBan | // Can ban users
    MumbleServer.PermissionMakeChannel; // Can create new sub-channels





  // Define ACL rules - processed in order, later rules can override earlier ones
  // ACL constructor: new ACL(applyHere, applySubs, inherited, userid, group, allow, deny)
  //   applyHere: (boolean) Apply to this channel
  //   applySubs: (boolean) Apply to sub-channels
  //   inherited: (boolean) Whether this ACL was inherited (always false for new ACLs)
  //   userid: (number) Specific user ID (0 = not user-specific)
  //   group: (string) Group name to apply to ("all" = everyone, empty = applies to specific userid)
  //   allow: (number) Permission bits to ALLOW (bitmask)
  //   deny: (number) Permission bits to DENY (bitmask, 0xffffffff = all permissions)
  const acls = [
    // ❌ Rule 1: DENY absolutely everyone by default (security-first approach)
    // This blocks ALL permissions (including PermissionTraverse = visibility) for everyone initially
    // Users without PermissionTraverse cannot SEE the channel in their client
    new MumbleServer.ACL(
        true,
        false,              // ❗ لا تورث
        false,
        0,
        "all",
        0,
        MumbleServer.PermissionTraverse
      ),

    // ✅ Rule 2: Allow ONLY employees of this company (regular users)
    // This overrides the deny rule above for members of the company group
    // By granting PermissionTraverse, ONLY company users can SEE the channel (others remain invisible)
    new MumbleServer.ACL(
      true, // applyHere: apply to this channel
      true, // applySubs: apply to sub-channels
      false, // inherited: not inherited
      0, // userid: 0 = group-based, not user-specific
      `company_${companyId}`, // group: only members of this company's group
      allowBasic, // allow: grant basic permissions including Traverse (makes channel visible only to company users)
      0 // deny: 0 = don't deny anything (already allowed above)
    ),

    // 👑 Rule 3: Grant additional permissions to company admins
    // Admins get all basic permissions PLUS admin capabilities
    new MumbleServer.ACL(
      true, // applyHere: apply to this channel
      true, // applySubs: apply to sub-channels
      false, // inherited: not inherited
      0, // userid: 0 = group-based, not user-specific
      `admin_${companyId}`, // group: only members of this company's admin group
      allowAdmin, // allow: grant admin permissions (includes basic + admin)
      0 // deny: 0 = don't deny anything
    ),
  ];

  // Define groups - collections of users that ACL rules can reference
  // Group constructor: new Group(name, inherited, inherit, inheritable, add, remove, members)
  //   name: (string) Unique group name
  //   inherited: (boolean) Whether this group was inherited from parent channel
  //   inherit: (boolean) Whether to inherit members from parent channel groups
  //   inheritable: (boolean) Whether child channels can inherit this group
  //   add: (Array<number>) User IDs to add to this group
  //   remove: (Array<number>) User IDs to remove from this group (empty = none)
  //   members: (Array<number>) Current members (deprecated, use add/remove)
  const groups = [
    // Group for all company employees (regular users)
    new MumbleServer.Group(
      `company_${companyId}`, // name: unique group name for this company
      false, // inherited: not inherited from parent
      false, // inherit: don't inherit members from parent
      false, // inheritable: don't allow children to inherit
      companyUsers.map((u) => u.userId), // add: extract userId from each user object
      [] // remove: empty = don't remove anyone
    ),
    // Group for company administrators (subset of company users with extra permissions)
    new MumbleServer.Group(
      `admin_${companyId}`, // name: unique admin group name for this company
      false, // inherited: not inherited from parent
      false, // inherit: don't inherit members from parent
      false, // inheritable: don't allow children to inherit
      companyAdmins.map((u) => u.userId), // add: extract userId from each admin object
      [] // remove: empty = don't remove anyone
    ),
  ];

  // Apply the ACL rules and groups to the channel
  // setACL(channelId, acls, groups, inherit)
  //   channelId: channel to apply ACL to
  //   acls: array of ACL rules (processed in order)
  //   groups: array of groups (user collections)
  //   inherit: (boolean, true) whether to inherit ACLs from parent channel (true = yes)
  await serverConnection.setACL(channelId, acls, groups, false);

  console.log(`🔐 Channel locked to company_${companyId}`);
}


import { MumbleServer } from "../../ICEBACKENDSERVER/MumbleServer.js";

export async function lockRootChannel(
  serverConnection,
  rootChannelId
) {
    const acls = [
        new MumbleServer.ACL(
            true,      // applyHere
            false,      // applySubs
            false,     // inherited
            0,         // all users
            "all",     // group
            MumbleServer.PermissionTraverse,         
            MumbleServer.PermissionEnter | MumbleServer.PermissionSpeak
        ),
    ];

  await serverConnection.setACL(rootChannelId, acls, [], false);

  console.log("🔒 Root channel locked (visible, not joinable)");
}

import { MumbleServer } from "../ICEBACKENDSERVER/MumbleServer.js";
import { applyCompanyACL } from "./setPermissions/applyCompanyACL.js";
import { getCompanyChannelId } from "./createChannels.js";

/* ============================
   Check if user exists
============================ */
const userExists = async (serverConnection, username) => {
  const users = await serverConnection.getRegisteredUsers(username);
  for (const [id, name] of users) {
    if (name === username) return { exists: true, userId: id };
  }
  return { exists: false, userId: null };
};

/* ============================
   Register single user
============================ */
const addSingleUser = async (serverConnection, user) => {
  const existing = await userExists(serverConnection, user.name);
  if (existing.exists) return existing.userId;

  const info = new Map();
  info.set(MumbleServer.UserInfo.UserName, user.name);

  if (user.email) info.set(MumbleServer.UserInfo.UserEmail, user.email);

  if (user.password)
    info.set(MumbleServer.UserInfo.UserPassword, user.password);

  const userId = await serverConnection.registerUser(info);
  console.log(`✅ Registered ${user.name} (ID ${userId})`);
  return userId;
};

/* ============================
   MAIN addUser
============================ */
const addUser = async (serverConnection, users, options = {}) => {
  const { companies = [] } = options;
  const input = Array.isArray(users) ? users : [users];

  // Track users per company
  const companyUsersMap = new Map();

  for (const user of input) {
    if (!user.name || !user.company_name) {
      console.warn("⚠️ User missing name or company_name", user);
      continue;
    }

    const company = companies.find((c) => c.name === user.company_name);
    if (!company) {
      console.warn(`⚠️ Company not found: ${user.company_name}`);
      continue;
    }

    const userId = await addSingleUser(serverConnection, user);

    
    if (!companyUsersMap.has(company.id)) {
      companyUsersMap.set(company.id, {
        company,
        users: [],
        admins: [],
      });
    }

    const entry = { userId, userName: user.name };

    if (user.role === "company_admin") {
      companyUsersMap.get(company.id).admins.push(entry);
    } else {
      companyUsersMap.get(company.id).users.push(entry);
    }
  }

  /* ============================
     Apply ACLs per company channel
     IMPORTANT: Apply ACLs to channels for companies we're adding users to.
     When setACL is called, it REPLACES the entire ACL and group membership,
     so only the users we specify will be in the groups. All other users will
     be denied by the "deny all" rule, making channels invisible to them.
  ============================ */
  for (const { company, users, admins } of companyUsersMap.values()) {
    const channelId = await getCompanyChannelId(serverConnection, company.name);

    if (!channelId) {
      console.warn(`⚠️ Channel not found for company: ${company.name}`);
      continue;
    }

    // Apply ACL to this company's channel
    // This will:
    // 1. Deny ALL users (including PermissionTraverse = visibility)
    // 2. Allow ONLY users in this company's groups to see the channel
    // Users from other companies will NOT be in these groups, so they'll be denied
    await applyCompanyACL(
      serverConnection,
      channelId,
      company.id,
      users,
      admins
    );
  }

  console.log("🎯 All users assigned & channels isolated correctly");
};

/* ============================
   Delete / Update 
============================ */
const deleteUser = async (serverConnection, userId) => {
  await serverConnection.unregisterUser(userId);
};

const getUserId = async (serverConnection, username) => {
  const users = await serverConnection.getRegisteredUsers(username);
  for (const [id, name] of users) {
    if (name === username) return id;
  }
  return null;
};

const updateUserInformation = async (serverConnection, userId, updates) => {
  const info = await serverConnection.getRegistration(userId);

  if (updates.name) info.set(MumbleServer.UserInfo.UserName, updates.name);
  if (updates.email) info.set(MumbleServer.UserInfo.UserEmail, updates.email);
  if (updates.password)
    info.set(MumbleServer.UserInfo.UserPassword, updates.password);

  await serverConnection.updateRegistration(userId, info);
};

export {
  userExists,
  addUser,
  addSingleUser,
  deleteUser,
  updateUserInformation,
  getUserId,
};



Mumble version

1.4

Mumble component

Server

OS

Windows

Additional information

No response

Originally created by @Nablusi on GitHub (Jan 10, 2026). ### The issue I am currently integrating Mumble with ICE for a multi-company setup. I want to ensure that users from one company can only see their own company channel and cannot see channels of other companies. Could you please let me know if there is a way to restrict channel visibility so that a user only sees the channels assigned to their company? I don't want the users to see the root channel or any other channel except their company channel ```createServer.js import { meta } from "../client.js"; import { checkServerConnection, findServerUniqueId, findServerInformation, editServerName, editServerPort, editServerMaxUsers, editServerWelcomeText, getServerChannels, getRegisteredUsersInformation, getAllRegisteredUsers, getAllRegisteredUsersForChannel, } from "./serverFunctions.js"; import { deleteChannels, companyChannelsIsExist, createCompanyChannel, createServerCompanyChannels, getCompanyChannelId, } from "./createChannels.js"; import { userExists, addUser, deleteUser, updateUserInformation, getUserId, } from "./addUser.js"; // import { setSuperUserPassword } from "./superUserFunctions.js"; // import { lockCompaniesChannel } from "./setPermissions/lockCompaniesChannel.js"; import { lockRootChannel } from "./setPermissions/lockRootChannel.js"; import fs from "fs"; import { fileURLToPath } from "url"; import { dirname, join } from "path"; // Get current directory for ES modules const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Read and parse JSON file const data = JSON.parse( fs.readFileSync(join(__dirname, "..", "users.json"), "utf8") ); const { company_list, companies, users } = data; const server = await meta.getServer(1); const serverConnection = server.ice_context( new Map([["secret", "iceSuperSecret123"]]) ); checkServerConnection(serverConnection); // findServerUniqueId(serverConnection); // editServerName(serverConnection, "Professional Mumble Server"); // editServerMaxUsers(serverConnection, 100); // editServerWelcomeText(serverConnection, "Welcome to the Professional Server !"); // findServerInformation(serverConnection); // getServerChannels(serverConnection); // getRegisteredUsersInformation(serverConnection); // getAllRegisteredUsers(serverConnection); //getAllRegisteredUsersForChannel(serverConnection, 1); /* Create the company channels on the server */ // 1️⃣ Create (or ensure) "companies" root channel // await createCompanyChannel(serverConnection, "companies", 0); // // 2️⃣ Get its REAL ID // const companiesChannelId = await getCompanyChannelId( // serverConnection, // "companies" // ); // 3️⃣ Create company sub-channels under "companies" await createServerCompanyChannels( serverConnection, companies, 0, ); // 4️⃣ Lock the "companies" parent channel (visible but not directly joinable) // This allows users to see the parent but forces them to enter specific company channels // await lockCompaniesChannel(serverConnection, companiesChannelId); /* Add all users from users.json to the server */ // Add all users from users.json to the server // Map users to the correct format and pass as array const usersToAdd = users .filter((user) => user.name && user.email && user.password) .map((user) => ({ name: user.name, email: user.email, password: user.password, role: user.role, company_name: user.company_name, comment: `Role: ${user.role}, Company: ${user.company_name}`, })); // // // addUser now accepts either a single user or an array of users // // // Pass companies list so users can be assigned to their company channels await addUser(serverConnection, usersToAdd, { companies }); // //Verify users were added and permissions were set // console.log("\n🔍 Verifying permissions..."); // const company1ChannelId = await getCompanyChannelId( // serverConnection, // "Company 1" // ); // if (company1ChannelId) { // await getAllRegisteredUsersForChannel(serverConnection, company1ChannelId); // } else { // console.log("⚠️ Company 1 channel not found"); // } // // Check if a specific user exists // userExists(serverConnection, "Carol Williams"); // //delete user // deleteUser(serverConnection, 4); // update user information // updateUserInformation(serverConnection, 4, { name: "Carol Williams", email: "carol@company1.com", password: "user123" }); // check the users on the server // const usersOnServer = await serverConnection.getRegisteredUsers(); // console.log(usersOnServer); // // Get user ID by username // const userId = await getUserId(serverConnection, "Carol Williams"); // if (userId !== null) { // console.log(`User ID: ${userId}`); // } else { // console.log("User not found"); // } /* Set the super user password and name */ // set the super user password and name // await setSuperUserPassword(serverConnection, "zaid"); await lockRootChannel(serverConnection, 0); export { serverConnection }; ``` ```applyCompanyACL.js import { MumbleServer } from "../../ICEBACKENDSERVER/MumbleServer.js"; export async function applyCompanyACL( serverConnection, channelId, companyId, companyUsers = [], companyAdmins = [] ) { // Define basic permissions for regular company users using bitwise OR operations // Each permission is a bit flag, and | combines them into a single permission mask const allowBasic = MumbleServer.PermissionTraverse | // ⭐ CRITICAL: Controls channel VISIBILITY - users without this CANNOT SEE the channel at all MumbleServer.PermissionEnter | // Can enter/join the channel (requires Traverse to see it first) MumbleServer.PermissionSpeak | // Can speak (voice chat) in the channel MumbleServer.PermissionTextMessage; // Can send text messages in the channel // Admin permissions: include all basic permissions PLUS administrative capabilities const allowAdmin = allowBasic | // All basic permissions (inherit from allowBasic) MumbleServer.PermissionMove | // Can move users between channels MumbleServer.PermissionKick | // Can kick users from the server MumbleServer.PermissionBan | // Can ban users MumbleServer.PermissionMakeChannel; // Can create new sub-channels // Define ACL rules - processed in order, later rules can override earlier ones // ACL constructor: new ACL(applyHere, applySubs, inherited, userid, group, allow, deny) // applyHere: (boolean) Apply to this channel // applySubs: (boolean) Apply to sub-channels // inherited: (boolean) Whether this ACL was inherited (always false for new ACLs) // userid: (number) Specific user ID (0 = not user-specific) // group: (string) Group name to apply to ("all" = everyone, empty = applies to specific userid) // allow: (number) Permission bits to ALLOW (bitmask) // deny: (number) Permission bits to DENY (bitmask, 0xffffffff = all permissions) const acls = [ // ❌ Rule 1: DENY absolutely everyone by default (security-first approach) // This blocks ALL permissions (including PermissionTraverse = visibility) for everyone initially // Users without PermissionTraverse cannot SEE the channel in their client new MumbleServer.ACL( true, false, // ❗ لا تورث false, 0, "all", 0, MumbleServer.PermissionTraverse ), // ✅ Rule 2: Allow ONLY employees of this company (regular users) // This overrides the deny rule above for members of the company group // By granting PermissionTraverse, ONLY company users can SEE the channel (others remain invisible) new MumbleServer.ACL( true, // applyHere: apply to this channel true, // applySubs: apply to sub-channels false, // inherited: not inherited 0, // userid: 0 = group-based, not user-specific `company_${companyId}`, // group: only members of this company's group allowBasic, // allow: grant basic permissions including Traverse (makes channel visible only to company users) 0 // deny: 0 = don't deny anything (already allowed above) ), // 👑 Rule 3: Grant additional permissions to company admins // Admins get all basic permissions PLUS admin capabilities new MumbleServer.ACL( true, // applyHere: apply to this channel true, // applySubs: apply to sub-channels false, // inherited: not inherited 0, // userid: 0 = group-based, not user-specific `admin_${companyId}`, // group: only members of this company's admin group allowAdmin, // allow: grant admin permissions (includes basic + admin) 0 // deny: 0 = don't deny anything ), ]; // Define groups - collections of users that ACL rules can reference // Group constructor: new Group(name, inherited, inherit, inheritable, add, remove, members) // name: (string) Unique group name // inherited: (boolean) Whether this group was inherited from parent channel // inherit: (boolean) Whether to inherit members from parent channel groups // inheritable: (boolean) Whether child channels can inherit this group // add: (Array<number>) User IDs to add to this group // remove: (Array<number>) User IDs to remove from this group (empty = none) // members: (Array<number>) Current members (deprecated, use add/remove) const groups = [ // Group for all company employees (regular users) new MumbleServer.Group( `company_${companyId}`, // name: unique group name for this company false, // inherited: not inherited from parent false, // inherit: don't inherit members from parent false, // inheritable: don't allow children to inherit companyUsers.map((u) => u.userId), // add: extract userId from each user object [] // remove: empty = don't remove anyone ), // Group for company administrators (subset of company users with extra permissions) new MumbleServer.Group( `admin_${companyId}`, // name: unique admin group name for this company false, // inherited: not inherited from parent false, // inherit: don't inherit members from parent false, // inheritable: don't allow children to inherit companyAdmins.map((u) => u.userId), // add: extract userId from each admin object [] // remove: empty = don't remove anyone ), ]; // Apply the ACL rules and groups to the channel // setACL(channelId, acls, groups, inherit) // channelId: channel to apply ACL to // acls: array of ACL rules (processed in order) // groups: array of groups (user collections) // inherit: (boolean, true) whether to inherit ACLs from parent channel (true = yes) await serverConnection.setACL(channelId, acls, groups, false); console.log(`🔐 Channel locked to company_${companyId}`); } ``` ```lockRootChannel.js import { MumbleServer } from "../../ICEBACKENDSERVER/MumbleServer.js"; export async function lockRootChannel( serverConnection, rootChannelId ) { const acls = [ new MumbleServer.ACL( true, // applyHere false, // applySubs false, // inherited 0, // all users "all", // group MumbleServer.PermissionTraverse, MumbleServer.PermissionEnter | MumbleServer.PermissionSpeak ), ]; await serverConnection.setACL(rootChannelId, acls, [], false); console.log("🔒 Root channel locked (visible, not joinable)"); } ``` ```addUser.js import { MumbleServer } from "../ICEBACKENDSERVER/MumbleServer.js"; import { applyCompanyACL } from "./setPermissions/applyCompanyACL.js"; import { getCompanyChannelId } from "./createChannels.js"; /* ============================ Check if user exists ============================ */ const userExists = async (serverConnection, username) => { const users = await serverConnection.getRegisteredUsers(username); for (const [id, name] of users) { if (name === username) return { exists: true, userId: id }; } return { exists: false, userId: null }; }; /* ============================ Register single user ============================ */ const addSingleUser = async (serverConnection, user) => { const existing = await userExists(serverConnection, user.name); if (existing.exists) return existing.userId; const info = new Map(); info.set(MumbleServer.UserInfo.UserName, user.name); if (user.email) info.set(MumbleServer.UserInfo.UserEmail, user.email); if (user.password) info.set(MumbleServer.UserInfo.UserPassword, user.password); const userId = await serverConnection.registerUser(info); console.log(`✅ Registered ${user.name} (ID ${userId})`); return userId; }; /* ============================ MAIN addUser ============================ */ const addUser = async (serverConnection, users, options = {}) => { const { companies = [] } = options; const input = Array.isArray(users) ? users : [users]; // Track users per company const companyUsersMap = new Map(); for (const user of input) { if (!user.name || !user.company_name) { console.warn("⚠️ User missing name or company_name", user); continue; } const company = companies.find((c) => c.name === user.company_name); if (!company) { console.warn(`⚠️ Company not found: ${user.company_name}`); continue; } const userId = await addSingleUser(serverConnection, user); if (!companyUsersMap.has(company.id)) { companyUsersMap.set(company.id, { company, users: [], admins: [], }); } const entry = { userId, userName: user.name }; if (user.role === "company_admin") { companyUsersMap.get(company.id).admins.push(entry); } else { companyUsersMap.get(company.id).users.push(entry); } } /* ============================ Apply ACLs per company channel IMPORTANT: Apply ACLs to channels for companies we're adding users to. When setACL is called, it REPLACES the entire ACL and group membership, so only the users we specify will be in the groups. All other users will be denied by the "deny all" rule, making channels invisible to them. ============================ */ for (const { company, users, admins } of companyUsersMap.values()) { const channelId = await getCompanyChannelId(serverConnection, company.name); if (!channelId) { console.warn(`⚠️ Channel not found for company: ${company.name}`); continue; } // Apply ACL to this company's channel // This will: // 1. Deny ALL users (including PermissionTraverse = visibility) // 2. Allow ONLY users in this company's groups to see the channel // Users from other companies will NOT be in these groups, so they'll be denied await applyCompanyACL( serverConnection, channelId, company.id, users, admins ); } console.log("🎯 All users assigned & channels isolated correctly"); }; /* ============================ Delete / Update ============================ */ const deleteUser = async (serverConnection, userId) => { await serverConnection.unregisterUser(userId); }; const getUserId = async (serverConnection, username) => { const users = await serverConnection.getRegisteredUsers(username); for (const [id, name] of users) { if (name === username) return id; } return null; }; const updateUserInformation = async (serverConnection, userId, updates) => { const info = await serverConnection.getRegistration(userId); if (updates.name) info.set(MumbleServer.UserInfo.UserName, updates.name); if (updates.email) info.set(MumbleServer.UserInfo.UserEmail, updates.email); if (updates.password) info.set(MumbleServer.UserInfo.UserPassword, updates.password); await serverConnection.updateRegistration(userId, info); }; export { userExists, addUser, addSingleUser, deleteUser, updateUserInformation, getUserId, }; ``` ### Mumble version 1.4 ### Mumble component Server ### OS Windows ### Additional information _No response_
deekerman 2026-02-20 22:17:56 -05:00
  • closed this issue
  • added the
    support
    label
Author
Owner

@Krzmbrzl commented on GitHub (Jan 10, 2026):

There is no way to do that. If you want different sets of users to only see specific channels, I recommend using different servers in the first place.

Related: #3057

@Krzmbrzl commented on GitHub (Jan 10, 2026): There is no way to do that. If you want different sets of users to only see specific channels, I recommend using different servers in the first place. Related: #3057
Author
Owner

@Nablusi commented on GitHub (Jan 11, 2026):

@Krzmbrzl
I tried to create five servers, each with its own port.
Here are the Docker commands I ran, which I repeated for each server, changing the port accordingly

docker run -d `
  --name murmur_c1 `
  -p 64738:64738/tcp `
  -p 64738:64738/udp `
  -p 6502:6502/tcp `
  -v ./mumble_data/c1:/data `
  -e MUMBLE_CUSTOM_CONFIG_FILE=/data/mumble-server-custom.ini `
  mumblevoip/mumble-server:latest

its creates two files

# Murmur Server Configuration
serverpassword=supersecret123
port=64738
users=100
welcometext="<br />Welcome to Company 1 Mumble Server!<br />Enjoy your stay!<br />"

# ICE Configuration
ice=tcp -h 0.0.0.0 -p 6502
icesecretwrite=iceSuperSecret123
icesecretread=iceSuperSecret123

# Database
database=/data/mumble-server-company1.sqlite

[Ice]
Ice.Warn.UnknownProperties=1
Ice.MessageSizeMax=65536

certrequired=true
allowunregistered=false

Mumble Server.PublishedEndpoints=tcp -h 127.0.0.1 -p 6502


import { Ice } from "@zeroc/ice";
import { MumbleServer } from "../ICEBACKENDSERVER/MumbleServer.js";
import process from "node:process";

import fs from "fs";
import { fileURLToPath } from "url";
import { dirname, join } from "path";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// Load companies
const data = JSON.parse(
  fs.readFileSync(join(__dirname, "..", "users.json"), "utf8")
);
const { companies } = data;

const communicator = new Ice.Communicator(process.argv);

const ICE_SECRET = "iceSuperSecret123";
const BASE_ICE_PORT = 6502;

// Map: companyId -> { meta, icePort, companyName }
const metaMap = new Map();

// Initialize a separate Meta proxy per company
companies.forEach((company, index) => {
  const icePort = BASE_ICE_PORT + index;

  let meta = new MumbleServer.MetaPrx(
    communicator,
    `Meta:tcp -h 127.0.0.1 -p ${icePort}`
  );

  console.log(icePort);
  meta = meta.ice_context(new Map([["secret", ICE_SECRET]]));

  metaMap.set(company.id, {
    meta,
    icePort,
    companyName: company.name,
  });
});

// Helper to get Meta by company ID
function getMeta(companyId) {
  const entry = metaMap.get(companyId);
  if (!entry) {
    throw new Error(`No Murmur server found for company ${companyId}`);
  }
  return entry.meta;
}

export { communicator, getMeta, metaMap };

import { getMeta, metaMap } from "../client.js";

const ICE_SECRET = "iceSuperSecret123";

// Check all company servers
async function checkAllServersStatus() {
  console.log("\n🔍 Checking status of all servers...\n");

  let totalRunning = 0;
  let totalErrors = 0;

  for (const [companyId, { meta, icePort, companyName }] of metaMap) {
    try {
      const bootedServers = await meta.getBootedServers();
      const allServers = await meta.getAllServers();

      console.log(
        `📋 Company ${companyId} (${companyName}) - Port: ${icePort}`
      );
      console.log(`   Total servers: ${allServers.length}`);
      console.log(`   Running servers: ${bootedServers.length}`);

      if (bootedServers.length > 0) {
        totalRunning += bootedServers.length;
        for (const server of bootedServers) {
          const serverWithSecret = server.ice_context(
            new Map([["secret", ICE_SECRET]])
          );
          const serverId = await serverWithSecret.id();
          const serverName = await serverWithSecret.getConf("name");
          const isRunning = await serverWithSecret.isRunning();
          console.log(
            `   ✅ Server ID ${serverId} (${serverName || "Not set"}) - ${
              isRunning ? "RUNNING" : "STOPPED"
            }`
          );
        }
      } else {
        console.log(`   ❌ No servers running`);
      }
      console.log();
    } catch (error) {
      totalErrors++;
      console.log(
        `⚠️  Company ${companyId} (${companyName}) - ERROR: ${
          error.message || error.toString()
        } (Port: ${icePort})\n`
      );
    }
  }

  console.log("=".repeat(60));
  console.log(`✅ Total running servers: ${totalRunning}`);
  console.log(`⚠️  Total errors: ${totalErrors}`);
  console.log("=".repeat(60) + "\n");
}

// Check all servers
await checkAllServersStatus();


The issue is one server is running and the the other one is not

here is result

node createServers.js --Ice.Trace.Network=3 --Ice.Trace.Protocol=1
6502
6503
6504
6505
6506

🔍 Checking status of all servers...

-- 1/11/2026, 11:20:05.283 Network: trying to establish tcp connection to 127.0.0.1:6502
-- 1/11/2026, 11:20:05.312 Network: received 14 of 14 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.313 Protocol: received validate connection
   message type = 3 (validate connection)
   compression status = 0 (not compressed; do not compress response, if any)
   message size = 14
   transport = tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.314 Network: established tcp connection
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.316 Protocol: sending request
   message type = 0 (request)
   compression status = 0 (not compressed; do not compress response, if any)
   message size = 75
   request id = 1
   identity = Meta
   facet =
   operation = getBootedServers
   mode = 2 (idempotent)
   context = secret/iceSuperSecret123
   encoding = 1.1
   transport = tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.317 Network: sent 75 of 75 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.319 Network: received 14 of 14 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.320 Network: received 51 of 51 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.320 Protocol: received reply
   message type = 2 (reply)
   compression status = 0 (not compressed; do not compress response, if any)
   message size = 65
   request id = 1
   reply status = Ok
   encoding = 1.1
   transport = tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.322 Protocol: sending request
   message type = 0 (request)
   compression status = 0 (not compressed; do not compress response, if any)
   message size = 72
   request id = 2
   identity = Meta
   facet =
   operation = getAllServers
   mode = 2 (idempotent)
   context = secret/iceSuperSecret123
   encoding = 1.1
   transport = tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.322 Network: sent 72 of 72 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.326 Network: received 14 of 14 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.326 Network: received 51 of 51 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.327 Protocol: received reply
   message type = 2 (reply)
   compression status = 0 (not compressed; do not compress response, if any)
   message size = 65
   request id = 2
   reply status = Ok
   encoding = 1.1
   transport = tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
📋 Company 1 (Company 1) - Port: 6502
   Total servers: 1
   Running servers: 1
-- 1/11/2026, 11:20:05.328 Protocol: sending request 
   message type = 0 (request)
   compression status = 0 (not compressed; do not compress response, if any)
   message size = 59
   request id = 3
   identity = s/1
   facet =
   operation = id
   mode = 2 (idempotent)
   context = secret/iceSuperSecret123
   encoding = 1.1
   transport = tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.329 Network: sent 59 of 59 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.332 Network: received 14 of 14 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.332 Network: received 15 of 15 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.333 Protocol: received reply
   message type = 2 (reply)
   compression status = 0 (not compressed; do not compress response, if any)
   message size = 29
   request id = 3
   reply status = Ok
   encoding = 1.1
   transport = tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.334 Protocol: sending request
   message type = 0 (request)
   compression status = 0 (not compressed; do not compress response, if any)
   message size = 69
   request id = 4
   identity = s/1
   facet =
   operation = getConf
   mode = 2 (idempotent)
   context = secret/iceSuperSecret123
   encoding = 1.1
   transport = tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.334 Network: sent 69 of 69 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.339 Network: received 14 of 14 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.339 Network: received 12 of 12 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.340 Protocol: received reply
   message type = 2 (reply)
   compression status = 0 (not compressed; do not compress response, if any)
   message size = 26
   request id = 4
   reply status = Ok
   encoding = 1.1
   transport = tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.341 Protocol: sending request
   message type = 0 (request)
   compression status = 0 (not compressed; do not compress response, if any)
   message size = 66
   request id = 5
   identity = s/1
   facet =
   operation = isRunning
   mode = 2 (idempotent)
   context = secret/iceSuperSecret123
   encoding = 1.1
   transport = tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.341 Network: sent 66 of 66 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.342 Network: received 14 of 14 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.343 Network: received 12 of 12 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:05.343 Protocol: received reply
   message type = 2 (reply)
   compression status = 0 (not compressed; do not compress response, if any)
   message size = 26
   request id = 5
   reply status = Ok
   encoding = 1.1
   transport = tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
   ✅ Server ID 1 (Not set) - RUNNING

-- 1/11/2026, 11:20:05.344 Network: trying to establish tcp connection to 127.0.0.1:6503
-- 1/11/2026, 11:20:05.348 Network: closed tcp connection
   local address = 127.0.0.1:62218
   remote address = 127.0.0.1:6503
   Ice.ConnectionLostException
-- 1/11/2026, 11:20:05.349 Network: connection to endpoint failed and no more endpoints to try
   Ice.ConnectionLostException
-- 1/11/2026, 11:20:05.359 Network: trying to establish tcp connection to 127.0.0.1:6503
-- 1/11/2026, 11:20:05.363 Network: closed tcp connection
   local address = 127.0.0.1:62219
   remote address = 127.0.0.1:6503
   Ice.ConnectionLostException
-- 1/11/2026, 11:20:05.363 Network: connection to endpoint failed and no more endpoints to try
   Ice.ConnectionLostException
⚠️  Company 2 (Company 2) - ERROR: Ice.ConnectionLostException (Port: 6503)

-- 1/11/2026, 11:20:05.364 Network: trying to establish tcp connection to 127.0.0.1:6504
-- 1/11/2026, 11:20:05.368 Network: closed tcp connection
   local address = 127.0.0.1:62220
   remote address = 127.0.0.1:6504
   Ice.ConnectionLostException
-- 1/11/2026, 11:20:05.368 Network: connection to endpoint failed and no more endpoints to try
   Ice.ConnectionLostException
-- 1/11/2026, 11:20:05.375 Network: trying to establish tcp connection to 127.0.0.1:6504
-- 1/11/2026, 11:20:05.378 Network: closed tcp connection
   local address = 127.0.0.1:62221
   remote address = 127.0.0.1:6504
   Ice.ConnectionLostException
-- 1/11/2026, 11:20:05.378 Network: connection to endpoint failed and no more endpoints to try
   Ice.ConnectionLostException
⚠️  Company 3 (Company 3) - ERROR: Ice.ConnectionLostException (Port: 6504)

-- 1/11/2026, 11:20:05.379 Network: trying to establish tcp connection to 127.0.0.1:6505
-- 1/11/2026, 11:20:05.382 Network: closed tcp connection
   local address = 127.0.0.1:62222
   remote address = 127.0.0.1:6505
   Ice.ConnectionLostException
-- 1/11/2026, 11:20:05.383 Network: connection to endpoint failed and no more endpoints to try
   Ice.ConnectionLostException
-- 1/11/2026, 11:20:05.390 Network: trying to establish tcp connection to 127.0.0.1:6505
-- 1/11/2026, 11:20:05.393 Network: closed tcp connection
   local address = 127.0.0.1:62223
   remote address = 127.0.0.1:6505
   Ice.ConnectionLostException
-- 1/11/2026, 11:20:05.393 Network: connection to endpoint failed and no more endpoints to try
   Ice.ConnectionLostException
⚠️  Company 4 (Company 4) - ERROR: Ice.ConnectionLostException (Port: 6505)

-- 1/11/2026, 11:20:05.394 Network: trying to establish tcp connection to 127.0.0.1:6506
-- 1/11/2026, 11:20:05.397 Network: closed tcp connection
   local address = 127.0.0.1:62224
   remote address = 127.0.0.1:6506
   Ice.ConnectionLostException
-- 1/11/2026, 11:20:05.398 Network: connection to endpoint failed and no more endpoints to try
   Ice.ConnectionLostException
-- 1/11/2026, 11:20:05.405 Network: trying to establish tcp connection to 127.0.0.1:6506
-- 1/11/2026, 11:20:05.408 Network: closed tcp connection
   local address = 127.0.0.1:62225
   remote address = 127.0.0.1:6506
   Ice.ConnectionLostException
-- 1/11/2026, 11:20:05.408 Network: connection to endpoint failed and no more endpoints to try
   Ice.ConnectionLostException
⚠️  Company 5 (Company 5) - ERROR: Ice.ConnectionLostException (Port: 6506)

============================================================
✅ Total running servers: 1
⚠️  Total errors: 4
============================================================

-- 1/11/2026, 11:20:35.347 Protocol: sending validate connection 
   message type = 3 (validate connection)
   compression status = 0 (not compressed; do not compress response, if any)
   message size = 14
   transport = tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:35.348 Network: sent 14 of 14 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:35.659 Protocol: sending close connection 
   message type = 4 (close connection)
   compression status = 0 (not compressed; do not compress response, if any)
   message size = 14
   transport = tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:35.660 Network: sent 14 of 14 bytes via tcp
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
-- 1/11/2026, 11:20:35.663 Network: closed tcp connection
   local address = 127.0.0.1:62217
   remote address = 127.0.0.1:6502
   Ice.ConnectionClosedException: connection closed because it remained inactive for longer than the inactivity timeout


Can you help me figure out the issue? Like why is just one server is running

@Nablusi commented on GitHub (Jan 11, 2026): @Krzmbrzl I tried to create five servers, each with its own port. Here are the Docker commands I ran, which I repeated for each server, changing the port accordingly ```bash docker run -d ` --name murmur_c1 ` -p 64738:64738/tcp ` -p 64738:64738/udp ` -p 6502:6502/tcp ` -v ./mumble_data/c1:/data ` -e MUMBLE_CUSTOM_CONFIG_FILE=/data/mumble-server-custom.ini ` mumblevoip/mumble-server:latest ``` its creates two files ```mumble-server-custom.ini # Murmur Server Configuration serverpassword=supersecret123 port=64738 users=100 welcometext="<br />Welcome to Company 1 Mumble Server!<br />Enjoy your stay!<br />" # ICE Configuration ice=tcp -h 0.0.0.0 -p 6502 icesecretwrite=iceSuperSecret123 icesecretread=iceSuperSecret123 # Database database=/data/mumble-server-company1.sqlite [Ice] Ice.Warn.UnknownProperties=1 Ice.MessageSizeMax=65536 certrequired=true allowunregistered=false Mumble Server.PublishedEndpoints=tcp -h 127.0.0.1 -p 6502 ``` ```client.js import { Ice } from "@zeroc/ice"; import { MumbleServer } from "../ICEBACKENDSERVER/MumbleServer.js"; import process from "node:process"; import fs from "fs"; import { fileURLToPath } from "url"; import { dirname, join } from "path"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Load companies const data = JSON.parse( fs.readFileSync(join(__dirname, "..", "users.json"), "utf8") ); const { companies } = data; const communicator = new Ice.Communicator(process.argv); const ICE_SECRET = "iceSuperSecret123"; const BASE_ICE_PORT = 6502; // Map: companyId -> { meta, icePort, companyName } const metaMap = new Map(); // Initialize a separate Meta proxy per company companies.forEach((company, index) => { const icePort = BASE_ICE_PORT + index; let meta = new MumbleServer.MetaPrx( communicator, `Meta:tcp -h 127.0.0.1 -p ${icePort}` ); console.log(icePort); meta = meta.ice_context(new Map([["secret", ICE_SECRET]])); metaMap.set(company.id, { meta, icePort, companyName: company.name, }); }); // Helper to get Meta by company ID function getMeta(companyId) { const entry = metaMap.get(companyId); if (!entry) { throw new Error(`No Murmur server found for company ${companyId}`); } return entry.meta; } export { communicator, getMeta, metaMap }; ``` ```createServers.js import { getMeta, metaMap } from "../client.js"; const ICE_SECRET = "iceSuperSecret123"; // Check all company servers async function checkAllServersStatus() { console.log("\n🔍 Checking status of all servers...\n"); let totalRunning = 0; let totalErrors = 0; for (const [companyId, { meta, icePort, companyName }] of metaMap) { try { const bootedServers = await meta.getBootedServers(); const allServers = await meta.getAllServers(); console.log( `📋 Company ${companyId} (${companyName}) - Port: ${icePort}` ); console.log(` Total servers: ${allServers.length}`); console.log(` Running servers: ${bootedServers.length}`); if (bootedServers.length > 0) { totalRunning += bootedServers.length; for (const server of bootedServers) { const serverWithSecret = server.ice_context( new Map([["secret", ICE_SECRET]]) ); const serverId = await serverWithSecret.id(); const serverName = await serverWithSecret.getConf("name"); const isRunning = await serverWithSecret.isRunning(); console.log( ` ✅ Server ID ${serverId} (${serverName || "Not set"}) - ${ isRunning ? "RUNNING" : "STOPPED" }` ); } } else { console.log(` ❌ No servers running`); } console.log(); } catch (error) { totalErrors++; console.log( `⚠️ Company ${companyId} (${companyName}) - ERROR: ${ error.message || error.toString() } (Port: ${icePort})\n` ); } } console.log("=".repeat(60)); console.log(`✅ Total running servers: ${totalRunning}`); console.log(`⚠️ Total errors: ${totalErrors}`); console.log("=".repeat(60) + "\n"); } // Check all servers await checkAllServersStatus(); ``` The issue is one server is running and the the other one is not here is result ```bash node createServers.js --Ice.Trace.Network=3 --Ice.Trace.Protocol=1 6502 6503 6504 6505 6506 🔍 Checking status of all servers... -- 1/11/2026, 11:20:05.283 Network: trying to establish tcp connection to 127.0.0.1:6502 -- 1/11/2026, 11:20:05.312 Network: received 14 of 14 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.313 Protocol: received validate connection message type = 3 (validate connection) compression status = 0 (not compressed; do not compress response, if any) message size = 14 transport = tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.314 Network: established tcp connection local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.316 Protocol: sending request message type = 0 (request) compression status = 0 (not compressed; do not compress response, if any) message size = 75 request id = 1 identity = Meta facet = operation = getBootedServers mode = 2 (idempotent) context = secret/iceSuperSecret123 encoding = 1.1 transport = tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.317 Network: sent 75 of 75 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.319 Network: received 14 of 14 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.320 Network: received 51 of 51 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.320 Protocol: received reply message type = 2 (reply) compression status = 0 (not compressed; do not compress response, if any) message size = 65 request id = 1 reply status = Ok encoding = 1.1 transport = tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.322 Protocol: sending request message type = 0 (request) compression status = 0 (not compressed; do not compress response, if any) message size = 72 request id = 2 identity = Meta facet = operation = getAllServers mode = 2 (idempotent) context = secret/iceSuperSecret123 encoding = 1.1 transport = tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.322 Network: sent 72 of 72 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.326 Network: received 14 of 14 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.326 Network: received 51 of 51 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.327 Protocol: received reply message type = 2 (reply) compression status = 0 (not compressed; do not compress response, if any) message size = 65 request id = 2 reply status = Ok encoding = 1.1 transport = tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 📋 Company 1 (Company 1) - Port: 6502 Total servers: 1 Running servers: 1 -- 1/11/2026, 11:20:05.328 Protocol: sending request message type = 0 (request) compression status = 0 (not compressed; do not compress response, if any) message size = 59 request id = 3 identity = s/1 facet = operation = id mode = 2 (idempotent) context = secret/iceSuperSecret123 encoding = 1.1 transport = tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.329 Network: sent 59 of 59 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.332 Network: received 14 of 14 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.332 Network: received 15 of 15 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.333 Protocol: received reply message type = 2 (reply) compression status = 0 (not compressed; do not compress response, if any) message size = 29 request id = 3 reply status = Ok encoding = 1.1 transport = tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.334 Protocol: sending request message type = 0 (request) compression status = 0 (not compressed; do not compress response, if any) message size = 69 request id = 4 identity = s/1 facet = operation = getConf mode = 2 (idempotent) context = secret/iceSuperSecret123 encoding = 1.1 transport = tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.334 Network: sent 69 of 69 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.339 Network: received 14 of 14 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.339 Network: received 12 of 12 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.340 Protocol: received reply message type = 2 (reply) compression status = 0 (not compressed; do not compress response, if any) message size = 26 request id = 4 reply status = Ok encoding = 1.1 transport = tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.341 Protocol: sending request message type = 0 (request) compression status = 0 (not compressed; do not compress response, if any) message size = 66 request id = 5 identity = s/1 facet = operation = isRunning mode = 2 (idempotent) context = secret/iceSuperSecret123 encoding = 1.1 transport = tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.341 Network: sent 66 of 66 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.342 Network: received 14 of 14 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.343 Network: received 12 of 12 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:05.343 Protocol: received reply message type = 2 (reply) compression status = 0 (not compressed; do not compress response, if any) message size = 26 request id = 5 reply status = Ok encoding = 1.1 transport = tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 ✅ Server ID 1 (Not set) - RUNNING -- 1/11/2026, 11:20:05.344 Network: trying to establish tcp connection to 127.0.0.1:6503 -- 1/11/2026, 11:20:05.348 Network: closed tcp connection local address = 127.0.0.1:62218 remote address = 127.0.0.1:6503 Ice.ConnectionLostException -- 1/11/2026, 11:20:05.349 Network: connection to endpoint failed and no more endpoints to try Ice.ConnectionLostException -- 1/11/2026, 11:20:05.359 Network: trying to establish tcp connection to 127.0.0.1:6503 -- 1/11/2026, 11:20:05.363 Network: closed tcp connection local address = 127.0.0.1:62219 remote address = 127.0.0.1:6503 Ice.ConnectionLostException -- 1/11/2026, 11:20:05.363 Network: connection to endpoint failed and no more endpoints to try Ice.ConnectionLostException ⚠️ Company 2 (Company 2) - ERROR: Ice.ConnectionLostException (Port: 6503) -- 1/11/2026, 11:20:05.364 Network: trying to establish tcp connection to 127.0.0.1:6504 -- 1/11/2026, 11:20:05.368 Network: closed tcp connection local address = 127.0.0.1:62220 remote address = 127.0.0.1:6504 Ice.ConnectionLostException -- 1/11/2026, 11:20:05.368 Network: connection to endpoint failed and no more endpoints to try Ice.ConnectionLostException -- 1/11/2026, 11:20:05.375 Network: trying to establish tcp connection to 127.0.0.1:6504 -- 1/11/2026, 11:20:05.378 Network: closed tcp connection local address = 127.0.0.1:62221 remote address = 127.0.0.1:6504 Ice.ConnectionLostException -- 1/11/2026, 11:20:05.378 Network: connection to endpoint failed and no more endpoints to try Ice.ConnectionLostException ⚠️ Company 3 (Company 3) - ERROR: Ice.ConnectionLostException (Port: 6504) -- 1/11/2026, 11:20:05.379 Network: trying to establish tcp connection to 127.0.0.1:6505 -- 1/11/2026, 11:20:05.382 Network: closed tcp connection local address = 127.0.0.1:62222 remote address = 127.0.0.1:6505 Ice.ConnectionLostException -- 1/11/2026, 11:20:05.383 Network: connection to endpoint failed and no more endpoints to try Ice.ConnectionLostException -- 1/11/2026, 11:20:05.390 Network: trying to establish tcp connection to 127.0.0.1:6505 -- 1/11/2026, 11:20:05.393 Network: closed tcp connection local address = 127.0.0.1:62223 remote address = 127.0.0.1:6505 Ice.ConnectionLostException -- 1/11/2026, 11:20:05.393 Network: connection to endpoint failed and no more endpoints to try Ice.ConnectionLostException ⚠️ Company 4 (Company 4) - ERROR: Ice.ConnectionLostException (Port: 6505) -- 1/11/2026, 11:20:05.394 Network: trying to establish tcp connection to 127.0.0.1:6506 -- 1/11/2026, 11:20:05.397 Network: closed tcp connection local address = 127.0.0.1:62224 remote address = 127.0.0.1:6506 Ice.ConnectionLostException -- 1/11/2026, 11:20:05.398 Network: connection to endpoint failed and no more endpoints to try Ice.ConnectionLostException -- 1/11/2026, 11:20:05.405 Network: trying to establish tcp connection to 127.0.0.1:6506 -- 1/11/2026, 11:20:05.408 Network: closed tcp connection local address = 127.0.0.1:62225 remote address = 127.0.0.1:6506 Ice.ConnectionLostException -- 1/11/2026, 11:20:05.408 Network: connection to endpoint failed and no more endpoints to try Ice.ConnectionLostException ⚠️ Company 5 (Company 5) - ERROR: Ice.ConnectionLostException (Port: 6506) ============================================================ ✅ Total running servers: 1 ⚠️ Total errors: 4 ============================================================ -- 1/11/2026, 11:20:35.347 Protocol: sending validate connection message type = 3 (validate connection) compression status = 0 (not compressed; do not compress response, if any) message size = 14 transport = tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:35.348 Network: sent 14 of 14 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:35.659 Protocol: sending close connection message type = 4 (close connection) compression status = 0 (not compressed; do not compress response, if any) message size = 14 transport = tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:35.660 Network: sent 14 of 14 bytes via tcp local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 -- 1/11/2026, 11:20:35.663 Network: closed tcp connection local address = 127.0.0.1:62217 remote address = 127.0.0.1:6502 Ice.ConnectionClosedException: connection closed because it remained inactive for longer than the inactivity timeout ``` Can you help me figure out the issue? Like why is just one server is running
Author
Owner

@Krzmbrzl commented on GitHub (Jan 11, 2026):

Are all servers using the same Ice endpoint (from the config file)? That could be the issue as only one of the serves will succeed to create the endpoint.

However, you don't have to spin up multiple server instances. You can use a single instance to host multiple virtual Mumble servers. You an use Ice to spin up and control more servers as needed

@Krzmbrzl commented on GitHub (Jan 11, 2026): Are all servers using the same Ice endpoint (from the config file)? That could be the issue as only one of the serves will succeed to create the endpoint. However, you don't have to spin up multiple server instances. You can use a single instance to host multiple virtual Mumble servers. You an use Ice to spin up and control more servers as needed
Author
Owner

@Nablusi commented on GitHub (Jan 11, 2026):

@Krzmbrzl

The issue I’m facing is not with server creation, but with accessing or testing the other servers. I always end up entering only the first company’s server.
maybe I am missing something, if u could help with this issue

Image
@Nablusi commented on GitHub (Jan 11, 2026): @Krzmbrzl The issue I’m facing is not with server creation, but with accessing or testing the other servers. I always end up entering only the first company’s server. maybe I am missing something, if u could help with this issue <img width="928" height="773" alt="Image" src="https://github.com/user-attachments/assets/de6735c1-b868-409c-8cf4-3d12d53d46e3" />
Author
Owner

@Krzmbrzl commented on GitHub (Jan 11, 2026):

The individual servers will be served at consecutive ports (by default). So if the first virtual server is configured to bind to port 64738, the next virtual server should be on 64739, then 64740 and so on. If one of those ports is already taken, the next port will be attempted. You can check the respective virtual server's log - it should contain a message telling you which port it has bound to (the port should also be queriable via Ice, I believe)

@Krzmbrzl commented on GitHub (Jan 11, 2026): The individual servers will be served at consecutive ports (by default). So if the first virtual server is configured to bind to port `64738`, the next virtual server should be on `64739`, then `64740` and so on. If one of those ports is already taken, the next port will be attempted. You can check the respective virtual server's log - it should contain a message telling you which port it has bound to (the port should also be queriable via Ice, I believe)
Author
Owner

@Nablusi commented on GitHub (Jan 12, 2026):

@Krzmbrzl
I believe that, in my case, the best approach is to build virtual servers for each company. I have already built a backend to support this architecture.

Assuming a scenario with 100 companies and approximately 1,000 active users, do you know how I can calculate the required resource consumption (CPU, memory, network, and storage)? Additionally, is there any official documentation that explains how to calculate these requirements theoretically?

@Nablusi commented on GitHub (Jan 12, 2026): @Krzmbrzl I believe that, in my case, the best approach is to build virtual servers for each company. I have already built a backend to support this architecture. Assuming a scenario with 100 companies and approximately 1,000 active users, do you know how I can calculate the required resource consumption (CPU, memory, network, and storage)? Additionally, is there any official documentation that explains how to calculate these requirements theoretically?
Author
Owner

@Krzmbrzl commented on GitHub (Jan 12, 2026):

know how I can calculate the required resource consumption (CPU, memory, network, and storage)? Additionally, is there any official documentation that explains how to calculate these requirements theoretically?

No

My guess would be to use whatever a single server of that size needs and multiply it by 100. However, I don't think there is a general way to compute resource usage of a server (it depends hugely on how exactly you use the server).

That being said, I have doubts that hosting all 100 servers on a single machine (which is what you'd need to do if you wanted them all to be virtual servers of a single Mumble instance) with 1000 users each will work out great. If all users are speaking you have voice packets of ~100k people, which will be an enormous bandwidth (and processing) requirement…

@Krzmbrzl commented on GitHub (Jan 12, 2026): > know how I can calculate the required resource consumption (CPU, memory, network, and storage)? Additionally, is there any official documentation that explains how to calculate these requirements theoretically? No My guess would be to use whatever a single server of that size needs and multiply it by 100. However, I don't think there is a general way to compute resource usage of a server (it depends hugely on how exactly you use the server). That being said, I have doubts that hosting all 100 servers on a single machine (which is what you'd need to do if you wanted them all to be virtual servers of a single Mumble instance) with 1000 users each will work out great. If all users are speaking you have voice packets of ~100k people, which will be an enormous bandwidth (and processing) requirement…
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/mumble-mumble-voip#3092
No description provided.