Configuration
Full reference for config.json and all REALM_ environment variables.
The server reads config from a config.json file and/or REALM_-prefixed environment variables. Environment variables always take priority over config.json.
Config file
Create a config.json in the same directory as your Compose file:
{
"identity": {
"name": "My Realm Server",
"description": "A community server",
"publicHost": "my-server.example.com",
"password": null
},
"coreApi": {
"baseUrl": "https://api.realmvoice.app"
},
"storage": {
"mongoUrl": "mongodb://mongo:27017/realm_dedicated"
},
"voice": {
"rtpMin": 40000,
"rtpMax": 49999
},
"webrtc": {
"listenIp": "0.0.0.0",
"announcedIp": null
},
"attachments": {
"provider": "local",
"maxFileSizeMb": 25,
"localPath": "./uploads"
},
"logLevel": "info"
}Mount it into the container:
# docker-compose.server.yml
volumes:
- ./config.json:/app/apps/server/config.json:roIdentity
| Field | Env var | Default | Description |
|---|---|---|---|
identity.name | REALM_IDENTITY_NAME | "Realm Server" | Server name shown in the server browser |
identity.description | REALM_IDENTITY_DESCRIPTION | "" | Optional description |
identity.publicHost | REALM_IDENTITY_PUBLIC_HOST | (auto-detected) | Public hostname/IP clients connect to. Required behind NAT or a reverse proxy |
identity.publicPort | REALM_IDENTITY_PUBLIC_PORT | 5000 | Port clients connect on. Set to 443 when using a reverse proxy |
identity.password | REALM_IDENTITY_PASSWORD | null | Require this password to join. Set to null or omit to allow open access |
Realm API
| Field | Env var | Default | Description |
|---|---|---|---|
coreApi.baseUrl | REALM_CORE_API_BASE_URL | "https://api.realmvoice.app" | URL of the Realm API |
Storage
| Field | Env var | Default | Description |
|---|---|---|---|
storage.mongoUrl | REALM_STORAGE_MONGO_URL | "mongodb://localhost:27017/realm" | Database connection string |
Voice
| Field | Env var | Default | Description |
|---|---|---|---|
voice.rtpMin | REALM_VOICE_RTP_MIN | 40000 | Start of UDP port range for voice media |
voice.rtpMax | REALM_VOICE_RTP_MAX | 49999 | End of UDP port range for voice media |
WebRTC
| Field | Env var | Default | Description |
|---|---|---|---|
webrtc.listenIp | REALM_WEBRTC_LISTEN_IP | "0.0.0.0" | Interface the voice server listens on |
webrtc.announcedIp | REALM_WEBRTC_ANNOUNCED_IP | null | Public IP for voice ICE candidates. Set to your server's public IP or hostname. Required if behind NAT |
webrtc.announcedIp is the most important voice setting. If it's wrong or
missing, voice connections will appear to connect but no audio will flow.
HTTPS / TLS
The web client at realmvoice.app is served over HTTPS, and browsers refuse to open an insecure http:// / ws:// connection from an HTTPS page (a "mixed content" error). So a server must be reachable over https:// for the web client to connect.
You have two options:
- Built-in auto-HTTPS (
tls.enabled). Settls.enabledand apublicHost, then start the bundled Caddy sidecar. Caddy obtains and renews a Let's Encrypt certificate automatically and the server registers itself on port 443. No reverse proxy of your own to configure. - Your own reverse proxy. Terminate TLS with Caddy/nginx/Traefik in front of the server yourself and set
identity.publicPortto443.
Enable the built-in option by opting into the tls Compose profile:
# config.json: { "identity": { "publicHost": "my-server.example.com" }, "tls": { "enabled": true } }
# or: REALM_IDENTITY_PUBLIC_HOST=my-server.example.com REALM_TLS_ENABLED=true
docker compose -f docker-compose.server.yml --profile tls up -dOpen ports 80 and 443 on your firewall (80 is needed for the certificate challenge).
| Field | Env var | Default | Description |
|---|---|---|---|
tls.enabled | REALM_TLS_ENABLED | false | Run the Caddy sidecar and register on the TLS port |
tls.email | REALM_TLS_EMAIL | null | ACME account email for Let's Encrypt expiry notices (optional) |
tls.port | REALM_TLS_PORT | 443 | Public TLS port Caddy listens on and the server registers |
tls.upstream | REALM_TLS_UPSTREAM | realm-server:5000 | Where Caddy reverse-proxies. Change only if you renamed the server service |
A real domain in publicHost is the reliable setup. A bare public IP is
best-effort: it works only if the Caddy image and certificate authority
support IP-address certificates, otherwise the certificate is untrusted. LAN
/ private IPs (192.168.x.x, 10.x.x.x) can never get a browser-trusted
certificate. To use an IP-only server, connect with the desktop app
instead, which is not subject to the browser's mixed-content rule.
Attachments
The server supports image and video attachments in chat. Uploads are stored on the local filesystem by default.
Supported formats: PNG, JPEG, GIF, WebP, SVG, MP4, WebM, MOV
Images are automatically compressed and thumbnailed. Videos are stored as-is with no server-side transcoding.
Local storage (default)
{
"attachments": {
"provider": "local",
"maxFileSizeMb": 25,
"localPath": "./uploads"
}
}The Docker Compose setup mounts a volume at /data which includes the uploads/ directory. Files survive container restarts and updates without any extra configuration.
S3-compatible storage
Use S3 for CDN delivery or if you'd rather not store files on disk:
{
"attachments": {
"provider": "s3",
"maxFileSizeMb": 50,
"s3": {
"bucket": "my-realm-uploads",
"region": "us-east-1",
"endpoint": "https://abc123.r2.cloudflarestorage.com",
"accessKeyId": "AKIA...",
"secretAccessKey": "wJal..."
}
}
}Or via environment variables:
REALM_ATTACHMENTS_PROVIDER=s3
REALM_ATTACHMENTS_S3_BUCKET=my-realm-uploads
REALM_ATTACHMENTS_S3_REGION=us-east-1
REALM_ATTACHMENTS_S3_ENDPOINT=https://abc123.r2.cloudflarestorage.com
REALM_ATTACHMENTS_S3_ACCESS_KEY_ID=AKIA...
REALM_ATTACHMENTS_S3_SECRET_ACCESS_KEY=wJal...Compatible with Cloudflare R2, MinIO, and AWS S3. For R2 and MinIO, set endpoint to the custom endpoint URL.
| Field | Env var | Default | Description |
|---|---|---|---|
attachments.provider | REALM_ATTACHMENTS_PROVIDER | "local" | "local" or "s3" |
attachments.maxFileSizeMb | REALM_ATTACHMENTS_MAX_FILE_SIZE_MB | 25 | Max upload size per file in MB (1-100) |
attachments.localPath | REALM_ATTACHMENTS_LOCAL_PATH | "./uploads" | Directory for local storage |
attachments.s3.bucket | REALM_ATTACHMENTS_S3_BUCKET | null | S3 bucket name |
attachments.s3.region | REALM_ATTACHMENTS_S3_REGION | null | AWS region (e.g. "us-east-1") |
attachments.s3.endpoint | REALM_ATTACHMENTS_S3_ENDPOINT | null | Custom endpoint for R2/MinIO |
attachments.s3.accessKeyId | REALM_ATTACHMENTS_S3_ACCESS_KEY_ID | null | Access key ID |
attachments.s3.secretAccessKey | REALM_ATTACHMENTS_S3_SECRET_ACCESS_KEY | null | Secret access key |
Logging
| Field | Env var | Default | Description |
|---|---|---|---|
logLevel | REALM_LOG_LEVEL | "info" | fatal, error, warn, info, debug, trace, or silent |
Full environment variable reference
| Env var | Config path | Example |
|---|---|---|
REALM_IDENTITY_NAME | identity.name | "My Server" |
REALM_IDENTITY_DESCRIPTION | identity.description | "A community server" |
REALM_IDENTITY_PUBLIC_HOST | identity.publicHost | "my-server.example.com" |
REALM_IDENTITY_PUBLIC_PORT | identity.publicPort | 443 |
REALM_IDENTITY_PASSWORD | identity.password | "s3cret" |
REALM_CORE_API_BASE_URL | coreApi.baseUrl | "https://api.realmvoice.app" (default) |
REALM_STORAGE_MONGO_URL | storage.mongoUrl | "mongodb://mongo:27017/realm" |
REALM_VOICE_RTP_MIN | voice.rtpMin | 40000 |
REALM_VOICE_RTP_MAX | voice.rtpMax | 49999 |
REALM_WEBRTC_LISTEN_IP | webrtc.listenIp | "0.0.0.0" |
REALM_WEBRTC_ANNOUNCED_IP | webrtc.announcedIp | "203.0.113.42" |
REALM_TLS_ENABLED | tls.enabled | true |
REALM_TLS_EMAIL | tls.email | "[email protected]" |
REALM_TLS_PORT | tls.port | 443 |
REALM_TLS_UPSTREAM | tls.upstream | "realm-server:5000" |
REALM_ATTACHMENTS_PROVIDER | attachments.provider | "local" or "s3" |
REALM_ATTACHMENTS_MAX_FILE_SIZE_MB | attachments.maxFileSizeMb | 25 |
REALM_ATTACHMENTS_LOCAL_PATH | attachments.localPath | "./uploads" |
REALM_ATTACHMENTS_S3_BUCKET | attachments.s3.bucket | "my-realm-uploads" |
REALM_ATTACHMENTS_S3_REGION | attachments.s3.region | "us-east-1" |
REALM_ATTACHMENTS_S3_ENDPOINT | attachments.s3.endpoint | "https://....r2.cloudflarestorage.com" |
REALM_ATTACHMENTS_S3_ACCESS_KEY_ID | attachments.s3.accessKeyId | "AKIA..." |
REALM_ATTACHMENTS_S3_SECRET_ACCESS_KEY | attachments.s3.secretAccessKey | "wJal..." |
REALM_LOG_LEVEL | logLevel | "info" |