Environment:OpenHands OpenHands SaaS Server Environment
| Knowledge Sources | |
|---|---|
| Domains | SaaS_Infrastructure, Server_Architecture |
| Last Updated | 2026-02-11 21:00 GMT |
Overview
Python 3.12+ SaaS server environment requiring PostgreSQL, Redis, Keycloak identity provider, LiteLLM proxy, and Stripe billing integration.
Description
This environment defines the full stack for running the OpenHands enterprise SaaS server. It is built on Python 3.12+ with FastAPI as the web framework, PostgreSQL as the primary database (with GCP Cloud SQL support), Redis for distributed state management and pub/sub, Keycloak for identity/authentication, LiteLLM as an LLM proxy, and Stripe for billing. The server runs as a uvicorn ASGI application on port 3000. The enterprise image extends the base OpenHands Docker image with additional enterprise dependencies including Datadog APM tracing, PostHog analytics, scikit-learn for solvability analysis, and Alembic for database migrations.
Usage
Use this environment for deploying the SaaS Server Assembly workflow and all Conversation Lifecycle Management workflows. It is the mandatory prerequisite for running the enterprise server, clustered conversation manager, organization onboarding, and all integration webhook handlers (GitHub, GitLab, Slack, Jira, Linear).
System Requirements
| Category | Requirement | Notes |
|---|---|---|
| OS | Linux (Ubuntu 22.04+ or equivalent) | Docker containers use Python 3.13.7 slim base; dev containers use Ubuntu 22.04 |
| Runtime | Python >= 3.12, < 3.14 | Specified in both root and enterprise pyproject.toml |
| Database | PostgreSQL 12+ | With asyncpg for async operations and pg8000 for sync; GCP Cloud SQL connector supported |
| Cache/Messaging | Redis >= 5.2, < 7 | Required for clustered mode; used for pub/sub, distributed locks, and rate limiting |
| Identity | Keycloak server | External dependency for OAuth/OIDC authentication |
| Container | Docker | For runtime sandbox management; Docker socket mount required |
| Disk | 50GB+ SSD | For application, dependencies, and Docker images |
Dependencies
System Packages
- `python` >= 3.12, < 3.14
- `postgresql-client` (for database migrations)
- `redis-server` >= 5.2 (or managed Redis)
- `docker` (for sandbox runtime management)
- `git`, `git-lfs`
- `curl`, `build-essential` (for native extensions)
Python Packages (Core)
- `fastapi` (ASGI web framework)
- `uvicorn` (ASGI server)
- `sqlalchemy[asyncio]` >= 2.0.40
- `asyncpg` >= 0.30
- `pg8000` >= 1.31.2
- `redis` >= 5.2, < 7
- `litellm` >= 1.74.3 (excludes 1.64.4 and 1.67.*)
- `openai` == 2.8 (pinned due to litellm incompatibility)
- `python-socketio` == 5.13
- `tenacity` >= 8.5, < 10
- `python-jose[cryptography]` >= 3.3
- `python-dotenv`
- `pyyaml` >= 6.0.2
- `requests` >= 2.32.5
Python Packages (Enterprise)
- `alembic` >= 1.14.1 (database migrations)
- `stripe` >= 11.5.0 (billing)
- `python-keycloak` >= 5.3.1 (identity)
- `slack-sdk` >= 3.35.0 (Slack integration)
- `ddtrace` == 3.13.0 (Datadog APM; pinned to avoid yanked 3.12.4)
- `posthog` >= 6.0.0 (analytics)
- `scikit-learn` >= 1.7.0 (solvability analysis)
- `shap` >= 0.48.0 (ML explainability)
- `google-cloud-recaptcha-enterprise` >= 1.24.0 (bot protection)
- `resend` >= 2.7.0 (email delivery)
- `mcp` >= 1.10.0 (Model Context Protocol)
- `cloud-sql-python-connector` >= 1.16.0 (GCP database)
- `coredis` >= 4.22.0 (async Redis)
Credentials
The following environment variables must be set for full SaaS server operation:
Database:
- `DB_HOST`: PostgreSQL host (default: localhost)
- `DB_PORT`: PostgreSQL port (default: 5432)
- `DB_NAME`: Database name (default: openhands)
- `DB_USER`: Database user (default: postgres)
- `DB_PASS`: Database password (default: postgres)
- `GCP_DB_INSTANCE`: GCP Cloud SQL instance (optional, for GCP deployments)
- `GCP_PROJECT`: GCP project ID (optional)
- `GCP_REGION`: GCP region (optional)
Redis:
- `REDIS_HOST`: Redis host (default: localhost)
- `REDIS_PORT`: Redis port (default: 6379)
- `REDIS_PASSWORD`: Redis password (default: empty)
- `REDIS_DB`: Redis database number (default: 0)
Identity (Keycloak):
- `KEYCLOAK_SERVER_URL`: Keycloak server internal URL
- `KEYCLOAK_SERVER_URL_EXT`: Keycloak external URL (for browser redirects)
- `KEYCLOAK_REALM_NAME`: Keycloak realm name
- `KEYCLOAK_CLIENT_ID`: OAuth client ID
- `KEYCLOAK_CLIENT_SECRET`: OAuth client secret
- `KEYCLOAK_ADMIN_PASSWORD`: Admin password (for sync operations)
- `AUTH_URL`: Authentication service URL
- `AUTH_WEB_HOST`: Authentication web host
LLM Proxy:
- `LITE_LLM_API_URL`: LiteLLM proxy URL (default: https://llm-proxy.app.all-hands.dev)
- `LITE_LLM_API_KEY`: LiteLLM API key
- `LITE_LLM_TEAM_ID`: LiteLLM team identifier
Billing:
- `STRIPE_API_KEY`: Stripe API key
- `REQUIRE_PAYMENT`: Enable payment requirement (0/1)
- `ENABLE_BILLING`: Enable billing features (true/false)
- `DEFAULT_INITIAL_BUDGET`: Initial credit budget (default: 10)
Analytics:
- `POSTHOG_CLIENT_KEY`: PostHog analytics key
- `POSTHOG_HOST`: PostHog host (default: https://us.i.posthog.com)
Application:
- `WEB_HOST`: Application hostname (default: app.all-hands.dev)
- `OPENHANDS_CONFIG_CLS`: Server config class override
- `CONVERSATION_MANAGER_CLASS`: Conversation manager implementation class
Quick Install
# Install core dependencies (root project)
pip install openhands-ai
# Install enterprise dependencies
cd enterprise && poetry install
# Run database migrations
alembic upgrade head
# Start the server
uvicorn enterprise.saas_server:app --host 0.0.0.0 --port 3000
Code Evidence
Database configuration from `enterprise/migrations/env.py:11-15`:
DB_USER = os.getenv('DB_USER', 'postgres')
DB_PASS = os.getenv('DB_PASS', 'postgres')
DB_HOST = os.getenv('DB_HOST', 'localhost')
DB_PORT = os.getenv('DB_PORT', '5432')
DB_NAME = os.getenv('DB_NAME', 'openhands')
Redis client creation from `enterprise/storage/redis.py:6-19`:
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = int(os.environ.get('REDIS_PORT', '6379'))
REDIS_PASSWORD = os.environ.get('REDIS_PASSWORD', '')
REDIS_DB = int(os.environ.get('REDIS_DB', '0'))
def create_redis_client():
return redis.Redis(
host=REDIS_HOST,
port=REDIS_PORT,
password=REDIS_PASSWORD,
db=REDIS_DB,
socket_timeout=2,
)
LiteLLM proxy configuration from `enterprise/server/constants.py:42-46`:
LITE_LLM_API_URL = os.environ.get(
'LITE_LLM_API_URL', 'https://llm-proxy.app.all-hands.dev'
)
LITE_LLM_TEAM_ID = os.environ.get('LITE_LLM_TEAM_ID', None)
LITE_LLM_API_KEY = os.environ.get('LITE_LLM_API_KEY', None)
Python version constraint from `pyproject.toml:13`:
requires-python = ">=3.12,<3.14"
Common Errors
| Error Message | Cause | Solution |
|---|---|---|
| `ModuleNotFoundError: No module named 'asyncpg'` | Missing PostgreSQL async driver | `pip install asyncpg>=0.30` |
| `redis.exceptions.ConnectionError` | Redis not running or unreachable | Start Redis: `docker run -p 6379:6379 --name openhands-redis -d redis` |
| `KeyError: 'STRIPE_API_KEY'` | Missing Stripe configuration | Set `STRIPE_API_KEY` environment variable or set `REQUIRE_PAYMENT=0` |
| `litellm.exceptions.BadRequestError` | Incompatible litellm/openai versions | Ensure `openai==2.8` and `litellm>=1.74.3` (not 1.64.4 or 1.67.*) |
| `alembic.util.exc.CommandError: Can't locate revision` | Database migrations out of sync | Run `alembic upgrade head` from enterprise directory |
Compatibility Notes
- GCP Cloud SQL: When `GCP_DB_INSTANCE` is set, the server uses Google Cloud SQL Connector instead of direct PostgreSQL. Requires `cloud-sql-python-connector` and appropriate GCP credentials.
- Clustered Mode: Requires `REDIS_HOST` to be set. Without Redis, the server runs in standalone mode with no cross-instance coordination.
- Docker Socket: The server needs access to `/var/run/docker.sock` for sandbox runtime management. In containerized deployments, mount the host Docker socket.
- ddtrace Pinning: Enterprise pins `ddtrace==3.13.0` to avoid a yanked version (3.12.4). Do not upgrade without checking the PyPI release status.
- openai Pinning: `openai==2.8` is pinned because newer versions cause incompatibilities with litellm. This is a known constraint.
Related Pages
- Implementation:OpenHands_OpenHands_SaaS_Server_ASGI_App
- Implementation:OpenHands_OpenHands_ClusteredConversationManager_Redis_Subscribe
- Implementation:OpenHands_OpenHands_ClusteredConversationManager_Close_Session
- Implementation:OpenHands_OpenHands_SaasNestedConversationManager_Maybe_Start_Agent_Loop
- Implementation:OpenHands_OpenHands_SaasNestedConversationManager_Create_Runtime
- Implementation:OpenHands_OpenHands_SetAuthCookieMiddleware
- Implementation:OpenHands_OpenHands_SaaSServerConfig
- Implementation:OpenHands_OpenHands_SaaSMonitoringListener
- Implementation:OpenHands_OpenHands_OrgService_Validate_Name_Uniqueness
- Implementation:OpenHands_OpenHands_OrgService_Create_LiteLLM_Integration