mirror of
https://github.com/DevVoxel/vectordns-server.git
synced 2026-02-27 01:40:12 +00:00
Add documentation for API reference, configuration, and self-hosting
This commit is contained in:
155
docs/api-reference.md
Normal file
155
docs/api-reference.md
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
# API Reference
|
||||||
|
|
||||||
|
Complete reference for the VectorDNS Go server REST API.
|
||||||
|
|
||||||
|
## Base URL & Authentication
|
||||||
|
|
||||||
|
**Base URL:** `https://<your-vps-host>/api/v1`
|
||||||
|
|
||||||
|
All requests (except `/health`) require an API key header:
|
||||||
|
|
||||||
|
```
|
||||||
|
X-API-Key: <your-shared-secret>
|
||||||
|
```
|
||||||
|
|
||||||
|
Set `API_KEY` in your server environment to enable authentication. If left empty, auth is disabled (not recommended for production).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
### `POST /dns/lookup`
|
||||||
|
|
||||||
|
Resolve DNS records for a domain. Query one or more record types in a single request.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"domain": "example.com",
|
||||||
|
"types": ["A", "AAAA", "MX", "TXT", "NS", "CNAME", "SOA", "CAA", "SRV"],
|
||||||
|
"nameserver": "8.8.8.8"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Required | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `domain` | Yes | The domain to query. |
|
||||||
|
| `types` | No | Record types to query. Defaults to all 9 supported types if omitted. |
|
||||||
|
| `nameserver` | No | Specific nameserver to query. Defaults to system resolver. |
|
||||||
|
|
||||||
|
**Response (200):**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"domain": "example.com",
|
||||||
|
"nameserver": "8.8.8.8",
|
||||||
|
"records": {
|
||||||
|
"A": [{ "value": "93.184.216.34", "ttl": 300 }],
|
||||||
|
"MX": [{ "value": "mail.example.com", "priority": 10, "ttl": 3600 }]
|
||||||
|
},
|
||||||
|
"query_time_ms": 12
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `POST /dns/propagation`
|
||||||
|
|
||||||
|
Check DNS propagation across multiple public resolvers. Queries resolvers in parallel and compares results.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"domain": "example.com",
|
||||||
|
"type": "A",
|
||||||
|
"resolvers": ["8.8.8.8", "1.1.1.1", "9.9.9.9"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Required | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `domain` | Yes | The domain to check. |
|
||||||
|
| `type` | Yes | The record type to check (e.g. `A`, `MX`). |
|
||||||
|
| `resolvers` | No | List of resolver IPs. Defaults to a built-in list of public resolvers. |
|
||||||
|
|
||||||
|
**Response (200):**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"domain": "example.com",
|
||||||
|
"type": "A",
|
||||||
|
"results": [
|
||||||
|
{ "resolver": "8.8.8.8", "values": ["93.184.216.34"], "ttl": 300 },
|
||||||
|
{ "resolver": "1.1.1.1", "values": ["93.184.216.34"], "ttl": 280 },
|
||||||
|
{ "resolver": "9.9.9.9", "values": ["93.184.216.34"], "ttl": 295 }
|
||||||
|
],
|
||||||
|
"consistent": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `POST /dns/validate`
|
||||||
|
|
||||||
|
DNSSEC validation for a domain. Checks the AD flag and verifies the signature chain.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"domain": "example.com"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Required | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `domain` | Yes | The domain to validate. |
|
||||||
|
|
||||||
|
**Response (200):**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"domain": "example.com",
|
||||||
|
"dnssec": true,
|
||||||
|
"chain_valid": true,
|
||||||
|
"details": "RRSIG verified for A record"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `GET /health`
|
||||||
|
|
||||||
|
Health check. No authentication required. Use this for uptime monitoring.
|
||||||
|
|
||||||
|
**Response (200):**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"version": "0.1.0"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error Responses
|
||||||
|
|
||||||
|
All errors return a consistent JSON body:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "invalid domain",
|
||||||
|
"code": "INVALID_DOMAIN"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| HTTP Status | Code | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| 400 | `INVALID_DOMAIN` | Malformed or missing domain |
|
||||||
|
| 400 | `INVALID_TYPE` | Unsupported record type |
|
||||||
|
| 401 | `UNAUTHORIZED` | Missing or invalid API key |
|
||||||
|
| 500 | `DNS_ERROR` | Upstream DNS query failed |
|
||||||
|
| 500 | `INTERNAL` | Unexpected server error |
|
||||||
119
docs/configuration.md
Normal file
119
docs/configuration.md
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
# Configuration
|
||||||
|
|
||||||
|
All server configuration is done via environment variables or a `.env` file in the project root.
|
||||||
|
|
||||||
|
## Example .env
|
||||||
|
|
||||||
|
```env
|
||||||
|
PORT=8080
|
||||||
|
API_KEY=your-secret-api-key
|
||||||
|
CORS_ORIGINS=https://yourdomain.com,https://app.yourdomain.com
|
||||||
|
LOG_FORMAT=json
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy `.env.example` to get started:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
| Variable | Default | Required | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `PORT` | `8080` | No | Port the HTTP server listens on. |
|
||||||
|
| `API_KEY` | — | No* | Shared secret for API key auth. Auth is disabled when empty — do not leave empty in production. |
|
||||||
|
| `CORS_ORIGINS` | `http://localhost:3000` | No | Comma-separated list of allowed CORS origins. |
|
||||||
|
| `LOG_FORMAT` | `text` | No | `text` for human-readable, `json` for structured logging (recommended for production). |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API Key Authentication
|
||||||
|
|
||||||
|
The Go server uses a shared API key. This is intentional: the server is an internal service called only by the Next.js backend, not directly by end users.
|
||||||
|
|
||||||
|
When `API_KEY` is set, every request (except `GET /health`) must include:
|
||||||
|
|
||||||
|
```
|
||||||
|
X-API-Key: your-secret-api-key
|
||||||
|
```
|
||||||
|
|
||||||
|
Requests with a missing or incorrect key get `401 UNAUTHORIZED`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "missing or invalid API key",
|
||||||
|
"code": "UNAUTHORIZED"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Calling from Next.js
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const res = await fetch(`${process.env.DNS_SERVER_URL}/api/v1/dns/lookup`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-API-Key": process.env.DNS_API_KEY!,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ domain, types }),
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Store `DNS_API_KEY` as a secret environment variable in your Next.js deployment. Never expose it client-side.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CORS
|
||||||
|
|
||||||
|
CORS is handled by [go-chi/cors](https://github.com/go-chi/cors). Configure allowed origins via `CORS_ORIGINS`.
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Development
|
||||||
|
CORS_ORIGINS=http://localhost:3000
|
||||||
|
|
||||||
|
# Production (single domain)
|
||||||
|
CORS_ORIGINS=https://app.yourdomain.com
|
||||||
|
|
||||||
|
# Production (multiple domains)
|
||||||
|
CORS_ORIGINS=https://app.yourdomain.com,https://yourdomain.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Since the Go server is an internal API called server-side by Next.js, CORS is mostly relevant for development. In production, only your Next.js server IP/domain needs access.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
Rate limiting is provided by [go-chi/httprate](https://github.com/go-chi/httprate) and is enabled by default.
|
||||||
|
|
||||||
|
- Rate limiting is applied per IP address.
|
||||||
|
- Limits are enforced at the router middleware level.
|
||||||
|
- Requests exceeding the limit receive `429 Too Many Requests`.
|
||||||
|
|
||||||
|
### Per-API-key rate limiting (planned)
|
||||||
|
|
||||||
|
When billing tiers are added, rate limits will be enforced per API key:
|
||||||
|
|
||||||
|
| Tier | Limit |
|
||||||
|
|---|---|
|
||||||
|
| Free | Limited requests per day, daily checks |
|
||||||
|
| Pro | Higher limits, hourly checks |
|
||||||
|
| Team | Highest limits, shared across org |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Redis Caching (planned)
|
||||||
|
|
||||||
|
DNS result caching via Redis is on the roadmap. When available, the server will check Redis before querying upstream DNS, storing results with TTL-based expiry.
|
||||||
|
|
||||||
|
Planned configuration:
|
||||||
|
|
||||||
|
```env
|
||||||
|
REDIS_URL=redis://localhost:6379
|
||||||
|
REDIS_TTL=300 # seconds
|
||||||
|
```
|
||||||
|
|
||||||
|
The cache layer will use [go-redis](https://github.com/redis/go-redis) as middleware before DNS resolution. A `docker-compose.yml` bundling the Go server with Redis will be provided for self-hosting. See [self-hosting.md](./self-hosting.md) for the planned compose configuration.
|
||||||
146
docs/self-hosting.md
Normal file
146
docs/self-hosting.md
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
# Self-Hosting
|
||||||
|
|
||||||
|
Run the VectorDNS Go server on your own VPS or infrastructure. The DNS API is a single stateless binary — no database required.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Docker** — Recommended. No Go toolchain needed on the host.
|
||||||
|
- **Go 1.22+** — Required only if building from source.
|
||||||
|
- **Port 8080** — Default port (configurable via `PORT` env var).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Docker (Recommended)
|
||||||
|
|
||||||
|
### 1. Clone the repository
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/yourusername/vectordns-server.git
|
||||||
|
cd vectordns-server
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Create your .env file
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
At minimum, set `API_KEY` and `CORS_ORIGINS`. See [configuration.md](./configuration.md) for all options.
|
||||||
|
|
||||||
|
### 3. Build the Docker image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t vectordns-server .
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Run the container
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d -p 8080:8080 --env-file .env --name vectordns-server vectordns-server
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Verify it's running
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:8080/api/v1/health
|
||||||
|
# {"status":"ok","version":"0.1.0"}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## From Source
|
||||||
|
|
||||||
|
Requires Go 1.22+.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install dependencies
|
||||||
|
go mod tidy
|
||||||
|
|
||||||
|
# Configure environment
|
||||||
|
cp .env.example .env && nano .env
|
||||||
|
|
||||||
|
# Run
|
||||||
|
go run ./cmd/server
|
||||||
|
|
||||||
|
# Or build a binary
|
||||||
|
go build -o vectordns-server ./cmd/server
|
||||||
|
./vectordns-server
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## VPS Deployment
|
||||||
|
|
||||||
|
### Reverse proxy with nginx
|
||||||
|
|
||||||
|
Serve the Go server behind nginx to add TLS and a clean domain path.
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
# /etc/nginx/sites-available/vectordns
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name api.yourdomain.com;
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://localhost:8080;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### systemd service (non-Docker)
|
||||||
|
|
||||||
|
Keep the server running across reboots without Docker.
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# /etc/systemd/system/vectordns-server.service
|
||||||
|
[Unit]
|
||||||
|
Description=VectorDNS Go Server
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/opt/vectordns/vectordns-server
|
||||||
|
EnvironmentFile=/opt/vectordns/.env
|
||||||
|
Restart=on-failure
|
||||||
|
User=www-data
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl enable vectordns-server
|
||||||
|
sudo systemctl start vectordns-server
|
||||||
|
```
|
||||||
|
|
||||||
|
### docker-compose with Redis (planned)
|
||||||
|
|
||||||
|
Once Redis caching ships, a docker-compose setup will be provided:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.yml (planned)
|
||||||
|
services:
|
||||||
|
server:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
env_file: .env
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Checklist
|
||||||
|
|
||||||
|
- Set a strong `API_KEY` — do not leave auth disabled in production.
|
||||||
|
- Set `CORS_ORIGINS` to your exact frontend domain, not `*`.
|
||||||
|
- Always run behind TLS (use Let's Encrypt via Certbot with nginx).
|
||||||
|
- Rate limiting is enabled by default — keep it on.
|
||||||
Reference in New Issue
Block a user