Resources & implementation
Everything needed to run Agentfy.ai 2.0. Hetzner-centric (cheap compute, co-located, EU/GDPR); AWS shrinks to optional S3 / KMS / SES — or zero. Cognito and Secrets Manager are not used. For when (if ever) any of this moves to AWS, see the Cloud strategy.
Which of this inventory is actually deployed
The list below is the plan. What runs today is declared in a second repository, Agentfy/gitops — Two repositories lists it file by file. The short version, and it changes four rows here:
api,app,adminand Redis run in the dev contour only. There is no prod equivalent ofagentfy-apps/dev/.- Postgres is not in the cluster. It runs on two dedicated Hetzner VMs configured by
ansible/roles/postgres; the api'sDATABASE_URLpoints at10.0.1.1:5432. No CloudNativePG anywhere. - LightRAG does not exist — no service, no chart, no Application.
- Object storage is settled in infrastructure and unused in code.
terraform/storage.tfcreates one private, versioned Hetzner Object Storage bucket per contour, and puts AWS S3 to work for Terraform state and backups only. This repository's only storage driver still writes to a local filesystem path, so nothing reads or writes those buckets yet.
One more correction, to Secrets & keys below: infra credentials — the KEK included — reach the cluster from HashiCorp Vault through the External Secrets Operator, not from a hand-written Kubernetes Secret. A Kubernetes Secret is still what the pod sees; it is produced, not authored.
Kubernetes (Hetzner)
A single k3s cluster (like Ranch) with three node pools — the control plane runs on its own node(s), separate from workloads. Full topology + autoscaling: Cluster & nodes.
| pool | runs | scaling |
|---|---|---|
control-plane (tainted, isolated) | k3s server: API server · etcd · scheduler · controller-manager | fixed: 1 (dev) / 3 (prod HA) |
core (always-on) | api, app, admin, LightRAG service, Postgres/Redis | HPA per app + cluster-autoscaler on the pool |
workers (tainted, node-role: workers) | ephemeral worker Jobs (+ heavy tasks) | scale-to-zero per task; cluster-autoscaler 0 → N under load |
Plus: Ingress (Traefik/nginx) + cert-manager (TLS), a container registry, GitOps CD (ArgoCD), cluster-autoscaler + HPA/VPA, per-tenant ResourceQuota/LimitRange, and NetworkPolicy (default deny-all egress; allowlist Core WS + required domains).
Deployables
| deployable | pool | lifecycle |
|---|---|---|
api | core | persistent (Core) and ephemeral brain (same image, run per-turn) |
app / admin | core | persistent (Nuxt) |
| LightRAG service (Python) | core | persistent; agent/knowledge is a thin gateway to it |
worker | workers | on-demand k8s Job per task; bundles Playwright + Chromium (launches a browser in-pod for browser tasks — no separate pool); ttlSecondsAfterFinished + idle reaper |
See Worker on Kubernetes for the Job lifecycle.
Datastores
| store | what it holds | host |
|---|---|---|
| Postgres (self-host) | app data · chat · usage/billing · encrypted secrets · vector (pgvector) · graph (AGE) for LightRAG | Hetzner |
| Redis | BullMQ queue · pub/sub (events) · locks · idle timers | Hetzner |
| Object storage | system/file (artifacts, avatars, docs, invoice PDFs, browser/workspace snapshots) | S3 / R2 / Hetzner OS (open) |
| (Neo4j + Qdrant/Milvus) | only if the large-scale LightRAG path is chosen instead of pgvector+AGE | Hetzner |
Postgres must be self-hosted because the unified LightRAG backend needs the pgvector + Apache AGE extensions (managed Neon blocks AGE). Postgres therefore carries app data and the agent's vector + graph — one store for small/medium scale.
Knowledge / LightRAG infra
- A separate Python service on the
corepool;agent/knowledgeproxies to it over MCP. - Storage backend by scale: many small bases → Postgres (pgvector + AGE); millions in one base → Neo4j + Qdrant/Milvus. Benchmark before committing.
- Ingestion is async/queued (BullMQ), incremental, token-budgeted — the LLM extraction is the cost wall, not storage. Per-knowledge-base workspaces isolate tenants.
See Knowledge — LightRAG.
Secrets & keys
- Agent secrets: encrypted in Postgres (app-layer envelope, AES-256-GCM, DEK wrapped by a KEK) — no Secrets Manager. See Agent secrets.
- KEK: a k8s Secret injected only into
api(MVP) → optional AWS KMS (wrap DEKs only) later. - Auth: own JWT (issuer = Core) — no Cognito. The same scheme mints short-lived runtime session tokens injected into the
workerJob (no long-lived creds in the pod).
Observability & ops
- Sentry (errors), Loki/Grafana (logs/metrics) self-hosted.
- Backups: Postgres (PITR) + object storage; audit log (
admin/audit) of runtime sessions. - HA: replicated
coredeployments; Postgres/Redis with replicas as the product grows.
External SaaS (neither Hetzner nor AWS)
- Claude API (Anthropic) — LLM (
system/llm). - Payment — PayPal (+ Stripe?).
- Email/SMTP — Resend (MVP) → AWS SES at scale; swappable behind
notification/email.
AWS footprint — what (if anything) stays
| AWS service | use | needed? |
|---|---|---|
| S3 | object storage for system/file | optional — vs Hetzner OS / R2 |
| KMS | wrap the secrets KEK | optional — vs KEK in a k8s Secret |
| SES | transactional email at scale | later — MVP starts on Resend (non-AWS) |
| — | dropped (own JWT) | |
| — | dropped (encrypted in Postgres) | |
| — | dropped (Claude API / BullMQ / Postgres) |
Net: Agentfy.ai 2.0 can run fully on Hetzner (+ Claude/payment/email as external SaaS); AWS is reduced to at most a few managed conveniences (S3/KMS/SES), each individually optional.
Recommended split
| Concern | Where |
|---|---|
| k8s (api/app/admin/worker/LightRAG) | Hetzner |
| Postgres (+ pgvector + AGE + encrypted secrets), Redis | Hetzner (self-host) |
| Object storage | Hetzner OS or AWS S3 / R2 (open) |
| Secrets KEK | k8s Secret (MVP) → KMS (open) |
| Resend (MVP) → AWS SES at scale | |
| LLM, payment | external |
See Open questions for what's still undecided (storage provider, vector/graph backend by scale, billing provider).