Self-Host
Deploy Ask0 on your own infrastructure for complete control and privacy. Self-hosting guide with Docker, Kubernetes, and cloud options.
Deploy Ask0 on your own infrastructure to maintain complete control over your data, customize the platform, and meet specific compliance requirements.
Why Self-Host?
Benefits
- Complete Data Control: Your data never leaves your infrastructure
- Customization: Modify code, add features, integrate with internal systems
- Compliance: Meet strict regulatory requirements (HIPAA, GDPR, SOC2)
- Cost Predictability: No usage-based pricing, fixed infrastructure costs
- Performance: Optimize for your specific use case
- Air-gapped Deployment: Run in completely isolated environments
Considerations
- Requires infrastructure management
- Responsible for updates and maintenance
- Need to handle scaling and monitoring
- Security is your responsibility
Architecture Overview
Ask0 consists of three main components:
Components:
1. Next.js Application:
- Admin console
- API server
- Widget server
2. Crawler Service:
- Web scraping
- Content processing
- Scheduled updates
3. PostgreSQL Database:
- Data storage
- Vector search (pgvector)
- Session managementQuick Start with Docker
Clone the Repository
git clone https://github.com/ask0/ask0.git
cd ask0Configure Environment
Create .env file:
DATABASE_URL=postgresql://ask0:password@postgres:5432/ask0
REDIS_URL=redis://redis:6379
NEXTAUTH_URL=https://your-domain.com
NEXTAUTH_SECRET=generate-random-secret-here
OPENAI_API_KEY=your-openai-key
ANTHROPIC_API_KEY=your-anthropic-key
OLLAMA_URL=http://ollama:11434
STORAGE_TYPE=local # or s3
S3_BUCKET=ask0-assets
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=your-key
S3_SECRET_ACCESS_KEY=your-secret
ENCRYPTION_KEY=generate-32-byte-key
JWT_SECRET=generate-jwt-secretStart with Docker Compose
docker-compose up -dThis starts:
- PostgreSQL with pgvector extension
- Redis for caching
- Ask0 application
- Crawler service
- Nginx reverse proxy
Access the Application
Open http://localhost:3000 and complete initial setup:
- Create admin account
- Configure organization
- Add your first project
- Start adding sources
Production Deployment
Kubernetes Deployment
helm repo add ask0 https://charts.ask0.ai
helm repo update
helm install ask0 ask0/ask0 \
--namespace ask0 \
--create-namespace \
--values values.yamlExample values.yaml:
replicaCount:
app: 3
crawler: 2
postgresql:
enabled: true
auth:
postgresPassword: secure-password
database: ask0
redis:
enabled: true
auth:
enabled: true
password: redis-password
ingress:
enabled: true
className: nginx
hosts:
- host: ask0.company.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: ask0-tls
hosts:
- ask0.company.com
resources:
app:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "2000m"Deploy components individually:
apiVersion: v1
kind: Namespace
metadata:
name: ask0
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgresql
namespace: ask0
spec:
serviceName: postgresql
replicas: 1
selector:
matchLabels:
app: postgresql
template:
metadata:
labels:
app: postgresql
spec:
containers:
- name: postgresql
image: pgvector/pgvector:pg16
env:
- name: POSTGRES_DB
value: ask0
- name: POSTGRES_USER
value: ask0
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: postgres-storage
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 50Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ask0-app
namespace: ask0
spec:
replicas: 3
selector:
matchLabels:
app: ask0-app
template:
metadata:
labels:
app: ask0-app
spec:
containers:
- name: app
image: ask0/ask0:latest
ports:
- containerPort: 3000
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: ask0-secrets
key: database-url
livenessProbe:
httpGet:
path: /api/health
port: 3000
initialDelaySeconds: 30
readinessProbe:
httpGet:
path: /api/ready
port: 3000
initialDelaySeconds: 10Use operators for automated management:
apiVersion: ask0.ai/v1
kind: Ask0Cluster
metadata:
name: production
namespace: ask0
spec:
version: v1.0.0
replicas:
app: 3
crawler: 2
database:
type: postgresql
size: 100Gi
backup:
enabled: true
schedule: "0 2 * * *"
monitoring:
enabled: true
prometheus: true
grafana: true
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPU: 70Database Setup
PostgreSQL with pgvector
-- Install pgvector extension
CREATE EXTENSION IF NOT EXISTS vector;
-- Create database
CREATE DATABASE ask0;
-- Connect to ask0 database
\c ask0;
-- Run migrations
-- These are automatically applied on first startHigh Availability Setup
PostgreSQL HA:
Primary: postgres-primary.local
Replicas:
- postgres-replica-1.local
- postgres-replica-2.local
Backup:
Type: WAL-G
Storage: S3
Schedule: "0 */6 * * *"
Monitoring:
- PostgreSQL Exporter
- PgBouncer for connection poolingStorage Configuration
STORAGE_TYPE=local
STORAGE_PATH=/var/lib/ask0/storageEnsure sufficient disk space and backup strategy.
STORAGE_TYPE=s3
S3_ENDPOINT=https://s3.amazonaws.com
S3_BUCKET=ask0-storage
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-keyWorks with AWS S3, MinIO, Wasabi, etc.
STORAGE_TYPE=azure
AZURE_STORAGE_ACCOUNT=ask0storage
AZURE_STORAGE_KEY=your-storage-key
AZURE_CONTAINER=ask0STORAGE_TYPE=gcs
GCS_PROJECT_ID=your-project
GCS_BUCKET=ask0-storage
GCS_KEY_FILE=/path/to/service-account.jsonAI Model Configuration
Bring Your Own Model
AI_PROVIDER=openai
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4-turbo-preview
OPENAI_EMBEDDING_MODEL=text-embedding-3-largeAI_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
ANTHROPIC_MODEL=claude-3-opusAI_PROVIDER=ollama
OLLAMA_URL=http://ollama:11434
OLLAMA_MODEL=llama2:70b
OLLAMA_EMBEDDING_MODEL=all-minilmRun Ollama:
docker run -d -v ollama:/root/.ollama -p 11434:11434 ollama/ollama
docker exec -it ollama ollama pull llama2:70bAI_PROVIDER=azure
AZURE_OPENAI_ENDPOINT=https://your-instance.openai.azure.com
AZURE_OPENAI_KEY=your-key
AZURE_OPENAI_DEPLOYMENT=gpt-4
AZURE_OPENAI_API_VERSION=2024-02-15-previewImplement custom provider:
// providers/custom.js
export class CustomAIProvider {
async complete(prompt, options) {
// Your implementation
}
async embed(text) {
// Your implementation
}
}Security Hardening
Network Security
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ask0-network-policy
spec:
podSelector:
matchLabels:
app: ask0
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: nginx
ports:
- protocol: TCP
port: 3000
egress:
- to:
- podSelector:
matchLabels:
app: postgresql
ports:
- protocol: TCP
port: 5432Authentication & SSO
Configure SSO providers:
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-secret
SAML_ENTRY_POINT=https://idp.company.com/sso
SAML_ISSUER=ask0
SAML_CERT=base64-encoded-cert
LDAP_URL=ldap://ldap.company.com
LDAP_BIND_DN=cn=admin,dc=company,dc=com
LDAP_BIND_PASSWORD=password
LDAP_SEARCH_BASE=dc=company,dc=comEncryption
ENCRYPTION_AT_REST=true
ENCRYPTION_KEY=32-byte-key-here
TLS_CERT=/path/to/cert.pem
TLS_KEY=/path/to/key.pem
TLS_MIN_VERSION=1.2
POSTGRES_SSL_MODE=require
POSTGRES_SSL_CERT=/path/to/client-cert.pemMonitoring & Observability
Metrics with Prometheus
scrape_configs:
- job_name: 'ask0-app'
static_configs:
- targets: ['ask0-app:9090']
- job_name: 'postgresql'
static_configs:
- targets: ['postgres-exporter:9187']Logging with ELK Stack
filebeat.inputs:
- type: container
paths:
- /var/lib/docker/containers/*/*.log
processors:
- add_kubernetes_metadata:
host: ${NODE_NAME}
matchers:
- logs_path:
logs_path: "/var/lib/docker/containers/"
output.elasticsearch:
hosts: ["elasticsearch:9200"]
index: "ask0-%{+yyyy.MM.dd}"Tracing with OpenTelemetry
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
OTEL_SERVICE_NAME=ask0
OTEL_TRACES_ENABLED=true
OTEL_METRICS_ENABLED=trueBackup & Recovery
Automated Backups
apiVersion: batch/v1
kind: CronJob
metadata:
name: ask0-backup
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: ask0/backup:latest
command:
- /bin/bash
- -c
- |
pg_dump $DATABASE_URL > backup.sql
aws s3 cp backup.sql s3://backups/$(date +%Y%m%d).sqlDisaster Recovery
psql $DATABASE_URL < backup.sql
aws s3 sync s3://backups/files /var/lib/ask0/storageScaling Considerations
Horizontal Scaling
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ask0-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ask0-app
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80Performance Tuning
NODE_OPTIONS="--max-old-space-size=4096"
WORKERS=4
POSTGRES_MAX_CONNECTIONS=200
POSTGRES_SHARED_BUFFERS=2GB
POSTGRES_EFFECTIVE_CACHE_SIZE=6GB
REDIS_MAXMEMORY=2gb
REDIS_MAXMEMORY_POLICY=allkeys-lruMaintenance
Updates
docker pull ask0/ask0:latest
kubectl set image deployment/ask0-app app=ask0/ask0:v1.2.0 -n ask0
kubectl rollout undo deployment/ask0-app -n ask0Health Checks
Endpoints:
- /api/health - Overall health
- /api/ready - Readiness check
- /api/metrics - Prometheus metrics
- /api/status - Detailed statusImportant: Always test updates in a staging environment before applying to production. Maintain regular backups and have a rollback plan ready.
Support for Self-Hosted
Community Support
- GitHub Issues
- Discord Community
- Community Forums
Enterprise Support
- Priority support tickets
- Installation assistance
- Custom development
- SLA agreements