skyvern Docker & Self-Hosted Deployment

GitHub

Automate browser based workflows with AI

22,740 stars Python Python 1 file ยท ~5,875 tokens #ai#api#automation#browser#browser-automation#computer#gpt#llm
RAW Compose
1. Pull Image (DOCKERHUB) docker pull public.ecr.aws/skyvern/skyvern
2. Docker Run (1-Click Launch) docker run -d --name skyvern -p 8000:8000 --restart always public.ecr.aws/skyvern/skyvern:latest
3. Podman Run podman run -d --name skyvern -p 8000:8000 --restart always public.ecr.aws/skyvern/skyvern:latest
4. Skopeo Inspect (Zero-Pull Manifest) skopeo inspect docker://public.ecr.aws/skyvern/skyvern:latest
5. ORAS Pull (OCI Artifact) oras pull public.ecr.aws/skyvern/skyvern:latest
6. Compose Deployment docker compose up -d
docker-compose.yml
Download .yml
services:
  postgres:
    image: postgres:14-alpine
    restart: always
    # comment out if you want to externally connect DB
    # ports:
    #   - 5432:5432
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
    environment:
      - PGDATA=/var/lib/postgresql/data/pgdata
      - POSTGRES_USER=skyvern
      - POSTGRES_PASSWORD=skyvern
      - POSTGRES_DB=skyvern
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U skyvern"]
      interval: 5s
      timeout: 5s
      retries: 5
  skyvern:
    image: public.ecr.aws/skyvern/skyvern:latest
    # For local backend development, replace the image line above with:
    # build:
    #   context: .
    #   dockerfile: Dockerfile
    # Or keep the public image and uncomment the source mounts below.
    restart: on-failure
    extra_hosts:
      - "host.docker.internal:host-gateway"
    env_file:
      - .env
    # comment out if you want to externally call skyvern API
    ports:
      - 8000:8000
      - 6080:6080 # for VNC WebSocket streaming
    volumes:
      - ./artifacts:/data/artifacts
      - ./videos:/data/videos
      - ./har:/data/har
      - ./log:/data/log
      - ./downloads:/data/downloads
      - ./browser_sessions:/data/browser_sessions
      - ./credential_vault:/data/credential_vault
      # Generated credentials allow the UI to pick up the local API key on first startup.
      - ./.skyvern:/app/.skyvern
      # Uncomment the following two lines if you want to connect to any local changes
      # - ./skyvern:/app/skyvern
      # - ./alembic:/app/alembic
    environment:
      # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
      # Compose-network values live here. These are infrastructure values
      # tied to the docker compose network (e.g. the `postgres` hostname
      # only resolves inside this compose stack). DO NOT move these into
      # .env โ€” `.env.example` uses a `localhost` host that points at the
      # backend container itself inside compose, which would break the DB
      # connection.
      #
      # User secrets (LLM API keys, etc.) go in `.env` (loaded above via
      # env_file). The split is intentional: compose owns infrastructure;
      # .env owns secrets.
      # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
      - DATABASE_STRING=postgresql+psycopg://skyvern:skyvern@postgres:5432/skyvern
      - BROWSER_STREAMING_MODE=${BROWSER_STREAMING_MODE:-cdp}
      - BROWSER_TYPE=${BROWSER_TYPE:-chromium-headful}
      - BROWSER_REMOTE_DEBUGGING_URL=${BROWSER_REMOTE_DEBUGGING_URL:-http://127.0.0.1:9222}
      - BROWSER_REMOTE_DEBUGGING_HOST_HEADER=${BROWSER_REMOTE_DEBUGGING_HOST_HEADER:-}
      - BROWSER_CDP_CONNECT_TIMEOUT_MS=${BROWSER_CDP_CONNECT_TIMEOUT_MS:-120000}
      - DOWNLOAD_PATH=/data/downloads
      - BROWSER_SESSION_BASE_PATH=/data/browser_sessions
      - CREDENTIAL_VAULT_TYPE=${CREDENTIAL_VAULT_TYPE:-skyvern}
      - ENABLE_LOCAL_CREDENTIAL_VAULT=${ENABLE_LOCAL_CREDENTIAL_VAULT:-true}
      - LOCAL_CREDENTIAL_VAULT_PATH=/data/credential_vault
      - ENABLE_CODE_BLOCK=true
      # --- Control your own browser (Chrome/Chromium) ---
      # Prefer Chrome's chrome://inspect/#remote-debugging flow for an existing profile.
      # On Windows, scripts/windows_chrome_inspect_cdp.ps1 can bridge a
      # chrome://inspect/#remote-debugging listener and write the full ws:// URL.
      # If Docker cannot reach that listener, start an isolated Chrome profile
      # with --remote-debugging-address=0.0.0.0 and a non-default --user-data-dir.
      # Then set:
      # - BROWSER_TYPE=cdp-connect
      # - BROWSER_REMOTE_DEBUGGING_URL=http://host.docker.internal:9222/
      # See docs/developers/self-hosted/browser.mdx for Windows/Docker Desktop notes.
    # =========================
    #       LLM Settings - Use `skyvern init llm` for interactive setup
    # =========================
    # Docs: https://www.skyvern.com/docs/self-hosted/llm-configuration
    #
    # OpenAI:
    # - ENABLE_OPENAI=true
    # - LLM_KEY=OPENAI_GPT5_5
    # - OPENAI_API_KEY=<your_openai_key>
    #
    # Anthropic:
    # - ENABLE_ANTHROPIC=true
    # - LLM_KEY=ANTHROPIC_CLAUDE4.7_OPUS
    # - ANTHROPIC_API_KEY=<your_anthropic_key>
    #
    # Gemini:
    # - ENABLE_GEMINI=true
    # - LLM_KEY=GEMINI_3.0_FLASH
    # - GEMINI_API_KEY=<your_gemini_key>
    #
    # Azure OpenAI:
    # - ENABLE_AZURE=true
    # - LLM_KEY=AZURE_OPENAI
    # - AZURE_DEPLOYMENT=<your_deployment>
    # - AZURE_API_KEY=<your_key>
    # - AZURE_API_BASE=<your_endpoint>
    # - AZURE_API_VERSION=2024-08-01-preview
    #
    # AWS Bedrock:
    # - ENABLE_BEDROCK=true
    # - LLM_KEY=BEDROCK_ANTHROPIC_CLAUDE4.7_OPUS_INFERENCE_PROFILE
    # - AWS_REGION=us-west-2
    # - AWS_ACCESS_KEY_ID=<your_key>
    # - AWS_SECRET_ACCESS_KEY=<your_secret>
    #
    # Ollama (local models):
    # - ENABLE_OLLAMA=true
    # - LLM_KEY=OLLAMA
    # - OLLAMA_MODEL=gemma4:e4b
    # - OLLAMA_SERVER_URL=http://host.docker.internal:11434
    # - OLLAMA_SUPPORTS_VISION=false
    #
    # OpenRouter:
    # - ENABLE_OPENROUTER=true
    # - LLM_KEY=OPENROUTER
    # - OPENROUTER_API_KEY=<your_key>
    # - OPENROUTER_MODEL=mistralai/mistral-small-3.1-24b-instruct
    #
    # Groq:
    # - ENABLE_GROQ=true
    # - LLM_KEY=GROQ
    # - GROQ_API_KEY=<your_key>
    # - GROQ_MODEL=openai/gpt-oss-120b

    # Bitwarden Settings
    # If you are looking to integrate Skyvern with a password manager (eg Bitwarden), you can use the following environment variables.
    # - BITWARDEN_SERVER=http://localhost  # OPTIONAL IF YOU ARE SELF HOSTING BITWARDEN
    # - BITWARDEN_SERVER_PORT=8002 # IF YOU ARE SELF HOSTING BITWARDEN AND USE THIS COMPOSE FILE, PORT IS 8002 UNLESS CHANGED
    # - SKYVERN_AUTH_BITWARDEN_ORGANIZATION_ID=your-org-id-here
    # - SKYVERN_AUTH_BITWARDEN_CLIENT_ID=user.your-client-id-here
    # - SKYVERN_AUTH_BITWARDEN_CLIENT_SECRET=your-client-secret-here
    # - SKYVERN_AUTH_BITWARDEN_MASTER_PASSWORD=your-master-password-here

    # 1Password Integration
    # If you are looking to integrate Skyvern with 1Password, you can use the following environment variables.
    # OP_SERVICE_ACCOUNT_TOKEN=""
    depends_on:
      postgres:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/v1/heartbeat', timeout=5)"]
      interval: 5s
      timeout: 5s
      retries: 24
      start_period: 180s
  skyvern-ui:
    image: public.ecr.aws/skyvern/skyvern-ui:latest
    # For local UI development/testing, replace the image line above with:
    # build:
    #   context: .
    #   dockerfile: Dockerfile.ui
    restart: on-failure
    ports:
      - 8080:8080
      - 9090:9090
    volumes:
      - ./artifacts:/data/artifacts
      - ./videos:/data/videos
      - ./har:/data/har
      # Generated credentials allow the UI to pick up the local API key on first startup.
      - ./.skyvern:/app/.skyvern
    # User secrets and most frontend config live in skyvern-frontend/.env
    # (loaded via env_file). CDP streaming is inline so local livestreaming is
    # enabled even if an older frontend .env is present.
    env_file:
      - skyvern-frontend/.env
    environment:
      - VITE_BROWSER_STREAMING_MODE=${VITE_BROWSER_STREAMING_MODE:-cdp}
    #  - VITE_ENABLE_CODE_BLOCK=true
    # if you want to run skyvern on a remote server,
    # you need to change the host in VITE_WSS_BASE_URL and VITE_API_BASE_URL to match your server ip
    # If you're self-hosting this behind a dns, you'll want to set:
    #   A route for the API: api.yourdomain.com -> localhost:8000
    #   A route for the UI: yourdomain.com -> localhost:8080
    #   A route for the artifact API: artifact.yourdomain.com -> localhost:9090 (maybe not needed)
    # - VITE_WSS_BASE_URL=ws://localhost:8000/api/v1
    #   - VITE_ARTIFACT_API_BASE_URL=http://localhost:9090
    #   - VITE_API_BASE_URL=http://localhost:8000/api/v1
    #   - VITE_SKYVERN_API_KEY=<get this from "settings" in the Skyvern UI>
    depends_on:
      skyvern:
        condition: service_healthy

# uncomment for local usage of `vaultwarden` & bitwarden-cli - see more at: https://github.com/dani-garcia/vaultwarden
# First this container needs to be started and configured to sign up, create master password and organization
# Once created, under SETTINGS/SECURITY/KEYS/API you should be able to get client id and secret for CLI & Skyvern integrations
#  vaultwarden:
#    image: vaultwarden/server:latest-alpine
#    container_name: vaultwarden
#    restart: unless-stopped
#    environment:
#      # DOMAIN: "https://vaultwarden.example.com"  # required when using a reverse proxy; your domain; vaultwarden needs to know it's https to work properly with attachments
#      SIGNUPS_ALLOWED: "true" # Deactivate this with "false" after you have created your account so that no strangers can register
#    volumes:
#      - ~/vw-data/:/data/ # the path before the : can be changed
#    ports:
#      - 127.0.0.1:11002:80 # you can replace the 11002 with your preferred port

# Bitwarden CLI Server (provides REST API endpoints for Skyvern)
# Once you have master password and api credentials, you can set them below and this CLI should start providing secure access for Skyvern to Vaultwarden
#  bitwarden-cli:
#    build:
#      context: ./bitwarden-cli-server
#      dockerfile: Dockerfile
#    environment:
#      # Vaultwarden server URL
#      BW_HOST: "http://vaultwarden"
#      # API credentials for vaultwarden
#      BW_CLIENTID: "user.your-client-id-here"
#      BW_CLIENTSECRET: "your-client-secret-here"
#      # Master password for unlocking vault
#      BW_PASSWORD: "your-master-password-here"
#    ports:
#      # Bind to localhost only for security
#      - "127.0.0.1:8002:8087"
#    restart: unless-stopped
#    healthcheck:
#      test: [ "CMD", "curl", "-f", "http://localhost:8087/status" ]
#      interval: 30s
#      timeout: 10s
#      retries: 5
#      start_period: 30s
#    depends_on:
#      vaultwarden:
#        condition: service_healthy
#    volumes:
#      # Optional: persist Bitwarden CLI config
#      - ~/bitwarden-cli-config:/app/.config
#    labels:
#      - "traefik.enable=false"  # Don't expose via reverse proxy