Restart=on-failure with RestartSec=5 and systemd's default start limit (5 starts in 10 s) never trips: one start every 5 s or more stays under it, so a daemon whose start cannot succeed, such as one given an empty or invalid config, respawned every 5 s for as long as it was left, paying its full start-up cost each time. The fips and fips-gateway units in the tarball, .deb, AUR (which installs the .deb units) and NixOS module now set RestartSteps=5 and RestartMaxDelaySec=30. systemd grows the delay exponentially from RestartSec to the maximum over the steps, so successive automatic restarts wait 5 s, 7 s, 10 s, 15 s, 21 s and then 30 s each. The step count is systemd's restart counter, which a successful run does not clear: it is reset by a stop then start, a restart while the unit is running, or systemctl reset-failed, and not by a restart issued while the unit is waiting to restart. A unit that has backed off once therefore keeps the longer delay for later failures until one of those happens. The comments in the units say so. The units keep restarting without a limit: a start limit would leave a remote node down after a bad boot, and the mesh may be the only way to reach it. systemd before v254 ignores both keys with a warning and keeps the fixed 5 s delay. A packaging test checks that each tarball and .deb unit that restarts sets both keys, that the two copies of each unit agree on them, and that each NixOS service restarted on failure sets the same values as the unit of that name. Other supervisors are left as they are. fips-dns and fips-firewall are Type=oneshot units without Restart=. OpenWrt's procd init scripts, which stop respawning after more than 5 consecutive runs shorter than an hour, are changed separately to respawn without a limit. launchd throttles the macOS KeepAlive job by its default ThrottleInterval of 10 s. The Windows service is installed without recovery actions, so the service manager does not restart it, and the FreeBSD rc script runs daemon(8) without -r, so it does not restart either.
FIPS Installation Guide
Quick Start
tar xzf fips-*-linux-*.tar.gz
cd fips-*-linux-*/
sudo ./install.sh
What Gets Installed
| File | Location |
|---|---|
| fips (daemon) | /usr/local/bin/fips |
| fipsctl (CLI) | /usr/local/bin/fipsctl |
| fipstop (TUI) | /usr/local/bin/fipstop |
| fips-gateway (LAN bridge) | /usr/local/bin/fips-gateway |
| Configuration | /etc/fips/fips.yaml |
| Identity key | /etc/fips/fips.key (generated on first start with persistent: true) |
| Public key | /etc/fips/fips.pub (written on every start) |
| Hosts file | /etc/fips/hosts |
| Firewall baseline | /etc/fips/fips.nft |
| Firewall drop-in directory | /etc/fips/fips.d/ |
| Daemon unit | /etc/systemd/system/fips.service (enabled) |
| DNS routing unit | /etc/systemd/system/fips-dns.service (enabled) |
| Gateway unit | /etc/systemd/system/fips-gateway.service (NOT enabled) |
| Firewall unit | /etc/systemd/system/fips-firewall.service (NOT enabled) |
| DNS helpers | /usr/lib/fips/fips-dns-{setup,teardown} |
A system group fips is created for control socket access. By
default, only fips.service and fips-dns.service are enabled at
install time. fips-gateway.service and fips-firewall.service
are installed but require explicit operator opt-in (see the
sections below).
Post-Install Configuration
Edit /etc/fips/fips.yaml before starting the service.
1. Identity
By default, the node generates a new ephemeral identity on each start
for privacy. If the node's npub will be published for others to use as a
static peer, enable a stable identity by uncommenting persistent: true
in the identity section:
node:
identity:
persistent: true
On first start with persistence enabled, a keypair is auto-generated and saved:
/etc/fips/fips.key(mode 0600) — secret key/etc/fips/fips.pub(mode 0644) — public key (npub)
The same identity is reused on subsequent starts. Alternatively, set
node.identity.nsec to use a specific key.
2. Ethernet Transport
If using Ethernet for local mesh discovery, uncomment the ethernet section and set the interface name:
transports:
ethernet:
interface: "eth0"
listen: true
announce: true
auto_connect: true
accept_connections: true
3. Bluetooth Transport
BLE is compiled automatically on glibc Linux and Android; there is no cargo feature to enable. BlueZ must be installed and running:
sudo apt install bluez
sudo systemctl enable --now bluetooth
Add your service user to the bluetooth group, or run with
CAP_NET_ADMIN + CAP_NET_RAW capabilities.
Configure BLE in the transports section:
transports:
ble:
adapter: "hci0"
advertise: true
scan: true
auto_connect: true
accept_connections: true
4. Static Peers
For bootstrapping over UDP or TCP, add known peers:
peers:
- npub: "npub1..."
alias: "gateway"
addresses:
- transport: udp
addr: "test-us01.fips.network:2121" # IP or hostname (e.g., "peer.example.com:2121")
connect_policy: auto_connect
5. DNS Resolver
FIPS includes a DNS responder for .fips domain names that listens on
fips0 and on [::1]:5354. The fips-dns.service helper detects the
host's DNS routing system and configures it to forward .fips queries
to the responder. Backends tried in order:
- systemd
dns-delegatedrop-in (systemd >= 258, declarative) systemd-resolvedglobal drop-in via/etc/systemd/resolved.conf.d/systemd-resolvedper-linkresolvectl(legacy fallback)dnsmasq(standalone, drops a config in/etc/dnsmasq.d/)- NetworkManager with the
dnsmasqplugin
If none of the supported backends is detected, fips-dns-setup logs a
warning with manual instructions and exits cleanly. The daemon itself
keeps working; only the host's .fips resolution is left unwired.
The installer enables fips-dns.service automatically. To disable
or re-enable later:
sudo systemctl disable --now fips-dns.service # disable
sudo systemctl enable --now fips-dns.service # re-enable
6. Mesh-interface firewall baseline (optional)
fips.nft is a default-deny baseline for inbound traffic on the
fips0 mesh interface. It is shipped as /etc/fips/fips.nft (not
loaded by default) along with a disabled fips-firewall.service
unit. Enable it explicitly:
sudo systemctl enable --now fips-firewall.service
The baseline polices only the interface named by the fips_if define
at the top of the file (fips0, the default tun.name), leaving
Docker, Tor, the host firewall, and other interfaces untouched. If you
set tun.name to another name, change fips_if to match and reload;
until then the baseline polices nothing on the TUN, the daemon logs a
warning at startup, and fipstop shows every listener as exposed. Outbound from fips0 is
unrestricted; inbound is dropped except for replies to outbound
flows, ICMPv6 echo-request, and any operator drop-ins under
/etc/fips/fips.d/*.nft. Read the comments at the top of
/etc/fips/fips.nft for the full policy and how to add per-service
allow rules.
7. Outbound LAN gateway (optional)
fips-gateway bridges unmodified LAN hosts to .fips destinations
through a DNS-allocated virtual IPv6 pool and kernel nftables NAT.
The binary is installed at /usr/local/bin/fips-gateway and a
fips-gateway.service unit ships disabled by default.
To enable it, configure the gateway block in /etc/fips/fips.yaml,
then:
sudo systemctl enable --now fips-gateway.service
The unit Requires=fips.service, waits up to 30 seconds for fips0
to come up, and runs fips-gateway --config /etc/fips/fips.yaml.
Inbound port-forward rules can be added in the same gateway:
block.
Firewall Ports
| Port | Protocol | Purpose |
|---|---|---|
| 2121 | UDP | Peer-to-peer mesh traffic |
| 8443 | TCP | Inbound peer connections |
Service Management
The install ships four units. fips.service and fips-dns.service
are enabled at install time. fips-gateway.service and
fips-firewall.service are installed but disabled until the
operator opts in.
# Daemon
sudo systemctl start fips
sudo systemctl stop fips
sudo systemctl restart fips
# DNS routing helper
sudo systemctl restart fips-dns
# Optional services (opt-in)
sudo systemctl enable --now fips-firewall # mesh-interface nftables baseline
sudo systemctl enable --now fips-gateway # outbound LAN gateway
# View logs (any of the units above)
sudo journalctl -u fips -f
sudo journalctl -u fips-gateway -f
sudo journalctl -u fips-firewall -f
# Switch to debug logging
sudo systemctl set-environment RUST_LOG=debug
sudo systemctl restart fips
Monitoring
# Quick status
fipsctl show status
# Interactive dashboard
fipstop
# Other queries
fipsctl show peers
fipsctl show links
fipsctl show sessions
fipsctl show routing
fipsctl show transports
Non-Root Access to fipsctl/fipstop
Add your user to the fips group:
sudo usermod -aG fips $USER
Log out and back in for the group change to take effect.
Uninstall
# Remove binaries and service, keep configuration
sudo ./uninstall.sh
# Remove everything including /etc/fips/ and the fips group
sudo ./uninstall.sh --purge