File server
The file server is the part of Fancy Mumble that handles:
- Custom server emote images.
- Chat file attachments (the share dialog).
It is an HTTP service that listens on port 64739 by default. The listener speaks plain HTTP - TLS is not built in. On a private network that is fine; on the public internet, put it behind a TLS-terminating reverse proxy (see Behind a reverse proxy below) so that clients reach it as HTTPS.
Without it, file sharing and custom emotes are unavailable, the buttons are hidden in the app.
Turn it on
Section titled “Turn it on”The Docker image ships with the file server already enabled. The defaults are:
plugin.file-server.enabled=trueplugin.file-server.storagePath=/data/file-server-storageplugin.file-server.bindAddress=0.0.0.0plugin.file-server.port=64739plugin.file-server.tlsTerminatedByProxy=true; plugin.file-server.baseUrl=https://your-domain.example/files; plugin.file-server.allowedOrigins=https://your-domain.exampleWhere does the config file live?
Section titled “Where does the config file live?”On a fresh container started with the official image, the config file is generated at boot under:
/data/mumble_server_config.iniThis is the file the entrypoint script writes whenever you change a
MUMBLE_CONFIG_* environment variable. It is regenerated on every
container start, so editing it directly does not survive a
restart unless you also set MUMBLE_CUSTOM_CONFIG_FILE to point at
a file you own.
To set plugin.* keys for the first time:
-
Copy the sample config out of the image to your host:
Terminal window docker cp mumble-server:/data/mumble_server_config.ini ./mumble-server.iniOr grab the template from the Docker repo at
mumble-server.ini.example. -
Edit the
plugin.file-server.*keys to your taste. -
Mount the file back into the container and tell the entrypoint to use it instead of the env-var-generated one:
environment:MUMBLE_CUSTOM_CONFIG_FILE: /data/mumble-server.inivolumes:- ./mumble-server.ini:/data/mumble-server.ini:ro- mumble-data:/data -
Restart the container:
Terminal window docker compose up -d --force-recreate mumble-server
| Key | Default | Description |
|---|---|---|
plugin.file-server.enabled | true | Master toggle. |
plugin.file-server.storagePath | /data/file-server-storage | Where files live on disk. Must be absolute. |
plugin.file-server.bindAddress | 127.0.0.1 (with safer default in the image) | Address to listen on. Use 0.0.0.0 to expose directly. |
plugin.file-server.port | 64739 | TCP port. |
plugin.file-server.tlsTerminatedByProxy | false | Set to true when a reverse proxy handles TLS. |
plugin.file-server.baseUrl | unset | Public URL clients use. Falls back to http://host:port when empty. |
plugin.file-server.allowedOrigins | unset | Comma-separated CORS origins. Empty blocks browser usage. |
plugin.file-server.maxUploadSizeBytes | 52428800 (50 MB) | Per-file upload limit. |
plugin.file-server.retentionDays | 90 | How long public files live. |
Expose the port
Section titled “Expose the port”In docker-compose.yml:
ports: - "64739:64739/tcp"Without this port exposed externally, the file server is only reachable from inside the container. Useful if you put a reverse proxy in front and only expose the proxy.
Behind a reverse proxy
Section titled “Behind a reverse proxy”Recommended for any deployment reachable from the public internet. The proxy accepts HTTPS from clients and forwards it as plain HTTP to the file server. Tell the file server to trust the proxy headers:
plugin.file-server.tlsTerminatedByProxy=trueplugin.file-server.baseUrl=https://files.example.complugin.file-server.allowedOrigins=https://files.example.comA minimal nginx config:
server { listen 443 ssl http2; server_name files.example.com;
ssl_certificate /etc/letsencrypt/live/files.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/files.example.com/privkey.pem;
client_max_body_size 100m;
location / { proxy_pass http://mumble-server:64739; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }}Storage layout
Section titled “Storage layout”Directory/data/file-server-storage/
Directoryemotes/ custom server emotes, keyed by shortcode
- …
Directoryattachments/ chat attachments
Directorypublic/ public-mode uploads
- …
Directorypassword/ password-protected uploads
- …
Directorysession/ session-only uploads (cleaned up)
- …
- index.sqlite metadata, not file data
Back up the whole file-server-storage folder along with the
mumble-server.sqlite database for a complete backup.
Access modes (recap)
Section titled “Access modes (recap)”When a user uploads a file, they pick one of three modes. See Files and images for the user view.
| Mode | Who can download | Lifetime |
|---|---|---|
| Public | Anyone with the link | retentionDays |
| Password | Anyone with the link AND the password | retentionDays |
| Session | Only currently connected users | A short while after every recipient disconnects |
You can restrict who is allowed to use public/password modes per role. See Permission flags.
Disk usage
Section titled “Disk usage”For a 50-user server, plan for roughly:
- Avatars: 100 KB per user. Negligible.
- Custom emotes: 50 KB per emote, often a few hundred per server.
- Attachments: this is the variable. A busy media-sharing server
can use 10 GB or more per month. Cap with
maxUploadSizeBytesandretentionDays.
Add monitoring on /data/file-server-storage to catch surprises.
Disabling
Section titled “Disabling”plugin.file-server.enabled=falseThe client UI hides the file-attach controls when no
fancy-file-server-config message is received. Existing avatars
and emotes still work as long as the storage directory and database
are intact.
Pitfalls
Section titled “Pitfalls”- Paperclip is missing in chat: the file server is not enabled, or
the client cannot reach the port. Check
curl -I http://server:64739/healthzfrom a client machine. - CORS errors in browser builds: set
allowedOriginsto your web client’s URL. - Uploads fail with 413:
maxUploadSizeBytesis too small, or your reverse proxy’sclient_max_body_sizeis. - Files stay forever:
retentionDays=0is “forever”. Set to a positive number for cleanup.
Next step
Section titled “Next step”Continue with Link previews.