@bobfromarcher/domainward
v1.0.0
Published
A single HTTP API over the mailward and dnsward audit engines: one request returns a domain's email-authentication and DNS-health report with an overall grade. Built on Node's http, no third-party runtime code, no AI.
Maintainers
Readme
domainward
One HTTP API over the mailward and dnsward audit engines. A single request returns a domain's email-authentication report, its DNS-health report, and a combined overall grade. Built on Node's built-in http, with no third-party runtime code and no AI. Results are deterministic because everything is read from live DNS.
Run it
npx @bobfromarcher/domainward
# domainward listening on http://localhost:8080Or with Docker:
docker build -t domainward .
docker run -p 8080:8080 domainwardEndpoints
| Method | Path | Returns |
| --- | --- | --- |
| GET | /v1/audit/{domain} | Combined mail and dns report with an overall grade |
| GET | /v1/audit/mail/{domain} | Email authentication (MX, SPF, DKIM, DMARC, MTA-STS, BIMI) |
| GET | /v1/audit/dns/{domain} | DNS health (A/AAAA, NS, SOA, CAA, TTL, DNSSEC) |
| GET | /health | Liveness |
| GET | / | A small HTML index of the endpoints |
You can also pass the domain as a query string: GET /v1/audit?domain=example.com.
Example
curl https://your-host/v1/audit/stripe.com{
"domain": "stripe.com",
"overall": { "score": 81, "grade": "B" },
"mail": { "score": 87, "grade": "B", "checks": [ ... ] },
"dns": { "score": 75, "grade": "C", "checks": [ ... ] }
}Each entry in checks has an id, title, status (pass, warn, fail, info), a detail, and a fix when the check is not passing.
Built in
- Response cache. Identical requests inside the TTL are served from memory and return
x-cache: HIT. Default 5 minutes. - Rate limiting. Per-IP, default 60 requests per minute. Over the limit returns
429withretry-after. - Input validation. Bare IPs,
localhostand malformed names are rejected with400. - Hard timeout. A slow audit returns
504rather than hanging the connection. - CORS.
access-control-allow-origin: *, so it can be called from a browser.
Configuration
| Variable | Default | Meaning |
| --- | --- | --- |
| PORT | 8080 | Listen port |
| CACHE_TTL_MS | 300000 | Response cache TTL |
| RATE_LIMIT | 60 | Requests per IP per minute |
| AUDIT_TIMEOUT | 6000 | Per-audit DNS timeout in ms |
Deploy
The image is a plain Node server with no third-party dependencies, so it runs anywhere that runs a container or a Node process:
- Docker / any VM:
docker run -p 8080:8080 domainward. - Render or Railway: point at this repo, they detect the Dockerfile, set the port to
8080. - Fly.io:
fly launchpicks up the Dockerfile.
DNSSEC checking uses a direct UDP DNS query. Most container hosts allow outbound UDP on port 53, but some serverless platforms block raw UDP, in which case the DNSSEC check degrades to "not checked" and the rest of the audit still works. For that reason a container or VM is the most reliable host.
A note on the vendored engines
lib/mailward.js and lib/dnsward.js are copies of the published @bobfromarcher/mailward and @bobfromarcher/dnsward packages. Vendoring keeps this service fully self-contained with no install step and no version surprises at deploy time.
Development
git clone https://github.com/bobfromarcher/domainward
cd domainward
node test/test.js
npm startThe server is created by createApp(deps) in lib/server.js, which accepts injected audit functions, a clock, and limits, so the whole API is tested without touching the network.
License
MIT, bobfromarcher.
