Production deployment guide: systemd service, Podman Compose stacks, container images, deb/rpm packages, and security hardening.
- Requirements
- Release Artifact Matrix
- Installation Methods
- systemd Service
- Podman Compose
- Container Image
- Security Hardening
- Production Checklist
- Linux kernel (raw sockets require Linux-specific APIs)
- CAP_NET_RAW and CAP_NET_ADMIN capabilities (for raw UDP sockets with TTL=255)
- Go 1.26+ (for building from source only)
| Artifact | Target systems | Architectures | Base image / package format |
|---|---|---|---|
| Static binaries | Linux distributions with glibc or musl user space | amd64, arm64 |
tar.gz archive |
| Debian package | Debian 13 trixie, Ubuntu-compatible systems |
amd64, arm64 |
.deb, systemd unit |
| RPM package | Oracle Linux 10, RHEL-compatible systems, Fedora-compatible systems | amd64, arm64 |
.rpm, systemd unit |
| Default OCI image | Docker, Podman, Kubernetes CRI runtimes | linux/amd64, linux/arm64 |
docker.io/library/debian:trixie-slim |
| Oracle Linux OCI image | Docker, Podman, Kubernetes CRI runtimes requiring Oracle Linux user space | linux/amd64, linux/arm64 |
docker.io/library/oraclelinux:10-slim |
| Image tag | Base |
|---|---|
ghcr.io/dantte-lp/gobfd:<version> |
Debian trixie-slim |
ghcr.io/dantte-lp/gobfd:latest |
Debian trixie-slim |
ghcr.io/dantte-lp/gobfd:<version>-debian-trixie |
Debian trixie-slim |
ghcr.io/dantte-lp/gobfd:debian-trixie |
Debian trixie-slim |
ghcr.io/dantte-lp/gobfd:<version>-oraclelinux10 |
Oracle Linux 10-slim |
ghcr.io/dantte-lp/gobfd:oraclelinux10 |
Oracle Linux 10-slim |
# Install .deb package
sudo dpkg -i gobfd_*.deb
# Install .rpm package
sudo rpm -i gobfd_*.rpm
# Edit configuration
sudo vim /etc/gobfd/gobfd.yml
# Start the daemon
sudo systemctl enable --now gobfd
# Verify
sudo systemctl status gobfd
gobfdctl session listPackages are built by GoReleaser v2 and include:
/usr/local/bin/gobfd,/usr/local/bin/gobfdctl,/usr/local/bin/gobfd-haproxy-agent,/usr/local/bin/gobfd-exabgp-bridgebinaries/etc/gobfd/gobfd.ymlexample configuration/usr/lib/systemd/system/gobfd.servicesystemd unitgobfdsystem user and group
git clone https://github.com/dantte-lp/gobfd.git
cd gobfd
# Build all 4 binaries with version info (recommended)
make build
# Or build manually with ldflags
VERSION=$(git describe --tags --always --dirty)
GIT_COMMIT=$(git rev-parse --short HEAD)
BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
LDFLAGS="-s -w \
-X github.com/dantte-lp/gobfd/internal/version.Version=${VERSION} \
-X github.com/dantte-lp/gobfd/internal/version.GitCommit=${GIT_COMMIT} \
-X github.com/dantte-lp/gobfd/internal/version.BuildDate=${BUILD_DATE}"
go build -ldflags="${LDFLAGS}" -o bin/gobfd ./cmd/gobfd
go build -ldflags="${LDFLAGS}" -o bin/gobfdctl ./cmd/gobfdctl
go build -ldflags="${LDFLAGS}" -o bin/gobfd-haproxy-agent ./cmd/gobfd-haproxy-agent
go build -ldflags="${LDFLAGS}" -o bin/gobfd-exabgp-bridge ./cmd/gobfd-exabgp-bridge
# Install
sudo install -m 755 bin/gobfd bin/gobfdctl bin/gobfd-haproxy-agent bin/gobfd-exabgp-bridge /usr/local/bin/The systemd unit file at deployments/systemd/gobfd.service:
[Unit]
Description=GoBFD -- BFD Protocol Daemon
Documentation=https://github.com/dantte-lp/gobfd
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/local/bin/gobfd -config /etc/gobfd/gobfd.yml
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
WatchdogSec=30s
# Security hardening
User=gobfd
Group=gobfd
AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadOnlyPaths=/etc/gobfd
PrivateTmp=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictSUIDSGID=true
SystemCallArchitectures=native
[Install]
WantedBy=multi-user.targetKey features:
| Feature | Description |
|---|---|
Type=notify |
Uses sd_notify(READY) for accurate readiness reporting |
WatchdogSec=30s |
systemd watchdog -- daemon sends keepalives at 15s intervals |
ExecReload |
SIGHUP triggers hot reload (log level + session reconciliation) |
Restart=on-failure |
Auto-restart on crash with 5s delay |
| Security directives | Least-privilege with only CAP_NET_RAW and CAP_NET_ADMIN |
# Start/stop
sudo systemctl start gobfd
sudo systemctl stop gobfd
# Reload configuration (hot reload via SIGHUP)
sudo systemctl reload gobfd
# View logs
sudo journalctl -u gobfd -f
# Check status
sudo systemctl status gobfddeployments/compose/compose.dev.yml -- development environment with hot reload:
# Start development environment
podman-compose -f deployments/compose/compose.dev.yml up -d --build
# Access the dev container
podman-compose -f deployments/compose/compose.dev.yml exec dev bash
# Build and test inside container
make build && make testdeployments/compose/compose.yml -- production stack with Prometheus and Grafana:
# Start production stack
podman-compose -f deployments/compose/compose.yml up -d
# Services:
# gobfd gRPC API: localhost:50051
# Prometheus: http://localhost:9090
# Grafana: http://localhost:3000 (admin/admin)graph LR
subgraph "Podman Compose"
G["gobfd<br/>:50051 gRPC<br/>:9100 metrics"]
P["Prometheus<br/>:9090"]
GR["Grafana<br/>:3000"]
end
G -->|scrape /metrics| P
P -->|data source| GR
style G fill:#1a73e8,color:#fff
style P fill:#E6522C,color:#fff
style GR fill:#F46800,color:#fff
Build the container image:
# Standard build
podman build -f deployments/docker/Containerfile -t gobfd .
# Multi-arch build (via GoReleaser)
goreleaser release --snapshot --cleanRelease images contain the four GoBFD binaries and no development toolchain:
gobfd, gobfdctl, gobfd-haproxy-agent, and
gobfd-exabgp-bridge.
Running the container requires:
CAP_NET_RAWandCAP_NET_ADMINcapabilitiesnetwork_mode: host(recommended) or proper port mapping for UDP 3784/4784
GoBFD follows the principle of least privilege:
| Layer | Mechanism |
|---|---|
| Capabilities | Only CAP_NET_RAW + CAP_NET_ADMIN (no root) |
| systemd | ProtectSystem=strict, NoNewPrivileges, PrivateTmp |
| Code | No unsafe package, all socket errors handled |
| TTL | GTSM (RFC 5082): TTL=255 on transmit, TTL=255 check on receive |
| Auth | Optional BFD authentication (5 types per RFC 5880 Section 6.7) |
Go 1.26 introduces the Green Tea garbage collector, which performs significantly better under bounded memory. GoBFD recommends setting GOMEMLIMIT with GOGC=off for production deployments to eliminate GC pauses on the hot path.
| Deployment | GOMEMLIMIT | Notes |
|---|---|---|
| Small (< 50 sessions) | 256MiB |
Sufficient for typical edge deployments |
| Medium (50-500 sessions) | 512MiB |
Route reflectors, aggregation routers |
| Large (500+ sessions) | 1GiB |
Large-scale BGP+BFD deployments |
Add to [Service] section of gobfd.service:
Environment=GOMEMLIMIT=256MiB
Environment=GOGC=offENV GOMEMLIMIT=256MiB
ENV GOGC=offMonitor memory usage via the Prometheus metric process_resident_memory_bytes. If the process approaches GOMEMLIMIT, increase the limit. The Go runtime will perform more aggressive GC as it nears the limit rather than OOM.
- Set
GOMEMLIMITandGOGC=offfor bounded memory operation - Monitor
process_resident_memory_bytesrelative toGOMEMLIMIT - Configure
gobfd.ymlwith appropriate session parameters - Set
log.format: jsonfor structured logging - Enable GoBGP integration if using BFD for BGP failover
- Enable flap dampening to prevent route churn
- Set up Prometheus scraping of
:9100/metrics - Import Grafana dashboard from
deployments/compose/configs/grafana/dashboards/bfd.json - Configure alerting on
gobfd_bfd_state_transitions_total{from_state="Up",to_state="Down"} - Verify
CAP_NET_RAWis available (test withgobfdctl session list) - Test SIGHUP reload:
systemctl reload gobfd - Verify graceful shutdown sends AdminDown (check peer logs)
- 03-configuration.md -- Configuration reference
- 07-monitoring.md -- Prometheus metrics and Grafana
- 09-development.md -- Development environment setup
Last updated: 2026-02-21