Deployment
Guide for deploying the Cloudflare SaaS Platform in production environments.
Infrastructure Requirements
Cloudflare Services
Required Cloudflare services:
R2 Bucket: For storing tenant static sites
Custom Hostname Zone: For managing custom domains
Workers (optional): For advanced routing
Database (Optional)
For production deployments, use PostgreSQL:
PostgreSQL 12+ recommended
Connection pooling recommended
Asyncpg driver required
Deployment Options
Docker Deployment
Using Docker Compose:
# docker-compose.yml
version: '3.8'
services:
api:
build: .
ports:
- "8000:8000"
environment:
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}
- CLOUDFLARE_ACCOUNT_ID=${CLOUDFLARE_ACCOUNT_ID}
- CLOUDFLARE_ZONE_ID=${CLOUDFLARE_ZONE_ID}
- R2_ACCESS_KEY_ID=${R2_ACCESS_KEY_ID}
- R2_SECRET_ACCESS_KEY=${R2_SECRET_ACCESS_KEY}
- R2_BUCKET_NAME=${R2_BUCKET_NAME}
- PLATFORM_DOMAIN=${PLATFORM_DOMAIN}
- DATABASE_URL=${DATABASE_URL}
- LOG_LEVEL=INFO
- LOG_FORMAT=json
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_DB: cloudflare_saas
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY cloudflare_saas ./cloudflare_saas
COPY examples ./examples
CMD ["uvicorn", "examples.fastapi_integration:app", "--host", "0.0.0.0", "--port", "8000"]
Kubernetes Deployment
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: cloudflare-saas-api
spec:
replicas: 3
selector:
matchLabels:
app: cloudflare-saas-api
template:
metadata:
labels:
app: cloudflare-saas-api
spec:
containers:
- name: api
image: your-registry/cloudflare-saas:latest
ports:
- containerPort: 8000
env:
- name: CLOUDFLARE_API_TOKEN
valueFrom:
secretKeyRef:
name: cloudflare-secrets
key: api-token
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secrets
key: url
- name: LOG_LEVEL
value: "INFO"
- name: LOG_FORMAT
value: "json"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: cloudflare-saas-api
spec:
selector:
app: cloudflare-saas-api
ports:
- port: 80
targetPort: 8000
type: LoadBalancer
Serverless Deployment
For AWS Lambda with API Gateway:
# lambda_handler.py
from mangum import Mangum
from examples.fastapi_integration import app
handler = Mangum(app)
Configuration
Environment Variables
Production environment variables:
# Required
CLOUDFLARE_API_TOKEN=your-token
CLOUDFLARE_ACCOUNT_ID=your-account
CLOUDFLARE_ZONE_ID=your-zone
R2_ACCESS_KEY_ID=your-key
R2_SECRET_ACCESS_KEY=your-secret
R2_BUCKET_NAME=production-sites
PLATFORM_DOMAIN=yourplatform.com
# Database
DATABASE_URL=postgresql://user:pass@db:5432/cloudflare_saas
# Logging
LOG_LEVEL=WARNING
LOG_FORMAT=json
LOG_FILE=/var/log/cloudflare-saas/app.log
ENABLE_CONSOLE_LOGGING=false
# Optional
WORKER_SCRIPT_NAME=site-router
INTERNAL_API_KEY=your-internal-key
Secrets Management
Use a secrets manager in production:
# Example with AWS Secrets Manager
import boto3
import json
from cloudflare_saas import Config
def load_config_from_secrets():
client = boto3.client('secretsmanager')
secret = client.get_secret_value(SecretId='cloudflare-saas/prod')
secrets = json.loads(secret['SecretString'])
return Config(
cloudflare_api_token=secrets['cloudflare_api_token'],
cloudflare_account_id=secrets['cloudflare_account_id'],
# ... other config
)
Database Setup
PostgreSQL Initialization
Run migrations:
# Install alembic
pip install alembic
# Initialize (first time only)
alembic init alembic
# Create migration
alembic revision --autogenerate -m "Initial schema"
# Apply migrations
alembic upgrade head
Using with Application:
from cloudflare_saas import (
CloudflareSaaSPlatform,
Config,
PostgresStorageAdapter
)
async def init_platform():
config = Config.from_env()
storage = await PostgresStorageAdapter.create(
config.database_url
)
platform = CloudflareSaaSPlatform(config, storage=storage)
return platform
Monitoring and Logging
Structured Logging
Configure for log aggregation:
from cloudflare_saas import configure_logging, LogLevel, LogFormat
configure_logging(
level=LogLevel.INFO,
log_format=LogFormat.JSON,
enable_console=True, # For container logs
log_file=None
)
Log Aggregation
Example Filebeat configuration:
filebeat.inputs:
- type: container
paths:
- '/var/lib/docker/containers/*/*.log'
processors:
- add_docker_metadata:
host: "unix:///var/run/docker.sock"
- decode_json_fields:
fields: ["message"]
target: ""
overwrite_keys: true
output.elasticsearch:
hosts: ["elasticsearch:9200"]
Health Checks
Implement health check endpoints:
from fastapi import FastAPI
from cloudflare_saas import CloudflareSaaSPlatform
app = FastAPI()
@app.get("/health")
async def health_check():
return {"status": "healthy"}
@app.get("/health/ready")
async def readiness_check():
# Check database connection
# Check Cloudflare API
return {"status": "ready"}
Performance Optimization
Connection Pooling
For PostgreSQL:
from cloudflare_saas import PostgresStorageAdapter
storage = await PostgresStorageAdapter.create(
database_url,
min_size=10,
max_size=100
)
Caching
Implement caching for frequently accessed data:
from functools import lru_cache
class CachedPlatform:
def __init__(self, platform):
self.platform = platform
@lru_cache(maxsize=1000)
async def get_tenant_cached(self, tenant_id):
return await self.platform.get_tenant(tenant_id)
Scaling Considerations
Horizontal Scaling
The platform is stateless and can be scaled horizontally:
Deploy multiple instances behind a load balancer
Share database connection pool across instances
Use Redis for distributed caching (optional)
Rate Limiting
Implement rate limiting for API endpoints:
from fastapi import FastAPI
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
app = FastAPI()
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
@app.post("/tenants")
@limiter.limit("10/minute")
async def create_tenant(request: Request):
# ...
Security Best Practices
API Token Security: Never commit tokens to version control
TLS/SSL: Use HTTPS for all API endpoints
Input Validation: Validate all user inputs
Rate Limiting: Protect against abuse
Audit Logging: Log all administrative actions
Access Control: Implement proper authentication/authorization
Backup and Recovery
Database Backups
Automated PostgreSQL backups:
# Daily backup script
#!/bin/bash
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
pg_dump cloudflare_saas > backup_$TIMESTAMP.sql
# Upload to cloud storage
aws s3 cp backup_$TIMESTAMP.sql s3://backups/
R2 Data Recovery
R2 objects are durable, but implement versioning:
# Enable versioning on bucket (do once)
# Then access previous versions if needed
Troubleshooting
Common Issues
Database Connection Errors
Check DATABASE_URL format
Verify network connectivity
Check connection pool settings
R2 Upload Failures
Verify R2 credentials
Check bucket permissions
Monitor rate limits
Custom Hostname Issues
Verify zone_id is correct
Check DNS configuration
Review Cloudflare dashboard
Monitoring Commands
# Check Docker logs
docker-compose logs -f api
# Check Kubernetes pods
kubectl logs -f deployment/cloudflare-saas-api
# Database connection count
psql -c "SELECT count(*) FROM pg_stat_activity"
See Also
Configuration - Configuration guide
Logging - Logging setup
Examples - Code examples