Run a Registry Node
agentdns is the Go binary that implements the Registry Spec. One process, talks Postgres + Redis + the mesh + the HTTP API.
This page is the operator's runbook. For protocol-level details see Architecture: Registry Spec and for binary internals see Architecture: AgentDNS.
Pre-flight
| Need | Detail |
|---|---|
| Linux VM | 2 vCPU, 4 GB RAM minimum for a small mesh node; 8+ GB once you start indexing thousands of entities |
| Postgres 14+ | Either local or managed (RDS / Cloud SQL fine) |
| Redis (optional) | Speeds up cards / rate limits / bloom filters; the node runs without it |
| A domain | Public registries should serve TLS at a real domain, e.g. registry.example.com |
| Outbound TCP+TLS to port 4001 | For mesh peering |
Install
# Download the latest binary (placeholder — adjust to actual release path)
curl -L -o /usr/local/bin/agentdns https://github.com/zyndai/AgentDNS/releases/latest/download/agentdns-linux-amd64
chmod +x /usr/local/bin/agentdns
agentdns versionOr build from source:
git clone https://github.com/zyndai/AgentDNS
cd AgentDNS
go build -o /usr/local/bin/agentdns ./cmd/agentdnsInitialise
agentdns initCreates:
~/.zynd/identity.json— node Ed25519 keypair. Back this up.~/.zynd/config.toml— default config; safe to edit beforestart.
Configure
~/.zynd/config.toml holds everything. Most operators only edit a handful of sections.
[node]
[node]
name = "my-registry"
type = "full" # "full" | "light" | "gateway"
data_dir = "~/.zynd/data"
external_ip = "auto" # or a fixed IP
https_endpoint = "https://my-registry.example.com"https_endpoint becomes the prefix of every FQAN your node mints, so set it to a domain you control.
[mesh]
[mesh]
listen_port = 4001
max_peers = 15
bootstrap_peers = ["zns-boot.zynd.ai:4001", "zns01.zynd.ai:4001"]
tls_enabled = truebootstrap_peers is how new nodes find the mesh. Leave the defaults to join the public Zynd mesh; replace with your own seeds for a private mesh.
[registry]
[registry]
postgres_url = "postgres://agentdns:agentdns@localhost:5432/agentdns?sslmode=require"
max_local_agents = 100000In production: sslmode=require. The connection pool is 2–20 connections.
[search]
[search]
embedding_backend = "onnx"
embedding_model = "bge-small-en-v1.5"
embedding_dimensions = 384
use_improved_keyword = true
max_federated_peers = 10
federated_timeout_ms = 1500
default_max_results = 20For tiny meshes / CI, embedding_backend = "hash" is zero-deps. For best recall, ONNX with bge-small-en-v1.5 (~130 MB; auto-downloaded with SHA-256 verification on first start). For shared embeddings via OpenAI / Ollama, embedding_backend = "http" with embedding_endpoint = "...".
[search.ranking]
[search.ranking]
method = "weighted" # or "rrf"
text_relevance_weight = 0.30
semantic_similarity_weight = 0.30
trust_weight = 0.20
freshness_weight = 0.10
availability_weight = 0.10weighted lets you tune. rrf needs no tuning.
[redis] (optional)
[redis]
url = "redis://localhost:6379/0"Without Redis the node still works — Tier-1 LRUs and in-memory rate buckets cover most needs.
[api]
[api]
listen = "0.0.0.0:8080"
rate_limit_search = 100
rate_limit_register = 10
cors_origins = ["https://my-dashboard.example.com"]Use a reverse proxy (Caddy / nginx) for TLS on this port.
[onboarding]
[onboarding]
mode = "open" # or "restricted"
auth_url = ""
webhook_secret = ""open = self-registration on first handle claim or entity registration. restricted = developers must be approved via webhook.
[heartbeat]
[heartbeat]
enabled = true
inactive_threshold_seconds = 300 # 5 min
sweep_interval_seconds = 60
max_clock_skew_seconds = 60[dht]
[dht]
enabled = true
k = 20
alpha = 3
republish_interval = 3600
expire_after = 86400
lookup_timeout_ms = 5000Disable for light and gateway nodes.
Env var overrides
| Env | Overrides |
|---|---|
AGENTDNS_CONFIG | Path to config file (same as --config) |
AGENTDNS_DATA_DIR | [node].data_dir |
AGENTDNS_POSTGRES_URL | [registry].postgres_url |
AGENTDNS_REDIS_URL | [redis].url |
AGENTDNS_LISTEN | [api].listen |
Start
agentdns startLogs go to stdout. Block on SIGINT/SIGTERM.
For a systemd unit:
# /etc/systemd/system/agentdns.service
[Unit]
Description=Zynd AgentDNS registry
After=network.target postgresql.service
Wants=postgresql.service
[Service]
ExecStart=/usr/local/bin/agentdns start --config /etc/agentdns/config.toml
EnvironmentFile=/etc/agentdns/agentdns.env
Restart=on-failure
User=agentdns
[Install]
WantedBy=multi-user.targetsudo systemctl enable --now agentdns
sudo journalctl -u agentdns -fTLS
Front the API with Caddy:
my-registry.example.com {
reverse_proxy localhost:8080
}Caddy auto-issues a Let's Encrypt cert. The mesh port (4001) does not need a CA cert — it uses self-signed TLS verified at the application layer.
CLI day-to-day
agentdns status # uptime, peers, agents, gossip rate, DHT state
agentdns peers # connected peers + verification tier
agentdns versionFor the full subcommand list see Architecture: AgentDNS — CLI.
Production checklist
- [ ]
[node].https_endpointset to a domain you control. - [ ] TLS via Let's Encrypt on port 8080 (Caddy / nginx).
- [ ]
[registry].postgres_urlusessslmode=require. - [ ]
[redis].urlset if running multiple instances behind a load balancer. - [ ]
[api].cors_originsrestricted to your dashboard origin(s). - [ ]
/.well-known/zynd-registry.jsonpublished (signed registry identity proof). - [ ]
_zynd.<your-domain>DNS TXT record published — peer verification falls back to it. - [ ]
[onboarding].mode = "restricted"if you don't want public developer signups. - [ ] Identity backed up —
~/.zynd/identity.json. - [ ] Postgres backed up daily.
- [ ] Metrics scrape configured — see Metrics & Monitoring.
Joining the public Zynd mesh
If you want your node to be part of the global Zynd network (so registrations on your node show up in zns01.zynd.ai searches and vice versa):
- Set
bootstrap_peers = ["zns-boot.zynd.ai:4001"]. - Make sure your
[node].external_ipis reachable on port 4001 from the public internet. - Publish a registry identity proof at
/.well-known/zynd-registry.jsonso peers verify your domain.
Then start the node — it'll announce itself, exchange bloom filters, and begin gossiping.
Running a private mesh
For an air-gapped or internal-only deployment:
- Stand up two or more
agentdnsnodes within your network. - Pick one to be the bootnode — set its address as
bootstrap_peerson every other node. - Don't publish to the public Zynd mesh — leave
bootstrap_peers = [](or just your private peers) on each node. - Point your developers'
ZYND_REGISTRY_URLat one of the nodes.
That's it — your developers' agents register on your private registry, your private peers gossip to each other, the public Zynd network is never touched.
See also
- Architecture: Registry Spec — what the protocol means.
- Architecture: AgentDNS — the binary's internals.
- Local Testing — same binary, dev mode.
- Metrics & Monitoring — what to watch.