mirror of
https://github.com/DevVoxel/VectorDNS.git
synced 2026-02-27 09:57:39 +00:00
- /docs route with sidebar navigation and index page - Architecture section: system overview with React Flow diagram, data flow, database schema - API reference, configuration guide, and self-hosting docs for Go DNS server - Feature planning document for future development - Added docs link to landing page nav
399 lines
13 KiB
TypeScript
399 lines
13 KiB
TypeScript
import type { Metadata } from "next";
|
|
import {
|
|
Settings,
|
|
ArrowRight,
|
|
Shield,
|
|
Globe,
|
|
Gauge,
|
|
Database,
|
|
} from "lucide-react";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Separator } from "@/components/ui/separator";
|
|
|
|
export const metadata: Metadata = {
|
|
title: "Configuration",
|
|
};
|
|
|
|
function CodeBlock({ code }: { code: string }) {
|
|
return (
|
|
<pre className="overflow-x-auto rounded-md border bg-muted/50 p-4 font-mono text-sm leading-relaxed">
|
|
<code>{code.trim()}</code>
|
|
</pre>
|
|
);
|
|
}
|
|
|
|
function EnvVar({
|
|
name,
|
|
defaultVal,
|
|
required,
|
|
description,
|
|
}: {
|
|
name: string;
|
|
defaultVal: string;
|
|
required?: boolean;
|
|
description: string;
|
|
}) {
|
|
return (
|
|
<tr className="border-b last:border-b-0">
|
|
<td className="py-3 pr-4 align-top">
|
|
<code className="font-mono text-xs">{name}</code>
|
|
</td>
|
|
<td className="py-3 pr-4 align-top">
|
|
{defaultVal ? (
|
|
<code className="font-mono text-xs text-muted-foreground">
|
|
{defaultVal}
|
|
</code>
|
|
) : (
|
|
<span className="text-xs text-muted-foreground">—</span>
|
|
)}
|
|
</td>
|
|
<td className="py-3 pr-4 align-top">
|
|
{required ? (
|
|
<Badge variant="secondary" className="text-xs">
|
|
required
|
|
</Badge>
|
|
) : (
|
|
<Badge variant="outline" className="text-xs">
|
|
optional
|
|
</Badge>
|
|
)}
|
|
</td>
|
|
<td className="py-3 align-top text-sm text-muted-foreground">
|
|
{description}
|
|
</td>
|
|
</tr>
|
|
);
|
|
}
|
|
|
|
export default function ConfigurationPage() {
|
|
return (
|
|
<div className="space-y-10">
|
|
{/* Header */}
|
|
<div>
|
|
<div className="mb-3 flex items-center gap-2 text-sm text-muted-foreground">
|
|
<Settings className="size-4" />
|
|
<span>Go Server</span>
|
|
<ArrowRight className="size-3" />
|
|
<span>Configuration</span>
|
|
</div>
|
|
<h1 className="text-3xl font-bold tracking-tight">Configuration</h1>
|
|
<p className="mt-2 text-muted-foreground">
|
|
All server configuration is done via environment variables or a{" "}
|
|
<span className="font-mono text-xs bg-muted px-1 rounded">.env</span>{" "}
|
|
file in the project root.
|
|
</p>
|
|
</div>
|
|
|
|
{/* .env example */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-base">Example .env</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<CodeBlock
|
|
code={`PORT=8080
|
|
API_KEY=your-secret-api-key
|
|
CORS_ORIGINS=https://yourdomain.com,https://app.yourdomain.com
|
|
LOG_FORMAT=json`}
|
|
/>
|
|
<p className="mt-3 text-sm text-muted-foreground">
|
|
Copy{" "}
|
|
<span className="font-mono text-xs bg-muted px-1 rounded">
|
|
.env.example
|
|
</span>{" "}
|
|
to{" "}
|
|
<span className="font-mono text-xs bg-muted px-1 rounded">
|
|
.env
|
|
</span>{" "}
|
|
to get started:{" "}
|
|
<code className="font-mono text-xs bg-muted px-1 rounded">
|
|
cp .env.example .env
|
|
</code>
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Environment Variables reference */}
|
|
<div className="space-y-4">
|
|
<h2 className="text-xl font-semibold tracking-tight">
|
|
Environment Variables
|
|
</h2>
|
|
<Card>
|
|
<CardContent className="pt-6">
|
|
<table className="w-full text-sm">
|
|
<thead>
|
|
<tr className="border-b text-left text-muted-foreground">
|
|
<th className="pb-2 pr-4 font-medium">Variable</th>
|
|
<th className="pb-2 pr-4 font-medium">Default</th>
|
|
<th className="pb-2 pr-4 font-medium"></th>
|
|
<th className="pb-2 font-medium">Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<EnvVar
|
|
name="PORT"
|
|
defaultVal="8080"
|
|
description="Port the HTTP server listens on."
|
|
/>
|
|
<EnvVar
|
|
name="API_KEY"
|
|
defaultVal=""
|
|
description="Shared secret for API key authentication. Auth is disabled when empty — do not leave empty in production."
|
|
/>
|
|
<EnvVar
|
|
name="CORS_ORIGINS"
|
|
defaultVal="http://localhost:3000"
|
|
description="Comma-separated list of allowed CORS origins. Set to your frontend domain in production."
|
|
/>
|
|
<EnvVar
|
|
name="LOG_FORMAT"
|
|
defaultVal="text"
|
|
description='Log output format. "text" for human-readable, "json" for structured logging (recommended for production).'
|
|
/>
|
|
</tbody>
|
|
</table>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
{/* API Key Auth */}
|
|
<div className="space-y-4">
|
|
<div className="flex items-center gap-2">
|
|
<Shield className="size-5 text-primary" />
|
|
<h2 className="text-xl font-semibold tracking-tight">
|
|
API Key Authentication
|
|
</h2>
|
|
</div>
|
|
<p className="text-sm text-muted-foreground">
|
|
The Go server uses a shared API key for authentication. This is
|
|
intentional: the server is designed to be an internal service called
|
|
only by your Next.js backend — not directly by end users.
|
|
</p>
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-sm">How it works</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-3">
|
|
<p className="text-sm text-muted-foreground">
|
|
When{" "}
|
|
<span className="font-mono text-xs bg-muted px-1 rounded">
|
|
API_KEY
|
|
</span>{" "}
|
|
is set, every request (except{" "}
|
|
<span className="font-mono text-xs bg-muted px-1 rounded">
|
|
GET /health
|
|
</span>
|
|
) must include the header:
|
|
</p>
|
|
<CodeBlock code="X-API-Key: your-secret-api-key" />
|
|
<p className="text-sm text-muted-foreground">
|
|
Requests missing or sending an incorrect key receive a{" "}
|
|
<span className="font-mono text-xs bg-muted px-1 rounded">
|
|
401 UNAUTHORIZED
|
|
</span>{" "}
|
|
response.
|
|
</p>
|
|
<CodeBlock
|
|
code={`{
|
|
"error": "missing or invalid API key",
|
|
"code": "UNAUTHORIZED"
|
|
}`}
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-sm">Calling from Next.js</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<CodeBlock
|
|
code={`// In your Next.js server action or API route
|
|
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 }),
|
|
});`}
|
|
/>
|
|
<p className="mt-3 text-sm text-muted-foreground">
|
|
Store{" "}
|
|
<span className="font-mono text-xs bg-muted px-1 rounded">
|
|
DNS_API_KEY
|
|
</span>{" "}
|
|
as a secret environment variable in your Next.js deployment. Never
|
|
expose it client-side.
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
{/* CORS */}
|
|
<div className="space-y-4">
|
|
<div className="flex items-center gap-2">
|
|
<Globe className="size-5 text-primary" />
|
|
<h2 className="text-xl font-semibold tracking-tight">CORS</h2>
|
|
</div>
|
|
<p className="text-sm text-muted-foreground">
|
|
CORS is handled by{" "}
|
|
<a
|
|
href="https://github.com/go-chi/cors"
|
|
className="text-primary underline-offset-4 hover:underline"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
go-chi/cors
|
|
</a>
|
|
. Configure allowed origins via the{" "}
|
|
<span className="font-mono text-xs bg-muted px-1 rounded">
|
|
CORS_ORIGINS
|
|
</span>{" "}
|
|
variable.
|
|
</p>
|
|
<Card>
|
|
<CardContent className="space-y-3 pt-6">
|
|
<p className="text-sm font-medium">Development</p>
|
|
<CodeBlock code="CORS_ORIGINS=http://localhost:3000" />
|
|
<p className="text-sm font-medium">Production (single domain)</p>
|
|
<CodeBlock code="CORS_ORIGINS=https://app.yourdomain.com" />
|
|
<p className="text-sm font-medium">Production (multiple domains)</p>
|
|
<CodeBlock code="CORS_ORIGINS=https://app.yourdomain.com,https://yourdomain.com" />
|
|
</CardContent>
|
|
</Card>
|
|
<p className="text-sm text-muted-foreground">
|
|
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.
|
|
</p>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
{/* Rate Limiting */}
|
|
<div className="space-y-4">
|
|
<div className="flex items-center gap-2">
|
|
<Gauge className="size-5 text-primary" />
|
|
<h2 className="text-xl font-semibold tracking-tight">
|
|
Rate Limiting
|
|
</h2>
|
|
</div>
|
|
<p className="text-sm text-muted-foreground">
|
|
Rate limiting is provided by{" "}
|
|
<a
|
|
href="https://github.com/go-chi/httprate"
|
|
className="text-primary underline-offset-4 hover:underline"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
go-chi/httprate
|
|
</a>{" "}
|
|
and is enabled by default.
|
|
</p>
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-sm">Current defaults</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<ul className="space-y-2 text-sm text-muted-foreground">
|
|
<li>• Rate limiting is applied per IP address.</li>
|
|
<li>• Limits are enforced at the router middleware level.</li>
|
|
<li>
|
|
• Requests exceeding the limit receive{" "}
|
|
<span className="font-mono text-xs bg-muted px-1 rounded">
|
|
429 Too Many Requests
|
|
</span>
|
|
.
|
|
</li>
|
|
</ul>
|
|
</CardContent>
|
|
</Card>
|
|
<Card className="border-dashed">
|
|
<CardHeader>
|
|
<div className="flex items-center gap-2">
|
|
<CardTitle className="text-sm">
|
|
Per-API-key rate limiting
|
|
</CardTitle>
|
|
<Badge variant="outline" className="text-xs">
|
|
Planned
|
|
</Badge>
|
|
</div>
|
|
<CardDescription>
|
|
When billing tiers are added, rate limits will be enforced per API
|
|
key to match the user`'`s plan (free vs. pro).
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<ul className="space-y-1.5 text-sm text-muted-foreground">
|
|
<li>• Free tier: limited requests per day</li>
|
|
<li>• Pro tier: higher limits, hourly checks</li>
|
|
<li>• Team tier: highest limits, shared across org</li>
|
|
</ul>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
{/* Redis Caching */}
|
|
<div className="space-y-4">
|
|
<div className="flex items-center gap-2">
|
|
<Database className="size-5 text-primary" />
|
|
<h2 className="text-xl font-semibold tracking-tight">
|
|
Redis Caching
|
|
</h2>
|
|
<Badge variant="outline" className="text-xs">
|
|
Planned
|
|
</Badge>
|
|
</div>
|
|
<p className="text-sm text-muted-foreground">
|
|
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.
|
|
</p>
|
|
<Card className="border-dashed">
|
|
<CardHeader>
|
|
<CardTitle className="text-sm">
|
|
Planned Redis configuration
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-3">
|
|
<CodeBlock
|
|
code={`# Planned env vars (not yet available)
|
|
REDIS_URL=redis://localhost:6379
|
|
REDIS_TTL=300 # seconds`}
|
|
/>
|
|
<p className="text-sm text-muted-foreground">
|
|
The cache layer will use{" "}
|
|
<a
|
|
href="https://github.com/redis/go-redis"
|
|
className="text-primary underline-offset-4 hover:underline"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
go-redis
|
|
</a>{" "}
|
|
and sit as middleware before DNS resolution. A{" "}
|
|
<span className="font-mono text-xs bg-muted px-1 rounded">
|
|
docker-compose.yml
|
|
</span>{" "}
|
|
bundling the Go server with Redis will be provided.
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|