forked from Paroxity/portal
-
Notifications
You must be signed in to change notification settings - Fork 0
Configuration
MEMOxiiii edited this page Sep 17, 2026
·
2 revisions
On first run, Portal generates a config.json file. Here's the full reference.
{
"network": {
"address": ":19132",
"transport": "nethernet",
"nethernet": {
"tls": {
"cert_file": "",
"key_file": ""
},
"ice_servers": [],
"udp_ports": "19133"
},
"flush_rate_ms": 20,
"communication": {
"address": ":19131",
"secret": "",
"tls": {
"enabled": false,
"cert_file": "",
"key_file": ""
}
},
"reader_limits": true
},
"logger": {
"file": "proxy.log",
"level": "info"
},
"player_latency": {
"report": true,
"update_interval": 5
},
"cluster": {
"enabled": false,
"proxy_id": "",
"ttl_seconds": 300,
"redis": {
"address": "localhost:6379",
"password": "",
"db": 0
}
},
"metrics": {
"enabled": false,
"address": ":9131"
},
"security": {
"banned_ips": [],
"rate_limit": {
"enabled": true,
"window_seconds": 10,
"max_attempts": 5
}
},
"health_check": {
"enabled": true,
"interval_seconds": 10,
"timeout_seconds": 3,
"failure_threshold": 3
},
"routing": {
"default_group": "",
"fallback_groups": []
},
"whitelist": {
"enabled": false,
"players": []
},
"resource_packs": {
"required": false,
"directory": "resource_packs",
"encryption_keys": {},
"hot_reload": {
"enabled": false,
"interval": 30
}
},
"motd": "Portal",
"sub_motd": "Transfer Proxy"
}| Key | Description | Default |
|---|---|---|
network.address |
Address players connect to. Meaning depends on network.transport — see NetherNet Transport
|
:19132 |
network.transport |
Player-facing transport: nethernet (default, official) or raknet (legacy UDP). See NetherNet Transport for what changes between the two |
nethernet |
network.nethernet.tls.cert_file / network.nethernet.tls.key_file
|
Optional PEM cert/key to serve the NetherNet signaling endpoint over HTTPS instead of plain HTTP. Only used when network.transport is nethernet
|
"" / ""
|
network.nethernet.ice_servers |
STUN/TURN servers offered to players for WebRTC NAT traversal, as [{"urls": [...], "username": "", "password": ""}]. Only used when network.transport is nethernet — see NetherNet Transport
|
[] |
network.nethernet.udp_ports |
UDP port, or "min-max" range, used for the actual WebRTC game connection. Must be unique on the host — it can't be shared with RakNet's port, Portal's own default, or any backend server's own NetherNet listener running on the same machine. See NetherNet Transport
|
"19133" |
network.flush_rate_ms |
Maximum client-bound packet buffering delay. Lower values reduce relay latency but increase CPU and network writes; 0 uses gophertunnel's default. |
20 |
network.communication.address |
Socket API address for backend servers — see Socket Protocol | :19131 |
network.communication.secret |
Authentication secret (must match backend configs) | "" |
network.communication.tls.enabled |
Serve the communication socket over TLS (backends must dial with TLS too) | false |
network.communication.tls.cert_file |
Path to the PEM encoded TLS certificate | "" |
network.communication.tls.key_file |
Path to the PEM encoded TLS private key | "" |
network.reader_limits |
Enable protocol reader limits | true |
logger.file |
Log file path (empty = no file logging) | proxy.log |
logger.level |
Minimum log level (debug, info, warn, error) |
info |
player_latency.report |
Send player latency to backend servers | true |
player_latency.update_interval |
Latency report interval in seconds | 5 |
metrics.enabled |
Serve Prometheus-style metrics at http://<metrics.address>/metrics
|
false |
metrics.address |
Address the metrics HTTP endpoint listens on | :9131 |
cluster.enabled |
Share player presence with other Portal instances over Redis — see Clustering | false |
cluster.proxy_id |
ID this proxy reports itself as in the cluster. Empty = the machine's hostname | "" |
cluster.ttl_seconds |
How long a player's presence record survives without a refresh before expiring (crash safety net) | 300 |
cluster.redis.address |
Redis server address (host:port) |
localhost:6379 |
cluster.redis.password |
Redis auth password, if required | "" |
cluster.redis.db |
Redis logical database index | 0 |
security.banned_ips |
IP addresses that are always rejected at the player listener | [] |
security.rate_limit.enabled |
Reject an IP once it connects too frequently | true |
security.rate_limit.window_seconds |
Size of the sliding window connection attempts are counted over | 10 |
security.rate_limit.max_attempts |
Max connection attempts allowed per IP within the window | 5 |
health_check.enabled |
Periodically ping registered servers (RakNet unconnected ping, or an HTTP /v1/join request for a NetherNet backend — see Backend Transports) and skip unreachable ones in load balancing |
true |
health_check.interval_seconds |
How often, in seconds, every registered server is pinged | 10 |
health_check.timeout_seconds |
How long to wait for a ping response before counting it as failed | 3 |
health_check.failure_threshold |
Consecutive failed pings before a server is marked unhealthy | 3 |
routing.default_group |
Server group new players are load balanced into on join. Empty = balance across every registered server, ignoring groups | "" |
routing.fallback_groups |
Ordered list of groups to try if default_group has no available (non-draining) servers |
[] |
whitelist.enabled |
Enable username whitelist | false |
whitelist.players |
Array of whitelisted usernames | [] |
resource_packs.required |
Require resource pack download | false |
resource_packs.directory |
Directory for resource packs (.zip, .mcpack, or folders) |
resource_packs |
resource_packs.encryption_keys |
Map of pack UUID → encryption key | {} |
resource_packs.hot_reload.enabled |
Reload changed resource packs without restarting Portal. New connections receive the latest successful snapshot. | false |
resource_packs.hot_reload.interval |
Resource pack change check interval in seconds | 30 |
motd |
Main server list MOTD line | Portal |
sub_motd |
Secondary server list MOTD line | Transfer Proxy |
-
NetherNet setup (firewall/port-forwarding, STUN/TURN, TLS for the signaling endpoint) is its own page — see NetherNet Transport before deploying
network.transport: "nethernet"(the default) anywhere reachable from outside its own host. -
Server groups & weight aren't configured here — they're set per-server when a backend registers itself over the socket API (
RegisterServer'sGroupandWeightfields).routing.default_group/routing.fallback_groupsonly control which group(s) new, ungrouped players are routed into. See Socket Protocol for details. -
Draining a server is also done at runtime, either via the socket API (
SetServerDraining) or the Admin Console (drain <server> [on|off]) — there's no static config for it. - Enabling
cluster.enabledrequires a reachable Redis instance; see Clustering for what clustering does and doesn't cover.
Getting started
Integrating a backend
Embedding Portal