A high-performance, globally distributed, read-only mirror of PeeringDB data. PeeringDB Plus incrementally syncs PeeringDB objects on a regular schedule (escalating to a periodic full re-fetch as a safety net), stores the result in SQLite with edge replication via LiteFS on Fly.io, and serves the same dataset through six coexisting API surfaces.
Live instance: https://peeringdb-plus.fly.dev
The upstream PeeringDB API is the canonical source for peering coordination data, but it is single-region and rate-limited. PeeringDB Plus offers:
- Low-latency reads from the nearest Fly.io region (LiteFS replicates SQLite transactions to every replica).
- Multiple wire formats from a single dataset — drop-in PeeringDB API
compatibility, OpenAPI REST, GraphQL, ConnectRPC/gRPC, MCP, and a Web UI all
read from the same
ent.Client. - Mandatory observability — OpenTelemetry traces, metrics, and structured logs are first-class, not an afterthought.
- No CGO, no Java, no orchestrator — a single static Go binary plus an out-of-process LiteFS FUSE mount.
All six surfaces are mounted on the same HTTP server and read from the same SQLite database.
| Surface | Path | Description |
|---|---|---|
| Web UI | /ui/ |
templ + htmx search, detail pages, ASN comparison; content-negotiates terminal vs browser |
| GraphQL | /graphql |
gqlgen via entgql; interactive playground on GET, queries on POST |
| REST | /rest/v1/ |
OpenAPI-compliant (entrest); spec at /rest/v1/openapi.json |
| PeeringDB Compat | /api/ |
Drop-in replacement for api.peeringdb.com — same paths, same envelope |
| ConnectRPC / gRPC | /peeringdb.v1.*/ |
Get / List / Stream RPCs for all 13 entity types; reflection + health checks enabled |
| MCP | /mcp |
Read-only tools, resources, and prompts for network research agents |
GET / returns a JSON service-discovery document;
browsers are redirected to the Web UI, terminal clients receive plain help text.
See docs/API.md for the full surface catalogue,
including filter semantics, ordering guarantees, divergences,
and the response-memory envelope governing pdbcompat list responses.
git clone https://github.com/dotwaffle/peeringdb-plus.git
cd peeringdb-plus
go build -o peeringdb-plus ./cmd/peeringdb-plus
./peeringdb-plus
# Listening on :8080, syncing from api.peeringdb.com every hourThe first sync takes 30-60 seconds against the public PeeringDB API.
While it runs, /healthz returns 200 and /readyz returns 503;
once the database is populated,
/readyz flips to 200 and every API surface is usable.
docker build -t peeringdb-plus .
docker run -p 8080:8080 -v pdbdata:/data peeringdb-plusThe image stores the database at /data/peeringdb-plus.db;
mount a volume to persist data across container restarts.
curl -s http://localhost:8080/healthz # liveness
curl -sI http://localhost:8080/readyz # readiness (200 once first sync completes)
curl -s http://localhost:8080/api/net/1 | head -c 500 # PeeringDB-compatible API
curl -sO http://localhost:8080/skills/peeringdb-plus.zip # Origin-aware Agent Skill
open http://localhost:8080/ui/ # Web UI
open http://localhost:8080/graphql # GraphQL playgroundFor the full first-30-minutes walkthrough, see
docs/GETTING-STARTED.md.
# List networks
curl https://peeringdb-plus.fly.dev/api/net
# Fetch a specific network by PeeringDB numeric ID
curl https://peeringdb-plus.fly.dev/api/net/42
# Search with query parameters (depth/limit/skip/fields/since/q all supported)
curl 'https://peeringdb-plus.fly.dev/api/net?q=cloudflare&limit=5'ConnectRPC, gRPC, and gRPC-Web all share the same endpoints.
Reflection (grpcreflect.NewHandlerV1 / V1Alpha)
and the standard gRPC health check service are enabled,
so grpcurl and gRPC-aware load balancers work out-of-the-box.
# List all services
grpcurl -plaintext localhost:8080 list
# Get a single network by ID
buf curl --protocol grpc --http2-prior-knowledge \
http://localhost:8080/peeringdb.v1.NetworkService/GetNetwork \
-d '{"id": 42}'
# Stream all networks (server-streaming, no manual pagination)
buf curl --protocol grpc --http2-prior-knowledge \
http://localhost:8080/peeringdb.v1.NetworkService/StreamNetworks \
-d '{"asn": 15169}'Streams accept the same filters as List* RPCs;
the grpc-total-count response header carries the approximate total.
Server-side timeout defaults to 60s (PDBPLUS_STREAM_TIMEOUT)
and clients can cancel at any time.
curl -X POST http://localhost:8080/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ networks(first: 3) { edges { node { id name asn } } } }"}'The stateless Streamable HTTP MCP endpoint is available at /mcp.
It provides bounded directory search, detail, comparison, IP lookup, and sync
freshness tools plus reusable resources and prompts.
Download the skill through the hostname agents should connect back to:
curl -fLO http://localhost:8080/skills/peeringdb-plus.zip
curl -fsS http://localhost:8080/skills/peeringdb-plus/SKILL.mdThe ZIP's agents/openai.yaml is generated per request and points to the same
origin's /mcp endpoint. Set PDBPLUS_PUBLIC_URL only when a reverse proxy
does not preserve the requested Host.
PeeringDB Plus is configured exclusively via environment variables, validated at startup with fail-fast diagnostics. Operationally-relevant defaults:
| Variable | Default | Purpose |
|---|---|---|
PDBPLUS_LISTEN_ADDR |
:8080 |
HTTP listen address |
PDBPLUS_DB_PATH |
./peeringdb-plus.db |
SQLite database file path |
PDBPLUS_PEERINGDB_URL |
https://api.peeringdb.com |
Upstream PeeringDB API |
PDBPLUS_PEERINGDB_API_KEY |
(unset) | Optional — raises rate limit and shortens default sync interval |
PDBPLUS_SYNC_MODE |
incremental |
incremental (delta) or full (re-fetch); full is the operator escape-hatch |
PDBPLUS_SYNC_INTERVAL |
1h (15m if API key set) |
Time between sync cycles |
PDBPLUS_RESPONSE_MEMORY_LIMIT |
128MiB |
pdbcompat list pre-flight 413 budget |
PDBPLUS_PUBLIC_TIER |
public |
Anonymous-caller tier; set users only for private deployments |
PDBPLUS_PUBLIC_URL |
(unset) | Optional public-origin override for generated Agent Skill metadata |
The full catalogue (sync, observability, LiteFS, Fly.io, CSP, security headers,
and OAuth-gated visibility) lives in
docs/CONFIGURATION.md.
Standard OTEL_* env vars are honoured via OpenTelemetry autoexport.
| Doc | Topic |
|---|---|
docs/GETTING-STARTED.md |
First-30-minutes walkthrough: prerequisites, build, first run, verification |
docs/ARCHITECTURE.md |
Component diagram, data flow, code-generation pipeline, middleware chain, privacy layer, sampling matrix |
docs/API.md |
All six API surfaces, filter semantics, ordering, cross-entity traversal, divergences |
docs/CONFIGURATION.md |
Full environment-variable catalogue with validation rules |
docs/DEVELOPMENT.md |
Local dev workflow, code generation, conventions, sibling-file pattern |
docs/TESTING.md |
Test layout, fixtures, parity harness, live tests against beta.peeringdb.com |
docs/DEPLOYMENT.md |
Fly.io rollout, asymmetric fleet topology, LiteFS operations |
CONTRIBUTING.md |
How to propose changes, run the verification suite, and submit a PR |
- Language: Go 1.26.5
- ORM / codegen: entgo underpins all six API surfaces
from a single set of schemas in
ent/schema/(entgql + entrest + entproto) - Database:
modernc.org/sqlite(pure Go, no CGO) plus LiteFS for edge replication - RPC: ConnectRPC — gRPC, gRPC-Web, and the Connect protocol on the same handlers
- GraphQL: gqlgen wired through entgql
- Web UI: templ + htmx + Tailwind CSS — zero JavaScript build toolchain
- Observability: OpenTelemetry with the
stdlib
log/slogbridge; per-route trace sampling; per-VM runtime metrics - Platform: Fly.io with an asymmetric
primary/replicaprocess-group fleet - Container base: Chainguard minimal
images (
cgr.dev/chainguard/go,cgr.dev/chainguard/glibc-dynamic)
mise install --locked # Install the pinned toolchain
mise run generate # Full codegen pipeline
mise run check # Generate, tidy, build, test, lint, scanMise supplies Go, code generators, Tailwind, gotestsum, linters, and security
tools from the committed cross-platform lockfile.
CI runs the same tools plus generated-code and module-tidiness checks on every PR.
See docs/DEVELOPMENT.md for the conventions,
including the sibling-file pattern
that protects hand-edited schema methods from being overwritten by
cmd/pdb-schema-generate.
PeeringDB Plus is open source.
Bug reports, feature suggestions, and pull requests are welcome —
please read CONTRIBUTING.md before opening a PR.
BSD 3-Clause.
See LICENSE.