A production-ready Python async library for building multi-tenant SaaS platforms with Cloudflare R2, Workers, and Custom Hostnames.
- ✅ Async R2 bucket operations (upload, delete, list)
- ✅ Tenant management with namespace isolation
- ✅ Custom domain onboarding with DNS verification
- ✅ Cloudflare for SaaS custom hostname provisioning
- ✅ Worker deployment automation via Terraform
- ✅ Configurable logging system (DEBUG, INFO, WARNING, ERROR, CRITICAL)
- ✅ Multiple log formats (simple, detailed, JSON)
- ✅ Full error handling and retry logic
- ✅ Type-safe with Pydantic models
- ✅ Comprehensive documentation
pip install cloudflare aiodns aioboto3 pydantic python-terraform httpx tenacityFor PostgreSQL storage:
pip install asyncpgFor development:
pip install -e ".[dev,web]"Working deployment and management scripts are available in the scripts/ folder:
deploy_worker.py- Deploy Cloudflare Worker script via APIcreate_token_with_global_key.py- Create API tokens with proper permissionscreate_r2_bucket.py- Create and manage R2 bucketstest_token_permissions.py- Test API token permissions (8 tests)
See scripts/README.md for detailed usage instructions.
Comprehensive documentation is available in the docs/ folder:
- Complete System Guide - Full system overview and operational guide
- DNS Setup Guide - Domain configuration for getai.page
- Deployment Success - Deployment results and metrics
- Permissions Guide - API token permissions and setup
See docs/README.md for a complete list of documentation files.
import asyncio
from cloudflare_saas import (
CloudflareSaaSPlatform,
Config,
configure_logging,
LogLevel
)
async def main():
# Configure logging
configure_logging(level=LogLevel.INFO)
# Load config from environment
config = Config.from_env()
# Initialize platform
platform = CloudflareSaaSPlatform(config)
# Create tenant
tenant = await platform.create_tenant("Acme Inc", "acme-123")
# Deploy site
await platform.deploy_tenant_site(
tenant.tenant_id,
local_path="./acme-site"
)
# Add custom domain
domain_status = await platform.add_custom_domain(
tenant.tenant_id,
"www.acme.com"
)
asyncio.run(main())Required:
CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_IDCLOUDFLARE_ZONE_IDR2_ACCESS_KEY_IDR2_SECRET_ACCESS_KEYR2_BUCKET_NAMEPLATFORM_DOMAIN
Optional - Logging:
LOG_LEVEL(default: INFO) - DEBUG, INFO, WARNING, ERROR, CRITICALLOG_FORMAT(default: detailed) - simple, detailed, jsonLOG_FILE- Path to log file (optional)ENABLE_CONSOLE_LOGGING(default: true) - Enable console output
from cloudflare_saas import Config
config = Config(
cloudflare_api_token="your-token",
cloudflare_account_id="your-account",
cloudflare_zone_id="your-zone",
r2_access_key_id="your-r2-key",
r2_secret_access_key="your-r2-secret",
r2_bucket_name="yourplatform-sites",
platform_domain="yourplatform.com",
log_level="DEBUG",
log_format="json",
log_file="app.log"
)from cloudflare_saas import configure_logging, LogLevel, LogFormat
# Simple console logging
configure_logging(level=LogLevel.INFO)
# Detailed file logging
configure_logging(
level=LogLevel.DEBUG,
log_format=LogFormat.DETAILED,
log_file="cloudflare-saas.log"
)
# JSON logging for production
configure_logging(
level=LogLevel.WARNING,
log_format=LogFormat.JSON,
log_file="/var/log/cloudflare-saas.log",
enable_console=False
)- DEBUG: Detailed diagnostic information
- INFO: General informational messages
- WARNING: Warning messages
- ERROR: Error messages
- CRITICAL: Critical errors
- simple: Minimal output
INFO: message - detailed: With timestamps and source
2025-12-17 10:30:45 - Module - INFO - [file.py:65] - message - json: Structured JSON for log aggregation
from cloudflare_saas import get_logger, LoggerMixin
# Get a logger
logger = get_logger(__name__)
logger.info("Starting operation")
# Use in a class
class MyService(LoggerMixin):
def do_work(self):
self.logger.info("Working...")Comprehensive documentation is available at Read the Docs.
# Install documentation dependencies
make install-docs
# Build HTML documentation
make docs
# Serve documentation locally
make docs-serveDocumentation includes:
- Getting Started Guide: Quick start and installation
- Configuration Guide: All configuration options
- Logging Guide: Comprehensive logging documentation
- API Reference: Complete API documentation
- Examples: Practical code examples
- Deployment Guide: Production deployment
- Contributing Guide: Development guidelines
make help # Show all available commands
# Development
make install # Install package
make install-dev # Install with dev dependencies
make install-docs # Install documentation dependencies
# Testing
make test # Run tests
make test-cov # Run tests with coverage
make test-watch # Run tests in watch mode
# Code Quality
make lint # Run linters (ruff, mypy)
make format # Format code (black, ruff)
make check # Run all checks (lint + test)
# Documentation
make docs # Build documentation
make docs-serve # Build and serve documentation
make docs-clean # Clean documentation build
# Docker
make docker-build # Build Docker image
make docker-run # Run Docker container
make docker-stop # Stop Docker containers
# API
make run-api # Run FastAPI development server
# Utilities
make clean # Clean build artifacts
make clean-all # Clean all generated files# Run all tests
make test
# Run with coverage
make test-cov
# Run specific test
pytest tests/test_platform.py::test_create_tenant -v# Format code
make format
# Check linting
make lint
# Run all checks
make checkSee cloudflare_r2_plan.md for detailed architecture.
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
- Fork and clone the repository
- Install development dependencies:
make install-dev - Create a branch for your feature
- Make your changes with tests
- Run tests and linting:
make check - Submit a pull request
[Add your license here]
- Documentation: https://cloudflare-saas.readthedocs.io/
- Issues: https://github.com/yourusername/cloudflare-saas/issues
- Discussions: https://github.com/yourusername/cloudflare-saas/discussions