A Go-based daemon for automated BGP peering on DN42. Manages WireGuard tunnels, BIRD routing configuration, and real-time metrics—all orchestrated by a central Control Plane.
- Features
- Quick Start
- Configuration
- Architecture
- Background Tasks
- API Reference
- BGP Communities
- Development
- Deployment
- Documentation
- License
- Automated BGP Session Management - Complete lifecycle from creation to teardown
- BIRD 3.x Integration - Connection pool with template-based config generation
- WireGuard Management - Direct kernel interface control (no wg-quick)
- P2P Mesh IGP - WireGuard-based underlay with Babel for internal routing
- Cold Potato Routing - Keep traffic inside the backbone via Large Communities
- Real-time Metrics - RTT measurement, route statistics, traffic monitoring
- Auto-update - GitHub release-based self-update (optional)
- Graceful Shutdown - Context-based cancellation with 30s timeout
The easiest way to deploy is via bootstrap script from the Control Plane:
# 1. Generate bootstrap script via Telegram Bot
# Use /addnode and /bootstrap commands
# 2. Run the generated script on your server
curl -fsSL "https://api.moenet.work/bootstrap/YOUR_TOKEN" | bash
# Agent starts automatically and connects to Control Plane# Download binary
curl -L -o moenet-agent \
https://github.com/moenet/moenet-agent/releases/latest/download/moenet-agent-linux-amd64
chmod +x moenet-agent
# Create minimal config
cat > config.json << 'EOF'
{
"bootstrap": {
"apiUrl": "https://api.moenet.work",
"nodeName": "your-node-name",
"token": "your-agent-token"
},
"server": { "listen": ":24368" }
}
EOF
# Run
./moenet-agent -c config.json# Copy service file
sudo cp moenet-agent.service /etc/systemd/system/
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable --now moenet-agent
# Check status
sudo systemctl status moenet-agent
sudo journalctl -u moenet-agent -fAgent fetches configuration from Control Plane at startup:
{
"bootstrap": {
"apiUrl": "https://api.moenet.work",
"nodeName": "jp1",
"token": "your-agent-token"
},
"server": { "listen": ":24368" }
}This automatically retrieves: nodeId, region, loopback IPs, ASN, and other settings.
For complete customization, see configs/config.example.json.
| Section | Key | Description |
|---|---|---|
node.name |
string | Node hostname (e.g., jp1) |
node.id |
int | Unique node ID (1-62) |
controlPlane.url |
string | Control Plane API URL |
controlPlane.token |
string | Agent authentication token |
bird.controlSocket |
string | BIRD control socket path |
bird.peerConfDir |
string | Directory for peer configs |
autoUpdate.enabled |
bool | Enable auto-update from GitHub |
| Variable | Config Path | Description |
|---|---|---|
MOENET_NODE_NAME |
node.name |
Node name |
MOENET_CP_URL |
controlPlane.url |
Control Plane URL |
MOENET_CP_TOKEN |
controlPlane.token |
Agent token |
┌─────────────────────────────────────────────────────────────────┐
│ moenet-agent │
├─────────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Task │ │ HTTP Client │ │ HTTP Server │ │
│ │ Scheduler │ │ (CP comms) │ │ (status) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────────────┘ │
│ │ │ │
│ ┌──────▼─────────────────▼──────┐ │
│ │ Core Engine │ │
│ │ • Session Sync │ │
│ │ • Config Rendering │ │
│ │ • iBGP Mesh Sync │ │
│ └──────┬─────────────────┬──────┘ │
│ │ │ │
│ ┌──────▼───────┐ ┌──────▼───────┐ ┌──────────────┐ │
│ │ BIRD Manager │ │ WG Manager │ │ Firewall │ │
│ │ (birdc) │ │ (wg/ip) │ │ (nftables) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
BIRD 3.x WireGuard nftables
| Status | Code | Description |
|---|---|---|
| PENDING_REVIEW | 3 | Awaiting admin approval |
| QUEUED_FOR_SETUP | 4 | Approved, agent will configure |
| ACTIVE | 1 | Running normally |
| ERROR | 2 | Configuration or connectivity issue |
| QUEUED_FOR_DELETE | 5 | Marked for removal |
| Task | Interval | Purpose |
|---|---|---|
heartbeat |
30s | Report health, version, system metrics |
sessionSync |
60s | Sync BGP sessions, configure WG+BIRD |
birdConfigSync |
300s | Sync BIRD filters and communities |
metricCollector |
60s | Collect BGP stats, report to CP |
rttMeasurement |
300s | Measure RTT to peers |
meshSync |
120s | Sync P2P WireGuard IGP mesh |
ibgpSync |
120s | Sync iBGP peer configurations |
| Endpoint | Method | Description |
|---|---|---|
/status |
GET | Agent status and version |
/sync |
GET | Trigger manual session sync |
/metrics |
GET | Prometheus metrics |
/maintenance |
GET | Maintenance mode status |
/maintenance/start |
POST | Enable maintenance mode |
/maintenance/stop |
POST | Disable maintenance mode |
/restart |
POST | Restart specific WG interface |
The agent polls these Control Plane endpoints:
| Endpoint | Interval | Purpose |
|---|---|---|
GET /agent/:router/sessions |
60s | Fetch BGP sessions |
GET /agent/:router/bird-config |
300s | Fetch BIRD config |
GET /agent/:router/mesh |
120s | Fetch mesh peers |
POST /agent/:router/heartbeat |
30s | Report health |
POST /agent/:router/modify |
On change | Update session status |
The agent tags only self-originated routes (static/device) with DN42 communities:
| Community | Description |
|---|---|
(64511, 1-9) |
Latency tier |
(64511, 21-25) |
Bandwidth tier |
(64511, 31-34) |
Encryption type |
(64511, 41-53) |
Region code |
Important: BGP-learned routes pass through unchanged to preserve upstream communities.
MoeNet Large Communities for internal routing optimization:
| Type | Format | Purpose |
|---|---|---|
| Origin Node | (4242420998, 3, nodeId) |
Ingress node |
| Bandwidth | (4242420998, 5, mbps) |
Link capacity |
# Clone
git clone https://github.com/moenet/moenet-agent.git
cd moenet-agent
# Build
go build -o moenet-agent ./cmd/moenet-agent
# Build with version info
go build -ldflags="-X main.Version=1.0.0 -X main.Commit=$(git rev-parse --short HEAD)" \
-o moenet-agent ./cmd/moenet-agentgo test ./...golangci-lint run# Build for Linux (from macOS or other host)
GOOS=linux GOARCH=amd64 go build -o moenet-agent-linux ./cmd/moenet-agentImportant: The binary must be fully replaced while the agent is stopped. SCP while the process is running can result in a corrupted binary (MD5 mismatch).
NODE="hk1.dn42.moenet.work"
KEY="~/.ssh/dn42_github_key"
# 1. Stop agent and remove old binary
ssh -i $KEY root@$NODE "systemctl stop moenet-agent && rm -f /opt/moenet-agent/moenet-agent"
# 2. Upload new binary
scp -i $KEY moenet-agent-linux root@$NODE:/opt/moenet-agent/moenet-agent
# 3. Verify MD5, set permissions, and start
ssh -i $KEY root@$NODE "chmod +x /opt/moenet-agent/moenet-agent && \
md5sum /opt/moenet-agent/moenet-agent && \
systemctl start moenet-agent"
# 4. Verify against local hash
md5 moenet-agent-linuxNODES=("hk1.dn42.moenet.work" "hk2.dn42.moenet.work" "jp1.dn42.moenet.work")
for NODE in "${NODES[@]}"; do
echo "=== Deploying to $NODE ==="
ssh -i $KEY root@$NODE "systemctl stop moenet-agent && rm -f /opt/moenet-agent/moenet-agent"
scp -i $KEY moenet-agent-linux root@$NODE:/opt/moenet-agent/moenet-agent
ssh -i $KEY root@$NODE "chmod +x /opt/moenet-agent/moenet-agent && systemctl start moenet-agent"
doneNote:
hk2uses SSH port10022. Add-p 10022to ssh/scp commands for that node.
- Architecture - Internal design and components
- API Reference - Detailed endpoint documentation
- Configuration - All configuration options
- BIRD Config - BIRD template rendering
- Troubleshooting - Common issues and solutions
MIT License - see LICENSE