File Provider
The file provider loads server configurations from .toml files in a directory. Each file defines one server. When you add, edit, or remove a file, Infrarust picks up the change automatically.
Directory structure
By default, Infrarust looks for server configs in ./servers/ relative to where you run the binary. You can change this in infrarust.toml:
servers_dir = "./servers"Place one .toml file per server inside that directory:
infrarust.toml
servers/
├── survival.toml
├── creative.toml
└── lobby.toml2
3
4
5
Files without a .toml extension are ignored. Subdirectories are not scanned.
This directory belongs to the file provider alone. A server you create through the admin API is written to that plugin's own data directory instead, so nothing else edits your files behind your back. Both sets of servers show up together in the router and in GET /api/v1/servers.
Server config format
Each file deserializes into a ServerConfig. Here is a minimal example:
domains = ["survival.mc.example.com"]
addresses = ["10.0.1.10:25565"]2
domains and addresses are the only fields you always need. Everything else has a default.
Full example
# Domains that route to this server (supports wildcards)
domains = ["survival.mc.example.com", "*.survival.example.com"]
# Backend addresses (host:port, port defaults to 25565). Multiple = load balanced.
addresses = ["10.0.1.10:25565", "10.0.1.11:25565"]
# Proxy mode: passthrough, zero_copy, client_only, offline, server_only
proxy_mode = "passthrough"
# Forward PROXY protocol headers to the backend
send_proxy_protocol = false
# Rewrite the domain in the handshake: "none", "from_backend",
# or { explicit = "backend.local" } for a custom domain
domain_rewrite = "none"
# Max players shown in the server list (0 = unlimited)
max_players = 100
# Disconnect message when the backend is unreachable
disconnect_message = "Server is down. Try again later."
# Limbo handler chain (plugin IDs, executed in order)
limbo_handlers = ["queue", "auth"]
# Server-specific timeouts (override global values)
[timeouts]
connect = "3s"
read = "30s"
write = "30s"
# MOTD per server state
[motd.online]
text = "§aSurvival §7| §fWelcome!"
favicon = "./icons/survival.png"
[motd.sleeping]
text = "§eSurvival §7| §fConnect to wake up!"
version_name = "Server Sleeping"
[motd.starting]
text = "§eSurvival §7| §fStarting..."2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
All fields
| Field | Type | Default | Description |
|---|---|---|---|
id | string | filename stem | Unique identifier. Derived from the filename if absent. |
name | string | none | Human-readable name. Takes priority over id for identification. Must match [a-z0-9_-]+. |
network | string | none | Network group for server switching. Only servers in the same network can switch between each other. |
domains | list of strings | [] | Domains that route to this server. Supports wildcards (*.example.com). |
addresses | list | required | Backend addresses, each "host:port" or { address = "host:port", weight = 3 }. Port defaults to 25565. Multiple addresses are load balanced per the server's balance strategy. |
proxy_mode | string | "passthrough" | One of: passthrough, zero_copy, client_only, offline, server_only. |
forwarding_mode | string | "none" | Per-server player identity forwarding override. One of: none, bungee_cord (alias legacy), bungee_guard, velocity (alias modern). Overrides the global [forwarding] setting for this server only. |
send_proxy_protocol | bool | false | Send PROXY protocol to the backend. |
domain_rewrite | string or table | "none" | Rewrite domain in handshake: "none", "from_backend", or { explicit = "domain" }. |
max_players | integer | 0 | Max players for status response. 0 means unlimited. |
disconnect_message | string | "Server is currently unreachable. Please try again later." | Message sent when backend is unreachable. |
limbo_handlers | list of strings | [] | Plugin IDs for the limbo handler chain. |
Nested sections
[timeouts] overrides global timeout values for this server:
| Field | Type | Default |
|---|---|---|
connect | duration | "5s" |
read | duration | "30s" |
write | duration | "30s" |
[motd.<state>] configures the MOTD for each server state (online, offline, sleeping, starting, crashed, stopping, unreachable):
| Field | Type | Default |
|---|---|---|
text | string | required |
favicon | string | none |
version_name | string | none |
max_players | integer | none |
[server_manager] configures automatic server start/stop. See Server Manager for details.
[ip_filter] restricts access by IP:
| Field | Type | Default |
|---|---|---|
whitelist | list of CIDRs | [] |
blacklist | list of CIDRs | [] |
Server identification
Each server gets an ID from the file provider in the format file@<filename> (e.g., file@survival.toml). This is used internally by the provider registry.
The server's effective identity (used for display and server switching) follows this priority:
namefield, if setidfield, if set- The filename without
.tomlextension (e.g.,survivalfromsurvival.toml)
Hot reload
The file provider watches the servers_dir directory using OS-level file notifications. When a file changes, Infrarust waits 200ms to batch rapid edits, then computes a diff against its in-memory state.
Three types of changes are detected:
- A new
.tomlfile appears in the directory. The server is added to the router. - An existing file's content changes. The server config is updated in place.
- A
.tomlfile is deleted. The server is removed from the router.
WARNING
If you save a file with invalid TOML or a config that fails validation, the previous version stays active. Infrarust logs a warning but does not remove the server.
You do not need to restart Infrarust after editing server configs. Add a new .toml file and players can connect to it within a second.
Validation
Each file is validated on load. The following rules apply:
- Forwarding modes (
passthrough,zero_copy,server_only) must have at least one domain. - Forwarding modes cannot belong to a
network(they don't support server switching). - At least one address must be defined.
- Domain strings must not be empty.
nameandnetworkmust match[a-z0-9_-]+and be at most 64 characters.- No two servers can share the same effective ID.
DANGER
The config uses deny_unknown_fields. A typo in a field name (e.g., adresses instead of addresses) will cause the file to be rejected entirely.
Example: multi-server setup
infrarust.toml
servers/
├── lobby.toml
├── survival.toml
└── creative.toml2
3
4
5
domains = ["mc.example.com"]
addresses = ["127.0.0.1:25565"]
proxy_mode = "client_only"
network = "main"2
3
4
domains = ["survival.mc.example.com"]
addresses = ["10.0.1.10:25565"]
proxy_mode = "client_only"
max_players = 100
network = "main"
[timeouts]
connect = "3s"
read = "30s"
write = "30s"
[motd.online]
text = "§aSurvival §7| §fWelcome!"2
3
4
5
6
7
8
9
10
11
12
13
domains = ["creative.mc.example.com"]
addresses = ["127.0.0.1:25566"]
proxy_mode = "client_only"
[server_manager]
type = "local"
command = "java"
working_dir = "/opt/minecraft/creative"
args = ["-Xmx4G", "-jar", "server.jar", "nogui"]
ready_pattern = 'For help, type "help"'
shutdown_timeout = "30s"
shutdown_after = "15m"2
3
4
5
6
7
8
9
10
11
12