Skip to content

Installation ​

Get Bandwidth Manager running on your Docker host in under a minute. This guide covers the automated installer, a manual from‑source build, systemd setup, and common pitfalls.


Prerequisites ​

RequirementMinimumNotes
Linux kernel4.x+tc htb and fq_codel qdiscs must be available. 5.x recommended.
Docker Engine20.10+Daemon needs access to the Docker socket (/var/run/docker.sock).
Root accessYestc netlink operations and Docker socket access require CAP_NET_ADMIN.
Architectureamd64 / arm64Pre‑built binaries for both.

Quick Dependency Check ​

Run these commands to verify your host is ready:

bash
# Kernel version
uname -r

# tc availability (should print qdisc list or "noqueue")
tc qdisc show 2>/dev/null | head -5

# Docker socket
docker info > /dev/null 2>&1 && echo "Docker OK" || echo "Docker not reachable"

If all three pass, you're good to go.


One‑Liner Install ​

bash
curl -sSL https://raw.githubusercontent.com/AnAverageBeing/Bandwidth-flow-maintainer/main/install.sh | sudo bash

Always inspect scripts before piping them to sudo.
View the installer source →


What the Installer Does (Step by Step) ​

The install script runs 7 steps in sequence. Each step is idempotent — you can re‑run the script safely.

Step 1 — OS & Kernel Validation ​

bash
# Checks /etc/os-release; confirms kernel >= 4.0
# Exits early on unsupported distros or ancient kernels

Step 2 — Dependency Bootstrap ​

Installs any missing OS packages required for the build or runtime:

bash
# Debian / Ubuntu
apt-get update && apt-get install -y curl tar iproute2

# RHEL / Fedora / Rocky
dnf install -y curl tar iproute-tc

Step 3 — Binary Download ​

Fetches the latest release from GitHub, verifies the SHA256 checksum, and extracts:

bash
curl -sSL "https://github.com/AnAverageBeing/Bandwidth-flow-maintainer/releases/latest/download/bwm_linux_amd64.tar.gz" \
  | sudo tar xz -C /usr/local/bin

Installed binaries:

BinaryPurpose
bwm-daemonBackground service, tc controller
bwmCLI client for querying and managing

Step 4 — Configuration Directory ​

bash
sudo mkdir -p /etc/bwm
sudo chmod 750 /etc/bwm

A default config is written to /etc/bwm/config.yaml if none exists. See Configuration → for every available option.

Step 5 — Data Directory ​

bash
sudo mkdir -p /var/lib/bwm
sudo chmod 750 /var/lib/bwm

The SQLite database (bandwidth.db) lives here. Keep this directory backed up if historical stats matter to you.

Step 6 — Systemd Unit File ​

A hardened unit is written to /etc/systemd/system/bwm.service:

ini
[Unit]
Description=Bandwidth Manager — Docker traffic control daemon
Documentation=https://github.com/AnAverageBeing/Bandwidth-flow-maintainer
After=docker.service network-online.target
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/local/bin/bwm-daemon --config /etc/bwm/config.yaml
Restart=always
RestartSec=5

# Sandbox hardening
ProtectSystem=strict
ReadWritePaths=/var/lib/bwm /run/docker.sock
ProtectHome=true
NoNewPrivileges=true
PrivateTmp=true
CapabilityBoundingSet=CAP_NET_ADMIN CAP_DAC_OVERRIDE

[Install]
WantedBy=multi-user.target

Key hardening directives:

DirectiveEffect
ProtectSystem=strict/usr, /boot, /etc are read‑only. Only whitelisted paths are writable.
NoNewPrivileges=truePrevents privilege escalation via setuid binaries.
CapabilityBoundingSetDrops every capability except CAP_NET_ADMIN (for tc) and CAP_DAC_OVERRIDE (for Docker socket).

Step 7 — Start & Enable ​

bash
sudo systemctl daemon-reload
sudo systemctl enable --now bwm

After step 7, the daemon is running and will auto‑start on boot.


Manual Install from Source ​

Prefer to build from source or need a custom patch? Here's the full build chain.

Prerequisites ​

  • Go 1.21 or later
  • make
  • gcc (for SQLite CGo bindings, if applicable)

Build Steps ​

bash
# 1. Clone the repository
git clone https://github.com/AnAverageBeing/Bandwidth-flow-maintainer.git
cd Bandwidth-flow-maintainer

# 2. Build both binaries
make build
# Equivalent to:
# CGO_ENABLED=1 go build -ldflags="-s -w -X main.version=$(git describe --tags)" -o bin/bwm-daemon ./cmd/daemon
# CGO_ENABLED=1 go build -ldflags="-s -w -X main.version=$(git describe --tags)" -o bin/bwm        ./cmd/cli

# 3. Install
sudo cp bin/bwm-daemon /usr/local/bin/
sudo cp bin/bwm        /usr/local/bin/
sudo chmod 755 /usr/local/bin/bwm-daemon /usr/local/bin/bwm

Verify the Build ​

bash
bwm version
# Expected output:
# bwm version v1.2.3 (commit: a1b2c3d, built: 2025-06-15T10:30:00Z)

Unit File (Manual) ​

If you built from source, write the systemd unit yourself:

bash
sudo tee /etc/systemd/system/bwm.service << 'EOF'
[Unit]
Description=Bandwidth Manager — Docker traffic control daemon
After=docker.service network-online.target
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/local/bin/bwm-daemon --config /etc/bwm/config.yaml
Restart=always
RestartSec=5
ProtectSystem=strict
ReadWritePaths=/var/lib/bwm /run/docker.sock
ProtectHome=true
NoNewPrivileges=true
PrivateTmp=true
CapabilityBoundingSet=CAP_NET_ADMIN CAP_DAC_OVERRIDE

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now bwm

Systemd Service Management ​

Everyday commands you'll need:

bash
# Check status
sudo systemctl status bwm

# Follow logs
sudo journalctl -u bwm -f

# Reload after config change
sudo systemctl reload bwm

# Restart
sudo systemctl restart bwm

# Stop
sudo systemctl stop bwm

# Disable auto-start
sudo systemctl disable bwm

Logging ​

All daemon output goes to the systemd journal. For structured logs, set log_format: json in your config:

bash
# Pretty-print recent JSON logs
sudo journalctl -u bwm --since "5 min ago" -o cat | jq '.'

Post‑Install Verification ​

Run these commands to confirm everything is wired up correctly:

1. Daemon Reachable ​

bash
bwm ping

Expected: pong (or daemon reachable).

2. Service Healthy ​

bash
sudo systemctl is-active bwm

Expected: active.

3. Docker Event Hook Working ​

bash
bwm status

Expected: a table summarising the daemon uptime, tracked containers, and overall bandwidth in/out.

4. End‑to‑End Test ​

Spin up a test container with a label and verify the limit is enforced:

bash
# Launch a container with a 1 Mbps upload cap
docker run -d --rm \
  --name bwm-test \
  --label bwm.limit.up=1mbps \
  alpine:latest sleep 3600

# Wait 5 seconds for discovery
sleep 5

# Inspect the rules applied to this container
bwm container inspect bwm-test

Expected: a tc class entry with a 1 Mbps ceiling on the container's veth.

bash
# Cleanup
docker rm -f bwm-test

Troubleshooting ​

Go Version Too Old ​

Symptom: make build fails with package slices is not in GOROOT or similar.

bash
# Check version
go version

Fix: Install Go 1.21+:

bash
# Using the official tarball
curl -sSL https://go.dev/dl/go1.22.5.linux-amd64.tar.gz | sudo tar xz -C /usr/local
export PATH=/usr/local/go/bin:$PATH

Docker Socket Permission Denied ​

Symptom: Daemon logs show permission denied when accessing /var/run/docker.sock.

Fix: Ensure the daemon runs as a user in the docker group, or use root:

bash
# Option A: run as root (default with systemd)
sudo systemctl cat bwm | grep User

# Option B: add a dedicated user to the docker group
sudo usermod -aG docker bwm
sudo systemctl restart bwm

tc Command Not Found ​

Symptom: Daemon logs show exec: "tc": executable file not found in $PATH.

Fix: Install iproute2 (or iproute on older distros):

bash
# Debian / Ubuntu
sudo apt-get install -y iproute2

# RHEL / Fedora
sudo dnf install -y iproute-tc

Then restart:

bash
sudo systemctl restart bwm

htb or fq_codel Qdisc Missing ​

Symptom: Daemon logs show RTNETLINK answers: No such file or directory or Unknown qdisc "htb".

Fix: Your kernel was compiled without traffic‑control modules. Verify:

bash
# Check if tc qdiscs are available
tc qdisc add dev lo root handle 1: htb 2>/dev/null && echo "htb OK" || echo "htb missing"
tc qdisc del dev lo root 2>/dev/null

If missing, rebuild your kernel with:

CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
CONFIG_NET_SCH_FQ_CODEL=y

Alternatively, switch to a stock distribution kernel (Ubuntu, Debian, Fedora all ship with these enabled).

Systemd Unit Fails to Start ​

Symptom: systemctl status bwm shows failed or inactive.

Diagnose step by step:

bash
# 1. Check the unit file syntax
sudo systemd-analyze verify /etc/systemd/system/bwm.service

# 2. Inspect the last boot log
sudo journalctl -u bwm --boot -e --no-pager

# 3. Run the daemon manually to see raw output
sudo /usr/local/bin/bwm-daemon --config /etc/bwm/config.yaml --debug

Common causes:

ErrorLikely Cause
exec format errorDownloaded the wrong architecture binary
bind: address already in useAnother instance is already running
config file not foundMissing /etc/bwm/config.yaml
failed to create database/var/lib/bwm not writable

Containers Not Being Discovered ​

Symptom: bwm status shows zero tracked containers despite running containers.

Fix: The daemon needs access to the Docker event stream. Verify:

bash
# Can the daemon reach Docker?
sudo -u bwm docker events --since 1s 2>&1 | head -5

# If that fails, check socket permissions
ls -la /var/run/docker.sock
# Expected: srw-rw---- 1 root docker

Add the daemon user to the docker group, or set docker_socket_group: docker in the config.


Uninstall ​

To completely remove Bandwidth Manager from the host:

bash
# 1. Stop and disable the service
sudo systemctl stop bwm
sudo systemctl disable bwm

# 2. Remove the unit file
sudo rm -f /etc/systemd/system/bwm.service
sudo systemctl daemon-reload

# 3. Remove binaries
sudo rm -f /usr/local/bin/bwm-daemon /usr/local/bin/bwm

# 4. (Optional) Remove config and data
sudo rm -rf /etc/bwm /var/lib/bwm

Removing /var/lib/bwm deletes all historical stats and quota counters. Back it up first if you plan to re‑install later.

Minimal Cleanup (Preserve Data) ​

bash
sudo systemctl stop bwm
sudo systemctl disable bwm
sudo rm -f /etc/systemd/system/bwm.service
sudo rm -f /usr/local/bin/bwm-daemon /usr/local/bin/bwm

This leaves /etc/bwm and /var/lib/bwm intact so a future re‑install picks up the same database and config.


What's Next? ​