This guide covers deploying Girard AI as a dedicated single-tenant instance for enterprise customers who require isolated infrastructure.
Overview
Single-tenant deployment provides:
- Complete isolation - Dedicated compute, database, and storage
- Custom domain - Your own branded domain (e.g.,
ai.yourcompany.com) - Data residency - Choose deployment region for compliance
- Enhanced security - Network isolation, dedicated encryption keys
- Custom SLAs - Guaranteed uptime and support response times
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Single-Tenant Architecture │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Vercel │ │ Neon │ │ Cloudflare │ │
│ │ (Compute) │───▶│ (Database) │ │ R2/CDN │ │
│ │ Dedicated │ │ Dedicated │ │ Dedicated │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ └───────────────────┴───────────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ Customer VPC │ │
│ │ (Optional) │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Deployment Options
Option 1: Vercel Enterprise (Recommended)
Best for: Most enterprise customers wanting managed infrastructure.
Prerequisites
- Vercel Enterprise account
- Custom domain configured
- DNS access for domain verification
Setup Steps
- Create Dedicated Vercel Project
# Clone repository to customer-specific branch
git clone https://github.com/Girard-Media/girardai-com.git
cd girardai-com
git checkout -b customer/acme-corp
# Install Vercel CLI
npm i -g vercel
# Link to new project
vercel link --project acme-girardai
- Configure Environment Variables
Set these in Vercel Dashboard → Project Settings → Environment Variables:
# Application
NEXT_PUBLIC_APP_URL="https://ai.acme.com"
ENCRYPTION_KEY="<unique-32-char-key>"
# Database (Dedicated Neon Project)
DATABASE_URL="postgresql://user:pass@ep-acme-xxx.region.aws.neon.tech/neondb?sslmode=require"
# Authentication (Dedicated Clerk Instance)
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_live_acme_..."
CLERK_SECRET_KEY="sk_live_acme_..."
CLERK_WEBHOOK_SECRET="whsec_acme_..."
# Payments (Customer's Stripe Account or Connected Account)
STRIPE_SECRET_KEY="sk_live_acme_..."
STRIPE_WEBHOOK_SECRET="whsec_acme_..."
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_live_acme_..."
# AI Providers (Customer-provided or Girard AI managed)
ANTHROPIC_API_KEY="sk-ant-..."
OPENAI_API_KEY="sk-..."
# Storage (Dedicated R2 Bucket)
R2_ACCOUNT_ID="acme_account_id"
R2_ACCESS_KEY_ID="acme_access_key"
R2_SECRET_ACCESS_KEY="acme_secret_key"
R2_BUCKET_NAME="acme-girardai-uploads"
R2_PUBLIC_URL="https://cdn.ai.acme.com"
# Caching (Dedicated Upstash Instance)
UPSTASH_REDIS_REST_URL="https://acme-xxx.upstash.io"
UPSTASH_REDIS_REST_TOKEN="acme_token"
- Configure Custom Domain
# Add custom domain in Vercel
vercel domains add ai.acme.com
# Configure DNS (customer's DNS provider)
# Add CNAME record: ai.acme.com → cname.vercel-dns.com
- Deploy
vercel --prod
- Run Database Migrations
# Set DATABASE_URL locally
export DATABASE_URL="postgresql://..."
# Run migrations
npx prisma migrate deploy
Option 2: AWS Deployment
Best for: Customers requiring AWS-specific compliance or existing AWS infrastructure.
Infrastructure Components
| Component | AWS Service | Configuration |
|---|---|---|
| Compute | ECS Fargate | 2 vCPU, 4GB RAM minimum |
| Database | RDS PostgreSQL | db.r6g.large, Multi-AZ |
| Cache | ElastiCache Redis | cache.r6g.large |
| Storage | S3 | Private bucket with CloudFront |
| CDN | CloudFront | Custom domain, WAF enabled |
| Secrets | Secrets Manager | All sensitive configuration |
| DNS | Route 53 | Customer domain delegation |
Terraform Configuration
# main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}
# Variables
variable "customer_name" {
description = "Customer identifier"
type = string
}
variable "aws_region" {
description = "AWS region for deployment"
type = string
default = "us-east-1"
}
variable "domain_name" {
description = "Custom domain for the application"
type = string
}
# VPC
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "${var.customer_name}-girardai-vpc"
cidr = "10.0.0.0/16"
azs = ["${var.aws_region}a", "${var.aws_region}b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
enable_nat_gateway = true
single_nat_gateway = false
tags = {
Customer = var.customer_name
Environment = "production"
}
}
# RDS PostgreSQL
module "rds" {
source = "terraform-aws-modules/rds/aws"
identifier = "${var.customer_name}-girardai-db"
engine = "postgres"
engine_version = "15"
family = "postgres15"
major_engine_version = "15"
instance_class = "db.r6g.large"
allocated_storage = 100
max_allocated_storage = 500
db_name = "girardai"
username = "girardai_admin"
port = 5432
multi_az = true
db_subnet_group_name = module.vpc.database_subnet_group_name
vpc_security_group_ids = [aws_security_group.rds.id]
backup_retention_period = 30
deletion_protection = true
performance_insights_enabled = true
tags = {
Customer = var.customer_name
}
}
# ElastiCache Redis
resource "aws_elasticache_cluster" "redis" {
cluster_id = "${var.customer_name}-girardai-redis"
engine = "redis"
node_type = "cache.r6g.large"
num_cache_nodes = 1
parameter_group_name = "default.redis7"
port = 6379
subnet_group_name = aws_elasticache_subnet_group.redis.name
security_group_ids = [aws_security_group.redis.id]
snapshot_retention_limit = 7
tags = {
Customer = var.customer_name
}
}
# ECS Cluster
resource "aws_ecs_cluster" "main" {
name = "${var.customer_name}-girardai-cluster"
setting {
name = "containerInsights"
value = "enabled"
}
tags = {
Customer = var.customer_name
}
}
# ECS Task Definition
resource "aws_ecs_task_definition" "app" {
family = "${var.customer_name}-girardai"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = 2048
memory = 4096
execution_role_arn = aws_iam_role.ecs_execution.arn
task_role_arn = aws_iam_role.ecs_task.arn
container_definitions = jsonencode([
{
name = "girardai"
image = "${aws_ecr_repository.app.repository_url}:latest"
portMappings = [
{
containerPort = 3000
hostPort = 3000
protocol = "tcp"
}
]
environment = [
{ name = "NODE_ENV", value = "production" },
{ name = "NEXT_PUBLIC_APP_URL", value = "https://${var.domain_name}" }
]
secrets = [
{ name = "DATABASE_URL", valueFrom = "${aws_secretsmanager_secret.app.arn}:DATABASE_URL::" },
{ name = "ENCRYPTION_KEY", valueFrom = "${aws_secretsmanager_secret.app.arn}:ENCRYPTION_KEY::" },
{ name = "CLERK_SECRET_KEY", valueFrom = "${aws_secretsmanager_secret.app.arn}:CLERK_SECRET_KEY::" }
# ... additional secrets
]
logConfiguration = {
logDriver = "awslogs"
options = {
"awslogs-group" = "/ecs/${var.customer_name}-girardai"
"awslogs-region" = var.aws_region
"awslogs-stream-prefix" = "ecs"
}
}
healthCheck = {
command = ["CMD-SHELL", "wget -q --spider http://localhost:3000/api/health || exit 1"]
interval = 30
timeout = 5
retries = 3
startPeriod = 60
}
}
])
}
# Application Load Balancer
resource "aws_lb" "main" {
name = "${var.customer_name}-girardai-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = module.vpc.public_subnets
enable_deletion_protection = true
tags = {
Customer = var.customer_name
}
}
# S3 Bucket for uploads
resource "aws_s3_bucket" "uploads" {
bucket = "${var.customer_name}-girardai-uploads"
tags = {
Customer = var.customer_name
}
}
resource "aws_s3_bucket_versioning" "uploads" {
bucket = aws_s3_bucket.uploads.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "uploads" {
bucket = aws_s3_bucket.uploads.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}
Deployment Steps
# Initialize Terraform
terraform init
# Plan deployment
terraform plan -var="customer_name=acme" -var="domain_name=ai.acme.com"
# Apply
terraform apply -var="customer_name=acme" -var="domain_name=ai.acme.com"
# Build and push Docker image
docker build -t girardai .
docker tag girardai:latest $ECR_REPO_URL:latest
docker push $ECR_REPO_URL:latest
# Run migrations
aws ecs run-task \
--cluster acme-girardai-cluster \
--task-definition acme-girardai-migration \
--launch-type FARGATE
Option 3: Google Cloud Platform
Best for: Customers with GCP preference or requiring specific GCP compliance certifications.
Infrastructure Components
| Component | GCP Service | Configuration |
|---|---|---|
| Compute | Cloud Run | 2 vCPU, 4GB RAM |
| Database | Cloud SQL PostgreSQL | db-custom-2-4096, HA |
| Cache | Memorystore Redis | 5GB Standard |
| Storage | Cloud Storage | Regional bucket |
| CDN | Cloud CDN | Custom domain |
| Secrets | Secret Manager | All configuration |
| DNS | Cloud DNS | Customer domain |
Deployment with Cloud Run
# Set project
gcloud config set project acme-girardai
# Build container
gcloud builds submit --tag gcr.io/acme-girardai/app
# Deploy to Cloud Run
gcloud run deploy girardai \
--image gcr.io/acme-girardai/app \
--platform managed \
--region us-central1 \
--memory 4Gi \
--cpu 2 \
--min-instances 2 \
--max-instances 10 \
--set-env-vars "NODE_ENV=production" \
--set-secrets "DATABASE_URL=girardai-db-url:latest,ENCRYPTION_KEY=girardai-encryption-key:latest"
# Map custom domain
gcloud run domain-mappings create \
--service girardai \
--domain ai.acme.com \
--region us-central1
Data Isolation
Database Isolation
Each single-tenant deployment gets:
- Dedicated PostgreSQL instance
- Unique encryption keys
- Separate backup retention
- Independent connection pooling
Storage Isolation
- Dedicated cloud storage bucket
- Customer-managed encryption keys (CMEK) optional
- Separate CDN distribution
Network Isolation
- Dedicated VPC (AWS/GCP) or project (Vercel)
- Private database connectivity
- WAF rules per customer
Security Configuration
Encryption
# Generate unique encryption key per customer
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# Store in secrets manager (never in environment variables directly)
SSL/TLS
- All traffic encrypted in transit (TLS 1.3)
- Customer can provide their own SSL certificates
- Automatic certificate renewal via Let's Encrypt or AWS ACM
Access Control
# Example: IP allowlist for admin access
security_policies:
ip_restriction:
enabled: true
admin_ips:
- "203.0.113.0/24" # Customer office
- "198.51.100.0/24" # Customer VPN
Monitoring & Observability
Metrics
Each deployment includes:
- Application metrics (response times, error rates)
- Infrastructure metrics (CPU, memory, disk)
- Database metrics (connections, query performance)
- Custom business metrics
Logging
# Structured logging format
{
"timestamp": "2026-01-22T10:00:00Z",
"level": "info",
"customer": "acme",
"service": "girardai",
"message": "Request processed",
"duration_ms": 125,
"user_id": "user_xxx",
"request_id": "req_xxx"
}
Alerting
Configure alerts per customer:
- Error rate > 1%
- Response time p99 > 2s
- Database connections > 80%
- Storage usage > 80%
Backup & Recovery
Backup Schedule
| Data Type | Frequency | Retention |
|---|---|---|
| Database | Continuous (WAL) | 30 days |
| Database snapshots | Daily | 90 days |
| File storage | Versioned | 30 days |
| Configuration | On change | Unlimited |
Recovery Procedures
See DISASTER_RECOVERY.md for detailed procedures.
Compliance
Available Certifications
- SOC 2 Type II
- HIPAA (with BAA)
- GDPR compliant
- ISO 27001 (roadmap)
Data Residency
Available regions:
- US East (Virginia)
- US West (Oregon)
- EU West (Ireland)
- EU Central (Frankfurt)
- Asia Pacific (Singapore, Sydney)
Pricing
Single-tenant deployments are priced based on:
| Component | Base Cost | Notes |
|---|---|---|
| Platform license | $2,000/mo | Includes updates, support |
| Compute | Variable | Based on usage |
| Database | ~$500/mo | Depends on size |
| Storage | ~$100/mo | Per TB |
| Support | Included | 4-hour SLA |
Contact sales@girardai.com for custom pricing.
Support
Included Support
- 24/7 infrastructure monitoring
- 4-hour response SLA for critical issues
- Dedicated Slack channel
- Monthly review calls
Escalation Path
- Support ticket → support@girardai.com
- Slack channel → #acme-girardai
- Account manager escalation
- Engineering escalation
Onboarding Checklist
- Customer agreement signed
- Infrastructure provisioned
- Custom domain configured
- SSL certificates installed
- Environment variables set
- Database migrated
- SSO configured (if applicable)
- IP allowlist configured
- Monitoring alerts configured
- Backup verified
- Security scan completed
- Load testing passed
- Documentation provided
- Training completed
- Go-live approved
Last updated: January 22, 2026