Search anything...
K
Back to Docs
  • Introduction
  • Quick Start
  • Account Setup
  • AI Studio
  • Chat
  • Agents
  • Voice
  • MCP Servers
  • Workflows
  • Authentication
  • Studio API
  • Chat API
  • Agents API
  • Voice API
  • Workflows API
  • Webhooks
  • Error Codes
  • Creating Custom Agents
  • MCP Integration
  • Building Workflows
  • Prompt Engineering
  • Team Management
  • Billing & Plans
  • Usage Monitoring
  • Single-Tenant Cloud
  • Private VPC Deployment
  • SSO Configuration
  • Security Policies
  • Compliance
  • Troubleshooting
  • API Versioning
DocsEnterprisePrivate VPC Deployment

Private VPC Deployment

Deploy within your own VPC

This guide covers deploying Girard AI within a customer's own Virtual Private Cloud (VPC) for maximum control and security.


Overview

Private VPC deployment provides:

  • Full network control - Deploy within your existing VPC
  • No internet exposure - Application accessible only via private network
  • Custom security policies - Integrate with existing firewalls and security tools
  • Data sovereignty - All data remains within your infrastructure
  • Compliance - Meet strict regulatory requirements (FedRAMP, ITAR, etc.)

Architecture

┌─────────────────────────────────────────────────────────────────────────────┐
│                         Customer VPC (10.0.0.0/16)                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                     Private Subnet (10.0.1.0/24)                     │    │
│  │                                                                      │    │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │    │
│  │  │  Girard AI    │  │  Girard AI    │  │  Girard AI    │              │    │
│  │  │  Node 1      │  │  Node 2      │  │  Node 3      │              │    │
│  │  │  (ECS/K8s)   │  │  (ECS/K8s)   │  │  (ECS/K8s)   │              │    │
│  │  └──────────────┘  └──────────────┘  └──────────────┘              │    │
│  │         │                 │                 │                       │    │
│  │         └─────────────────┼─────────────────┘                       │    │
│  │                           │                                         │    │
│  │                    ┌──────▼──────┐                                  │    │
│  │                    │   Internal   │                                  │    │
│  │                    │     ALB      │                                  │    │
│  │                    └──────────────┘                                  │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                    Database Subnet (10.0.2.0/24)                     │    │
│  │                                                                      │    │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │    │
│  │  │  PostgreSQL  │  │    Redis     │  │   S3/Minio   │              │    │
│  │  │  Primary     │──│   Cluster    │  │   Storage    │              │    │
│  │  │  + Replica   │  │              │  │              │              │    │
│  │  └──────────────┘  └──────────────┘  └──────────────┘              │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│  ┌─────────────────────────┐    ┌─────────────────────────┐                │
│  │    NAT Gateway         │    │    VPN/Direct Connect   │                │
│  │   (Outbound only)      │    │   (Admin access)        │                │
│  └─────────────────────────┘    └─────────────────────────┘                │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
                        ┌─────────────────────────┐
                        │   External AI APIs      │
                        │   (via NAT Gateway)     │
                        │   - OpenAI              │
                        │   - Anthropic           │
                        │   - Google AI           │
                        └─────────────────────────┘

Deployment Options

Option 1: Kubernetes (Helm)

Best for: Organizations with existing Kubernetes infrastructure.

Prerequisites

  • Kubernetes 1.28+
  • Helm 3.x
  • kubectl configured
  • Container registry access
  • PostgreSQL 15+
  • Redis 7+

Installation

  1. Add Helm Repository
# Add Girard AI Helm repo (private)
helm repo add girardai https://charts.girardai.com --username $HELM_USER --password $HELM_PASS
helm repo update
  1. Create Namespace
kubectl create namespace girardai
  1. Create Secrets
# Create secrets for sensitive configuration
kubectl create secret generic girardai-secrets \
  --namespace girardai \
  --from-literal=database-url="postgresql://user:pass@postgres.internal:5432/girardai?sslmode=require" \
  --from-literal=encryption-key="$(openssl rand -hex 32)" \
  --from-literal=clerk-secret-key="sk_live_xxx" \
  --from-literal=stripe-secret-key="sk_live_xxx" \
  --from-literal=anthropic-api-key="sk-ant-xxx" \
  --from-literal=openai-api-key="sk-xxx"
  1. Create Values File
# values-private-vpc.yaml

replicaCount: 3

image:
  repository: your-registry.internal/girardai
  tag: "1.0.0"
  pullPolicy: IfNotPresent

imagePullSecrets:
  - name: registry-credentials

# Application configuration
config:
  nodeEnv: production
  appUrl: https://girardai.internal.company.com
  logLevel: info

# Use existing secrets
existingSecret: girardai-secrets

# Database - use external PostgreSQL
postgresql:
  enabled: false

externalDatabase:
  host: postgres.internal
  port: 5432
  database: girardai
  existingSecret: girardai-secrets
  existingSecretKey: database-url

# Redis - use external Redis
redis:
  enabled: false

externalRedis:
  host: redis.internal
  port: 6379
  password: ""

# Storage configuration
storage:
  type: s3  # or minio for on-prem
  bucket: girardai-uploads
  region: us-east-1
  endpoint: https://s3.internal.company.com  # For MinIO
  accessKeyId: ""
  secretAccessKey: ""
  existingSecret: girardai-s3-secrets

# Ingress - Internal only
ingress:
  enabled: true
  className: nginx-internal
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "100m"
  hosts:
    - host: girardai.internal.company.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: girardai-tls
      hosts:
        - girardai.internal.company.com

# Resources
resources:
  requests:
    cpu: "1"
    memory: "2Gi"
  limits:
    cpu: "2"
    memory: "4Gi"

# Autoscaling
autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70
  targetMemoryUtilizationPercentage: 80

# Pod Disruption Budget
podDisruptionBudget:
  enabled: true
  minAvailable: 2

# Service Account
serviceAccount:
  create: true
  annotations:
    # For AWS IRSA
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/girardai-role

# Security Context
podSecurityContext:
  runAsNonRoot: true
  runAsUser: 1001
  fsGroup: 1001

securityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop:
      - ALL

# Health checks
livenessProbe:
  httpGet:
    path: /api/health
    port: 3000
  initialDelaySeconds: 30
  periodSeconds: 10
  failureThreshold: 3

readinessProbe:
  httpGet:
    path: /api/health
    port: 3000
  initialDelaySeconds: 5
  periodSeconds: 5
  failureThreshold: 3

# Node selector for dedicated nodes
nodeSelector:
  workload: girardai

# Tolerations
tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "girardai"
    effect: "NoSchedule"

# Affinity for HA
affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
              - key: app.kubernetes.io/name
                operator: In
                values:
                  - girardai
          topologyKey: kubernetes.io/hostname

# Network Policy
networkPolicy:
  enabled: true
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx
        - podSelector:
            matchLabels:
              app: monitoring
  egress:
    - to:
        - ipBlock:
            cidr: 10.0.0.0/8  # Internal network
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0  # External AI APIs
      ports:
        - protocol: TCP
          port: 443

# Monitoring
metrics:
  enabled: true
  serviceMonitor:
    enabled: true
    namespace: monitoring
  1. Install Chart
helm install girardai girardai/girardai \
  --namespace girardai \
  --values values-private-vpc.yaml \
  --wait
  1. Run Database Migrations
# Create migration job
kubectl apply -f - <<EOF
apiVersion: batch/v1
kind: Job
metadata:
  name: girardai-migration
  namespace: girardai
spec:
  template:
    spec:
      containers:
        - name: migrate
          image: your-registry.internal/girardai:1.0.0
          command: ["npx", "prisma", "migrate", "deploy"]
          envFrom:
            - secretRef:
                name: girardai-secrets
      restartPolicy: Never
  backoffLimit: 3
EOF

# Wait for completion
kubectl wait --for=condition=complete job/girardai-migration -n girardai --timeout=300s

Option 2: Docker Compose (Air-Gapped)

Best for: Smaller deployments or environments without Kubernetes.

Prerequisites

  • Docker 24+
  • Docker Compose 2.x
  • PostgreSQL 15+ (external or included)
  • 8GB RAM minimum
  • 50GB storage

Installation

  1. Download Deployment Package
# Download from secure distribution (air-gapped transfer)
tar -xzf girardai-private-vpc-1.0.0.tar.gz
cd girardai-private-vpc
  1. Configure Environment
# Copy and edit environment file
cp .env.example .env
# .env
NODE_ENV=production
NEXT_PUBLIC_APP_URL=https://girardai.internal.company.com

# Database
DATABASE_URL=postgresql://girardai:secure_password@postgres:5432/girardai?sslmode=require

# Encryption (generate with: openssl rand -hex 32)
ENCRYPTION_KEY=your-32-char-encryption-key

# Authentication
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_xxx
CLERK_SECRET_KEY=sk_live_xxx
CLERK_WEBHOOK_SECRET=whsec_xxx

# Payments
STRIPE_SECRET_KEY=sk_live_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_xxx

# AI Providers
ANTHROPIC_API_KEY=sk-ant-xxx
OPENAI_API_KEY=sk-xxx

# Storage (MinIO for air-gapped)
S3_ENDPOINT=http://minio:9000
S3_ACCESS_KEY=minioadmin
S3_SECRET_KEY=minioadmin
S3_BUCKET=girardai-uploads
S3_REGION=us-east-1

# Redis
REDIS_URL=redis://redis:6379
  1. Docker Compose Configuration
# docker-compose.yml
version: '3.8'

services:
  app:
    image: girardai:1.0.0
    build:
      context: .
      dockerfile: Dockerfile
    restart: always
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    env_file:
      - .env
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
      minio:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/api/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '2'
          memory: 4G
        reservations:
          cpus: '1'
          memory: 2G
    networks:
      - girardai-internal

  postgres:
    image: postgres:15-alpine
    restart: always
    environment:
      POSTGRES_DB: girardai
      POSTGRES_USER: girardai
      POSTGRES_PASSWORD: secure_password
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init-db:/docker-entrypoint-initdb.d
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U girardai -d girardai"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - girardai-internal

  redis:
    image: redis:7-alpine
    restart: always
    command: redis-server --appendonly yes --maxmemory 1gb --maxmemory-policy allkeys-lru
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - girardai-internal

  minio:
    image: minio/minio:latest
    restart: always
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    volumes:
      - minio_data:/data
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 10s
      retries: 3
    networks:
      - girardai-internal

  nginx:
    image: nginx:alpine
    restart: always
    ports:
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - app
    networks:
      - girardai-internal
      - girardai-external

volumes:
  postgres_data:
  redis_data:
  minio_data:

networks:
  girardai-internal:
    internal: true
  girardai-external:
  1. Nginx Configuration
# nginx.conf
events {
    worker_connections 1024;
}

http {
    upstream girardai {
        least_conn;
        server app:3000 weight=1;
    }

    server {
        listen 443 ssl http2;
        server_name girardai.internal.company.com;

        ssl_certificate /etc/nginx/certs/server.crt;
        ssl_certificate_key /etc/nginx/certs/server.key;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
        ssl_prefer_server_ciphers off;

        # Security headers
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

        location / {
            proxy_pass http://girardai;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            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;
            proxy_cache_bypass $http_upgrade;
            proxy_read_timeout 300s;
            proxy_connect_timeout 75s;
            client_max_body_size 100M;
        }

        location /api/health {
            proxy_pass http://girardai;
            proxy_http_version 1.1;
            access_log off;
        }
    }
}
  1. Start Services
# Start all services
docker-compose up -d

# Run migrations
docker-compose exec app npx prisma migrate deploy

# Check health
curl -k https://girardai.internal.company.com/api/health

Option 3: AWS ECS in Private Subnets

Best for: AWS-native organizations wanting managed containers without Kubernetes.

Terraform Configuration

# private-vpc-ecs.tf

# VPC with no internet gateway
module "vpc" {
  source = "terraform-aws-modules/vpc/aws"

  name = "girardai-private-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["us-east-1a", "us-east-1b", "us-east-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]

  # No public subnets - completely private
  enable_nat_gateway = false
  enable_vpn_gateway = false

  # VPC Endpoints for AWS services
  enable_s3_endpoint       = true
  enable_ecr_api_endpoint  = true
  enable_ecr_dkr_endpoint  = true
  enable_logs_endpoint     = true
  enable_secrets_endpoint  = true

  tags = {
    Environment = "production"
    Application = "girardai"
  }
}

# VPC Endpoints for AWS Services
resource "aws_vpc_endpoint" "ecr_api" {
  vpc_id              = module.vpc.vpc_id
  service_name        = "com.amazonaws.us-east-1.ecr.api"
  vpc_endpoint_type   = "Interface"
  subnet_ids          = module.vpc.private_subnets
  security_group_ids  = [aws_security_group.vpc_endpoints.id]
  private_dns_enabled = true
}

resource "aws_vpc_endpoint" "ecr_dkr" {
  vpc_id              = module.vpc.vpc_id
  service_name        = "com.amazonaws.us-east-1.ecr.dkr"
  vpc_endpoint_type   = "Interface"
  subnet_ids          = module.vpc.private_subnets
  security_group_ids  = [aws_security_group.vpc_endpoints.id]
  private_dns_enabled = true
}

resource "aws_vpc_endpoint" "secretsmanager" {
  vpc_id              = module.vpc.vpc_id
  service_name        = "com.amazonaws.us-east-1.secretsmanager"
  vpc_endpoint_type   = "Interface"
  subnet_ids          = module.vpc.private_subnets
  security_group_ids  = [aws_security_group.vpc_endpoints.id]
  private_dns_enabled = true
}

resource "aws_vpc_endpoint" "logs" {
  vpc_id              = module.vpc.vpc_id
  service_name        = "com.amazonaws.us-east-1.logs"
  vpc_endpoint_type   = "Interface"
  subnet_ids          = module.vpc.private_subnets
  security_group_ids  = [aws_security_group.vpc_endpoints.id]
  private_dns_enabled = true
}

# S3 Gateway Endpoint (free)
resource "aws_vpc_endpoint" "s3" {
  vpc_id       = module.vpc.vpc_id
  service_name = "com.amazonaws.us-east-1.s3"
}

# Internal Application Load Balancer
resource "aws_lb" "internal" {
  name               = "girardai-internal-alb"
  internal           = true
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb.id]
  subnets            = module.vpc.private_subnets

  enable_deletion_protection = true

  tags = {
    Application = "girardai"
  }
}

# ECS Cluster
resource "aws_ecs_cluster" "main" {
  name = "girardai-private"

  setting {
    name  = "containerInsights"
    value = "enabled"
  }

  configuration {
    execute_command_configuration {
      kms_key_id = aws_kms_key.ecs.arn
      logging    = "OVERRIDE"

      log_configuration {
        cloud_watch_encryption_enabled = true
        cloud_watch_log_group_name     = aws_cloudwatch_log_group.ecs.name
      }
    }
  }
}

# ECS Service
resource "aws_ecs_service" "app" {
  name            = "girardai"
  cluster         = aws_ecs_cluster.main.id
  task_definition = aws_ecs_task_definition.app.arn
  desired_count   = 3
  launch_type     = "FARGATE"

  network_configuration {
    subnets          = module.vpc.private_subnets
    security_groups  = [aws_security_group.ecs_tasks.id]
    assign_public_ip = false
  }

  load_balancer {
    target_group_arn = aws_lb_target_group.app.arn
    container_name   = "girardai"
    container_port   = 3000
  }

  deployment_circuit_breaker {
    enable   = true
    rollback = true
  }

  deployment_configuration {
    maximum_percent         = 200
    minimum_healthy_percent = 100
  }
}

# RDS in Private Subnet
resource "aws_db_instance" "postgres" {
  identifier     = "girardai-db"
  engine         = "postgres"
  engine_version = "15"
  instance_class = "db.r6g.large"

  allocated_storage     = 100
  max_allocated_storage = 500
  storage_encrypted     = true
  kms_key_id           = aws_kms_key.rds.arn

  db_name  = "girardai"
  username = "girardai"
  password = random_password.db.result

  multi_az               = true
  db_subnet_group_name   = aws_db_subnet_group.main.name
  vpc_security_group_ids = [aws_security_group.rds.id]

  backup_retention_period = 30
  deletion_protection     = true

  # No public accessibility
  publicly_accessible = false

  performance_insights_enabled = true
  monitoring_interval          = 60
  monitoring_role_arn         = aws_iam_role.rds_monitoring.arn
}

# ElastiCache Redis in Private Subnet
resource "aws_elasticache_replication_group" "redis" {
  replication_group_id = "girardai-redis"
  description          = "Girard AI Redis cluster"

  node_type            = "cache.r6g.large"
  num_cache_clusters   = 2
  port                 = 6379

  subnet_group_name  = aws_elasticache_subnet_group.main.name
  security_group_ids = [aws_security_group.redis.id]

  at_rest_encryption_enabled = true
  transit_encryption_enabled = true
  kms_key_id                = aws_kms_key.redis.arn

  automatic_failover_enabled = true
  multi_az_enabled          = true

  snapshot_retention_limit = 7
}

# Security Groups
resource "aws_security_group" "ecs_tasks" {
  name        = "girardai-ecs-tasks"
  description = "Security group for Girard AI ECS tasks"
  vpc_id      = module.vpc.vpc_id

  ingress {
    from_port       = 3000
    to_port         = 3000
    protocol        = "tcp"
    security_groups = [aws_security_group.alb.id]
  }

  egress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = [module.vpc.vpc_cidr_block]
    description = "VPC Endpoints"
  }

  egress {
    from_port       = 5432
    to_port         = 5432
    protocol        = "tcp"
    security_groups = [aws_security_group.rds.id]
    description     = "PostgreSQL"
  }

  egress {
    from_port       = 6379
    to_port         = 6379
    protocol        = "tcp"
    security_groups = [aws_security_group.redis.id]
    description     = "Redis"
  }
}

Network Configuration

No Internet Access

For completely air-gapped deployments:

# All external API calls must go through a proxy
AI_PROXY_URL: https://ai-proxy.internal.company.com

# The proxy handles:
# - OpenAI API calls
# - Anthropic API calls
# - Google AI calls
# - Webhook callbacks

Proxy Configuration

# AI API Proxy
server {
    listen 443 ssl;
    server_name ai-proxy.internal.company.com;

    # Only allow specific endpoints
    location /v1/chat/completions {
        proxy_pass https://api.openai.com;
        proxy_ssl_server_name on;
        proxy_set_header Authorization $http_authorization;
    }

    location /v1/messages {
        proxy_pass https://api.anthropic.com;
        proxy_ssl_server_name on;
        proxy_set_header x-api-key $http_x_api_key;
    }
}

VPN/Direct Connect Access

# AWS Direct Connect for hybrid connectivity
resource "aws_dx_gateway" "main" {
  name            = "girardai-dx-gateway"
  amazon_side_asn = "64512"
}

resource "aws_dx_gateway_association" "main" {
  dx_gateway_id         = aws_dx_gateway.main.id
  associated_gateway_id = aws_vpn_gateway.main.id
}

Security Hardening

Network Segmentation

┌─────────────────────────────────────────────────────────────┐
│                    Security Zones                            │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  DMZ (Optional)                                              │
│  ├── Reverse Proxy / WAF                                    │
│  └── Load Balancer                                          │
│                                                              │
│  Application Zone                                            │
│  ├── Girard AI Application Nodes                             │
│  └── Background Workers                                      │
│                                                              │
│  Data Zone                                                   │
│  ├── PostgreSQL                                             │
│  ├── Redis                                                  │
│  └── Object Storage                                         │
│                                                              │
│  Management Zone                                             │
│  ├── Monitoring                                             │
│  ├── Logging                                                │
│  └── Bastion Host                                           │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Encryption

# All encryption keys managed by customer
encryption:
  # Database encryption
  database:
    at_rest: AES-256 (customer KMS)
    in_transit: TLS 1.3

  # Storage encryption
  storage:
    at_rest: AES-256 (customer KMS)
    in_transit: TLS 1.3

  # Application secrets
  secrets:
    provider: HashiCorp Vault / AWS Secrets Manager
    rotation: 90 days

Access Control

# Role-based access to infrastructure
roles:
  admin:
    - Full access via bastion host
    - Requires MFA
    - Session recording enabled

  operator:
    - Read-only access to logs/metrics
    - Cannot access data stores directly

  auditor:
    - Read-only access to audit logs
    - Compliance report generation

Monitoring

Internal Monitoring Stack

# docker-compose-monitoring.yml
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    networks:
      - girardai-internal

  grafana:
    image: grafana/grafana:latest
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana/dashboards:/etc/grafana/provisioning/dashboards
    networks:
      - girardai-internal

  alertmanager:
    image: prom/alertmanager:latest
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
    networks:
      - girardai-internal

  loki:
    image: grafana/loki:latest
    volumes:
      - loki_data:/loki
    networks:
      - girardai-internal

volumes:
  prometheus_data:
  grafana_data:
  loki_data:

Metrics Exported

# Application metrics
- http_request_duration_seconds
- http_requests_total
- ai_generation_duration_seconds
- ai_tokens_used_total
- database_query_duration_seconds
- cache_hit_ratio

# Infrastructure metrics
- container_cpu_usage_seconds_total
- container_memory_usage_bytes
- container_network_receive_bytes_total

Backup & Recovery

Backup Strategy

# Database backup (daily)
pg_dump -h postgres -U girardai -Fc girardai > backup-$(date +%Y%m%d).dump

# Encrypt backup
gpg --encrypt --recipient backup@company.com backup-$(date +%Y%m%d).dump

# Transfer to secure storage
aws s3 cp backup-$(date +%Y%m%d).dump.gpg s3://company-backups/girardai/

Recovery Procedure

# Download backup
aws s3 cp s3://company-backups/girardai/backup-20260122.dump.gpg .

# Decrypt
gpg --decrypt backup-20260122.dump.gpg > backup.dump

# Restore
pg_restore -h postgres -U girardai -d girardai backup.dump

Maintenance

Updates

# Pull new version
docker pull your-registry.internal/girardai:1.1.0

# Rolling update (Kubernetes)
kubectl set image deployment/girardai girardai=your-registry.internal/girardai:1.1.0 -n girardai

# Rolling update (Docker Compose)
docker-compose up -d --no-deps app

Database Migrations

# Always backup first
pg_dump -h postgres -U girardai -Fc girardai > pre-migration-backup.dump

# Run migrations
docker-compose exec app npx prisma migrate deploy

# Verify
docker-compose exec app npx prisma migrate status

Troubleshooting

Common Issues

IssueCauseSolution
Cannot pull imagesNo registry accessConfigure registry mirror or pre-pull images
Database connection timeoutNetwork policyCheck security groups allow port 5432
AI API errorsNo internet accessConfigure AI proxy
Slow performanceInsufficient resourcesScale up nodes or increase limits

Health Checks

# Application health
curl -k https://girardai.internal/api/health

# Database connectivity
docker-compose exec app npx prisma db execute --stdin <<< "SELECT 1"

# Redis connectivity
docker-compose exec redis redis-cli ping

Support

For private VPC deployments, contact:

  • Technical Support: support@girardai.com
  • Professional Services: ps@girardai.com
  • Emergency: +1-800-GIRARD-AI

Last updated: January 22, 2026

Previous
Single-Tenant Cloud
Next
SSO Configuration