buildmymcpserver/apps/web/app/docs/self-hosting/page.tsx

83 lines
3.1 KiB
TypeScript
Raw Normal View History

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&apos;t ship dev defaults to
prod.
</DocsP>
</>
);
}