Reticulum-Go/docs/en/configuration.md
2026-08-25 16:41:36 -05:00

19 KiB

Configuration

Overview

Reticulum-Go reads the same INI-style configuration shape as Python Reticulum. The canonical parser lives in pkg/reticulumconfig. The daemon imports it through internal/config.

Default config path:

~/.reticulum-go/config

Override with --config on the daemon command line.

Config directory layout

~/.reticulum-go/
  config
  storage/
    identities/
    cache/
      announces/
    resources/
    ratchets/
    blackhole
    destination_table
    known_destinations/
    transport_identity
    dos_protect.mpack

Python uses ~/.reticulum or /etc/reticulum by default. Reticulum-Go uses a separate directory so both stacks can run on one host.

storage/ratchets/ holds known-peer public keys named by destination hash (Python {ratchet, received} msgpack) and destination-private signed lists at the path EnableRatchets was given. Pageserver names that file by destination hash, same as Python LXMF. EnableRatchetsInMemory and in_memory_storage keep ratchet material in RAM.

File format

Aspect Behavior
Sections [reticulum], [logging], Interface Name
Interface blocks Double-bracket headers at nesting depth 2
Comments # or ; (including end-of-line after a space)
Booleans yes, no, true, false, on, off, 1, 0 (case insensitive)
Unknown keys Ignored (allows boot with extra or damaged lines)
UTF-8 BOM Stripped on read
Missing file Default config is created

Section [reticulum]

Key Default Description
enable_transport yes Enable mesh transport routing. A shared-instance owner still relays local-client path and link traffic when this is no
share_instance yes Use shared instance multiplexing
shared_instance_port 37428 TCP port for shared instance
instance_control_port 37429 Control port when this process owns the instance
shared_instance_type unix on Linux, tcp elsewhere tcp or unix (unset uses platform default, matching Python RNS)
instance_name (empty) Unix socket name when type is unix
rpc_key (empty) Hex key for shared-instance RPC and control API auth
enable_sandbox yes Apply OS sandbox after startup (Go-only)
enable_seccomp yes Linux seccomp-bpf denylist after Landlock (TSYNC, then all-threads, then prctl fallback, soft-fails if unsupported)
sandbox_strict no Exit if Landlock, seccomp, OpenBSD unveil lock, or FreeBSD CapEnter fail. Stub and WASM still start
sandbox_profile full full keeps /bin for pipe and pageserver exec. router omits those trees on Linux Landlock only. Not tied to node_profile
sandbox_extra_paths (empty) Comma-separated extra filesystem paths for Landlock and OpenBSD unveil (serial, custom binaries)
sandbox_exec_rlimits no Linux only. Apply NPROC=32 and CORE=0 to pipe, discovery, and dynamic .mu child processes
enable_control_api no Start localhost control API
control_api_host 127.0.0.1 Control API bind address
control_api_port 37430 Control API port
control_api_socket (empty) Optional Unix socket path in addition to TCP
backbone_io auto Backbone poller: auto, epoll, kqueue, io_uring, go
in_memory_path_table no Keep path table in RAM only
in_memory_known_destinations no Keep known destinations in RAM only
in_memory_storage no Fully ephemeral mode: no disk for paths, known dests, known-peer ratchets, transport identity, blackhole, or split resources. Implies both table flags
identity_backend file Identity at-rest store: file, secretservice (Freedesktop Secret Service), or keyring (Linux kernel keyring)
soft_memory_limit (none) Soft heap budget (K/M/G or bytes) via Go debug.SetMemoryLimit. Env: RETICULUM_SOFT_MEMORY_LIMIT
dos_protection off Go-only local IDS/IPS gates. Default off. Values: off, detect, prevent, auto (alias smart). See DoS protection
max_in_memory_paths 100000 Soft cap on the live path table in RAM (disk-backed and in-memory). Zero uses default. Negative disables. Env: RETICULUM_MAX_IN_MEMORY_PATHS
max_in_memory_known_destinations 100000 Soft cap on known destinations in RAM. Zero uses default. Negative disables. Env: RETICULUM_MAX_IN_MEMORY_KNOWN_DESTINATIONS
max_in_memory_resource_bytes 256M Split-resource staging budget when in_memory_storage is yes. Negative disables
max_packet_hashlist auto Packet hash loop-filter size. Zero: 1M when enable_transport is yes, else 100k. Negative forces 1M. Env: RETICULUM_MAX_PACKET_HASHLIST
max_packet_handlers 512 HandlePacket worker count and queue depth. Overflow sheds under dos_protection
node_profile default Go-only overlay: default, core_router, or embedded. Fills unset knobs only. Explicit keys always win
discover_interfaces no Start rnstransport interface discovery listener
autoconnect_discovered_interfaces 0 Max concurrent autoconnect peers from discovery (>0 enables)
autoconnect_interface_gravity (unset) Gravity applied to autoconnected interfaces
autoconnect_interface_mode (unset) Mode override for autoconnected interfaces
autoconnect_announces_to_internal (unset) announces_to_internal on autoconnect peers
publish_blackhole no Register rnstransport.info.blackhole with /list
blackhole_sources (empty) Comma-separated transport identity hashes to pull blackhole lists from
blackhole_update_interval 60 Minutes between blackhole source pulls (floor 2)
watch_interfaces no Poll NIC up/down and rescan Auto interfaces (Go-only)
static_transport_identity no Keep persisted transport identity on the wire when enable_transport is no (RNS 1.3.6+)
local_hops_delta no Mangling applied on local-origin hop-0 packets (delta 2-7)
respond_to_probes / allow_probes no Register rnstransport.probe with prove-all
enable_remote_management no Register rnstransport.remote.management for Python rnpath/rnstatus and Go rgopath/rgostatus -R
remote_management_allowed (empty) Comma-separated identity hashes allowed to use remote management
network_identity (empty) Path to network identity for discovery encrypt/decrypt
panic_on_interface_error no Panic on fatal interface errors

node_profile (Go-only)

node_profile fills unset knobs. Keys present in the file are never overwritten.

Profile Effect when unset
default No overlay
core_router backbone_io=auto, watch_interfaces=yes, max_packet_handlers=max(512, GOMAXPROCS*64), max_in_memory_paths=500000. Does not enable dos_protection
embedded max_packet_handlers=32, max_in_memory_paths=4096, smaller known-dest and hashlist caps

dos_protection (Go-only)

Local overload gates in pkg/protect. They keep this node alive under floods and resource storms. They do not ban peers mesh-wide and do not replace IFAC, link crypto, or Sybil-resistant admission policy.

Mode Behavior
off Disabled
detect (alias ids) Trip, count, and rate-limited stdout warnings. Traffic still flows
prevent (aliases block, ips) Same as detect, and shed or block on trip
auto (alias smart) Learn quietly, then arm prevent. Relearn on interface fingerprint change or sustained moderate drift. Floods stay armed

Default is off. Mesh announce and path-request filtering still runs in Transport regardless of this key. Turn detect or auto on only after you have watched a busy node, and prevent only if you accept local shedding.

Example (opt-in):

[reticulum]
  dos_protection = auto

Learning state is written as msgpack to {config_dir}/storage/dos_protect.mpack (atomic replace). Restarts restore armed baselines when the interface fingerprint still matches.

Optional limits (zero or unset keeps built-in defaults):

Key Purpose
dos_max_pps Absolute per-iface packet rate ceiling
dos_max_bps Absolute per-iface byte rate ceiling
dos_floor_pps Minimum adaptive trip line (pps)
dos_floor_bps Minimum adaptive trip line (bps)
dos_max_conns Concurrent stream accepts per iface
dos_max_resources Concurrent incoming resources process-wide
dos_max_crypto Concurrent crypto verify jobs
dos_max_handshake Concurrent link handshake jobs

Ingress uses interface bitrate when available to scale adaptive floors. Announce-class traffic sheds at the adaptive trip line. Path requests, data, and established link or proof traffic may stay admitted above that line (up to 2x, or the advertised bitrate if higher). That band does not arm interface cool-down. Interface-wide cool-down is off by default so a public UDP listener is not blackholed. A single flooder can still be peer-cooled.

Operator visibility: reticulum-go status -json and shared-instance interface_stats include a protect object (mode, phase, trip lines, cool-down). Control API GET /v1/status includes the same protect block.

Surfaces gated when mode is not off:

Gate Typical attack class
Per-iface packet pps / bps Packet floods (adaptive EWMA baseline, once-per-second peak samples)
Handler overflow Packet handler overload
Stream accepts TCP / QUIC / VSOCK / I2P / Local connection storms
Incoming resources Resource / transfer pile-up
Crypto jobs Decrypt / verify / HMAC storms
Handshakes Link setup / proof floods
Memory shed Soft heap pressure (pairs with soft_memory_limit)
Iface cool-down Opt-in 15s hard reject after a burst of trips on one iface. Off by default so a public UDP listener is not blackholed

Stdout trip lines look like:

WARNING: dos_protection prevent trip reason=pps iface=udp0
WARNING: dos_protection auto/learning trip reason=pps iface=udp0
WARNING: dos_protection auto promote reason=stable phase=armed
WARNING: dos_protection auto relearn reason=network phase=learning

Health kinds dos_* increment on trips. See Security and Development and testing.

Keys present in Python but ignored in Go

None for blackhole federation or discovery autoconnect. Those keys are driven in Go.

local_hops_delta applies a random hop field (2-7) on locally originated hop-0 packets when not connected to a shared instance.

Section [logging]

Key Supported
loglevel Yes (0 silent, 1 critical, 2 error, 3 warning, 4 info, 5 verbose, 6 trace, 7 packets)
destination Yes (stderr, file, both, syslog, journald, and combinations such as syslog+stderr)
logfile Yes (default {config_dir}/logfile/reticulum.log)
format Yes (text or json)

Default loglevel is 4 (info). That prints start/stop, interface up/down, and link established/closed. It does not print per-packet forwarding.

loglevel Name Typical content
0 silent nothing
1 critical fatal conditions
2 error failed operations
3 warning recovered problems (bad signature, timeout)
4 info operator lifecycle (default)
5 verbose per-session protocol detail
6 trace per-packet headers and forwarding
7 packets wire dumps and packet hex

CLI -debug N overrides config for one run (0 through 7). Hot paths skip argument formatting unless the active level would emit the line.

Interface blocks Name

Each block defines one interface. Common keys:

Key Applies to Description
type All Interface type string (see Interfaces)
enabled / interface_enabled All Enable or disable
mode / interface_mode All full, gateway, access_point, roaming, boundary, ptp, internal (RNS 1.3.6+)
recursive_prs All Discover unknown paths on this interface (RNS 1.3.6+)
announces_from_internal All Rebroadcast announces learned via internal-mode next hops (default yes)
address / listen_ip UDP, TCP/QUIC/WebTransport/HTTPS server, DNSRendezvous Bind address
port / listen_port UDP, TCP/QUIC/WebTransport/HTTPS/VSOCK server, DNSRendezvous Bind or VSOCK port
target_host / target_port TCP, QUIC, WebTransport, HTTPS client Remote peer
target_address UDP Remote peer (preferred over target_host)
interface Auto OS network interface name
prefer_ipv6 TCP, Auto Prefer IPv6 when available
max_reconnect_tries TCP, UDP, backbone, QUIC, WebTransport, HTTPS, VSOCK -1 or omitted means unlimited
bitrate All Declared bitrate hint
mtu All Interface MTU (default packet MTU is 500 bytes)
discovery_port Auto Multicast discovery port
data_port Auto Data port
discovery_scope Auto Multicast scope
group_id Auto Group identifier
multicast_address_type Auto Multicast address type
announce_cap All Cap on outbound announces as a percent of bitrate (default 2). Excess announces wait on the per-interface queue
announce_rate_* All Announce rate control
ingress_control / ic_* All Ingress rate limits
network_name IFAC IFAC network name
passphrase IFAC IFAC passphrase
ifac_* IFAC Additional IFAC options
sam_address I2P SAM server host:port
peers I2P Outbound tunnel peers
connectable I2P SAM server tunnel mode
i2p_tunneled TCP client, backbone client Tunnel over I2P
command Pipe External program for stdin/stdout HDLC bridge
respawn_delay / respawn_interval Pipe Seconds before respawning subprocess (default 5)
shared_instance_type Local tcp or unix for explicit local interface blocks
instance_name Local Unix socket name when type is unix
cert_file / key_file QUIC, WebTransport, HTTPS Optional TLS PEM paths
peer_key QUIC, WebTransport, HTTPS Leaf SPKI SHA-256 pin (hex)
sni QUIC, WebTransport, HTTPS client TLS ServerName
path WebTransport, HTTPS URL path (default /rns)
transport_mode WebTransport datagram, stream, or dual
domain DNSRendezvous DNS name for TXT lookup
resolve_interval DNSRendezvous Seconds between TXT re-queries (default 60)
context_id / cid VSOCK client Peer AF_VSOCK context ID
long_poll_sec HTTPS Long-poll timeout seconds (default 25)
outgoing / selected_outgoing All Transmit permit (default yes). When no, interface is receive-only

Unknown type values load Go-native plugins from {config_dir}/interfaces/ (JSON manifest or executable pipe driver), or from interfaces.RegisterExternalFactory.

Interface types

type value Implementation
UDPInterface pkg/interfaces/udp.go
TCPClientInterface pkg/interfaces/tcp.go
TCPServerInterface pkg/interfaces/tcp.go
AutoInterface pkg/interfaces/auto.go
I2PInterface pkg/interfaces/i2p.go
BackboneInterface pkg/interfaces/backbone.go
BackboneClientInterface pkg/interfaces/backbone_client.go
PipeInterface pkg/interfaces/pipe.go
LocalInterface pkg/interfaces/local.go (client to shared instance)
LocalServerInterface pkg/interfaces/local.go (explicit server block)
WebSocketInterface Go-only, native or WASM
QUICClientInterface Go-only, native (quic-go)
QUICServerInterface Go-only, native (quic-go)
WebTransportClientInterface Go-only, HTTP/3 WebTransport
WebTransportServerInterface Go-only, HTTP/3 WebTransport
DNSRendezvousInterface Go-only, DNS TXT to UDP peer
VSOCKClientInterface Go-only Linux, AF_VSOCK HDLC
VSOCKServerInterface Go-only Linux, AF_VSOCK HDLC
HTTPSClientInterface Go-only, TLS long-poll
HTTPSServerInterface Go-only, TLS long-poll

Example: TCP client with IFAC

[[Gateway]]
type = TCPClientInterface
enabled = yes
target_host = mesh.example.com
target_port = 7825
network_name = MyMesh
passphrase = long-random-secret
ifac_size = 16
max_reconnect_tries = 0

max_reconnect_tries = 0 means no reconnect attempts after disconnect. Omit the key or set -1 for unlimited retries.

Example: QUIC client and server

[[QUIC Hub]]
type = QUICServerInterface
enabled = yes
listen_ip = 0.0.0.0
listen_port = 4242

[[QUIC Uplink]]
type = QUICClientInterface
enabled = yes
target_host = hub.example.com
target_port = 4242
peer_key = aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899
max_reconnect_tries = -1

QUIC is Go-only. TLS uses ephemeral self-signed certificates by default. Set peer_key to the remote leaf SPKI SHA-256 (hex) to pin the peer. Optional cert_file / key_file and sni are supported. Not available on WASM.

Example: AutoInterface on Wi-Fi

[reticulum]
watch_interfaces = yes

[[WiFi Mesh]]
type = AutoInterface
enabled = yes
interface = wlan0
discovery_port = 35615
data_port = 35616

watch_interfaces rescans NICs when link state changes and helps AutoInterface follow Wi-Fi roam events.

Example: PipeInterface subprocess bridge

[[Radio Bridge]]
type = PipeInterface
enabled = yes
command = /opt/mesh/radio-bridge --stdio
respawn_delay = 5

Reticulum writes HDLC-framed packets to the subprocess stdin and reads frames from stdout. When the subprocess exits, the interface respawns after respawn_delay seconds.

Example: shared-instance RPC for Go CLI tools

On Linux, unset shared_instance_type uses abstract Unix sockets (@rns/<instance_name>/rpc), matching stock Python rnsd. Go utilities try that default first, then fall back to TCP when the type is unset.

make build
./bin/reticulum-go status -config ~/.reticulum -json

Optional shared auth (recommended when mixing stacks):

[reticulum]
share_instance = yes
instance_name = default
shared_instance_type = unix
rpc_key = <64 hex characters>

Use shared_instance_type = tcp with instance_control_port when you want TCP on every OS. Use -config ~/.reticulum for Python rnsd and -config ~/.reticulum-go for a Go shared instance. Full utility docs are in CLI utilities.

Example: explicit LocalInterface client

When share_instance = no, attach to another process that owns the shared instance:

[reticulum]
share_instance = no

[[Local]]
type = LocalInterface
enabled = yes
port = 37428
shared_instance_type = tcp

Hot reload

On Unix the daemon reloads interface blocks on SIGHUP via node.ReloadInterfaces. Reload compares normalized config for each interface including MTU, bitrate, prefer_ipv6, announce-rate, ingress/egress control, mode, and outgoing. See Interfaces.

Programmatic access

import "quad4/reticulum-go/pkg/reticulumconfig"

cfg, err := reticulumconfig.LoadConfig("/path/to/config")

Defaults without a file:

cfg := reticulumconfig.DefaultConfig()

Save:

err := reticulumconfig.SaveConfig(cfg)

Storage and identity files

Identity files use a 64-byte software layout (X25519 private plus Ed25519 seed). Reticulum-Go stores identity blobs under storage/identities/ keyed by hash. Python may use per-name files. Both layouts are supported for loading.

Optional hardware-bound descriptors (RHB1, 72 bytes) are documented in Identity and destinations.