Skip to content

Self-Hosting Guide ​

DocIntel is a self-hosted product — your documents never leave your infrastructure. This guide covers deployment options.

Single command ​

bash
docker run -d \
  --name purple8-docintel \
  -p 8200:8200 \
  -e LLM__API_KEY=sk-... \
  -e SERVER__API_KEY=change-me-min-32-chars \
  -e LICENSE__KEY=your-license-key \
  purple8/docintel:latest

The API is live at http://localhost:8200. Interactive docs at http://localhost:8200/docs.

Docker Compose — standalone ​

yaml
# docker-compose.yml
version: '3.9'
services:
  docintel:
    image: purple8/docintel:latest
    ports:
      - "8200:8200"
    environment:
      LLM__API_KEY: "${LLM__API_KEY}"
      SERVER__API_KEY: "${SERVER__API_KEY}"
      LICENSE__KEY: "${LICENSE__KEY}"
    volumes:
      - docintel-data:/data
    restart: unless-stopped

volumes:
  docintel-data:
bash
docker compose up -d

Docker Compose — with Redis (multi-worker) ​

yaml
# docker-compose.production.yml
version: '3.9'
services:
  docintel:
    image: purple8/docintel:latest
    ports:
      - "8200:8200"
    environment:
      LLM__API_KEY: "${LLM__API_KEY}"
      SERVER__API_KEY: "${SERVER__API_KEY}"
      LICENSE__KEY: "${LICENSE__KEY}"
      STORAGE__JOB_STORE: "redis"
      STORAGE__REDIS_URL: "redis://redis:6379/0"
      SERVER__WORKERS: "3"
    depends_on:
      - redis
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data
    restart: unless-stopped

volumes:
  redis-data:

Kubernetes ​

Helm chart (coming soon) ​

A Helm chart for Kubernetes deployment is on the roadmap. In the meantime, use the Docker image with a Kubernetes Deployment:

yaml
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: docintel
  labels:
    app: docintel
spec:
  replicas: 3
  selector:
    matchLabels:
      app: docintel
  template:
    metadata:
      labels:
        app: docintel
    spec:
      containers:
        - name: docintel
          image: purple8/docintel:latest
          ports:
            - containerPort: 8200
          env:
            - name: LLM__API_KEY
              valueFrom:
                secretKeyRef:
                  name: docintel-secrets
                  key: llm-api-key
            - name: SERVER__API_KEY
              valueFrom:
                secretKeyRef:
                  name: docintel-secrets
                  key: api-secret-key
            - name: LICENSE__KEY
              valueFrom:
                secretKeyRef:
                  name: docintel-secrets
                  key: license-key
            - name: STORAGE__JOB_STORE
              value: redis
            - name: STORAGE__REDIS_URL
              value: redis://redis-svc:6379/0
          resources:
            requests:
              memory: "512Mi"
              cpu: "500m"
            limits:
              memory: "2Gi"
              cpu: "2000m"
          livenessProbe:
            httpGet:
              path: /health
              port: 8200
            initialDelaySeconds: 10
            periodSeconds: 30
          readinessProbe:
            httpGet:
              path: /health
              port: 8200
            initialDelaySeconds: 5
            periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: docintel-svc
spec:
  selector:
    app: docintel
  ports:
    - port: 8200
      targetPort: 8200
  type: ClusterIP

Air-gapped deployment ​

For environments with no internet access (Enterprise plan):

  1. Pre-pull images on a connected machine:

    bash
    docker pull purple8/docintel:latest
    docker save purple8/docintel:latest | gzip > docintel.tar.gz
  2. Transfer docintel.tar.gz to the air-gapped environment

  3. Load and run:

    bash
    docker load < docintel.tar.gz
    docker compose up -d
  4. Use Ollama for LLM (no external API calls):

    bash
    LLM__PROVIDER=ollama
    LLM__BASE_URL=http://ollama:11434
    LLM__MODEL=llama3.1:70b

Output modes ​

JSON API (default) ​

Poll or stream results from the REST API:

bash
# Submit
curl -X POST http://localhost:8200/process \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@invoice.pdf"

# Poll result
curl http://localhost:8200/jobs/{job_id} \
  -H "Authorization: Bearer $API_KEY"

Response:

json
{
  "job_id": "abc-123",
  "status": "completed",
  "entities": [...],
  "relationships": [...],
  "metadata": {...}
}

Webhook delivery (Pro+) ​

Configure webhook delivery via the Purple8 Graph connector. When Graph emission is enabled, you can set up downstream webhooks inside Purple8 Graph to forward extraction results to any endpoint.

Purple8 Graph emission ​

Emit extracted entities and relationships directly into Purple8 Graph for knowledge graph storage, Cypher queries, embeddings, and hybrid search.

Standalone DocIntel — if you omit GRAPH__BASE_URL, DocIntel returns JSON only. No Graph required.

DocIntel + Graph — set GRAPH__BASE_URL and DocIntel will POST /ingest/commit to Graph on every completed extraction.

Docker Compose (DocIntel + Graph) ​

yaml
version: "3.9"
services:
  docintel:
    image: purple8/docintel:latest
    ports:
      - "8200:8200"
    environment:
      LLM__API_KEY: "${LLM__API_KEY}"
      SERVER__API_KEY: "${SERVER__API_KEY}"
      LICENSE__KEY: "${LICENSE__KEY}"
      GRAPH__BASE_URL: "http://graph:8100"
    depends_on:
      - graph
    restart: unless-stopped

  graph:
    image: purple8/graph:latest
    ports:
      - "8100:8100"
    environment:
      PORT: "8100"
    restart: unless-stopped
VariableDefaultDescription
GRAPH__BASE_URLhttp://localhost:8100Purple8 Graph API URL. Omit to disable emission.
GRAPH__API_KEY(empty)Graph API authentication key
GRAPH__TENANT_ID(none)Multi-tenant tenant ID
GRAPH__AUTO_COMMITtrueAuto-commit extracted data to Graph on completion
GRAPH__TIMEOUT_S30Connection timeout (seconds)

Verify end-to-end ​

bash
# 1. Check both services
curl http://localhost:8200/health   # DocIntel
curl http://localhost:8100/health   # Graph

# 2. Process a document — results are emitted to Graph automatically
curl -X POST http://localhost:8200/process \
  -H "Authorization: Bearer $SERVER__API_KEY" \
  -F "file=@contract.pdf"

# 3. Query Graph for the extracted entities
curl http://localhost:8100/api/entities \
  -H "Authorization: Bearer $GRAPH_API_KEY"

Resource requirements ​

DeploymentCPUMemoryStorageDocuments/min
Minimal (1 worker)1 vCPU512 MB1 GB~5
Recommended (3 workers)4 vCPU2 GB10 GB~15
Production (5+ workers)8+ vCPU4+ GB50+ GB~30+

TIP

Document processing speed is primarily bottlenecked by LLM API latency, not DocIntel compute. More workers help with concurrency, not per-document speed.

Monitoring ​

EndpointDescription
GET /healthReturns {"status": "ok"} — use for liveness probes
GET /metricsPrometheus-format metrics — jobs processed, latency histograms, error rates

Prometheus scrape config ​

yaml
scrape_configs:
  - job_name: docintel
    static_configs:
      - targets: ['docintel:8200']
    metrics_path: /metrics
    scrape_interval: 15s

Security hardening ​

DocIntel runs as a non-root user inside the container and includes these security measures:

  • SSRF guard — blocks RFC 1918, loopback, link-local, and cloud metadata endpoints
  • Bearer token auth — all endpoints require Authorization: Bearer <token>
  • Non-root container — runs as uid=1000
  • Read-only filesystem — mount /tmp and /data as the only writable paths
  • No ambient capabilities — drop all Linux capabilities

Systemd hardening (bare metal) ​

ini
[Service]
User=docintel
Group=docintel
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/docintel

Purple8 DocIntel v0.12.5 · Universal Document Intelligence · NVIDIA Inception Member · Red Hat Technology Partner.