Skip to content

IFM Configuration Reference

Overview

IFM uses TOML for configuration. The config file is loaded from (in priority order):

  1. --config / -c CLI flag
  2. IFM_CONFIG environment variable
  3. ./config.toml (current directory)
  4. ~/.config/ifm/config.toml (Linux/macOS)
  5. %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 buffer

Configuration Sections Detail

[node] — Node Identity & Storage

KeyTypeDefaultDescription
namestringrandomDisplay name for this node
storagepath./dataData directory (identity, cache, logs, plugins)
relaybooltrueParticipate in the relay plane (serve + use relays); relays are pool-wide, never bound to a frequency or station
cachesize256MBPacket cache size (KB/MB/GB)
connectionsint128Max 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

KeyTypeDefaultDescription
bootstrapbooltrueConnect to bootstrap peers
lanbooltrueEnable local network discovery
quicbooltrueEnable QUIC transport
webrtcbooltrueEnable WebRTC transport
tcpboolfalseEnable TCP fallback

Transport Priority: QUIC > WebRTC > TCP

[network.quic] — QUIC Settings

KeyTypeDefaultDescription
portint0Listen port (0 = ephemeral)
max_idle_timeoutint30000Max idle (ms)
keep_alive_intervalint10000Keep-alive (ms)
congestion_controllerstring"bbr"bbr, cubic, newreno
max_concurrent_streamsint256Bidirectional streams
max_uni_streamsint128Unidirectional streams
datagram_enabledbooltrueUnreliable datagrams

[network.webrtc] — WebRTC Settings

KeyTypeDefaultDescription
stun_serversarrayGoogle/CloudflareSTUN servers
turn_serversarray[]TURN servers (with auth)
ice_gathering_policystring"all"all, relay, none
ice_candidate_pool_sizeint10Pre-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

KeyTypeDefaultDescription
enabledbooltrueEnable DHT
modestring"client"client or server
replication_factorint20Record replication
refresh_intervalint3600Refresh (seconds)
bootstrap_peersarraybuilt-inBootstrap multiaddrs

Modes:

  • client — Only lookups, doesn't store records for others
  • server — Full DHT participation (uses more resources)

[network.local] — Local Discovery

KeyTypeDefaultDescription
enabledbooltrueEnable local discovery
mdnsbooltruemDNS (port 5353)
broadcastbooltrueUDP broadcast (port 4002)
mdns_intervalint30Query interval (s)
broadcast_intervalint10Broadcast interval (s)
service_namestring"_ifm._udp"mDNS service type

[gossip] — GossipSub Mesh

KeyTypeDefaultDescription
ttlint16Packet TTL (hops)
fanoutint6Forward to N peers
mesh_nint6Target mesh degree
mesh_n_lowint4Min mesh degree
mesh_n_highint12Max mesh degree
gossip_factorfloat0.25Gossip percentage
history_lengthint5History for new peers
history_gossipint3Gossip history count
duplicate_cache_sizeint100000Dedup cache entries
validate_messagesbooltrueValidate before forward
max_message_sizeint1048576Max 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

KeyTypeDefaultDescription
enabledbooltrueEnable audio
sample_rateint48000Sample rate (Hz)
channelsint11=mono, 2=stereo
frame_msint20Frame duration
input_devicestring"default"Capture device
output_devicestring"default"Playback device
input_volumefloat1.0Input gain
output_volumefloat1.0Output gain

[audio.opus] — Opus Encoder

KeyTypeDefaultDescription
bitratestring/int"auto"Target bitrate or "auto"
complexityint10Complexity 0-10
fecbooltrueForward Error Correction
dtxbooltrueDiscontinuous Transmission
packet_loss_percentageint0Expected loss %

Bitrate Recommendations:

Use CaseBitrate
Voice (auto)24-48 kbps
Voice (high quality)64-96 kbps
Music128-256 kbps
Low bandwidth8-16 kbps

[audio.jitter] — Jitter Buffer

KeyTypeDefaultDescription
target_latency_msint60Target latency
min_latency_msint40Minimum latency
max_latency_msint200Maximum latency
adaptivebooltrueAuto-adjust

[audio.processing] — Audio Processing (Desktop)

KeyTypeDefaultDescription
noise_suppressionbooltrueRNNoise suppression
echo_cancellationboolfalseAEC (needs loopback)
auto_gain_controlboolfalseAGC
high_pass_filterbooltrue80Hz HPF

[security] — Security

KeyTypeDefaultDescription
require_signed_packetsbooltrueAlways verify signatures
packet_expiry_msint300000Max packet age (5 min)
max_clock_skew_msint30000Max clock skew (30s)
dedup_cache_sizeint100000Packet ID cache
replay_windowint2^32Sequence window

[logging] — Logging

KeyTypeDefaultDescription
levelstring"info"trace/debug/info/warn/error
formatstring"text"text/json
filepath"./logs/ifm.log"Log file
max_file_sizesize"10MB"Rotation size
max_filesint5Rotated files
include_timestampbooltrueTimestamps
include_levelbooltrueLog level
include_targetbooltrueModule name

[plugins] — Plugin System

KeyTypeDefaultDescription
auto_loadbooltrueAuto-load from plugins/
plugins_dirpath"./plugins"Plugin directory
allowed_pluginsarray[]Allowlist (empty=all)
blocked_pluginsarray[]Blocklist
permissionstabledefaultsDefault permissions

[experimental] — Experimental Features

KeyTypeDefaultDescription
webtransportboolfalseWebTransport (browser)
multipathboolfalseMultipath QUIC
datagram_receive_bufferint1024QUIC 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=debug

Mapping:

Config PathEnvironment Variable
node.nameIFM_NODE_NAME
network.quic.portIFM_NETWORK_QUIC_PORT
gossip.fanoutIFM_GOSSIP_FANOUT
audio.opus.bitrateIFM_AUDIO_OPUS_BITRATE
logging.levelIFM_LOGGING_LEVEL
node.storageIFM_DATA_DIR (special)
node.identityIFM_IDENTITY (special)

Example Configurations

Minimal (Default-like)

toml
[node]
name = "my-node"

[network]
bootstrap = true
lan = true
quic = true

High-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 only

Config Validation

bash
# Validate config file
ifm config validate

# Show effective config (with defaults)
ifm config show

# Show specific value
ifm config get network.quic.port

Validation 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

PlatformDefault 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:

  1. --config flag
  2. IFM_CONFIG env var
  3. Current directory config.toml
  4. Platform default location
  5. Built-in defaults

Hot Reload

Some settings support hot reload (no restart needed):

  • logging.level
  • gossip.fanout, gossip.mesh_n*
  • audio.opus.bitrate, audio.opus.complexity
  • audio.volume settings

Restart Required:

  • Network transports (network.quic, network.webrtc, network.tcp)
  • DHT mode
  • Identity/storage paths
  • Port bindings
  • Plugin permissions

Released under the MIT License.