IFM Configuration Reference
Overview
IFM uses TOML for configuration. The config file is loaded from (in priority order):
--config/-cCLI flagIFM_CONFIGenvironment variable./config.toml(current directory)~/.config/ifm/config.toml(Linux/macOS)%APPDATA%\ifm\config.toml(Windows)
Complete Configuration Schema
toml
# Node identity and storage
[node]
name = "enzo" # Display name (optional)
storage = "./data" # Data directory path
relay = true # Participate in the relay plane (serve + use relays)
connections = 128 # Max concurrent connections
# Network transports and discovery
[network]
bootstrap = true # Connect to bootstrap peers
lan = true # Enable local (mDNS/UDP) discovery
quic = true # Enable QUIC transport
webrtc = true # Enable WebRTC transport
tcp = false # Enable TCP fallback (explicit)
# QUIC-specific settings
[network.quic]
port = 0 # Listen port (0 = random)
max_idle_timeout = 30000 # Max idle timeout (ms)
keep_alive_interval = 10000 # Keep-alive interval (ms)
congestion_controller = "bbr" # Congestion control: bbr, cubic, newreno
max_concurrent_streams = 256 # Max bidirectional streams
max_uni_streams = 128 # Max unidirectional streams
datagram_enabled = true # Enable unreliable datagrams
# WebRTC-specific settings
[network.webrtc]
stun_servers = [ # STUN servers for NAT traversal
"stun:stun.l.google.com:19302",
"stun:stun.cloudflare.com:3478"
]
turn_servers = [] # TURN servers (optional)
# Example TURN:
# turn_servers = [
# { urls = ["turn:turn.example.com:3478"], username = "user", credential = "pass" }
# ]
ice_gathering_policy = "all" # all, relay, none
ice_candidate_pool_size = 10 # Pre-gather candidates
# TCP-specific settings
[network.tcp]
port = 0 # Listen port (0 = random)
nodelay = true # TCP_NODELAY
keepalive = 30 # Keepalive interval (seconds)
# DHT settings
[network.dht]
enabled = true # Enable Kademlia DHT
mode = "client" # client (default) or server
replication_factor = 20 # Store records on N closest peers
refresh_interval = 3600 # Refresh interval (seconds)
bootstrap_peers = [ # Bootstrap peer multiaddrs
"/ip4/bootstrap.ifm.network/udp/4001/quic-v1/p2p/12D3KooWBootstrap1",
"/ip4/bootstrap2.ifm.network/udp/4001/quic-v1/p2p/12D3KooWBootstrap2",
"/ip4/bootstrap3.ifm.network/udp/4001/quic-v1/p2p/12D3KooWBootstrap3"
]
# Local discovery (mDNS/UDP broadcast)
[network.local]
enabled = true # Enable local discovery
mdns = true # Use mDNS (port 5353)
broadcast = true # Use UDP broadcast (port 4002)
mdns_interval = 30 # mDNS query interval (seconds)
broadcast_interval = 10 # Broadcast interval (seconds)
service_name = "_ifm._udp" # mDNS service name
# GossipSub (mesh broadcast) settings
[gossip]
ttl = 16 # Packet TTL (hops)
fanout = 6 # Forward to N peers (mesh degree)
mesh_n = 6 # Target mesh degree
mesh_n_low = 4 # Min mesh degree (prune below)
mesh_n_high = 12 # Max mesh degree (gossip above)
gossip_factor = 0.25 # Gossip to 25% of mesh
history_length = 5 # Message history for new peers
history_gossip = 3 # Gossip N history messages
duplicate_cache_size = 100000 # Dedup cache entries
validate_messages = true # Validate before forwarding
max_message_size = 1048576 # Max message size (bytes)
# Audio/Voice settings
[audio]
enabled = true # Enable audio subsystem
sample_rate = 48000 # Sample rate (Hz)
channels = 1 # Channels (1=mono, 2=stereo)
frame_ms = 20 # Frame duration (ms)
input_device = "default" # Input device (name or "default")
output_device = "default" # Output device (name or "default")
input_volume = 1.0 # Input gain (0.0-2.0)
output_volume = 1.0 # Output gain (0.0-2.0)
# Opus encoder settings
[audio.opus]
bitrate = "auto" # Target bitrate: auto, 6000-510000
complexity = 10 # Encoding complexity (0-10)
fec = true # Forward Error Correction
dtx = true # Discontinuous Transmission
packet_loss_percentage = 0 # Expected packet loss (0-100)
# Jitter buffer settings
[audio.jitter]
target_latency_ms = 60 # Target buffer latency (ms)
min_latency_ms = 40 # Minimum latency (ms)
max_latency_ms = 200 # Maximum latency (ms)
adaptive = true # Adapt to network conditions
# Audio processing (desktop)
[audio.processing]
noise_suppression = true # Enable noise suppression (rnnoise)
echo_cancellation = false # Enable echo cancellation
auto_gain_control = false # Enable automatic gain control
high_pass_filter = true # High-pass filter at 80Hz
# Security settings
[security]
require_signed_packets = true # Reject unsigned packets (always true)
packet_expiry_ms = 300000 # Reject packets older than this (ms)
max_clock_skew_ms = 30000 # Max allowed clock skew (ms)
dedup_cache_size = 100000 # Packet ID dedup cache size
replay_window = 4294967296 # Sequence replay window (2^32)
# Frequency encryption defaults
[security.encryption]
default_algorithm = "chacha20poly1305" # Only supported currently
key_rotation_interval = 0 # Key rotation (0 = disabled)
# Logging
[logging]
level = "info" # trace, debug, info, warn, error
format = "text" # text, json
file = "./logs/ifm.log" # Log file path (empty = stdout only)
max_file_size = "10MB" # Rotate at size
max_files = 5 # Max rotated files
include_timestamp = true # Include timestamps
include_level = true # Include log level
include_target = true # Include module target
# Plugin settings
[plugins]
auto_load = true # Auto-load plugins from plugins/ directory
plugins_dir = "./plugins" # Plugin directory
allowed_plugins = [] # Empty = allow all, list = allowlist
blocked_plugins = [] # Blocklist
permissions = { # Default permissions for plugins
broadcast = true,
send_to = true,
storage = true,
rpc = true,
identity = false,
network = false,
audio = false,
video = false,
filesystem = false
}
# Experimental features
[experimental]
webtransport = false # WebTransport support (browser)
multipath = false # Multipath QUIC
datagram_receive_buffer = 1024 # QUIC datagram receive bufferConfiguration Sections Detail
[node] — Node Identity & Storage
| Key | Type | Default | Description |
|---|---|---|---|
name | string | random | Display name for this node |
storage | path | ./data | Data directory (identity, cache, logs, plugins) |
relay | bool | true | Participate in the relay plane (serve + use relays); relays are pool-wide, never bound to a frequency or station |
cache | size | 256MB | Packet cache size (KB/MB/GB) |
connections | int | 128 | Max concurrent connections |
Storage Layout:
{storage}/
├── identity.key # Ed25519 private key (600 perms)
├── config.toml # Active config (symlink or copy)
├── cache/ # Packet cache (dedup, store-forward)
├── logs/ # Log files
├── plugins/ # Loaded plugins (WASM, native)
└── plugin_data/ # Plugin persistent storage[network] — Transport & Discovery
| Key | Type | Default | Description |
|---|---|---|---|
bootstrap | bool | true | Connect to bootstrap peers |
lan | bool | true | Enable local network discovery |
quic | bool | true | Enable QUIC transport |
webrtc | bool | true | Enable WebRTC transport |
tcp | bool | false | Enable TCP fallback |
Transport Priority: QUIC > WebRTC > TCP
[network.quic] — QUIC Settings
| Key | Type | Default | Description |
|---|---|---|---|
port | int | 0 | Listen port (0 = ephemeral) |
max_idle_timeout | int | 30000 | Max idle (ms) |
keep_alive_interval | int | 10000 | Keep-alive (ms) |
congestion_controller | string | "bbr" | bbr, cubic, newreno |
max_concurrent_streams | int | 256 | Bidirectional streams |
max_uni_streams | int | 128 | Unidirectional streams |
datagram_enabled | bool | true | Unreliable datagrams |
[network.webrtc] — WebRTC Settings
| Key | Type | Default | Description |
|---|---|---|---|
stun_servers | array | Google/Cloudflare | STUN servers |
turn_servers | array | [] | TURN servers (with auth) |
ice_gathering_policy | string | "all" | all, relay, none |
ice_candidate_pool_size | int | 10 | Pre-gather count |
TURN Server Format:
toml
turn_servers = [
{ urls = ["turn:turn.example.com:3478?transport=udp"], username = "user", credential = "pass" },
{ urls = ["turns:turn.example.com:5349?transport=tcp"], username = "user", credential = "pass" }
][network.dht] — Kademlia DHT
| Key | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | Enable DHT |
mode | string | "client" | client or server |
replication_factor | int | 20 | Record replication |
refresh_interval | int | 3600 | Refresh (seconds) |
bootstrap_peers | array | built-in | Bootstrap multiaddrs |
Modes:
client— Only lookups, doesn't store records for othersserver— Full DHT participation (uses more resources)
[network.local] — Local Discovery
| Key | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | Enable local discovery |
mdns | bool | true | mDNS (port 5353) |
broadcast | bool | true | UDP broadcast (port 4002) |
mdns_interval | int | 30 | Query interval (s) |
broadcast_interval | int | 10 | Broadcast interval (s) |
service_name | string | "_ifm._udp" | mDNS service type |
[gossip] — GossipSub Mesh
| Key | Type | Default | Description |
|---|---|---|---|
ttl | int | 16 | Packet TTL (hops) |
fanout | int | 6 | Forward to N peers |
mesh_n | int | 6 | Target mesh degree |
mesh_n_low | int | 4 | Min mesh degree |
mesh_n_high | int | 12 | Max mesh degree |
gossip_factor | float | 0.25 | Gossip percentage |
history_length | int | 5 | History for new peers |
history_gossip | int | 3 | Gossip history count |
duplicate_cache_size | int | 100000 | Dedup cache entries |
validate_messages | bool | true | Validate before forward |
max_message_size | int | 1048576 | Max message (bytes) |
Mesh Degree Guidelines:
- Low bandwidth:
mesh_n=4,fanout=4 - Default:
mesh_n=6,fanout=6 - High bandwidth:
mesh_n=8,fanout=8
[audio] — Audio Settings
| Key | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | Enable audio |
sample_rate | int | 48000 | Sample rate (Hz) |
channels | int | 1 | 1=mono, 2=stereo |
frame_ms | int | 20 | Frame duration |
input_device | string | "default" | Capture device |
output_device | string | "default" | Playback device |
input_volume | float | 1.0 | Input gain |
output_volume | float | 1.0 | Output gain |
[audio.opus] — Opus Encoder
| Key | Type | Default | Description |
|---|---|---|---|
bitrate | string/int | "auto" | Target bitrate or "auto" |
complexity | int | 10 | Complexity 0-10 |
fec | bool | true | Forward Error Correction |
dtx | bool | true | Discontinuous Transmission |
packet_loss_percentage | int | 0 | Expected loss % |
Bitrate Recommendations:
| Use Case | Bitrate |
|---|---|
| Voice (auto) | 24-48 kbps |
| Voice (high quality) | 64-96 kbps |
| Music | 128-256 kbps |
| Low bandwidth | 8-16 kbps |
[audio.jitter] — Jitter Buffer
| Key | Type | Default | Description |
|---|---|---|---|
target_latency_ms | int | 60 | Target latency |
min_latency_ms | int | 40 | Minimum latency |
max_latency_ms | int | 200 | Maximum latency |
adaptive | bool | true | Auto-adjust |
[audio.processing] — Audio Processing (Desktop)
| Key | Type | Default | Description |
|---|---|---|---|
noise_suppression | bool | true | RNNoise suppression |
echo_cancellation | bool | false | AEC (needs loopback) |
auto_gain_control | bool | false | AGC |
high_pass_filter | bool | true | 80Hz HPF |
[security] — Security
| Key | Type | Default | Description |
|---|---|---|---|
require_signed_packets | bool | true | Always verify signatures |
packet_expiry_ms | int | 300000 | Max packet age (5 min) |
max_clock_skew_ms | int | 30000 | Max clock skew (30s) |
dedup_cache_size | int | 100000 | Packet ID cache |
replay_window | int | 2^32 | Sequence window |
[logging] — Logging
| Key | Type | Default | Description |
|---|---|---|---|
level | string | "info" | trace/debug/info/warn/error |
format | string | "text" | text/json |
file | path | "./logs/ifm.log" | Log file |
max_file_size | size | "10MB" | Rotation size |
max_files | int | 5 | Rotated files |
include_timestamp | bool | true | Timestamps |
include_level | bool | true | Log level |
include_target | bool | true | Module name |
[plugins] — Plugin System
| Key | Type | Default | Description |
|---|---|---|---|
auto_load | bool | true | Auto-load from plugins/ |
plugins_dir | path | "./plugins" | Plugin directory |
allowed_plugins | array | [] | Allowlist (empty=all) |
blocked_plugins | array | [] | Blocklist |
permissions | table | defaults | Default permissions |
[experimental] — Experimental Features
| Key | Type | Default | Description |
|---|---|---|---|
webtransport | bool | false | WebTransport (browser) |
multipath | bool | false | Multipath QUIC |
datagram_receive_buffer | int | 1024 | QUIC datagram buffer |
Environment Variable Overrides
Any config value can be overridden via environment variables:
bash
# Format: IFM_<SECTION>_<KEY> (uppercase, underscores)
export IFM_NODE_NAME="My Radio"
export IFM_NETWORK_QUIC_PORT=4001
export IFM_GOSSIP_FANOUT=8
export IFM_AUDIO_OPUS_BITRATE=64000
export IFM_LOGGING_LEVEL=debugMapping:
| Config Path | Environment Variable |
|---|---|
node.name | IFM_NODE_NAME |
network.quic.port | IFM_NETWORK_QUIC_PORT |
gossip.fanout | IFM_GOSSIP_FANOUT |
audio.opus.bitrate | IFM_AUDIO_OPUS_BITRATE |
logging.level | IFM_LOGGING_LEVEL |
node.storage | IFM_DATA_DIR (special) |
node.identity | IFM_IDENTITY (special) |
Example Configurations
Minimal (Default-like)
toml
[node]
name = "my-node"
[network]
bootstrap = true
lan = true
quic = trueHigh-Performance Relay Node
toml
[node]
name = "relay.ifm.network"
relay = true
cache = "1GB"
connections = 1000
[network]
bootstrap = false
lan = false
quic = true
webrtc = false
tcp = true
[network.quic]
port = 4001
congestion_controller = "bbr"
max_concurrent_streams = 1024
[network.dht]
mode = "server"
replication_factor = 20
[gossip]
fanout = 12
mesh_n = 12
mesh_n_high = 24
[logging]
level = "warn"
file = "/var/log/ifm/relay.log"Low-Bandwidth Mobile
toml
[node]
name = "mobile"
cache = "64MB"
connections = 32
[network]
bootstrap = true
lan = true
quic = true
webrtc = true
[network.quic]
congestion_controller = "bbr"
[gossip]
fanout = 4
mesh_n = 4
mesh_n_low = 3
mesh_n_high = 8
[audio.opus]
bitrate = 16000
complexity = 5
[audio.jitter]
target_latency_ms = 100
max_latency_ms = 500
[logging]
level = "error"Development/Debug
toml
[node]
name = "dev-node"
storage = "./dev-data"
[network]
bootstrap = true
lan = true
quic = true
webrtc = true
tcp = true
[network.dht]
bootstrap_peers = [
"/ip4/127.0.0.1/udp/4001/quic-v1/p2p/12D3KooWLocalBootstrap"
]
[gossip]
validate_messages = true
[logging]
level = "debug"
format = "text"
file = "./dev-logs/ifm.log"
[plugins]
auto_load = true
plugins_dir = "./dev-plugins"Browser (WASM) — Limited Config
toml
# Only these settings apply in browser
[node]
name = "browser-user"
storage = "indexeddb" # Special value for browser
[network]
bootstrap = true
lan = false
quic = false
webrtc = true
tcp = false
[network.webrtc]
stun_servers = ["stun:stun.l.google.com:19302"]
[audio]
input_device = "default"
output_device = "default"
[logging]
level = "warn"
format = "json"
file = "" # Console onlyConfig Validation
bash
# Validate config file
ifm config validate
# Show effective config (with defaults)
ifm config show
# Show specific value
ifm config get network.quic.portValidation Rules
- All paths must be readable/writable
- Port numbers: 0-65535 (0 = auto)
- Cache sizes: positive, with KB/MB/GB suffix
- Durations: positive integers (ms or seconds as noted)
- Enum values must match allowed options
- Bootstrap peers must be valid multiaddrs
Config File Locations
| Platform | Default Location |
|---|---|
| Linux | ~/.config/ifm/config.toml |
| macOS | ~/Library/Application Support/ifm/config.toml |
| Windows | %APPDATA%\ifm\config.toml |
| Current Dir | ./config.toml (highest priority) |
Priority Order:
--configflagIFM_CONFIGenv var- Current directory
config.toml - Platform default location
- Built-in defaults
Hot Reload
Some settings support hot reload (no restart needed):
logging.levelgossip.fanout,gossip.mesh_n*audio.opus.bitrate,audio.opus.complexityaudio.volumesettings
Restart Required:
- Network transports (
network.quic,network.webrtc,network.tcp) - DHT mode
- Identity/storage paths
- Port bindings
- Plugin permissions