No description
  • Go 73.9%
  • Just 12.5%
  • Makefile 12%
  • Shell 1.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Oleksii Khilkevych bc22205e18
All checks were successful
CI / Test & Build (push) Successful in 52s
CI / Build All Platforms (push) Successful in 38s
CI / Linux Fixture Suite (push) Successful in 40s
CI / Release (push) Has been skipped
Harden tests via mutation: stdout, routes, edges, volume-coherent gate
CLI tests capture stdout and assert content/icons/counts/labels; route
info asserted exactly against the live default route; port edges and
absolute timeouts covered; warnServePort extracted with both branches;
fake-binary exec-failure and empty-table reseed tests added. New
mutation-linux target runs the gate on a volume-populated tree (macOS
bind mounts misattribute verdicts); test-linux drops its vestigial bind
mount to match CI exactly.
2026-09-27 20:08:44 +02:00
.forgejo/workflows Bake source into test image: fix empty checkout mount on CI 2026-09-27 19:08:45 +02:00
cmd/bahnhof Bless 2025-12-06 09:26:10 +01:00
docs Harden tests via mutation: stdout, routes, edges, volume-coherent gate 2026-09-27 20:08:44 +02:00
internal Harden tests via mutation: stdout, routes, edges, volume-coherent gate 2026-09-27 20:08:44 +02:00
test Harden tests via mutation: stdout, routes, edges, volume-coherent gate 2026-09-27 20:08:44 +02:00
.gitignore Bake source into test image: fix empty checkout mount on CI 2026-09-27 19:08:45 +02:00
.golangci.yml Refresh from kpr bootstrap: config centralization, toolchain, CI, first tests 2026-09-27 18:37:46 +02:00
AGENTS.md Fixture-seeded Linux suite: no more skips in CI 2026-09-27 18:59:50 +02:00
bahnhof.service Bless 2025-12-06 09:26:10 +01:00
BUILD.md Refresh from kpr bootstrap: config centralization, toolchain, CI, first tests 2026-09-27 18:37:46 +02:00
docker-compose.yml Compose-first dev loop: run/up/down/fixtures targets 2026-09-27 18:50:15 +02:00
Dockerfile.dev Compose-first dev loop: run/up/down/fixtures targets 2026-09-27 18:50:15 +02:00
Dockerfile.test Bake source into test image: fix empty checkout mount on CI 2026-09-27 19:08:45 +02:00
go.mod Refresh from kpr bootstrap: config centralization, toolchain, CI, first tests 2026-09-27 18:37:46 +02:00
go.sum Bless 2025-12-06 09:26:10 +01:00
justfile Harden tests via mutation: stdout, routes, edges, volume-coherent gate 2026-09-27 20:08:44 +02:00
Makefile Harden tests via mutation: stdout, routes, edges, volume-coherent gate 2026-09-27 20:08:44 +02:00
README.md Compose-first dev loop: run/up/down/fixtures targets 2026-09-27 18:50:15 +02:00

Bahnhof

Control plane agent for maglev IPVS load balancers. Monitors IPVS virtual servers, firewall mark flows, and tunnel interfaces.

Features

  • Web Dashboard: IPVS virtual servers, FWM flows, tunnel interfaces, routing info
  • CLI Tools: Colorful terminal output with lipgloss styling
  • FWM Support: Firewall mark mapping via nftables, shows VIP:port flows
  • Tunnel Monitoring: Displays tunnel interfaces (ipip, sit, gre, fou)
  • Routing Info: Shows route/gateway for each backend
  • Dual-stack: IPv4/IPv6 support
  • JSON API: All data available as JSON

Installation

From Source

Requires Go 1.27+ for building:

# Clone the repository
git clone https://nrtn.dev/catalyst/bahnhof.git
cd bahnhof

# Build the binary
just build

# Or use make
make build

# Install to system
sudo cp bahnhof /usr/local/bin/

Prebuilt Binaries

Download from releases:

# Linux amd64
curl -LO https://nrtn.dev/catalyst/bahnhof/releases/download/v0.1.0/bahnhof-linux-amd64
chmod +x bahnhof-linux-amd64
sudo mv bahnhof-linux-amd64 /usr/local/bin/bahnhof

# Linux arm64
curl -LO https://nrtn.dev/catalyst/bahnhof/releases/download/v0.1.0/bahnhof-linux-arm64
chmod +x bahnhof-linux-arm64
sudo mv bahnhof-linux-arm64 /usr/local/bin/bahnhof

Platforms: linux/amd64, linux/arm64, linux/arm

Usage

Web Server

Start the web dashboard and API server:

# Start on default port 9300 (dual-stack IPv4+IPv6)
bahnhof serve

# Custom host and port
bahnhof serve --host :: --port 9300

# IPv4 only
bahnhof serve --host 0.0.0.0

# Or use environment variables
export BAHNHOF_HOST=::        # Dual-stack (default)
export BAHNHOF_PORT=9300
bahnhof serve

Open http://localhost:9300 in your browser to view the dashboard.

CLI Commands

# IPVS status (colorful output with flows and routing)
bahnhof status
bahnhof status --json

# Tunnel interfaces
bahnhof links
bahnhof links --json

Shows virtual servers with FWM flows, backends with routing info, and tunnel encapsulation details.

API Endpoints

# Web dashboard
curl http://localhost:9300/

# JSON status (all virtual servers)
curl http://localhost:9300/status

# Health check (200 if VS configured, 503 otherwise)
curl http://localhost:9300/health

Systemd Integration

Copy the service file and enable:

sudo cp bahnhof.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now bahnhof.service

# Check status
sudo systemctl status bahnhof

# View logs
journalctl -u bahnhof.service -f

The service file runs bahnhof as root (required for IPVS access) on port 9300.

Development

Local Development

# Check prerequisites
just prereqs

# Install dependencies
just deps

# Run locally (compose dev container with IPVS)
just up             # detached; or: just run (foreground, Ctrl-C stops)
just fixtures       # seed demo IPVS/nft/tunnel data
# dashboard: http://localhost:9300

# Check status via CLI
docker compose exec bahnhof bahnhof status   # macOS (no local IPVS)
just status                                  # Linux with IPVS

# Format code
just fmt

# Run checks
just check

# Build for Linux (cross-compile from macOS)
just build-linux-amd64

CI/CD

Single Forgejo Actions workflow:

  • On push/PR: Lint, format check, test, build all platforms
  • On tag (v)*: All above + create release with binaries

Builds: linux/amd64, linux/arm64, linux/arm (Linux only - IPVS requirement)

Project structure:

bahnhof/
├── cmd/bahnhof/           # Main entry point
├── internal/
│   ├── ipvs/             # IPVS + nftables reader
│   ├── network/          # Tunnel interface parser
│   ├── web/              # HTTP server + templates
│   └── cli/              # CLI commands (status, links)
├── justfile
└── Makefile

Requirements

Build Requirements

  • Go 1.27+ (for building from source)
  • git (for version information)

Runtime Requirements (Linux only)

  • Linux with IPVS kernel module
  • ipvsadm - IPVS configuration reader
  • nft - Firewall mark flow mapping (optional, for FWM displays)
  • ip - Route and tunnel interface info
  • Root or CAP_NET_ADMIN capability

Note: Builds on macOS/Windows, runs on Linux only.

Configuration

Configuration via environment variables or CLI flags:

Environment Variable CLI Flag Default Description
BAHNHOF_HOST --host :: Host to bind to (:: = dual-stack IPv4+IPv6)
BAHNHOF_PORT --port 9300 Port to bind to

Troubleshooting

# Port already in use
sudo lsof -i :9300
sudo systemctl stop bahnhof

# Check IPVS is available
which ipvsadm
sudo ipvsadm -Ln

# Permission issues (needs root or CAP_NET_ADMIN)
sudo bahnhof status

# Check service logs
journalctl -u bahnhof.service -f --no-pager

Future Roadmap

  • Real-time connection tracking visualization
  • IPVS configuration management (add/remove VS/RS)
  • Metrics export (Prometheus format)
  • Multi-node cluster view
  • WebSocket for live updates
  • BGP announcement status integration

Notes

  • Port 9300 matches haproxy-health for consistency in maglev cluster
  • No authentication - restrict access via firewall/network policy
  • Requires root for IPVS access (uses ipvsadm -Ln)
  • Dashboard auto-refreshes on page reload (no live updates yet)