391 lines
10 KiB
Plaintext
391 lines
10 KiB
Plaintext
|
|
---
|
||
|
|
title: Docker Setup
|
||
|
|
subtitle: Get Skyvern running in 10 minutes with Docker Compose
|
||
|
|
slug: self-hosted/docker
|
||
|
|
---
|
||
|
|
|
||
|
|
This guide walks you through deploying Skyvern using Docker Compose. By the end, you'll have a working Skyvern instance with the API server, browser, database, and web UI running on your machine.
|
||
|
|
|
||
|
|
## Prerequisites
|
||
|
|
|
||
|
|
- Docker and Docker Compose v2 installed ([Get Docker](https://docs.docker.com/get-docker/)). All commands use `docker compose` (with a space). If you have an older installation, replace with `docker-compose`.
|
||
|
|
- 4GB+ RAM available
|
||
|
|
- An LLM API key (OpenAI, Anthropic, Azure, Gemini, or Bedrock)
|
||
|
|
|
||
|
|
## Quick start
|
||
|
|
|
||
|
|
### 1. Clone the repository
|
||
|
|
|
||
|
|
```bash
|
||
|
|
git clone https://github.com/Skyvern-AI/skyvern.git
|
||
|
|
cd skyvern
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Configure environment variables
|
||
|
|
|
||
|
|
Copy the example environment file and configure your LLM provider:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cp .env.example .env
|
||
|
|
```
|
||
|
|
|
||
|
|
Open `.env` and set your LLM provider. Here's an example for OpenAI:
|
||
|
|
|
||
|
|
```bash .env
|
||
|
|
ENABLE_OPENAI=true
|
||
|
|
OPENAI_API_KEY=sk-your-api-key-here
|
||
|
|
LLM_KEY=OPENAI_GPT4O
|
||
|
|
```
|
||
|
|
|
||
|
|
For other providers, see [LLM Configuration](/self-hosted/llm-configuration).
|
||
|
|
|
||
|
|
### 3. Configure the frontend
|
||
|
|
|
||
|
|
Copy the frontend environment file:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cp skyvern-frontend/.env.example skyvern-frontend/.env
|
||
|
|
```
|
||
|
|
|
||
|
|
The default values work for local development. You'll update `VITE_SKYVERN_API_KEY` after the first startup.
|
||
|
|
|
||
|
|
### 4. Start the services
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker compose up -d
|
||
|
|
```
|
||
|
|
|
||
|
|
This pulls the images and starts three services:
|
||
|
|
- **postgres**: Database on port 5432 (internal only)
|
||
|
|
- **skyvern**: API server on port 8000
|
||
|
|
- **skyvern-ui**: Web interface on port 8080
|
||
|
|
|
||
|
|
First startup takes 1-2 minutes as it runs database migrations and creates your organization.
|
||
|
|
|
||
|
|
### 5. Get your API key
|
||
|
|
|
||
|
|
Wait for all services to be healthy before continuing:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker compose ps
|
||
|
|
```
|
||
|
|
|
||
|
|
All three services should show `healthy` in the STATUS column. The `skyvern` container runs database migrations and generates credentials on first startup. This takes 1-2 minutes.
|
||
|
|
|
||
|
|
Once healthy, retrieve your API key:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cat .streamlit/secrets.toml
|
||
|
|
```
|
||
|
|
|
||
|
|
This file is auto-generated by Skyvern on first startup. The `.streamlit` path is a legacy artifact. The credentials inside are standard Skyvern API keys.
|
||
|
|
|
||
|
|
You'll see output like:
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[skyvern]
|
||
|
|
configs = [
|
||
|
|
{env = "local", host = "http://skyvern:8000/api/v1", orgs = [{name="Skyvern", cred="eyJhbGciOiJIUzI1..."}]}
|
||
|
|
]
|
||
|
|
```
|
||
|
|
|
||
|
|
The `host` value uses the Docker-internal hostname `skyvern`. From your machine, use `http://localhost:8000` instead. You only need the `cred` value. This is your API key.
|
||
|
|
|
||
|
|
### 6. Update frontend configuration
|
||
|
|
|
||
|
|
Add your API key to the frontend environment:
|
||
|
|
|
||
|
|
```bash skyvern-frontend/.env
|
||
|
|
VITE_SKYVERN_API_KEY=eyJhbGciOiJIUzI1...
|
||
|
|
```
|
||
|
|
|
||
|
|
Restart the UI to pick up the change:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker compose restart skyvern-ui
|
||
|
|
```
|
||
|
|
|
||
|
|
### 7. Verify the installation
|
||
|
|
|
||
|
|
Open [http://localhost:8080](http://localhost:8080) in your browser. You should see the Skyvern dashboard.
|
||
|
|
|
||
|
|
Test the API by listing workflows (should return an empty array on fresh install):
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s http://localhost:8000/v1/workflows \
|
||
|
|
-H "x-api-key: YOUR_API_KEY_HERE"
|
||
|
|
```
|
||
|
|
|
||
|
|
<Note>
|
||
|
|
The API accepts requests on both `/v1/` and `/api/v1/`. The frontend uses `/api/v1` for backward compatibility. New integrations should use `/v1/`.
|
||
|
|
</Note>
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Understanding the services
|
||
|
|
|
||
|
|
The Docker Compose file defines three services that work together:
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
flowchart LR
|
||
|
|
UI[skyvern-ui<br/>:8080] --> API[skyvern<br/>:8000]
|
||
|
|
API --> DB[(postgres<br/>:5432)]
|
||
|
|
API --> Browser[Browser<br/>internal]
|
||
|
|
API --> LLM[Your LLM<br/>Provider]
|
||
|
|
```
|
||
|
|
|
||
|
|
| Service | Image | Ports | Purpose |
|
||
|
|
|---------|-------|-------|---------|
|
||
|
|
| `postgres` | postgres:14-alpine | 5432 (internal) | Stores tasks, workflows, credentials, and run history |
|
||
|
|
| `skyvern` | public.ecr.aws/skyvern/skyvern | 8000, 9222 | API server + embedded browser |
|
||
|
|
| `skyvern-ui` | public.ecr.aws/skyvern/skyvern-ui | 8080, 9090 | Web dashboard and artifact server |
|
||
|
|
|
||
|
|
The `skyvern` container includes Playwright with Chromium. The browser runs inside the same container as the API server. No separate browser service is needed.
|
||
|
|
|
||
|
|
### Data volumes
|
||
|
|
|
||
|
|
Docker Compose mounts several directories for persistent storage:
|
||
|
|
|
||
|
|
| Local path | Container path | Contents |
|
||
|
|
|------------|----------------|----------|
|
||
|
|
| `./postgres-data` | `/var/lib/postgresql/data` | Database files |
|
||
|
|
| `./artifacts` | `/data/artifacts` | Extracted data, screenshots |
|
||
|
|
| `./videos` | `/data/videos` | Browser session recordings |
|
||
|
|
| `./har` | `/data/har` | HTTP Archive files for debugging |
|
||
|
|
| `./log` | `/data/log` | Application logs |
|
||
|
|
| `./.streamlit` | `/app/.streamlit` | Generated API credentials |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Environment variables reference
|
||
|
|
|
||
|
|
The `.env` file controls the Skyvern server. Here are the most important variables grouped by purpose.
|
||
|
|
|
||
|
|
### LLM Configuration
|
||
|
|
|
||
|
|
Configure at least one LLM provider. See [LLM Configuration](/self-hosted/llm-configuration) for all providers.
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# OpenAI
|
||
|
|
ENABLE_OPENAI=true
|
||
|
|
OPENAI_API_KEY=sk-...
|
||
|
|
LLM_KEY=OPENAI_GPT4O
|
||
|
|
|
||
|
|
# Or Anthropic
|
||
|
|
ENABLE_ANTHROPIC=true
|
||
|
|
ANTHROPIC_API_KEY=sk-ant-...
|
||
|
|
LLM_KEY=ANTHROPIC_CLAUDE3.5_SONNET
|
||
|
|
```
|
||
|
|
|
||
|
|
### Browser settings
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Browser mode: chromium-headful (visible) or chromium-headless (no display)
|
||
|
|
BROWSER_TYPE=chromium-headful
|
||
|
|
|
||
|
|
# Timeout for individual browser actions (milliseconds)
|
||
|
|
BROWSER_ACTION_TIMEOUT_MS=5000
|
||
|
|
|
||
|
|
# Where to save recordings
|
||
|
|
VIDEO_PATH=./videos
|
||
|
|
```
|
||
|
|
|
||
|
|
### Task execution
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Maximum steps before a task times out
|
||
|
|
MAX_STEPS_PER_RUN=50
|
||
|
|
|
||
|
|
# Server port
|
||
|
|
PORT=8000
|
||
|
|
|
||
|
|
# Log verbosity: DEBUG, INFO, WARNING, ERROR
|
||
|
|
LOG_LEVEL=INFO
|
||
|
|
```
|
||
|
|
|
||
|
|
### Database
|
||
|
|
|
||
|
|
The database connection is set in `docker-compose.yml`, not `.env`:
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
environment:
|
||
|
|
- DATABASE_STRING=postgresql+psycopg://skyvern:skyvern@postgres:5432/skyvern
|
||
|
|
```
|
||
|
|
|
||
|
|
To use an external database, update this connection string and remove the `postgres` service.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Common operations
|
||
|
|
|
||
|
|
### View logs
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# All services
|
||
|
|
docker compose logs -f
|
||
|
|
|
||
|
|
# Specific service
|
||
|
|
docker compose logs -f skyvern
|
||
|
|
```
|
||
|
|
|
||
|
|
### Restart after configuration changes
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker compose restart skyvern
|
||
|
|
```
|
||
|
|
|
||
|
|
### Stop all services
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker compose down
|
||
|
|
```
|
||
|
|
|
||
|
|
### Update to latest version
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker compose pull
|
||
|
|
docker compose up -d
|
||
|
|
```
|
||
|
|
|
||
|
|
### Reset everything (including database)
|
||
|
|
|
||
|
|
<Warning>
|
||
|
|
This deletes all data including task history, credentials, and recordings.
|
||
|
|
</Warning>
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker compose down -v
|
||
|
|
rm -rf postgres-data artifacts videos har log .streamlit
|
||
|
|
docker compose up -d
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Exposing to the network
|
||
|
|
|
||
|
|
By default, Skyvern only accepts connections from localhost. To expose it on your network:
|
||
|
|
|
||
|
|
### Option 1: Bind to all interfaces
|
||
|
|
|
||
|
|
Edit `docker-compose.yml` to change the port bindings:
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
services:
|
||
|
|
skyvern:
|
||
|
|
ports:
|
||
|
|
- "0.0.0.0:8000:8000" # Accept connections from any IP
|
||
|
|
```
|
||
|
|
|
||
|
|
### Option 2: Use a reverse proxy
|
||
|
|
|
||
|
|
For production deployments, put Skyvern behind nginx or Traefik:
|
||
|
|
|
||
|
|
```
|
||
|
|
your-domain.com → nginx → localhost:8080 (UI)
|
||
|
|
api.your-domain.com → nginx → localhost:8000 (API)
|
||
|
|
```
|
||
|
|
|
||
|
|
Update the frontend environment to use your domain:
|
||
|
|
|
||
|
|
```bash skyvern-frontend/.env
|
||
|
|
VITE_API_BASE_URL=https://api.your-domain.com/api/v1
|
||
|
|
VITE_WSS_BASE_URL=wss://api.your-domain.com/api/v1
|
||
|
|
VITE_ARTIFACT_API_BASE_URL=https://artifacts.your-domain.com
|
||
|
|
```
|
||
|
|
|
||
|
|
<Warning>
|
||
|
|
If exposing Skyvern to the internet, add authentication at the reverse proxy layer or use a VPN.
|
||
|
|
</Warning>
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Troubleshooting
|
||
|
|
|
||
|
|
<Accordion title="Container exits immediately">
|
||
|
|
Check the logs for the failing service:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker compose logs skyvern
|
||
|
|
```
|
||
|
|
|
||
|
|
Common causes:
|
||
|
|
- Missing or invalid LLM API key: look for LLM-related errors in logs
|
||
|
|
- Database connection failed: check if `postgres` service is healthy with `docker compose ps`
|
||
|
|
</Accordion>
|
||
|
|
|
||
|
|
<Accordion title='API returns "Invalid credentials" (403)'>
|
||
|
|
The API key is missing, malformed, or doesn't match the organization. Verify:
|
||
|
|
|
||
|
|
1. The `x-api-key` header is included in your request
|
||
|
|
2. The key matches exactly what's in `.streamlit/secrets.toml`
|
||
|
|
3. No extra whitespace or newlines in the key
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Correct format
|
||
|
|
curl -H "x-api-key: eyJhbGciOiJIUzI1..." http://localhost:8000/v1/workflows
|
||
|
|
```
|
||
|
|
</Accordion>
|
||
|
|
|
||
|
|
<Accordion title='API returns "Could not validate credentials" (403)'>
|
||
|
|
The API key format is invalid (JWT decode failed). This usually means:
|
||
|
|
- The key was truncated or corrupted during copy-paste
|
||
|
|
- You're using an API key from a different Skyvern installation
|
||
|
|
|
||
|
|
Regenerate credentials by resetting the installation:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
rm -rf .streamlit
|
||
|
|
docker compose restart skyvern
|
||
|
|
cat .streamlit/secrets.toml # Get new key
|
||
|
|
```
|
||
|
|
</Accordion>
|
||
|
|
|
||
|
|
<Accordion title="UI shows blank page or connection errors">
|
||
|
|
Check that `skyvern-frontend/.env` has the correct values:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
VITE_API_BASE_URL=http://localhost:8000/api/v1
|
||
|
|
VITE_WSS_BASE_URL=ws://localhost:8000/api/v1
|
||
|
|
VITE_SKYVERN_API_KEY=<your-key-from-secrets.toml>
|
||
|
|
```
|
||
|
|
|
||
|
|
After updating, restart the UI:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker compose restart skyvern-ui
|
||
|
|
```
|
||
|
|
</Accordion>
|
||
|
|
|
||
|
|
<Accordion title='Task fails with "Unknown browser type"'>
|
||
|
|
The `BROWSER_TYPE` environment variable has an invalid value. Valid options:
|
||
|
|
- `chromium-headful`: Browser with visible window (default)
|
||
|
|
- `chromium-headless`: No visible window
|
||
|
|
- `cdp-connect`: Connect to external Chrome
|
||
|
|
</Accordion>
|
||
|
|
|
||
|
|
<Accordion title='Task fails with "Context window exceeded"'>
|
||
|
|
The page content is too large for the LLM. Try:
|
||
|
|
- Simplifying your prompt
|
||
|
|
- Starting from a more specific URL
|
||
|
|
- Using a model with a larger context window
|
||
|
|
</Accordion>
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Next steps
|
||
|
|
|
||
|
|
<CardGroup cols={2}>
|
||
|
|
<Card title="LLM Configuration" icon="microchip" href="/self-hosted/llm-configuration">
|
||
|
|
Configure OpenAI, Anthropic, Azure, Ollama, and other providers
|
||
|
|
</Card>
|
||
|
|
<Card title="Browser Configuration" icon="window" href="/self-hosted/browser">
|
||
|
|
Customize browser settings, locales, and connect to external Chrome
|
||
|
|
</Card>
|
||
|
|
<Card title="Storage Configuration" icon="hard-drive" href="/self-hosted/storage">
|
||
|
|
Store artifacts in S3 or Azure Blob instead of local disk
|
||
|
|
</Card>
|
||
|
|
<Card title="Proxy Setup" icon="shield" href="/self-hosted/proxy">
|
||
|
|
Configure proxies to avoid bot detection
|
||
|
|
</Card>
|
||
|
|
</CardGroup>
|