OpenViking Server Deployment: My Journey from Local Dev to Production
Purpose
This post shows how to deploy OpenViking server in production using Docker, Docker Compose, and Kubernetes.
The Problem
After building my AI agent with OpenViking SDK locally, I needed to deploy it as a service. My agent needed to share context across multiple sessions and users, but running everything locally wouldn’t work for production.
I tried running OpenViking locally first:
pip install openvikingopenviking-server --config ./ov.confThis worked for development, but when I tried to deploy to my server, I hit several issues:
Issue 1: No authentication - anyone could access the APIIssue 2: Data lost on restart - no persistent storageIssue 3: Hard to scale - running on bare metalIssue 4: No monitoring - couldn't see server healthI needed a proper production deployment strategy.
Deployment Options
OpenViking provides three deployment paths:
- Direct installation - Good for testing, bad for production
- Docker/Docker Compose - Good for single-server production
- Kubernetes (Helm) - Good for distributed, scalable deployments
Let me show you what worked for each.
Option 1: Docker Deployment
I started with Docker since it’s the simplest containerized approach.
Building the Image
First, I checked the Dockerfile:
FROM python:3.11-slim
WORKDIR /app
# Install dependenciesCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt
# Copy applicationCOPY . .
# Expose portEXPOSE 1933
# Run serverCMD ["openviking-server", "--config", "/data/ov.conf"]I built the image:
docker build -t openviking:latest .Running the Container
My first attempt failed:
docker run -d -p 1933:1933 openviking:latest
# Error: Config file not found at /data/ov.confI realized I needed to mount my config file. I created a config directory:
mkdir -p ./openviking-dataThen created the config file:
{ "storage": { "workspace": "/data/openviking" }, "log": { "level": "INFO", "output": "stdout" }, "embedding": { "dense": { "api_base": "https://api.openai.com/v1", "api_key": "${OPENAI_API_KEY}", "provider": "openai", "model": "text-embedding-3-large", "dimension": 3072 } }, "vlm": { "api_base": "https://api.openai.com/v1", "api_key": "${OPENAI_API_KEY}", "provider": "openai", "model": "gpt-4o" }}Now I ran with volume mounts:
docker run -d \ --name openviking \ -p 1933:1933 \ -v ./openviking-data:/data \ -e OPENVIKING_CONFIG_FILE=/data/ov.conf \ -e OPENAI_API_KEY=sk-your-key-here \ openviking:latestI verified it was running:
curl http://localhost:1933/health# {"status": "ok"}But I still had a problem: no authentication.
Adding Authentication
I added authentication to my config:
{ "storage": { "workspace": "/data/openviking" }, "log": { "level": "INFO", "output": "stdout" }, "auth": { "enabled": true, "api_keys": ["my-secret-api-key-12345"] }, "embedding": { "dense": { "api_base": "https://api.openai.com/v1", "api_key": "${OPENAI_API_KEY}", "provider": "openai", "model": "text-embedding-3-large", "dimension": 3072 } }, "vlm": { "api_base": "https://api.openai.com/v1", "api_key": "${OPENAI_API_KEY}", "provider": "openai", "model": "gpt-4o" }}Now clients need to include the API key:
# Without API key - failscurl http://localhost:1933/v1/resources# {"error": "Unauthorized"}
# With API key - workscurl -H "X-API-Key: my-secret-api-key-12345" \ http://localhost:1933/v1/resources# {"resources": []}Option 2: Docker Compose
For a more complete setup, I used Docker Compose. This is what I recommend for single-server production.
I created a docker-compose.yml:
services: openviking: build: . ports: - "1933:1933" volumes: - ./openviking-data:/data environment: - OPENVIKING_CONFIG_FILE=/data/ov.conf - OPENAI_API_KEY=${OPENAI_API_KEY} restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:1933/health"] interval: 30s timeout: 10s retries: 3I started the service:
docker-compose up -dI could now check the health:
docker-compose ps# NAME COMMAND STATUS# openviking "openviking-server..." Up 2 minutes (healthy)Option 3: Kubernetes with Helm
For scalable production deployments, I used Kubernetes with Helm.
The Helm Chart Structure
OpenViking provides a Helm chart in examples/k8s-helm/:
examples/k8s-helm/├── Chart.yaml├── values.yaml├── templates/│ ├── deployment.yaml│ ├── service.yaml│ ├── secret.yaml│ └── configmap.yamlInstalling the Chart
I set up the values:
replicaCount: 2
image: repository: openviking tag: latest pullPolicy: IfNotPresent
service: type: ClusterIP port: 1933
config: vlm: apiKey: "" # Set via --set embedding: apiKey: "" # Set via --set
auth: enabled: true apiKeys: - "production-api-key-xxxxx"
persistence: enabled: true size: 10Gi storageClass: standardI installed the chart:
helm install openviking ./examples/k8s-helm \ --set config.vlm.apiKey=$OPENAI_API_KEY \ --set config.embedding.apiKey=$OPENAI_API_KEY \ --namespace openviking --create-namespaceI verified the deployment:
kubectl get pods -n openviking# NAME READY STATUS# openviking-6d4f8b9c4-x2k7m 1/1 Running# openviking-6d4f8b9c4-8p3n1 1/1 RunningPersistent Storage
For Kubernetes, I needed to configure persistent storage. OpenViking stores data in the workspace directory, so I needed a PersistentVolumeClaim:
apiVersion: v1kind: PersistentVolumeClaimmetadata: name: openviking-pvc namespace: openvikingspec: accessModes: - ReadWriteOnce resources: requests: storage: 50Gi storageClassName: standardThe Helm chart handles this automatically when persistence.enabled: true.
Configuration Details
Let me explain the key configuration options I learned.
Environment Variables
OpenViking accepts configuration via environment variables:
export OPENVIKING_CONFIG_FILE=/path/to/ov.confexport OPENAI_API_KEY=sk-xxxexport OPENVIKING_LOG_LEVEL=DEBUGStorage Configuration
The storage section controls where data is persisted:
{ "storage": { "workspace": "/data/openviking", "vector_db": { "type": "pgvector", "connection_string": "postgresql://user:pass@localhost:5432/openviking" } }}Embedding Configuration
For embeddings, I tested multiple providers:
{ "embedding": { "dense": { "api_base": "https://api.openai.com/v1", "api_key": "${OPENAI_API_KEY}", "provider": "openai", "model": "text-embedding-3-large", "dimension": 3072 }, "sparse": { "provider": "bm25", "enabled": true } }}VLM Configuration
The Vision Language Model (VLM) is used for document understanding:
{ "vlm": { "api_base": "https://api.openai.com/v1", "api_key": "${OPENAI_API_KEY}", "provider": "openai", "model": "gpt-4o" }}Health Checks and Monitoring
OpenViking provides a health endpoint:
curl http://localhost:1933/health# {"status": "ok"}For more detailed status:
# Using the CLIov status
# Output:# Server: http://localhost:1933# Status: healthy# Version: 0.5.0# Resources: 42 indexed# Sessions: 3 activePrometheus Metrics
OpenViking exposes Prometheus metrics at /metrics:
curl http://localhost:1933/metrics# HELP openviking_requests_total Total number of requests# TYPE openviking_requests_total counter# openviking_requests_total{method="GET",endpoint="/v1/resources"} 1523# openviking_requests_total{method="POST",endpoint="/v1/search"} 892Security Best Practices
I learned these security practices the hard way.
1. Never Hardcode API Keys
Wrong:
{ "embedding": { "dense": { "api_key": "sk-hardcoded-key-bad-idea" } }}Right:
{ "embedding": { "dense": { "api_key": "${OPENAI_API_KEY}" } }}Then set the environment variable:
export OPENAI_API_KEY=sk-your-actual-key2. Use a Reverse Proxy
I put OpenViking behind nginx:
server { listen 443 ssl; server_name openviking.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / { proxy_pass http://localhost:1933; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }}3. Rotate API Keys
I rotate my API keys periodically:
{ "auth": { "enabled": true, "api_keys": [ "new-key-abc123", "old-key-xyz789" # Keep old key during transition ] }}Troubleshooting
Here are issues I encountered and how I fixed them.
Server Won’t Start
Error: Config file not found at /data/ov.confFix: Ensure the config file exists and is mounted correctly:
docker exec openviking ls -la /data/# Should show ov.confConnection Refused
curl: (7) Failed to connect to localhost port 1933: Connection refusedFix: Check if the port is exposed:
docker port openviking# 1933/tcp -> 0.0.0.0:1933Authentication Errors
{"error": "Unauthorized"}Fix: Verify the API key header:
# Check header name - must be exactly X-API-Keycurl -H "X-API-Key: your-key" http://localhost:1933/v1/resourcesStorage Permission Errors
PermissionError: [Errno 13] Permission denied: '/data/openviking'Fix: Ensure the container user has write permissions:
chmod -R 777 ./openviking-dataCloud Deployment Example
I deployed OpenViking on AWS EC2. Here’s what I did:
Step 1: Launch EC2 Instance
# Using AWS CLIaws ec2 run-instances \ --image-id ami-0c55b159cbfafe1f0 \ --instance-type t3.medium \ --key-name my-key \ --security-group-ids sg-xxxxxStep 2: Install Docker
# SSH into instance
# Install Dockersudo yum update -ysudo yum install -y dockersudo service docker startsudo usermod -a -G docker ec2-userStep 3: Run OpenViking
# Create data directorymkdir -p ~/openviking-data
# Create configcat > ~/openviking-data/ov.conf << 'EOF'{ "storage": { "workspace": "/data/openviking" }, "auth": { "enabled": true, "api_keys": ["prod-api-key-secure"] }, "embedding": { "dense": { "api_base": "https://api.openai.com/v1", "api_key": "${OPENAI_API_KEY}", "provider": "openai", "model": "text-embedding-3-large", "dimension": 3072 } }}EOF
# Run containerdocker run -d \ --name openviking \ -p 1933:1933 \ -v ~/openviking-data:/data \ -e OPENVIKING_CONFIG_FILE=/data/ov.conf \ -e OPENAI_API_KEY=$OPENAI_API_KEY \ --restart unless-stopped \ openviking:latestStep 4: Set Up Load Balancer
I used AWS Application Load Balancer with HTTPS:
Target Group: openviking-tg Protocol: HTTP Port: 1933 Health Check: /health
Listener: HTTPS:443 Forward to: openviking-tg SSL Certificate: my-certSummary
In this post, I showed how to deploy OpenViking server from local development to production. The key point is that OpenViking supports multiple deployment paths with proper authentication and persistent storage.
For single-server production, I recommend Docker Compose with mounted volumes and API key authentication. For scalable deployments, Kubernetes with Helm charts provides the best flexibility.
The main things I learned:
- Always mount config files and data directories as volumes
- Enable authentication before exposing the API
- Use environment variables for secrets, never hardcode
- Put OpenViking behind a reverse proxy with TLS
- Monitor health endpoint and Prometheus metrics
With these practices, OpenViking runs reliably in production for my AI agent applications.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments