Self-Hosted Installation
Deploy DuraGraph in your own infrastructure for full control, data sovereignty, and cost optimization.
Architecture Overview
Section titled “Architecture Overview”DuraGraph uses a modern, event-driven architecture:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐│ Client │────▶│ API Server │────▶│ PostgreSQL ││ (SDK/CLI) │ │ (Echo) │ │ (Events) │└─────────────┘ └──────┬──────┘ └─────────────┘ │ ┌──────▼──────┐ │ NATS │ │ JetStream │ └─────────────┘Components:
- API Server - Go-based REST API with SSE streaming
- PostgreSQL - Event store, projections, and checkpoints
- NATS JetStream - Real-time event streaming and messaging
Quick Start (Docker Compose)
Section titled “Quick Start (Docker Compose)”The fastest way to get DuraGraph running:
# Clone the repositorygit clone https://github.com/duragraph/duragraph.gitcd duragraph
# Start all servicesdocker compose up -d
# Verify services are runningdocker compose ps
# Check healthcurl http://localhost:8081/healthThis starts:
- API Server (
:8081) - REST API and SSE streaming - PostgreSQL (
:5433) - Database for events and state - NATS (
:4223) - Message broker with JetStream - Dashboard (
:5173) - Web interface
Environment Configuration
Section titled “Environment Configuration”Required Variables
Section titled “Required Variables”Create a .env file or set environment variables:
# DatabaseDB_HOST=localhostDB_PORT=5432DB_USER=appuserDB_PASSWORD=apppassDB_NAME=appdbDB_SSLMODE=disable
# NATSNATS_URL=nats://localhost:4222
# ServerPORT=8080HOST=0.0.0.0
# Optional: AuthenticationAUTH_ENABLED=falseJWT_SECRET=your-256-bit-secret
# Optional: LLM ProvidersOPENAI_API_KEY=sk-...ANTHROPIC_API_KEY=sk-ant-...Configuration Reference
Section titled “Configuration Reference”| Variable | Description | Default |
|---|---|---|
DB_HOST | PostgreSQL host | localhost |
DB_PORT | PostgreSQL port | 5432 |
DB_USER | Database user | appuser |
DB_PASSWORD | Database password | apppass |
DB_NAME | Database name | appdb |
DB_SSLMODE | SSL mode (disable, require) | disable |
NATS_URL | NATS connection URL | nats://localhost:4222 |
PORT | API server port | 8080 |
HOST | API server host | 0.0.0.0 |
AUTH_ENABLED | Enable JWT authentication | false |
JWT_SECRET | JWT signing secret | - |
Production Deployment
Section titled “Production Deployment”Docker Compose (Recommended)
Section titled “Docker Compose (Recommended)”services: db: image: postgres:15 container_name: duragraph-postgres environment: POSTGRES_USER: ${DB_USER:-duragraph} POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_DB: ${DB_NAME:-duragraph} ports: - '5432:5432' volumes: - pgdata:/var/lib/postgresql/data - ./deploy/sql:/docker-entrypoint-initdb.d healthcheck: test: ['CMD-SHELL', 'pg_isready -U ${DB_USER:-duragraph}'] interval: 10s timeout: 5s retries: 5 restart: unless-stopped
nats: image: nats:2.10-alpine container_name: duragraph-nats command: '-js -sd /data -m 8222' ports: - '4222:4222' # Client connections - '8222:8222' # HTTP management/monitoring volumes: - natsdata:/data healthcheck: test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:8222/healthz'] interval: 10s timeout: 5s retries: 3 restart: unless-stopped
server: image: duragraph/server:latest container_name: duragraph-server ports: - '8080:8080' environment: - DB_HOST=db - DB_PORT=5432 - DB_USER=${DB_USER:-duragraph} - DB_PASSWORD=${DB_PASSWORD} - DB_NAME=${DB_NAME:-duragraph} - DB_SSLMODE=disable - NATS_URL=nats://nats:4222 - PORT=8080 - HOST=0.0.0.0 - AUTH_ENABLED=${AUTH_ENABLED:-true} - JWT_SECRET=${JWT_SECRET} depends_on: db: condition: service_healthy nats: condition: service_healthy restart: unless-stopped
volumes: pgdata: natsdata:Start production deployment:
# Set required secrets (replace with your actual values)export DB_PASSWORD="<YOUR_DB_PASSWORD>"export JWT_SECRET="<YOUR_JWT_SECRET>"
# Deploydocker compose -f docker-compose.prod.yml up -dKubernetes Deployment
Section titled “Kubernetes Deployment”Prerequisites
Section titled “Prerequisites”- Kubernetes 1.24+
- kubectl configured
- Helm 3.x (optional)
Using Manifests
Section titled “Using Manifests”apiVersion: v1kind: Namespacemetadata: name: duragraph
---# configmap.yamlapiVersion: v1kind: ConfigMapmetadata: name: duragraph-config namespace: duragraphdata: DB_HOST: 'postgres' DB_PORT: '5432' DB_NAME: 'duragraph' DB_SSLMODE: 'require' NATS_URL: 'nats://nats:4222' PORT: '8080' HOST: '0.0.0.0'
---# secret.yamlapiVersion: v1kind: Secretmetadata: name: duragraph-secrets namespace: duragraphtype: OpaquestringData: DB_USER: duragraph DB_PASSWORD: '<YOUR_DB_PASSWORD>' JWT_SECRET: '<YOUR_JWT_SECRET>'
---# deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata: name: duragraph-server namespace: duragraphspec: replicas: 3 selector: matchLabels: app: duragraph-server template: metadata: labels: app: duragraph-server spec: containers: - name: server image: duragraph/server:latest ports: - containerPort: 8080 envFrom: - configMapRef: name: duragraph-config - secretRef: name: duragraph-secrets resources: requests: cpu: 250m memory: 256Mi limits: cpu: 1000m memory: 1Gi livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 5 periodSeconds: 5
---# service.yamlapiVersion: v1kind: Servicemetadata: name: duragraph-server namespace: duragraphspec: selector: app: duragraph-server ports: - port: 8080 targetPort: 8080 type: ClusterIP
---# ingress.yamlapiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: duragraph-ingress namespace: duragraph annotations: nginx.ingress.kubernetes.io/proxy-read-timeout: '3600' nginx.ingress.kubernetes.io/proxy-send-timeout: '3600'spec: ingressClassName: nginx tls: - hosts: - duragraph.yourcompany.com secretName: duragraph-tls rules: - host: duragraph.yourcompany.com http: paths: - path: / pathType: Prefix backend: service: name: duragraph-server port: number: 8080Apply manifests:
kubectl apply -f namespace.yamlkubectl apply -f configmap.yamlkubectl apply -f secret.yamlkubectl apply -f deployment.yamlkubectl apply -f service.yamlkubectl apply -f ingress.yamlDatabase Setup
Section titled “Database Setup”Schema Migrations
Section titled “Schema Migrations”DuraGraph automatically runs migrations on startup. For manual setup:
# Run all migrationspsql $DATABASE_URL -f deploy/sql/001_init.sqlpsql $DATABASE_URL -f deploy/sql/002_event_store.sqlpsql $DATABASE_URL -f deploy/sql/003_outbox.sqlpsql $DATABASE_URL -f deploy/sql/004_projections.sqlExternal PostgreSQL
Section titled “External PostgreSQL”To use a managed PostgreSQL instance (RDS, Cloud SQL, etc.):
# Set connection stringexport DATABASE_URL="postgresql://user:pass@your-db-host:5432/duragraph?sslmode=require"
# Or individual variablesexport DB_HOST=your-db-hostexport DB_PORT=5432export DB_USER=duragraphexport DB_PASSWORD=your-passwordexport DB_NAME=duragraphexport DB_SSLMODE=requireNATS Configuration
Section titled “NATS Configuration”JetStream Setup
Section titled “JetStream Setup”DuraGraph requires NATS JetStream for event streaming:
# Standalone NATS with JetStreamdocker run -d --name nats \ -p 4222:4222 \ -p 8222:8222 \ -v natsdata:/data \ nats:2.10-alpine -js -sd /data -m 8222NATS Cluster (Production)
Section titled “NATS Cluster (Production)”For high availability, deploy a NATS cluster:
apiVersion: apps/v1kind: StatefulSetmetadata: name: nats namespace: duragraphspec: serviceName: nats replicas: 3 selector: matchLabels: app: nats template: metadata: labels: app: nats spec: containers: - name: nats image: nats:2.10-alpine args: - '-js' - '-sd' - '/data' - '-m' - '8222' - '--cluster_name' - 'duragraph-nats' - '--cluster' - 'nats://0.0.0.0:6222' - '--routes' - 'nats://nats-0.nats:6222,nats://nats-1.nats:6222,nats://nats-2.nats:6222' ports: - containerPort: 4222 name: client - containerPort: 6222 name: cluster - containerPort: 8222 name: monitor volumeMounts: - name: data mountPath: /data volumeClaimTemplates: - metadata: name: data spec: accessModes: ['ReadWriteOnce'] resources: requests: storage: 10GiMonitoring NATS
Section titled “Monitoring NATS”Access NATS monitoring:
# Health checkcurl http://localhost:8222/healthz
# Server infocurl http://localhost:8222/varz
# JetStream infocurl http://localhost:8222/jsz
# Connectionscurl http://localhost:8222/connzMonitoring
Section titled “Monitoring”Prometheus Metrics
Section titled “Prometheus Metrics”DuraGraph exposes Prometheus metrics at /metrics:
curl http://localhost:8081/metricsAdd to prometheus.yml:
scrape_configs: - job_name: 'duragraph' static_configs: - targets: ['duragraph-server:8080'] metrics_path: /metrics scrape_interval: 15sKey Metrics
Section titled “Key Metrics”| Metric | Description |
|---|---|
duragraph_runs_total | Total runs created |
duragraph_runs_active | Currently running runs |
duragraph_http_requests_total | HTTP requests by endpoint |
duragraph_http_request_duration_seconds | Request latency histogram |
Health Checks
Section titled “Health Checks”# API healthcurl http://localhost:8081/health
# Simple liveness checkcurl http://localhost:8081/ok
# Server infocurl http://localhost:8081/infoLogging
Section titled “Logging”Configure structured logging:
# JSON logs for productionexport LOG_FORMAT=jsonexport LOG_LEVEL=info
# View logsdocker compose logs -f serverScaling
Section titled “Scaling”Horizontal Scaling
Section titled “Horizontal Scaling”Scale API servers behind a load balancer:
# Docker Composedocker compose up --scale server=3
# Kuberneteskubectl scale deployment duragraph-server --replicas=5 -n duragraphResource Guidelines
Section titled “Resource Guidelines”| Component | CPU | Memory | Storage |
|---|---|---|---|
| API Server | 0.5-2 cores | 512MB-2GB | - |
| PostgreSQL | 2-4 cores | 4-8GB | 50-500GB |
| NATS | 0.5-1 core | 256MB-1GB | 10-50GB |
Security
Section titled “Security”SSL/TLS with Nginx
Section titled “SSL/TLS with Nginx”server { listen 443 ssl http2; server_name duragraph.yourcompany.com;
ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; ssl_protocols TLSv1.2 TLSv1.3;
location / { proxy_pass http://localhost:8081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
# SSE support proxy_buffering off; proxy_cache off; proxy_set_header Connection ''; proxy_http_version 1.1; chunked_transfer_encoding off; proxy_read_timeout 3600s; }}Authentication
Section titled “Authentication”Enable JWT authentication:
export AUTH_ENABLED=trueexport JWT_SECRET="your-256-bit-secret-key"Generate tokens:
# Using jwt-cli or similarjwt encode --secret "$JWT_SECRET" '{"sub": "user-id", "exp": 1735689600}'Backup and Recovery
Section titled “Backup and Recovery”Database Backups
Section titled “Database Backups”# Backupdocker exec duragraph-postgres pg_dump -U appuser appdb > backup.sql
# Restoredocker exec -i duragraph-postgres psql -U appuser appdb < backup.sqlAutomated Backups (Kubernetes)
Section titled “Automated Backups (Kubernetes)”apiVersion: batch/v1kind: CronJobmetadata: name: postgres-backup namespace: duragraphspec: schedule: '0 2 * * *' # Daily at 2 AM jobTemplate: spec: template: spec: containers: - name: backup image: postgres:15 command: - /bin/sh - -c - pg_dump -h postgres -U $DB_USER $DB_NAME | gzip > /backups/backup-$(date +%Y%m%d).sql.gz envFrom: - secretRef: name: duragraph-secrets volumeMounts: - name: backups mountPath: /backups volumes: - name: backups persistentVolumeClaim: claimName: backup-pvc restartPolicy: OnFailureTroubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”Services won’t start:
# Check logsdocker compose logs serverdocker compose logs dbdocker compose logs nats
# Verify database connectiondocker exec duragraph-server ping dbDatabase connection errors:
# Test connectionpsql -h localhost -p 5433 -U appuser -d appdb
# Check if migrations ranpsql -h localhost -p 5433 -U appuser -d appdb -c "\dt"NATS connection issues:
# Check NATS statuscurl http://localhost:8223/healthz
# View NATS logsdocker compose logs natsHigh latency:
# Check resource usagedocker stats
# Check database performancedocker exec duragraph-postgres pg_stat_activityPerformance Tuning
Section titled “Performance Tuning”services: server: environment: - GOMAXPROCS=4 deploy: resources: limits: cpus: '2.0' memory: 2GNext Steps
Section titled “Next Steps”- Configure monitoring
- Set up SSL certificates
- Enable authentication
- Configure backups
- Migrate from LangGraph Cloud
Need help? Open an issue or check discussions.