Hosting Plan: wiki.graffold.com¶
Goal¶
Three domains on one Hetzner VPS:
| Domain | Purpose |
|---|---|
wiki.graffold.com |
Unified docs for graffold-api + graffold-ingest |
api.graffold.com |
Live API with interactive Swagger/ReDoc |
graphrag.graffold.com |
Temporary replica of Olink graphrag_api wiki (legacy reference) |
Architecture¶
wiki.graffold.com ← mkdocs Material (graffold-api + ingest)
├── / ← Landing / home
├── /getting-started/ ← Quick start guides
├── /architecture/ ← System design
├── /ingestion/ ← Pipeline + graffold-ingest docs
├── /querying/ ← Query agents, modes
├── /operations/ ← Redis, Grafana, hosting
└── /development/ ← Testing, CLI, SDK API reference
api.graffold.com ← FastAPI (live, auto-generated)
├── /docs ← Swagger UI (interactive)
├── /redoc ← ReDoc (clean reference layout)
└── /openapi.json ← Machine-readable spec
graphrag.graffold.com ← mkdocs Material (legacy Olink wiki replica)
├── / ← GraphRAG API docs (temporary)
├── /ingestion/ ← Pipeline guides
├── /architecture/ ← System design
├── /benchmarks/ ← Gold standard evals
└── /operations/ ← Maintenance & validation
Deployment¶
Static Wikis → Cloudflare Pages¶
Both wiki sites are deployed as static mkdocs builds to Cloudflare Pages. This gives:
- Zero infra to manage (no Caddy/nginx for static content)
- Global CDN with edge caching
- Automatic preview deployments on PRs
- Instant rollbacks via CF dashboard
- Free custom domains with auto-TLS
wiki.graffold.com → CF Pages project "graffold-wiki"
graphrag.graffold.com → CF Pages project "graphrag-wiki"
Live API → Hetzner VPS¶
The API needs a server (database connections, LLM calls, state). The wikis don't.
Setup: Cloudflare Pages¶
- Create two Pages projects in CF dashboard:
graffold-wiki→ custom domainwiki.graffold.com-
graphrag-wiki→ custom domaingraphrag.graffold.com -
Add GitHub secrets to the repo:
CLOUDFLARE_API_TOKEN— API token with Pages edit permission-
CLOUDFLARE_ACCOUNT_ID— your CF account ID -
Push to
main— the workflow builds mkdocs and deploys viawrangler pages deploy
Setup: API (Hetzner)¶
The API continues to run on Hetzner with a simpler Caddyfile (only one domain now):
api.graffold.com {
reverse_proxy localhost:8000
header {
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
}
}
Wiki Build Pipeline¶
# Build wiki (runs in CI or on deploy)
pip install mkdocs-material
mkdocs build --site-dir wiki-build/
# Deploy to Hetzner
rsync -avz wiki-build/ hetzner:/srv/wiki/
FastAPI Docs Customization¶
To match the clean layout of the Olink API reference, customize the Swagger UI:
# In api/app.py
app = FastAPI(
title="Graffold API",
version="0.2.0",
description="Scientific Knowledge Graph Platform API",
docs_url="/docs",
redoc_url="/redoc",
openapi_url="/openapi.json",
openapi_tags=[
{"name": "sdk", "description": "SDK endpoints for external integrations"},
{"name": "query", "description": "Knowledge graph query and session management"},
{"name": "ingestion", "description": "Document ingestion and KG construction"},
{"name": "enrichment", "description": "External database enrichment"},
{"name": "platform", "description": "Health, metrics, and configuration"},
],
)
CI/CD¶
# .github/workflows/docs.yml
name: Deploy Docs
on:
push:
branches: [main]
paths: ['docs/**', 'mkdocs.yml']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install mkdocs-material
- run: mkdocs build --site-dir wiki-build
- name: Deploy to Hetzner
run: rsync -avz -e "ssh -o StrictHostKeyChecking=no" wiki-build/ deploy@${{ secrets.HETZNER_IP }}:/srv/wiki/
DNS Records¶
wiki.graffold.com CNAME → graffold-wiki.pages.dev (CF Pages)
graphrag.graffold.com CNAME → graphrag-wiki.pages.dev (CF Pages)
api.graffold.com A → 89.167.10.208 (Hetzner VPS)
Wiki domains use Cloudflare Pages custom domains (CNAME to *.pages.dev).
The API domain points to Hetzner where the FastAPI container runs.
All get TLS automatically — CF Pages via their edge, Hetzner via Caddy + Let's Encrypt.