Run as a service
You want the node to start on boot, stay running, restart on crash, and log somewhere predictable. Three options below.
Linux: systemd
Create /etc/systemd/system/exfer.service:
[Unit]
Description=Exfer node
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=exfer
Group=exfer
ExecStart=/usr/local/bin/exfer node \
--datadir /var/lib/exfer \
--rpc-bind 127.0.0.1:9334 \
--repair-perms
Restart=on-failure
RestartSec=10
LimitNOFILE=65536
# Hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/exfer
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Create the user and data directory once:
sudo useradd --system --home /var/lib/exfer --shell /usr/sbin/nologin exfer
sudo install -d -o exfer -g exfer -m 0750 /var/lib/exfer
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable --now exfer
sudo systemctl status exfer
sudo journalctl -fu exfer
Mining variant — replace the ExecStart line with:
ExecStart=/usr/local/bin/exfer mine \
--datadir /var/lib/exfer \
--miner-pubkey YOUR_PUBKEY_HEX \
--rpc-bind 127.0.0.1:9334 \
--repair-perms
The pubkey-only mining mode means the wallet private key never lives on the mining host. See Solo mine.
macOS: launchd
Create ~/Library/LaunchAgents/org.exfer.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>org.exfer.node</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/exfer</string>
<string>node</string>
<string>--datadir</string>
<string>/Users/you/.exfer</string>
<string>--rpc-bind</string>
<string>127.0.0.1:9334</string>
<string>--repair-perms</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>StandardOutPath</key><string>/tmp/exfer.log</string>
<key>StandardErrorPath</key><string>/tmp/exfer.log</string>
</dict>
</plist>
Load it:
launchctl load ~/Library/LaunchAgents/org.exfer.node.plist
launchctl list | grep exfer
tail -f /tmp/exfer.log
To stop / reload:
launchctl unload ~/Library/LaunchAgents/org.exfer.node.plist
launchctl load ~/Library/LaunchAgents/org.exfer.node.plist
Docker
Minimal Dockerfile:
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl \
&& rm -rf /var/lib/apt/lists/*
RUN curl -L -o /usr/local/bin/exfer \
https://github.com/ahuman-exfer/exfer/releases/latest/download/exfer-linux-x86_64 \
&& chmod +x /usr/local/bin/exfer
WORKDIR /data
EXPOSE 9333
CMD ["exfer", "node", "--datadir", "/data", "--rpc-bind", "0.0.0.0:9334", "--repair-perms"]
Run:
docker build -t exfer .
docker run -d --name exfer \
-p 9333:9333 -p 127.0.0.1:9334:9334 \
-v exfer-data:/data \
--restart unless-stopped \
exfer
docker logs -f exfer
Notes:
- Use a named volume (
-v exfer-data:/data) to persist the chain across container restarts. - Map
9334only to localhost (127.0.0.1:9334:9334). The RPC has no authentication — exposing it on0.0.0.0is dangerous on shared hosts.
Resource expectations
A small VPS is plenty for a full node:
| Resource | Comfortable | Tight |
|---|---|---|
| RAM | 1 GB | 512 MB |
| Disk | 50 GB | 20 GB (grows over time) |
| CPU | 1 vCPU | shared-CPU is OK |
| Network | 10 Mbps | 1 Mbps still works once synced |
Mining changes the picture — Argon2id is memory-hard, so each miner thread needs ~64 MiB of resident memory. See Solo mine.