Operations guide β
How to install, configure, update, back up, and remove Supply Drop BBS.
Quick install
Auto-detects your architecture (arm64, armhf, or amd64):
ARCH=$(dpkg --print-architecture)
curl -fsSL \
"https://github.com/Mesh-America/supply-drop-bbs/releases/latest/download/supply-drop-bbs_${ARCH}.deb" \
-o supply-drop-bbs.deb
sudo dpkg -i supply-drop-bbs.deb
sudo supply-drop-bbs setup
sudo systemctl start supply-drop-bbsJump to the full installation section for all options and details.
This guide covers MeshCore
The installation and configuration steps here are written for MeshCore LoRa hardware (USB companion devices and Pi HATs). Supply Drop BBS supports additional transports β Meshtastic, APRS, Telnet, and others β and dedicated guides for those will be added as they mature.
Audience β
Sysops running a Supply Drop BBS deployment:
- Hobbyist mesh radio operators on a Raspberry Pi
- Researchers and educators running a community BBS
- Anyone managing a small-scale BBS deployment over LoRa mesh
If you're a contributor or plugin author, see CONTRIBUTING.md and PLUGIN_API.md.
System requirements β
| Component | Minimum |
|---|---|
| CPU | ARMv7 or better. ARM64 (Pi 4+) recommended. |
| RAM | 256 MB available to the BBS process |
| Disk | 2 GB free for DB + logs + backups; SD card OK |
| Radio | SX1262 Pi HAT or USB MeshCore companion device |
| OS | Linux - Raspberry Pi OS / Debian tested. Other Unixes likely work. |
| Python | 3.10+ - Pi HAT mode only (for pymc_core) |
The BBS itself is a single static Rust binary with no runtime dependencies. Python is only required when using a Pi HAT (ADR-0007). USB device operators need nothing else (ADR-0013).
Architecture at a glance β
Supply Drop BBS supports two deployment topologies depending on your radio hardware.
USB device (single-process) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
β supply-drop-bbs (Rust - one process) β
β β
β bbs-core ββ bbs-mesh ββ meshcore-companion β
β β β
β serial (USB) β
βββββββββββββββββββββββββββββββββββΌβββββββββββββββββ
β
USB companion device
(Heltec V3, T-Beam, β¦)
running MeshCore firmwareThe BBS speaks the companion-frame protocol directly over the serial port. No bridge process, no Python. One service to manage.
Pi HAT (two-process) β
ββββββββββββββββββββββββ ββββββββββββββββββββββββββ
β pymc-companion β β supply-drop-bbs β
β (Python - pymc_core βββTCPβββΊ β (Rust BBS host) β
β CompanionRadio + β β β
β CompanionFrameServerβ β also exposes: β
β β β - web UI (opt-in) β
β manages GPIO/SPI β ββββββββββββββββββββββββββ
β for the LoRa HAT β
ββββββββββββββββββββββββ
β
βΌ
SX1262 LoRa HAT
(ZebraHat, Waveshare, PiMesh, β¦)pymc-companion owns the radio hardware. The BBS connects to it over 127.0.0.1:5000. Two independent processes - either can restart without breaking the other.
Installation β
Before installing, have ready:
- Radio type β USB companion device or Pi HAT
- HAT model β if using a Pi HAT (ZebraHat, Waveshare, PiMesh, etc.)
- Region / frequency β US (910.525 MHz) or EU (869.618 MHz), or your local frequency
Option 1 β Debian package (recommended) β
The .deb package is the easiest way to install on Raspberry Pi OS, Ubuntu, or any Debian-based system. It creates the service user, sets up the directory layout, and registers the systemd unit β no cloning required.
One-liner install β auto-detects your architecture:
ARCH=$(dpkg --print-architecture) # arm64, armhf, or amd64
curl -fsSL \
"https://github.com/Mesh-America/supply-drop-bbs/releases/latest/download/supply-drop-bbs_${ARCH}.deb" \
-o supply-drop-bbs.deb
sudo dpkg -i supply-drop-bbs.deb
sudo supply-drop-bbs setup
sudo systemctl start supply-drop-bbsOr download manually from the latest release if you prefer to inspect the file first:
| Hardware | File |
|---|---|
| Raspberry Pi 4 / 5 (64-bit) | supply-drop-bbs_arm64.deb |
| Raspberry Pi 2 / 3 / Zero 2 (32-bit) | supply-drop-bbs_armhf.deb |
| x86-64 Linux | supply-drop-bbs_amd64.deb |
The package:
- Creates the
supply-dropsystem user - Creates
/var/lib/supply-drop-bbs(data) and/etc/supply-drop-bbs(config) - Installs the
supply-drop-bbs.servicesystemd unit and enables it
Then run the setup wizard and start:
sudo supply-drop-bbs setup
sudo systemctl start supply-drop-bbsPi HAT users
The .deb installs the BBS itself. For Pi HAT support you still need pymc-companion (the Python radio bridge). After the BBS is running, follow the Pi HAT section below, or use the guided setup script (Option 3) which handles the full HAT setup automatically.
Option 2 β Raw binary β
Works on any systemd-based Linux β not just Debian. Download the binary, verify its checksum, then install it and the service unit manually.
# Set these for your system
TAG=v0.6.2 # replace with the latest release tag
ARCH=$(uname -m)
case "$ARCH" in
aarch64) TARGET="aarch64-unknown-linux-gnu" ;;
armv7l) TARGET="armv7-unknown-linux-gnueabihf" ;;
x86_64) TARGET="x86_64-unknown-linux-gnu" ;;
esac
# Download binary and checksum file
curl -fsSL \
"https://github.com/Mesh-America/supply-drop-bbs/releases/download/${TAG}/supply-drop-bbs-${TAG}-${TARGET}" \
-o supply-drop-bbs
curl -fsSL \
"https://github.com/Mesh-America/supply-drop-bbs/releases/download/${TAG}/SHA256SUMS" \
-o SHA256SUMS
# Verify before installing
grep "supply-drop-bbs-${TAG}-${TARGET}" SHA256SUMS | sha256sum -c
# Install binary and service unit
sudo install -m 755 supply-drop-bbs /usr/local/bin/supply-drop-bbs
sudo useradd --system --no-create-home --shell /sbin/nologin \
--home-dir /var/lib/supply-drop-bbs supply-drop 2>/dev/null || true
sudo mkdir -p /var/lib/supply-drop-bbs /etc/supply-drop-bbs
sudo chown supply-drop:supply-drop /var/lib/supply-drop-bbs
# Config dir ownership is set automatically by 'sudo supply-drop-bbs setup'.
# If you create config.toml manually, fix ownership so the web admin can save changes:
sudo chown supply-drop:supply-drop /etc/supply-drop-bbs /etc/supply-drop-bbs/config.toml
sudo curl -fsSL \
"https://raw.githubusercontent.com/Mesh-America/supply-drop-bbs/${TAG}/supply-drop-bbs.service" \
-o /lib/systemd/system/supply-drop-bbs.service
sudo systemctl daemon-reload
sudo systemctl enable supply-drop-bbs
# Run setup then start
sudo supply-drop-bbs setup
sudo systemctl start supply-drop-bbsAppend -headless to the binary name for a smaller build without the admin web UI (e.g. supply-drop-bbs-${TAG}-${TARGET}-headless).
Option 3 β Guided setup script β
The install.sh script handles the full stack including Pi HAT configuration (pymc_core, SPI, pymc-companion.service). Download and read it before running:
curl -fsSL https://raw.githubusercontent.com/Mesh-America/supply-drop-bbs/main/install.sh \
-o install.sh
less install.sh # review before running
sudo bash install.shWhat the script does β
- Installs minimal system packages (
curl,git,figlet) - Clones (or updates) the repository to
/opt/supply-drop-bbs - Downloads the pre-built binary for your architecture and verifies its SHA256 checksum
- Falls back to building from source if no pre-built binary is available (5β15 min on a Pi)
- Installs the binary to
/usr/local/bin/supply-drop-bbs - Creates the
supply-dropsystem user and the config/data directories - Installs the
supply-drop-bbs.servicesystemd unit - Runs the setup wizard
- Pi HAT only: installs
pymc_corein a Python venv, writespymc-companion.yaml, and enablespymc-companion.service - Enables and starts both services
What the setup wizard asks β
- Radio connection type - USB serial or Pi HAT
- Serial port (USB only) - detected automatically; you confirm or enter manually
- BBS name - displayed to users on connect
- Data directory - defaults to
/var/lib/supply-drop-bbs - Web admin UI - whether to enable it, and if so, the password and bind address
The wizard writes /etc/supply-drop-bbs/config.toml. Run supply-drop-bbs setup at any time to reconfigure.
Pi HAT additional wizard steps (in the installer) β
After the BBS wizard, the installer asks:
- Region / frequency - US, EU, or enter manually
- HAT model - choose from the supported list
The installer then:
- Enables SPI via
raspi-configif not already active - Creates
/opt/pymc-companion/venvwithpymc_core,spidev, andlgpio - Writes
/etc/supply-drop-bbs/pymc-companion.yamlwith your HAT's pin config - Installs and enables
pymc-companion.service
Supported Pi HATs β
| # | Model | Notes |
|---|---|---|
| 1 | ZebraHat 1W | wehooper4 |
| 2 | Waveshare SX1262 LoRa HAT | |
| 3 | PiMesh-1W (V1) | |
| 4 | PiMesh-1W (V2) | |
| 5 | MeshAdv Mini | |
| 6 | MeshAdv | |
| 7 | FemtoFox SX1262 1W | Uses gpiod backend |
| 8 | FemtoFox SX1262 2W | Uses gpiod backend |
| 9 | NebraHat 2W | |
| 10 | RAK6421 + RAK13300x (Slot 1) | Uses gpiod backend |
| 11 | RAK6421 + RAK13300x (Slot 2) | Uses gpiod backend |
| 12 | Zindello UltraPeater E22 | Uses gpiod backend |
| 13 | Zindello UltraPeater E22P | Uses gpiod backend |
| 14 | uConsole LoRa Module v1 | |
| 15 | uConsole LoRa Module v2 |
After installation β
Check both services are running:
sudo systemctl status supply-drop-bbs
sudo systemctl status pymc-companion # Pi HAT onlyTail the logs:
sudo journalctl -u supply-drop-bbs -f
sudo journalctl -u pymc-companion -f # Pi HAT onlyIf the web admin UI is enabled, open it at http://<your-pi-ip>:8080.
Reconfigure β
Re-run the BBS setup wizard at any time:
sudo supply-drop-bbs setup --config /etc/supply-drop-bbs/config.toml
sudo systemctl restart supply-drop-bbsTo change the HAT or frequency, edit /etc/supply-drop-bbs/pymc-companion.yaml and restart:
sudo systemctl restart pymc-companionBuilding from source (manual) β
Required: Rust 1.88+ (rustup install 1.88).
git clone https://github.com/Mesh-America/supply-drop-bbs
cd supply-drop-bbs
cargo build --release
sudo install -m 0755 target/release/supply-drop-bbs /usr/local/bin/
supply-drop-bbs setupUse --profile release-min instead of --release to produce a smaller binary with the same settings used in the official releases (opt-level = "z", lto = "thin", debug symbols stripped).
Uninstall β
Debian package uninstall β
sudo dpkg -r supply-drop-bbsThis stops the service and removes the binary and systemd unit. Config (/etc/supply-drop-bbs) and data (/var/lib/supply-drop-bbs) are intentionally preserved β remove them manually when you're sure you no longer need them:
sudo rm -rf /etc/supply-drop-bbs
sudo rm -rf /var/lib/supply-drop-bbs # contains your message store!
sudo userdel supply-drop 2>/dev/null || trueScript-installed uninstall β
If you installed via install.sh, use the built-in uninstall flag:
sudo bash /opt/supply-drop-bbs/install.sh --uninstallThe uninstaller:
- Stops and disables
supply-drop-bbsandpymc-companion - Removes their systemd unit files
- Removes the binary (
/usr/local/bin/supply-drop-bbs) - Removes
/opt/pymc-companionand/opt/supply-drop-bbs - Asks before deleting the config directory (
/etc/supply-drop-bbs) - Asks before deleting the data directory (
/var/lib/supply-drop-bbs) - this contains your message store and identity key - Asks before removing the
supply-dropsystem user
If you answer N to the data directory prompt, your messages and identity are preserved and can be used with a fresh install.
systemd units β
USB device - one service β
supply-drop-bbs.service
[Unit]
Description=Supply Drop BBS
After=network.target
Wants=network.target
[Service]
Type=simple
User=supply-drop
Group=supply-drop
SupplementaryGroups=dialout
ExecStart=/usr/local/bin/supply-drop-bbs run --config /etc/supply-drop-bbs/config.toml
Restart=always
RestartSec=5s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=supply-drop-bbs
ReadWritePaths=/var/lib/supply-drop-bbs
NoNewPrivileges=yes
PrivateTmp=yes
[Install]
WantedBy=multi-user.targetWeb "Restart service" button. The web admin's restart action works by having the BBS process exit, which
Restart=alwaysthen brings back up β it does not shell out tosystemctl, because the unit runs as a non-root user withNoNewPrivileges=yes(sosudocan't escalate). No sudoers rule is needed; if an older install left/etc/sudoers.d/supply-drop-bbs, it's removed on upgrade.
Pi HAT - two services β
pymc-companion.service starts first (the BBS connects to it):
[Unit]
Description=pymc-companion - LoRa radio bridge for Supply Drop BBS
After=network.target
Before=supply-drop-bbs.service
[Service]
Type=simple
User=supply-drop
Group=supply-drop
SupplementaryGroups=dialout spi gpio
ExecStart=/opt/pymc-companion/venv/bin/python \
/opt/pymc-companion/pymc-companion.py \
--config /etc/supply-drop-bbs/pymc-companion.yaml
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=pymc-companion
ReadWritePaths=/var/lib/supply-drop-bbs
[Install]
WantedBy=multi-user.targetsupply-drop-bbs.service (HAT variant) waits for pymc-companion:
[Unit]
Description=Supply Drop BBS
After=network.target pymc-companion.service
Wants=network.target
[Service]
...same as USB variant above...The two services are independent at the socket level - the BBS reconnects automatically if pymc-companion restarts.
Update β
Debian package update (recommended) β
dpkg stops the running service, replaces the binary, and restarts it automatically β your config and data are untouched.
ARCH=$(dpkg --print-architecture)
curl -fsSL \
"https://github.com/Mesh-America/supply-drop-bbs/releases/latest/download/supply-drop-bbs_${ARCH}.deb" \
-o supply-drop-bbs.deb
sudo dpkg -i supply-drop-bbs.debTypical update time: under a minute.
Manual binary-only update β
For non-Debian systems, download the new binary directly:
ARCH=$(uname -m)
case "$ARCH" in
aarch64) TARGET="aarch64-unknown-linux-gnu" ;;
armv7l) TARGET="armv7-unknown-linux-gnueabihf" ;;
x86_64) TARGET="x86_64-unknown-linux-gnu" ;;
esac
TAG=$(curl -sSf https://api.github.com/repos/Mesh-America/supply-drop-bbs/releases/latest \
| python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'])")
curl -fsSL \
"https://github.com/Mesh-America/supply-drop-bbs/releases/download/${TAG}/supply-drop-bbs-${TAG}-${TARGET}" \
-o /tmp/supply-drop-bbs-new
curl -fsSL \
"https://github.com/Mesh-America/supply-drop-bbs/releases/download/${TAG}/SHA256SUMS" \
| grep "${TARGET}" | sha256sum -c
sudo systemctl stop supply-drop-bbs
sudo install -m 755 /tmp/supply-drop-bbs-new /usr/local/bin/supply-drop-bbs
sudo systemctl start supply-drop-bbs
supply-drop-bbs --versionGuided script update β
If you originally installed via the setup script and want it to handle everything (including updating pymc-companion for Pi HAT users):
curl -fsSL https://raw.githubusercontent.com/Mesh-America/supply-drop-bbs/main/install.sh \
-o install.sh
less install.sh # review before running
sudo bash install.shWhen asked "Reconfigure now?", answer N to keep your existing config unchanged.
Source build update β
Use this path only if no pre-built binary is available for your architecture:
sudo systemctl stop supply-drop-bbs
cd /opt/supply-drop-bbs
sudo git pull
sudo cargo build --release
sudo install -m 0755 target/release/supply-drop-bbs /usr/local/bin/
sudo systemctl start supply-drop-bbsBackups β
Automatic backups β
If [backup] enabled = true (default), the BBS runs VACUUM INTO 'backup-YYYY-MM-DD-HHMMSS.sqlite' on the configured interval. Backups land in <data_dir>/backups. VACUUM INTO is non-blocking.
Retention defaults: 7 daily + 4 weekly. Configurable.
Manual backup β
supply-drop-bbs backupOr use the Trigger backup button in the web admin UI.
Off-host backups β
# Cron: copy the latest backup nightly to a remote host
0 3 * * * rsync -a /var/lib/supply-drop-bbs/backups/ \
backup-host:/srv/bbs-backups/$(hostname)/Rooms and access control β
Built-in rooms β
Supply Drop BBS ships with five permanent rooms that cannot be deleted. Three of them (Mail, Aides, Sysop) also have locked permission settings β their minimum access level and read-only flag cannot be changed, even by a sysop.
| Room | ID | Min access | Read-only | Locked |
|---|---|---|---|---|
| Lobby | 1 | Unvalidated | No | No |
| 2 | User | No | Yes | |
| Aides | 3 | Aide | No | Yes |
| Sysop | 4 | Sysop | No | Yes |
| System | 5 | Sysop | Yes | No |
Locked means the web admin edit form and the REST API will refuse any attempt to change the permission level or read-only setting for that room. The description field remains editable on all rooms.
Mail privacy β
Mail is strictly private. Every message stored in Mail has an explicit sender and recipient; the database query enforces that a user can only retrieve messages where they are the sender or the recipient. There is no admin view that bypasses this.
System notifications (such as new-user registration alerts) are sent as mail from the reserved sender bbs. The new user is never the sender of their own registration notification, so they cannot see it in their own inbox. Only the addressed sysops receive it.
User-created rooms β
Rooms created with .C <name> (in-session) or supply-drop-bbs room create (CLI) start with:
- min permission level β User (10)
- read-only β false
Sysops can change these through the web admin Rooms page or a future in-session command. Any min-level from Unvalidated (0) to Sysop (100) is valid.
Web admin β Rooms page β
The Rooms table shows all rooms. For Mail, Aides, and Sysop the edit form shows only the description field; the permission-level and read-only controls are hidden. Any API attempt to set those fields on those rooms returns 422 Unprocessable Entity.
Open access and guest rooms (SHTF mode) β
In normal operation every new account must be verified by an aide or sysop before the user can read or post in any room. When sysops are unreachable (off-grid emergency / SHTF scenario) two complementary knobs keep the BBS useful.
require_verify = false β open access β
All registrations are immediately treated as User-level. No aide or sysop action is required. Set this in config.toml:
[bbs]
require_verify = falseOr via the CLI (restart required):
sudo supply-drop-bbs config require-verify off \
--config /etc/supply-drop-bbs/config.toml
sudo systemctl restart supply-drop-bbsOr live from within the BBS (sysop session, no restart):
OPENACCESS # disable verification immediately
CLOSEACCESS # restore verification immediatelyThe web admin Settings β Access policy card also exposes this toggle.
guest_room = "Guests" β guest room confinement β
Unverified users land in a single designated room and can only read and post there. All other rooms and mail are invisible until a sysop verifies them. The room is created automatically on startup if it does not already exist.
[bbs]
guest_room = "Guests"Or via the CLI (restart required):
sudo supply-drop-bbs config guest-room Guests \
--config /etc/supply-drop-bbs/config.toml
sudo systemctl restart supply-drop-bbsOr live from within the BBS (sysop session, no restart):
GUESTROOM Guests # set guest room (created automatically if needed)
GUESTROOM OFF # disable guest roomThe web admin Settings β Access policy card also exposes this field.
Composing the two options β
The options are independent and compose naturally:
require_verify | guest_room set | Behaviour |
|---|---|---|
true (default) | no | Default strict mode β no access until verified |
true | yes | Unverified users allowed into the guest room only |
false | no | All registrations get full access immediately |
false | yes | Full access immediately; guest room exists as an ordinary room |
Disaster recovery β
Corrupted database β
sudo systemctl stop supply-drop-bbs
sudo mv /var/lib/supply-drop-bbs/bbs.sqlite /var/lib/supply-drop-bbs/bbs.sqlite.corrupt
sudo mv /var/lib/supply-drop-bbs/bbs.sqlite-wal /var/lib/supply-drop-bbs/bbs.sqlite-wal.corrupt 2>/dev/null || true
ls -lt /var/lib/supply-drop-bbs/backups/
sudo cp /var/lib/supply-drop-bbs/backups/<latest>.sqlite /var/lib/supply-drop-bbs/bbs.sqlite
sudo chown supply-drop:supply-drop /var/lib/supply-drop-bbs/bbs.sqlite
sudo systemctl start supply-drop-bbsLost sysop access β
sudo systemctl stop supply-drop-bbs
sudo supply-drop-bbs user promote <username> \
--config /etc/supply-drop-bbs/config.toml
sudo systemctl start supply-drop-bbsReset a user's password β
Three options, from most to least convenient:
In-session (BBS must be running; no server access needed):
A logged-in sysop types .PW <username> and follows two prompts (new password, then confirm). The change takes effect immediately.
From the web admin UI (BBS must be running; requires sysop login):
Open Users, click the username to open the detail drawer, then click reset password.
From the CLI (BBS does not need to be stopped):
sudo supply-drop-bbs user set-password <username> \
--config /etc/supply-drop-bbs/config.tomlThe new password must be at least 8 characters. The action is audit-logged when performed via the web UI.
See CLI.md for the full user subcommand reference.
Monitoring β
Health endpoint β
If the web admin plugin is enabled, GET /health returns:
{
"status": "healthy",
"uptime_seconds": 1234567,
"version": "0.1.0",
"bridge_connected": true,
"transports": { "mesh": "running", "web": "running" },
"db": { "size_bytes": 12345678, "last_backup": "2026-05-08T03:00:00Z" }
}status is "healthy" only if every transport reports running and the bridge is connected; otherwise "degraded".
Mesh link health β
When the web admin UI is enabled, the Metrics page includes a Mesh link health section that surfaces reply-delivery quality for the MeshCore transport β so you can see whether replies are reaching users, which nodes have bad links, how fast round-trips are, and whether reliability is trending up or down as you tune the link:
- summary cards β confirm rate (per reply), route failures, total sends, gave-up count, and average round-trip latency
- a worst-links table β per-node delivery stats, joined to advert names
- a per-minute confirm-rate trend sparkline
The same data backs a sysop-authenticated JSON API (handy for external dashboards or scripting against a logged-in session):
GET /api/v1/transports/meshcore/stats # current snapshot
GET /api/v1/transports/meshcore/history # recent ~8h of samplesLatency and the per-node breakdown are populated only when reply retransmission is active (reply_max_attempts > 1). Retransmission is off by default β enable it only on a link with a non-zero confirm rate (see CONFIG.md). Samples are persisted in the database and pruned after 7 days, so the trend survives a service restart or upgrade rather than resetting.
Diagnosing message deliverability β
When users report that DMs to the BBS are "less reliable than normal messaging" or that "the BBS didn't respond", the stats snapshot (GET /api/v1/transports/meshcore/stats) carries inbound counters alongside the outbound reply metrics above. Together they localize where a message is being lost β the radio return path or the BBS's own dedup:
inbound_receivedβ plain-text DMs the BBS accepted for processing.dedup_dropped_timestamp/dedup_dropped_textβ inbound messages the BBS dropped as retransmissions before acting on them.
(Messages queued at the bridge while the BBS was offline are all processed on reconnect β they get replies like live traffic β so there is no separate reconnect-loss counter.)
Read them against the outbound sends_total / confirm_rate / failed_no_route to tell the failure modes apart:
| Symptom | What the numbers show | Likely cause |
|---|---|---|
| BBS replies, user never sees them | sends_total climbs, confirm_rate β 0, failed_no_route β 0 | Outbound return-path loss. The device accepts every send but no end-to-end ACK returns β a lossy multi-hop reverse path. Replies are not retried by default (reply_max_attempts = 1). |
| BBS "ignores" repeated commands | dedup_dropped_timestamp rises against inbound_received for that node | Inbound dedup. The dedup keys on the timestamp the sender stamped. Senders bridged through pyMC are re-stamped whole-second int(time.time()) at send time, so two identical sends from such a sender in the same second collide and the second is dropped. Senders on real firmware carry their app's stamp, which is normally distinct per send. Confirm with a DEBUG log line dropping retransmitted message (timestamp dedup). |
For a live trace, raise the log level to DEBUG (Settings page or [logging] level = "DEBUG") and watch for mesh: inbound message received and mesh: dropping retransmitted message β¦.
Note: retrying lost outbound replies is not as simple as raising
reply_max_attemptsβ on a link that never confirms, the tracker would retransmit every reply to exhaustion and flood the mesh with duplicates. A confirm-gated retransmission strategy for far nodes is planned separately.
Logs β
journalctl -u supply-drop-bbs -f # tail
journalctl -u supply-drop-bbs --since "1 hour ago" -p err # errors only
journalctl -u pymc-companion -f # Pi HAT radio bridgeThe default log level is INFO. To increase verbosity temporarily, change the Log level dropdown in the web admin Settings page β the change takes effect immediately without restarting the service. To make it permanent, edit [logging] level = "DEBUG" in config.toml.
Reverse-proxy setup (HTTPS) β
The web admin plugin doesn't terminate TLS. Use nginx or Caddy:
Caddy β
admin.bbs.example.com {
reverse_proxy 127.0.0.1:8080
}[plugins.web]
bind = "127.0.0.1:8080"
external_origin = "https://admin.bbs.example.com"
cookie_secure = truenginx β
TBD
Troubleshooting β
BBS won't start β
supply-drop-bbs config check
sudo journalctl -u supply-drop-bbs -n 100 --no-pagerLook for the first ERROR line. Subsequent errors are usually cascading from it.
Radio bridge disconnected β
USB device:
ls -la /dev/ttyACM* /dev/ttyUSB*
sudo journalctl -u supply-drop-bbs -fCommon causes: wrong serial_port in config; permission denied on the port (see Serial port: Permission denied below); firmware crashed (unplug and replug).
Pi HAT:
sudo systemctl status pymc-companion
sudo journalctl -u pymc-companion -fCommon causes:
- SPI not enabled -
sudo raspi-configβ Interface Options β SPI supply-dropuser not inspi/gpiogroups (installer adds these; a reboot may be needed)- Missing Python dependency -
sudo /opt/pymc-companion/venv/bin/pip install spidev lgpio - Wrong HAT selected - edit
/etc/supply-drop-bbs/pymc-companion.yamland restart pymc-companion
Serial port: Permission denied β
Symptom β the log repeats:
could not open serial port /dev/ttyACM0: Permission denied (os error 13)The service (running as the supply-drop user) is not in the group that owns the serial device. Check the owning group:
ls -l /dev/ttyACM* /dev/ttyUSB*crw-rw----+ 1 root plugdev 166, 0 β¦ /dev/ttyACM0The owning group varies by distro β dialout on many systems, but plugdev on current Raspberry Pi OS / Debian 13 "Trixie". The trailing + is a POSIX ACL that grants the interactive desktop (seat) user; a headless system service never receives it, so access depends on group membership.
Packaged installs (.deb / install.sh) ship a udev rule (/lib/udev/rules.d/70-supply-drop-bbs.rules) that re-owns the radio's tty to the supply-drop group automatically. If it has not taken effect, reapply it:
sudo udevadm control --reload-rules && sudo udevadm trigger --subsystem-match=tty
sudo systemctl restart supply-drop-bbsManual / raw-binary installs β add the service user to the owning group, then restart:
sudo usermod -aG <owning-group> supply-drop # e.g. plugdev or dialout
sudo systemctl restart supply-drop-bbsudevadm trigger re-applies device ownership without unplugging the radio, but a group-membership change takes effect only after the service restarts (a reboot always works).
Database locked β
Almost always means two BBS instances are running against the same DB:
sudo systemctl status supply-drop-bbs
ps -ef | grep supply-drop-bbsWeb UI returns 502 β
systemctl status supply-drop-bbs
ss -ltnp | grep supply-drop-bbsCheck [plugins.web] bind and external_origin in config.
Web admin Settings page shows "Config file is not writable by the server process" β
This warning appears when the supply-drop service user does not have write permission on config.toml (or its parent directory). The Settings page needs write access to save configuration changes.
Fix for new installs β run setup as root:
sudo supply-drop-bbs setup --config /etc/supply-drop-bbs/config.tomlWhen run as root, the setup wizard automatically sets the owner of config.toml and its parent directory to supply-drop:supply-drop and prints:
ownership set to supply-drop:supply-drop (web admin can save config)Fix for existing installs β chown manually:
sudo chown supply-drop:supply-drop \
/etc/supply-drop-bbs \
/etc/supply-drop-bbs/config.tomlNo restart is required β the Settings page will work immediately after ownership is corrected.
Where to get help β
- Bugs: GitHub Issues
- Security: see SECURITY.md
- General questions: GitHub Discussions
Versioning β
Pre-1.0: each release may include breaking changes - read the release notes.
After 1.0: semver. Major bumps are breaking; minor releases add features compatibly; patches are bug fixes only.