Skip to content

Deployment

This guide covers deploying YAAI to production. No repo clone needed -- everything installs from PyPI.

Important

This page is for production deployments. For local development, see Server Setup.

Production checklist

Before going live, make sure you've set these:

  • ENVIRONMENT=production -- the server refuses to start with default credentials in production mode
  • BASE_URL -- your public URL (e.g. https://yaai.mycompany.com). Used for CORS, OAuth redirects, and service account audience.
  • DATABASE_URL -- point to a managed PostgreSQL instance with strong credentials (not changeme)
  • AUTH_JWT_SECRET and SESSION_SECRET -- optional but recommended. If not set, the server auto-generates ephemeral secrets on startup (sessions won't survive restarts). Generate with openssl rand -base64 32.

Docker Compose

The recommended way to deploy. Create these two files -- no repo clone required.

Dockerfile

FROM python:3.12-slim-bookworm

WORKDIR /app

RUN pip install "yaai-monitoring[server]"

EXPOSE 8000

CMD ["uvicorn", "yaai.server.main:app", "--host", "0.0.0.0", "--port", "8000"]

Tip

For Google Cloud SQL support, use "yaai-monitoring[server,gcp]" instead.

docker-compose.yml

Username + password login with API key auth for service accounts. An admin account is created automatically on first startup -- check the server logs for the generated password.

services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: aimon
      POSTGRES_PASSWORD: change-me-in-production
      POSTGRES_DB: aimonitoring
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U aimon -d aimonitoring"]
      interval: 5s
      timeout: 3s
      retries: 5

  yaai:
    build: .
    ports:
      - "8000:8000"
    environment:
      BASE_URL: http://localhost:8000
      DATABASE_URL: postgresql+asyncpg://aimon:change-me-in-production@db:5432/aimonitoring
      ENVIRONMENT: production
      AUTH_ENABLED: "true"
      # AUTH_JWT_SECRET: <generate with: openssl rand -base64 32>
      # SESSION_SECRET: <generate with: openssl rand -base64 32>
    depends_on:
      db:
        condition: service_healthy

volumes:
  pgdata:

Browser users sign in with Google. Local auth is automatically disabled when Google OAuth is enabled. API key auth still works for service accounts.

Note

Google OAuth requires the frontend and backend to share the same origin (same host and port). Docker Compose handles this -- the server serves both the API and the frontend on port 8000.

services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: aimon
      POSTGRES_PASSWORD: change-me-in-production
      POSTGRES_DB: aimonitoring
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U aimon -d aimonitoring"]
      interval: 5s
      timeout: 3s
      retries: 5

  yaai:
    build: .
    ports:
      - "8000:8000"
    environment:
      BASE_URL: https://yaai.mycompany.com
      DATABASE_URL: postgresql+asyncpg://aimon:change-me-in-production@db:5432/aimonitoring
      ENVIRONMENT: production
      AUTH_ENABLED: "true"
      # AUTH_JWT_SECRET: <generate with: openssl rand -base64 32>
      # SESSION_SECRET: <generate with: openssl rand -base64 32>

      # Google OAuth
      AUTH_OAUTH_GOOGLE_ENABLED: "true"
      AUTH_OAUTH_GOOGLE_CLIENT_ID: your-client-id
      AUTH_OAUTH_GOOGLE_CLIENT_SECRET: your-client-secret
      AUTH_OAUTH_GOOGLE_ALLOWED_DOMAINS: mycompany.com
      AUTH_OAUTH_GOOGLE_AUTO_CREATE_USERS: "true"
      AUTH_OAUTH_GOOGLE_OWNER_EMAILS: admin@mycompany.com
      # AUTH_OAUTH_GOOGLE_VIEWER_EMAILS: analyst@mycompany.com

      # Google service account auth (SDK clients)
      AUTH_SERVICE_ACCOUNTS_GOOGLE_ENABLED: "true"
      AUTH_SERVICE_ACCOUNTS_GOOGLE_ALLOWED_EMAILS: ml-pipeline@my-project.iam.gserviceaccount.com
      # AUTH_SERVICE_ACCOUNTS_GOOGLE_AUDIENCE: https://yaai.mycompany.com  # defaults to BASE_URL
    depends_on:
      db:
        condition: service_healthy

volumes:
  pgdata:

Set the OAuth redirect URI in Google Cloud Console to:

{BASE_URL}/api/v1/auth/oauth/google/callback

Start the server

docker compose up -d

Open your BASE_URL -- you should see the login screen. Migrations run automatically on startup.

Tip

Already cloned the repo? You can also deploy directly with the included docker-compose.yml and Dockerfile.dev. Copy .env.example to .env, set your values, and run docker compose up -d. The repo's Dockerfile builds the frontend from source and includes a healthcheck.

Without Docker

Install the server package and run uvicorn directly. You need Python 3.11+ and a PostgreSQL instance.

pip install "yaai-monitoring[server]"

Set environment variables (via .env file, shell exports, or your process manager):

export BASE_URL=https://yaai.mycompany.com
export DATABASE_URL=postgresql+asyncpg://user:password@your-db-host:5432/aimonitoring
export ENVIRONMENT=production
export AUTH_ENABLED=true

Start the server:

uvicorn yaai.server.main:app --host 0.0.0.0 --port 8000

The server runs migrations automatically, creates the admin account, and serves both the API and the frontend.

Google Cloud SQL

If your PostgreSQL runs on Google Cloud SQL, YAAI can connect using the Cloud SQL Python Connector with IAM authentication -- no IP allow-lists, SSL certificates, or Auth Proxy needed.

Install the GCP extras

pip install "yaai-monitoring[server,gcp]"

This adds the Cloud SQL Connector, pg8000 (for migrations), and google-auth.

Configure connection

Set these environment variables instead of DATABASE_URL:

CLOUD_SQL_INSTANCE=my-project:us-central1:yaai-db
CLOUD_SQL_USER=yaai-server@my-project.iam.gserviceaccount.com
CLOUD_SQL_DATABASE=aimonitoring
CLOUD_SQL_IAM_AUTH=true
CLOUD_SQL_IP_TYPE=public    # public, private, or psc
Variable Required Default Description
CLOUD_SQL_INSTANCE Yes -- Instance connection name (project:region:instance)
CLOUD_SQL_USER Yes -- IAM user email (full service account email)
CLOUD_SQL_DATABASE No aimonitoring Database name
CLOUD_SQL_IAM_AUTH No true Use IAM authentication (set false for password auth)
CLOUD_SQL_IP_TYPE No public Connection type: public, private, or psc

When CLOUD_SQL_INSTANCE is set, the connector handles all database connections automatically. DATABASE_URL is ignored.

Google service account auth for SDK clients

SDK clients on GCP workloads can authenticate using Google Application Default Credentials instead of API keys:

AUTH_SERVICE_ACCOUNTS_GOOGLE_ENABLED=true
AUTH_SERVICE_ACCOUNTS_GOOGLE_ALLOWED_EMAILS=ml-pipeline@my-project.iam.gserviceaccount.com
# Audience defaults to BASE_URL -- only set if you need a different value
# AUTH_SERVICE_ACCOUNTS_GOOGLE_AUDIENCE=https://yaai.mycompany.com
from yaai import YaaiClient

# No api_key → automatically uses Google ADC
async with YaaiClient("https://yaai.mycompany.com/api/v1") as client:
    model = await client.create_model("my-model")

Tip

SDK clients using Google SA auth need the gcp extra: pip install "yaai-monitoring[gcp]". Clients using API keys only need the base package.

Troubleshooting

Server refuses to start in production mode : You're running with ENVIRONMENT=production but haven't changed the default changeme password in DATABASE_URL. Use strong credentials.

Migrations fail on startup : Check that PostgreSQL is running and DATABASE_URL is correct. Disable auto-migration with AUTO_MIGRATE=false and run manually: alembic upgrade head.

Google OAuth login redirects fail : Verify BASE_URL matches the origin users access in their browser, and that the OAuth redirect URI in Google Cloud Console matches {BASE_URL}/api/v1/auth/oauth/google/callback.

Cloud SQL connection fails : Check that the service account has both Cloud SQL Client and Cloud SQL Instance User roles. Verify the IAM database user was created with gcloud sql users list --instance=yaai-db.

"Could not automatically determine credentials" : No GCP credentials found. Run gcloud auth application-default login locally, or attach a service account to your Cloud Run / GKE workload.