Skip to content

Ports & networking

The Fancy Mumble server uses up to four ports. Only the first one is strictly required.

PortProtocolPurposeRequired?
64738TCP and UDPVoice and controlyes
64739TCPFile server - plain HTTP (emotes, avatars, attachments)for file features
64740TCPLive document WebSocket (Yjs CRDT sync)for live documents
10000UDPScreen-share relayfor smooth screen sharing
6502TCPAdmin RPC (Ice)rarely, internal
Server HostFancy Mumble ServerReverse Proxynginx · Traefik · Caddy(optional)TCP/UDP 64738Voice & ControlUDP 10000Screen-share RelayTCP 64739File Server (HTTP)TCP 64740Live-doc WebSocketTCP 6502 Admin RPC(loopback only by default)Push Relay→ FirebaseMumble Clientdesktop / mobileBrowserFirebase Cloud Messaging(optional)Live-doc proxy requires:Upgrade + Connection headersQuery string preserved(JWT in ?token=...)always requiredscreen sharingadmin tools onlyHTTPS 443HTTPS 443HTTP 64739WSS → WS 64740HTTP 64739 (direct, LAN only)WS 64740 (direct, LAN only)HTTP 64739 (direct, LAN only)WS 64740 (direct, LAN only)HTTPS 443

The classic Mumble port. Used for:

  • The initial TLS handshake that authenticates the connection.
  • Control messages (channel updates, chat, user actions).
  • Voice (UDP preferred for low latency, TCP fallback).

This is the only port you absolutely must expose. Without it nobody can connect.

Open both TCP and UDP. Modern routers and firewalls treat them as two distinct rules.

Used for:

  • Uploading and downloading files that were shared in chat.
  • Custom server emote images.
  • Avatar uploads from the profile editor.
  • Link preview images rendered server-side.

The file server speaks plain HTTP - there is no built-in TLS. Traffic on this port is unencrypted unless you put a TLS-terminating reverse proxy in front. For anything beyond a private LAN, a reverse proxy is strongly recommended.

If you skip this port, the paperclip button in chat is hidden and avatars fall back to the older inline-only mode.

You can put a reverse proxy in front (recommended for production) to terminate TLS, add caching, and so on. See File server.

Used for:

  • Real-time CRDT synchronization of shared channel documents via the Yjs protocol.
  • Transporting collaborative cursor positions and awareness updates.

Like the file server, this port speaks plain WebSocket (ws://) with no built-in TLS. Put it behind a TLS-terminating reverse proxy in production so clients reach it as wss://. The live-doc plugin is disabled by default - see Live Documents to enable it.

If this port is unreachable, the “Open Live Doc” button will time out waiting for an invite reply from the server.

Used for:

  • One incoming WebRTC stream from each broadcaster.
  • Many outgoing WebRTC streams to viewers.

Without this port (or without the relay enabled), screen sharing falls back to direct peer-to-peer, which is less reliable behind strict NATs.

Used for:

  • The legacy Ice administrative interface.
  • Third-party authentication scripts.

By default this port is only bound to localhost inside the container. Expose it (and set up authentication) only if you have a specific tool that needs it.

ports:
- "64738:64738/tcp"
- "64738:64738/udp"
- "64739:64739/tcp"
- "64740:64740/tcp" # live documents (optional)
- "10000:10000/udp"
# Only if you need admin RPC from outside the host:
# - "127.0.0.1:6502:6502/tcp"

The screen-share relay needs to advertise a reachable IP address to viewers. Set it with:

environment:
MUMBLE_CONFIG_WEBRTCSFUENABLED: true
MUMBLE_CONFIG_WEBRTCSFUPORT: 10000
MUMBLE_CONFIG_WEBRTCSFUPUBLICIP: "203.0.113.5"
  • For a public server, use the public IP.
  • For a home server with a public DNS, use the IP that DNS resolves to.
  • For local testing, use 127.0.0.1.
  • Do not use 0.0.0.0, it is not a valid candidate and viewers will fail to connect.

You can put the file server (64739) and the live-doc WebSocket (64740) behind nginx, Caddy, or Traefik.

For the file server:

plugin.file-server.tlsTerminatedByProxy=true
plugin.file-server.baseUrl=https://files.example.com
plugin.file-server.allowedOrigins=https://files.example.com

The live-doc plugin is a standard axum HTTP server - the WebSocket connection is a normal HTTP Upgrade. Three things are required for the proxy to work correctly:

RequirementWhy
Strip the /live-doc path prefixThe axum backend serves routes at /ws/… — without stripping, the backend returns 404
Forward Upgrade + Connection headersWithout them the proxy returns HTTP 400 on connect
Preserve the query stringThe handshake JWT is passed as ?token=... and must reach the backend
Set plugin.live-doc.public_urlTells clients the wss:// URL to connect to instead of ws://bind-address:64740

handle_path strips the prefix automatically:

chat.example.com {
handle_path /live-doc/* {
reverse_proxy localhost:64740
}
}

Then in your mumble-server.ini:

plugin.live-doc.public_url=wss://chat.example.com/live-doc

The voice port (64738) cannot easily go behind a generic HTTP proxy since it is a custom binary protocol. Use TCP-level passthrough or a dedicated TLS-terminating load balancer if needed.

If the server is on a home network, forward each port from your router:

  • TCP 64738 to the server.
  • UDP 64738 to the server.
  • TCP 64739 to the server (optional, file server).
  • TCP 64740 to the server (optional, live documents).
  • UDP 10000 to the server (optional, screen-share relay).

For IPv6, open the same ports in the AAAA firewall rules.

For UFW (Ubuntu firewall):

Terminal window
sudo ufw allow 64738/tcp
sudo ufw allow 64738/udp
sudo ufw allow 64739/tcp
sudo ufw allow 64740/tcp
sudo ufw allow 10000/udp

For firewalld (Fedora and friends):

Terminal window
sudo firewall-cmd --add-port=64738/tcp --permanent
sudo firewall-cmd --add-port=64738/udp --permanent
sudo firewall-cmd --add-port=64739/tcp --permanent
sudo firewall-cmd --add-port=64740/tcp --permanent
sudo firewall-cmd --add-port=10000/udp --permanent
sudo firewall-cmd --reload

From another host:

Terminal window
# Voice port (TCP)
nc -zv your-host 64738
# File server (HTTP)
curl -sI https://your-host:64739/healthz | head -1

A Connected to ... (TCP) and a 200 OK (HTTP) mean you are good.

Mumble’s voice bandwidth depends on the audio quality setting chosen by each client. The server sets a cap via bandwidth.

Per-user rules of thumb:

ScenarioBandwidth
Minimum (any packet loss below this)15.8 kbit/s per user
Typical (20 ms packets, ~50 kbit/s quality)65 kbit/s per user
Maximum (10 ms packets, 96 kbit/s quality)134 kbit/s per user

Server-side formula (all speakers in one channel, everyone talking at once - the theoretical worst case):

incoming=quality×users\text{incoming} = \text{quality} \times \text{users} outgoing=quality×(users1)×users\text{outgoing} = \text{quality} \times (\text{users} - 1) \times \text{users} total=incoming+outgoing\text{total} = \text{incoming} + \text{outgoing}

Example: 16 users at 128 kbit/s each, all talking simultaneously:

  • incoming = 128 × 16 = 2 048 kbit/s
  • outgoing = 128 × 15 × 16 = 30 720 kbit/s
  • total = 32 768 kbit/s ≈ 4 MiB/s

In practice, not everyone speaks at once. A realistic 30-user server with a few active channels is usually well under 1 MiB/s.

An SRV record lets users connect with just a domain name - no port required. Fancy Mumble resolves the record automatically when a user types a bare domain into the server address field.

Add this to your DNS zone:

_mumble._tcp.yourdomain.com. 3600 IN SRV 10 0 64738 mumble.yourdomain.com.

The four fields after SRV are: priority (10), weight (0), port (64738), target hostname.

With the record in place, users can type yourdomain.com and the client picks up the correct host and port automatically. Without it they must type mumble.yourdomain.com:64738 explicitly.

Continue with the Feature deep-dives to pick what to enable:

Persistent chat

Encrypted, server-stored chat history. Learn more.

Push notifications

Notify mobile users when the app is closed. Learn more.

Screen-share relay

One upload, many downloads. Learn more.

File server

Emotes, avatars, file uploads. Learn more.