83 lines
3.1 KiB
TypeScript
83 lines
3.1 KiB
TypeScript
|
|
import {
|
||
|
|
DocsTitle,
|
||
|
|
DocsLead,
|
||
|
|
DocsH2,
|
||
|
|
DocsP,
|
||
|
|
DocsList,
|
||
|
|
DocsLi,
|
||
|
|
DocsCode,
|
||
|
|
Mono,
|
||
|
|
} from '@/components/docs-page';
|
||
|
|
|
||
|
|
export const metadata = { title: 'Self-hosting — BuildMyMCPServer docs' };
|
||
|
|
|
||
|
|
export default function SelfHosting() {
|
||
|
|
return (
|
||
|
|
<>
|
||
|
|
<DocsTitle kicker="Build">Self-hosting</DocsTitle>
|
||
|
|
<DocsLead>
|
||
|
|
The control plane and generator are open. Bring your own Postgres, Redis, Docker host and
|
||
|
|
Anthropic API key. Production uses Hetzner + Coolify + Traefik; the seams are the same.
|
||
|
|
</DocsLead>
|
||
|
|
|
||
|
|
<DocsH2 id="requirements">Requirements</DocsH2>
|
||
|
|
<DocsList>
|
||
|
|
<DocsLi>Node.js 20+</DocsLi>
|
||
|
|
<DocsLi>pnpm 9+</DocsLi>
|
||
|
|
<DocsLi>Docker engine reachable from the generator process</DocsLi>
|
||
|
|
<DocsLi>Postgres 16+ and Redis 7+ (docker-compose for dev)</DocsLi>
|
||
|
|
<DocsLi>Anthropic API key (optional — mock fallback for offline dev)</DocsLi>
|
||
|
|
</DocsList>
|
||
|
|
|
||
|
|
<DocsH2 id="dev">Local dev</DocsH2>
|
||
|
|
<DocsCode
|
||
|
|
label="bash"
|
||
|
|
code={`git clone <repo>
|
||
|
|
cd buildmymcpserver
|
||
|
|
pnpm install
|
||
|
|
cp .env.example .env
|
||
|
|
pnpm dev`}
|
||
|
|
/>
|
||
|
|
<DocsP>
|
||
|
|
<Mono>pnpm dev</Mono> loads <Mono>.env</Mono>, brings up Postgres and Redis via
|
||
|
|
docker-compose, pushes the Drizzle schema, and starts web (<Mono>:3001</Mono>), api
|
||
|
|
(<Mono>:4000</Mono>) and generator concurrently.
|
||
|
|
</DocsP>
|
||
|
|
|
||
|
|
<DocsH2 id="env">Environment variables</DocsH2>
|
||
|
|
<DocsList>
|
||
|
|
<DocsLi><Mono>DATABASE_URL</Mono> — Postgres connection string</DocsLi>
|
||
|
|
<DocsLi><Mono>REDIS_URL</Mono> — Redis (BullMQ + pubsub + preview cache)</DocsLi>
|
||
|
|
<DocsLi><Mono>ANTHROPIC_API_KEY</Mono> — unset = mock generator</DocsLi>
|
||
|
|
<DocsLi><Mono>SECRETS_ENCRYPTION_KEY</Mono> — 32-byte hex, AES-256-GCM key</DocsLi>
|
||
|
|
<DocsLi><Mono>CONTROL_PLANE_PUBLIC_URL</Mono> — issuer for OAuth tokens</DocsLi>
|
||
|
|
<DocsLi><Mono>OAUTH_KEY_DIR</Mono> — where RS256 keypair lives (auto-generated on boot)</DocsLi>
|
||
|
|
<DocsLi><Mono>RUNNER_PORT_RANGE_START/END</Mono> — host port window for generated containers</DocsLi>
|
||
|
|
</DocsList>
|
||
|
|
|
||
|
|
<DocsH2 id="prod">Production deployment</DocsH2>
|
||
|
|
<DocsP>
|
||
|
|
The intended production setup is a Hetzner AX52 running Coolify, Traefik for wildcard SSL
|
||
|
|
on <Mono>*.mcp.yourdomain.com</Mono>, and Cloudflare for DNS+DDoS. The runner-deploy
|
||
|
|
adapter is the only environment-specific seam — swap the Docker-CLI implementation in
|
||
|
|
<Mono>apps/generator/src/lib/deploy.ts</Mono> for the Coolify HTTP API.
|
||
|
|
</DocsP>
|
||
|
|
|
||
|
|
<DocsH2 id="sandboxing">Container sandboxing</DocsH2>
|
||
|
|
<DocsP>
|
||
|
|
Production flags (commented in deploy.ts):
|
||
|
|
</DocsP>
|
||
|
|
<DocsList>
|
||
|
|
<DocsLi><Mono>--read-only</Mono></DocsLi>
|
||
|
|
<DocsLi><Mono>--cap-drop=ALL</Mono></DocsLi>
|
||
|
|
<DocsLi><Mono>--security-opt=no-new-privileges</Mono></DocsLi>
|
||
|
|
<DocsLi><Mono>--cpus=0.5 --memory=512m</Mono></DocsLi>
|
||
|
|
</DocsList>
|
||
|
|
<DocsP>
|
||
|
|
Dev relaxes these for Docker Desktop on Windows compat. Don't ship dev defaults to
|
||
|
|
prod.
|
||
|
|
</DocsP>
|
||
|
|
</>
|
||
|
|
);
|
||
|
|
}
|