IFM Deployment Guide
Overview
This guide covers deploying IFM nodes in various environments: from development laptops to production bootstrap nodes, mobile devices, and browser applications.
Deployment Scenarios
| Scenario | Use Case | Complexity |
|---|---|---|
| Development | Local testing, single machine | Low |
| Personal Node | Daily use on laptop/phone | Low |
| Community Relay | Help network connectivity | Medium |
| Bootstrap Node | Network entry points | High |
| Server/Headless | Bots, bridges, services | Medium |
| Browser/WASM | Web applications | Medium |
| Mobile | iOS/Android apps | Medium |
| IoT/Embedded | Sensors, devices | High |
Development Deployment
Quick Start (Single Machine)
bash
# Terminal 1: Bootstrap node (optional, for isolated testing)
ifm bootstrap --port 4001 --data-dir ./bootstrap-data
# Terminal 2: Node A
ifm init --name "Alice" --data-dir ./alice-data
ifm --data-dir ./alice-data config set network.bootstrap_peers '["/ip4/127.0.0.1/udp/4001/quic-v1/p2p/BOOTSTRAP_PEER_ID"]'
ifm --data-dir ./alice-data connect
ifm --data-dir ./alice-data tune 91.700
# Terminal 3: Node B
ifm init --name "Bob" --data-dir ./bob-data
ifm --data-dir ./bob-data config set network.bootstrap_peers '["/ip4/127.0.0.1/udp/4001/quic-v1/p2p/BOOTSTRAP_PEER_ID"]'
ifm --data-dir ./bob-data connect
ifm --data-dir ./bob-data tune 91.700
# Now they can communicate!
ifm --data-dir ./alice-data broadcast "Hello Bob"Docker Compose (Multi-node Testing)
yaml
# docker-compose.yml
version: '3.8'
services:
bootstrap:
image: ifmprotocol/ifm:latest
command: bootstrap --port 4001 --data-dir /data
volumes:
- ./bootstrap-data:/data
ports:
- "4001:4001/udp"
- "4001:4001/tcp"
networks:
- ifm-net
alice:
image: ifmprotocol/ifm:latest
command: sh -c "ifm init --name Alice --data-dir /data --force && ifm connect --bootstrap /ip4/bootstrap/udp/4001/quic-v1/p2p/BOOTSTRAP_ID && ifm tune 91.700 && tail -f /dev/null"
volumes:
- ./alice-data:/data
depends_on:
- bootstrap
networks:
- ifm-net
bob:
image: ifmprotocol/ifm:latest
command: sh -c "ifm init --name Bob --data-dir /data --force && ifm connect --bootstrap /ip4/bootstrap/udp/4001/quic-v1/p2p/BOOTSTRAP_ID && ifm tune 91.700 && tail -f /dev/null"
volumes:
- ./bob-data:/data
depends_on:
- bootstrap
networks:
- ifm-net
networks:
ifm-net:
driver: bridgebash
docker-compose up -d
docker-compose logs -f alicePersonal Node Deployment
Linux/macOS (Systemd/User Service)
ini
# ~/.config/systemd/user/ifm.service
[Unit]
Description=IFM Node
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=%h/.cargo/bin/ifm connect --config %h/.config/ifm/config.toml
Restart=on-failure
RestartSec=5
Environment=IFM_DATA_DIR=%h/.local/share/ifm
Environment=IFM_CONFIG=%h/.config/ifm/config.toml
# Resource limits
MemoryMax=256M
CPUQuota=50%
[Install]
WantedBy=default.targetbash
# Enable and start
systemctl --user daemon-reload
systemctl --user enable --now ifm.service
# Check status
systemctl --user status ifm.service
journalctl --user -u ifm.service -fmacOS (LaunchAgent)
xml
<!-- ~/Library/LaunchAgents/network.ifm.node.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>network.ifm.node</string>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/bin/ifm</string>
<string>connect</string>
<string>--config</string>
<string>/Users/USERNAME/.config/ifm/config.toml</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/USERNAME/.local/share/ifm/logs/ifm.log</string>
<key>StandardErrorPath</key>
<string>/Users/USERNAME/.local/share/ifm/logs/ifm.error.log</string>
<key>EnvironmentVariables</key>
<dict>
<key>IFM_DATA_DIR</key>
<string>/Users/USERNAME/.local/share/ifm</string>
</dict>
</dict>
</plist>bash
launchctl load ~/Library/LaunchAgents/network.ifm.node.plist
launchctl start network.ifm.nodeWindows (Task Scheduler / NSSM)
powershell
# Using NSSM (Non-Sucking Service Manager)
nssm install IFMNode
nssm set IFMNode Application "C:\Program Files\ifm\ifm.exe"
nssm set IFMNode AppParameters "connect --config C:\Users\USERNAME\AppData\Roaming\ifm\config.toml"
nssm set IFMNode AppDirectory "C:\Users\USERNAME\AppData\Roaming\ifm"
nssm set IFMNode Environment "IFM_DATA_DIR=C:\Users\USERNAME\AppData\Local\ifm"
nssm start IFMNodeProduction Bootstrap Node
Bootstrap nodes are critical infrastructure. They only introduce peers — they never see user traffic.
Requirements
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 1 vCPU | 2+ vCPU |
| RAM | 512 MB | 2 GB |
| Disk | 1 GB | 10 GB SSD |
| Network | 100 Mbps | 1 Gbps |
| IP | Static IPv4 | Static IPv4 + IPv6 |
| Location | Single region | Multi-region (anycast) |
Hardened Configuration
toml
# /etc/ifm/bootstrap.toml
[node]
name = "bootstrap.ifm.network"
storage = "/var/lib/ifm-bootstrap"
relay = true
connections = 2000 # High connection limit
[network]
bootstrap = false # Don't bootstrap from others
lan = false # No local discovery
quic = true
webrtc = false # Not needed for bootstrap
tcp = true # Fallback
[network.quic]
port = 4001
congestion_controller = "bbr"
max_concurrent_streams = 1024
[network.tcp]
port = 4001
nodelay = true
[network.dht]
mode = "server" # Full DHT participation
replication_factor = 20
[gossip]
fanout = 20 # High fanout for bootstrap
mesh_n = 20
mesh_n_high = 40
[logging]
level = "warn"
file = "/var/log/ifm/bootstrap.log"
format = "json"
max_file_size = "100MB"
max_files = 10
[security]
dedup_cache_size = 1000000 # Large dedup cacheSystemd Service (Production)
ini
# /etc/systemd/system/ifm-bootstrap.service
[Unit]
Description=IFM Bootstrap Node
Documentation=https://docs.ifm.network/deployment/bootstrap
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
User=ifm-bootstrap
Group=ifm-bootstrap
ExecStart=/usr/local/bin/ifm bootstrap --config /etc/ifm/bootstrap.toml
Restart=always
RestartSec=10
TimeoutStartSec=60
TimeoutStopSec=30
# Security hardening
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/ifm-bootstrap /var/log/ifm
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_RAW
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW
# Resource limits
LimitNOFILE=65536
LimitNPROC=4096
MemoryMax=2G
CPUQuota=200%
# Monitoring
WatchdogSec=30
[Install]
WantedBy=multi-user.targetbash
# Create user
sudo useradd -r -s /bin/false -d /var/lib/ifm-bootstrap ifm-bootstrap
# Create directories
sudo mkdir -p /var/lib/ifm-bootstrap /var/log/ifm
sudo chown ifm-bootstrap:ifm-bootstrap /var/lib/ifm-bootstrap /var/log/ifm
# Install and start
sudo systemctl daemon-reload
sudo systemctl enable --now ifm-bootstrap.serviceFirewall Rules
bash
# UFW (Ubuntu/Debian)
sudo ufw allow 4001/udp comment "IFM QUIC"
sudo ufw allow 4001/tcp comment "IFM TCP"
sudo ufw enable
# firewalld (RHEL/Fedora)
sudo firewall-cmd --permanent --add-port=4001/udp
sudo firewall-cmd --permanent --add-port=4001/tcp
sudo firewall-cmd --reload
# iptables (raw)
sudo iptables -A INPUT -p udp --dport 4001 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 4001 -j ACCEPTMonitoring (Prometheus + Grafana)
yaml
# prometheus.yml scrape config
scrape_configs:
- job_name: 'ifm-bootstrap'
static_configs:
- targets: ['localhost:9090'] # IFM metrics endpointKey Metrics to Alert On:
ifm_peers_connected < 10(for bootstrap)ifm_dht_routing_table_size < 100ifm_memory_bytes > 1.5GBifm_cpu_percent > 80%ifm_network_errors_total increasing
DNS & TLS
bash
# A record for IPv4
bootstrap.ifm.network. IN A 1.2.3.4
# AAAA record for IPv6
bootstrap.ifm.network. IN AAAA 2001:db8::1
# SRV record for QUIC (optional)
_quic._udp.bootstrap.ifm.network. IN SRV 0 0 4001 bootstrap.ifm.network.Multiaddr for users:
/ip4/1.2.3.4/udp/4001/quic-v1/p2p/12D3KooWBootstrap1
/ip6/2001:db8::1/udp/4001/quic-v1/p2p/12D3KooWBootstrap1
/dns/bootstrap.ifm.network/udp/4001/quic-v1/p2p/12D3KooWBootstrap1Community Relay Node
Relays help peers behind NATs connect. Lower requirements than bootstrap.
Configuration
toml
# /etc/ifm/relay.toml
[node]
name = "relay.community.ifm"
storage = "/var/lib/ifm-relay"
relay = true
connections = 500
[network]
bootstrap = true
lan = false
quic = true
webrtc = false
[network.quic]
port = 4001
[gossip]
fanout = 8Deployment
Same as bootstrap but with lower resource limits and relay = true in config.
Headless Server Deployment
For bots, bridges, automated services.
Docker
dockerfile
# Dockerfile
FROM rust:1.75-slim as builder
WORKDIR /app
COPY . .
RUN cargo build --release --bin ifm-cli
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates libssl3 && \
rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/ifm-cli /usr/local/bin/ifm
USER 1000:1000
ENTRYPOINT ["ifm"]yaml
# docker-compose.yml for headless bot
version: '3.8'
services:
ifm-bot:
image: myorg/ifm-bot:latest
environment:
- IFM_CONFIG=/config/bot.toml
- IFM_DATA_DIR=/data
volumes:
- ./bot-config.toml:/config/bot.toml:ro
- bot-data:/data
restart: unless-stopped
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
volumes:
bot-data:Kubernetes
yaml
# ifm-bot-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ifm-bot
spec:
replicas: 1
selector:
matchLabels:
app: ifm-bot
template:
metadata:
labels:
app: ifm-bot
spec:
containers:
- name: ifm-bot
image: myorg/ifm-bot:latest
env:
- name: IFM_CONFIG
value: /config/bot.toml
- name: IFM_DATA_DIR
value: /data
volumeMounts:
- name: config
mountPath: /config
readOnly: true
- name: data
mountPath: /data
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
livenessProbe:
exec:
command: ["ifm", "stats", "--json"]
initialDelaySeconds: 30
periodSeconds: 60
volumes:
- name: config
configMap:
name: ifm-bot-config
- name: data
emptyDir: {} # Or persistent volumeMobile Deployment
iOS (Swift)
swift
// IFMBridge.swift
import Foundation
import ifm_ffi // Generated from uniffi
class IFMManager {
private var node: OpaquePointer?
func start(config: IFMConfig) async throws {
node = try await IFMFFI.createNode(config: config)
try await IFMFFI.connect(node: node!)
}
func tune(_ frequency: String) async throws {
try await IFMFFI.tune(node: node!, frequency: frequency)
}
func broadcast(_ text: String) async throws {
try await IFMFFI.broadcast(node: node!, text: text)
}
func onMessage(_ handler: @escaping (IFMMessage) -> Void) {
IFMFFI.setMessageHandler(node: node!) { msg in
handler(IFMMessage(from: msg))
}
}
}Android (Kotlin)
kotlin
// IFMManager.kt
class IFMManager(private val context: Context) {
private var node: Long = 0
suspend fun start(config: IFMConfig) {
node = IFMNative.createNode(config)
IFMNative.connect(node)
}
suspend fun tune(frequency: String) {
IFMNative.tune(node, frequency)
}
suspend fun broadcast(text: String) {
IFMNative.broadcast(node, text)
}
fun setMessageHandler(handler: (IFMMessage) -> Unit) {
IFMNative.setMessageHandler(node) { msg ->
handler(IFMMessage.fromNative(msg))
}
}
}Permissions (Android)
xml
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<service
android:name=".IFMService"
android:foregroundServiceType="microphone" />Browser/WASM Deployment
Build WASM Module
bash
# Install wasm-pack
cargo install wasm-pack
# Build
cd crates/ffi
wasm-pack build --target web --out-dir ../../pkg/webWeb Application
html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>IFM Web Radio</title>
<script type="module">
import init, { IFM } from './pkg/web/ifm_sdk.js';
async function main() {
await init();
const radio = await IFM.create({
storage: 'indexeddb',
name: 'Web User'
});
await radio.connect();
await radio.tune('91.700');
radio.on('message', (msg) => {
console.log('Message:', msg.text);
addMessage(msg);
});
// UI handlers
document.getElementById('send').onclick = async () => {
const input = document.getElementById('input');
await radio.broadcast(input.value);
input.value = '';
};
}
main().catch(console.error);
</script>
</head>
<body>
<div id="messages"></div>
<input id="input" placeholder="Type message...">
<button id="send">Send</button>
</body>
</html>HTTPS Required
bash
# Development with mkcert
mkcert -install
mkcert localhost 127.0.0.1 ::1
# Serve with HTTPS
npx serve -s . -l 3000 --ssl-cert localhost+2.pem --ssl-key localhost+2-key.pemService Worker (Offline Support)
javascript
// sw.js
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('ifm-v1').then((cache) => {
return cache.addAll([
'/',
'/pkg/web/ifm_sdk.js',
'/pkg/web/ifm_sdk_bg.wasm'
]);
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
);
});IoT/Embedded Deployment
Raspberry Pi
bash
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source ~/.cargo/env
# Build for ARM
rustup target add aarch64-unknown-linux-gnu
cargo build --release --target aarch64-unknown-linux-gnu
# Run
./target/aarch64-unknown-linux-gnu/release/ifm-cli connectsystemd for Pi
ini
# /etc/systemd/system/ifm-sensor.service
[Unit]
Description=IFM Sensor Node
After=network-online.target
[Service]
Type=simple
User=pi
ExecStart=/home/pi/ifm-cli connect --config /home/pi/.config/ifm/sensor.toml
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetSensor Config
toml
# sensor.toml
[node]
name = "greenhouse-sensor-01"
storage = "./data"
relay = false
connections = 16
[network]
bootstrap = true
lan = true
quic = true
webrtc = false
[audio]
enabled = false
[plugins]
auto_load = falseUpgrading Nodes
Zero-Downtime Upgrade (Relay/Bootstrap)
bash
# 1. Prepare new binary
cp ifm-new /usr/local/bin/ifm-new
# 2. Test with new binary
/usr/local/bin/ifm-new stats --json
# 3. Swap atomically
mv /usr/local/bin/ifm /usr/local/bin/ifm-old
mv /usr/local/bin/ifm-new /usr/local/bin/ifm
# 4. Restart service
systemctl reload ifm-bootstrap # Or restart for non-reloadable changesConfiguration Migration
bash
# Validate new config format
ifm config validate --config new-config.toml
# Migrate
ifm config migrate --from old-config.toml --to new-config.tomlBackup & Recovery
Identity Backup
bash
# Backup identity (CRITICAL)
cp ~/.local/share/ifm/identity.key ~/backups/ifm-identity-$(date +%Y%m%d).key
chmod 600 ~/backups/ifm-identity-*.key
# Encrypt backup
gpg --symmetric --cipher-algo AES256 ~/backups/ifm-identity-$(date +%Y%m%d).keyFull Data Backup
bash
#!/bin/bash
# backup-ifm.sh
DATA_DIR="${IFM_DATA_DIR:-~/.local/share/ifm}"
BACKUP_DIR="$HOME/backups/ifm-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"
rsync -av --exclude='cache/' --exclude='logs/' "$DATA_DIR/" "$BACKUP_DIR/"
tar czf "$BACKUP_DIR.tar.gz" -C "$(dirname "$BACKUP_DIR")" "$(basename "$BACKUP_DIR")"
rm -rf "$BACKUP_DIR"
echo "Backup saved to $BACKUP_DIR.tar.gz"Restore
bash
# Stop node
systemctl --user stop ifm.service
# Restore identity
cp backup/identity.key ~/.local/share/ifm/identity.key
chmod 600 ~/.local/share/ifm/identity.key
# Restore config
cp backup/config.toml ~/.config/ifm/config.toml
# Start node
systemctl --user start ifm.serviceTroubleshooting Deployment
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| "Address already in use" | Port conflict | Change port in config, check ss -tulpn |
| "Permission denied" | File perms | Fix ownership: chown -R user:user ~/.local/share/ifm |
| "No peers found" | Firewall/NAT | Open UDP 4001, enable UPnP, check bootstrap |
| "Out of memory" | Cache too large | Reduce node.cache in config |
| "Too many open files" | FD limit | Increase ulimit -n 65536 |
| "Identity corrupted" | Disk error | Restore from backup, or regenerate |
Debug Commands
bash
# Verbose connection
ifm connect -v
# Check network
ifm stats --json | jq '.network'
# Test specific bootstrap
ifm connect --bootstrap /ip4/1.2.3.4/udp/4001/quic-v1/p2p/12D3KooW...
# Check ports
ss -tulpn | grep 4001
# Check logs
journalctl -u ifm-bootstrap -f
tail -f ~/.local/share/ifm/logs/ifm.logSecurity Checklist
- [ ] Identity key backed up securely (offline, encrypted)
- [ ] Config file permissions: 640 (root:ifm group)
- [ ] Data directory permissions: 700 (ifm user)
- [ ] Firewall: Only required ports open (4001 UDP/TCP)
- [ ] Systemd: Hardening options enabled
- [ ] Monitoring: Alerts on peer count, memory, CPU
- [ ] Updates: Automatic security updates enabled
- [ ] Logging: No sensitive data in logs
- [ ] Bootstrap nodes: Multiple, geographically distributed
- [ ] Relay nodes: Bandwidth limits configured
Scaling Guidelines
| Nodes | Bootstrap | Relays | Config Adjustments |
|---|---|---|---|
| < 100 | 1 | 0 | Default |
| 100-1K | 2-3 | 2-5 | connections=500, cache=512MB |
| 1K-10K | 5+ | 10+ | connections=1000, cache=1GB, DHT server mode |
| 10K+ | 10+ (anycast) | 50+ | connections=5000, cache=5GB, dedicated hardware |
Support
- Documentation: https://docs.ifm.network/deployment
- GitHub Issues: https://github.com/ifmprotocol/ifm/issues
- Discord: https://discord.gg/ifm (deployment channel)
- Email: deployment@ifm.network