This document summarizes the domain management implementation for AMTP gateways, following the "one gateway = one domain" architecture.
File: internal/config/config.go
- Comprehensive domain validation at startup
- RFC-compliant domain format checking
- Length limits (253 chars total, 63 chars per label)
- Character validation (no underscores, proper hyphen placement)
- Special handling for localhost (development)
- IP address warnings (discouraged but not blocked)
Example validation errors:
# Invalid domain with underscore
AMTP_DOMAIN="invalid_domain" ./agentry
# Error: domain cannot contain underscores: invalid_domain
# Domain starting with hyphen
AMTP_DOMAIN="-invalid.com" ./agentry
# Error: label cannot start or end with hyphen in domain: -invalid.comFiles:
docker/docker-compose.multi-domain.yml- Production multi-domain setupdocker/docker-compose.local-dev.yml- Development setupdocker/nginx/nginx.conf- Nginx reverse proxy configuration
Features:
- Separate containers for each domain
- Domain-based routing via Nginx
- TLS termination per domain
- Health checks and monitoring
File: scripts/deploy-multi-domain.sh
Capabilities:
- Start/stop/restart multiple gateways
- Status monitoring of all instances
- Health testing across domains
- Log management per domain
- Automatic configuration generation
- Agent registration helpers
Usage:
# Start all gateways (company-a.com, subsidiary.com, partner.com)
./scripts/deploy-multi-domain.sh start
# Check status
./scripts/deploy-multi-domain.sh status
# Test health endpoints
./scripts/deploy-multi-domain.sh test
# View logs for specific domain
./scripts/deploy-multi-domain.sh logs company-a.com
# Stop all gateways
./scripts/deploy-multi-domain.sh stopFile: k8s/company-a-gateway.yaml
Features:
- Production-ready K8s deployment
- Resource limits and requests
- Health/readiness probes
- TLS secret management
- Ingress configuration
- Service definitions
File: docs/DEPLOYMENT.md
Covers:
- Architecture overview (one gateway = one domain)
- Configuration methods (env vars, YAML, CLI flags)
- Deployment scenarios (single, multi-domain, Docker, K8s)
- DNS configuration requirements
- Security considerations
- Monitoring setup
- Troubleshooting guide
File: internal/config/config_test.go
Test scenarios:
- ✅ Valid domains (
example.com,api.company.com) - ✅ Development domains (
localhost) - ❌ Invalid formats (
invalid_domain,-bad.com) - ❌ Length violations (>253 chars, >63 char labels)
- ❌ Character violations (underscores, improper hyphens)
- ❌ Empty domains and labels
Gateway A (company-a.com) Gateway B (subsidiary.com) Gateway C (partner.com)
├── sales@company-a.com ├── hr@subsidiary.com ├── api@partner.com
├── support@company-a.com ├── finance@subsidiary.com ├── webhook@partner.com
└── api@company-a.com └── legal@subsidiary.com └── orders@partner.com
- No cross-domain agent registration
- Domain-specific TLS certificates
- Isolated admin keys and authentication
- Separate configuration and logs
- Scale per domain based on load
- Domain-specific resource allocation
- Independent deployment cycles
- Isolated failure domains
# Production gateway for company-a.com
export AMTP_DOMAIN="company-a.com"
export AMTP_SERVER_ADDRESS=":8443"
export AMTP_TLS_ENABLED=true
export AMTP_TLS_CERT_FILE="/etc/ssl/certs/company-a.com.crt"
export AMTP_TLS_KEY_FILE="/etc/ssl/private/company-a.com.key"
export AMTP_AUTH_REQUIRED=true
./agentry# config/company-a.yaml
server:
domain: "company-a.com" # ← Managed domain
address: ":8443"
tls:
enabled: true
cert_file: "/etc/ssl/certs/company-a.com.crt"
key_file: "/etc/ssl/private/company-a.com.key"
auth:
require_auth: true
admin_key_file: "/etc/ssl/admin/company-a.key"# Register agents using names only (domain auto-appended)
agentry-admin agent register sales --mode pull
# Creates: sales@company-a.com
agentry-admin agent register support --mode push --webhook https://support.company-a.com/webhook
# Creates: support@company-a.com
# List all agents for this domain
agentry-admin agent list
# Shows: sales@company-a.com, support@company-a.com# Each domain needs its own DNS TXT record
_amtp.company-a.com. IN TXT "v=amtp1;gateway=https://company-a.com:443"
_amtp.subsidiary.com. IN TXT "v=amtp1;gateway=https://subsidiary.com:443"
_amtp.partner.com. IN TXT "v=amtp1;gateway=https://partner.com:443"
- Startup validation prevents invalid configurations
- RFC compliance ensures proper domain format
- Character restrictions prevent injection attacks
- Length limits prevent buffer overflows
- Name-only registration (no full addresses accepted)
- Automatic domain appending using configured domain
- No cross-domain agent creation
- Validation at registration time
- Domain-specific TLS certificates
- Admin key authentication for management operations
- Agent API keys for inbox access
- Secure defaults (TLS enabled, auth required in production)
- Admin message inspection: the admin key (
X-Admin-Keyheader) also authenticates the message query endpoints (GET /v1/messages,GET /v1/messages/{id},GET /v1/messages/{id}/status). Message submission is public by design (AMTP is federated), so messages from unregistered or foreign senders have no matching agent key; the admin key lets operators inspect such messages. Agent keys remain scoped to messages the agent sent or received. - Conversation filters: on
GET /v1/messages, an agent may filter its own traffic by the other side of a conversation —?recipient=bob@remote.comlists messages the agent sent to bob and?sender=bob@remote.comlists messages bob sent to the agent. The agent is always pinned as one side of the query; filters where neither side is the agent are rejected. - Cursor polling: the
sinceparameter onGET /v1/messagesis an inclusive lower bound on the message timestamp, kept at full timestamp precision.?since=2026-08-09T12:00:00.999Zreturns messages stamped at or after 12:00:00.999Z, so cursor-style pollers do not re-receive messages from the same second on the next page.
GET /health- Basic health checkGET /ready- Readiness probeGET /metrics- Simple JSON metrics
- Structured JSON logging in production
- Domain-specific log files in multi-domain deployments
- Request tracing with correlation IDs
- Error context with detailed information
- One Gateway = One Domain: Never configure multiple domains per gateway
- Environment Variables: Use
AMTP_DOMAINfor production deployments - TLS Always: Never disable TLS in production (
AMTP_TLS_ENABLED=true) - Authentication Required: Always enable auth in production (
AMTP_AUTH_REQUIRED=true) - Agent Names Only: Register agents with names, let gateway add domain
- DNS Records: Maintain proper
_amtp.{domain}TXT records - Monitoring: Set up comprehensive health checks and metrics
- Security: Use domain-specific certificates and admin keys
All implementations include comprehensive tests:
# Test domain validation
go test ./internal/config -v
# Test all functionality
go test ./... -short
# Test deployment script
./scripts/deploy-multi-domain.sh start
./scripts/deploy-multi-domain.sh test
./scripts/deploy-multi-domain.sh stop
# Test Docker deployment
docker-compose -f docker/docker-compose.local-dev.yml up -d
docker-compose -f docker/docker-compose.local-dev.yml downThis implementation provides a robust, secure, and scalable domain management system for AMTP gateways. The "one gateway = one domain" architecture ensures:
- ✅ Clear ownership and responsibility boundaries
- ✅ Security isolation between domains
- ✅ Independent scaling and deployment
- ✅ Simplified management and troubleshooting
- ✅ Production-ready deployment options
- ✅ Comprehensive monitoring and observability
The system is ready for production use with proper security, monitoring, and operational practices built-in.