[Skyvern](https://github.com/skyvern-ai/skyvern) is a tool for autonomous web browsing - just the kind of thing you might want to deploy on Coolify. However, as of December 2025, if you try to do this using the [official docker-compose](https://github.com/Skyvern-AI/skyvern/blob/main/docker-compose.yml) you're in for a bad time: Skyvern is optimized for local development (via `git clone` and bind mounts) and you'll run into the following problems trying to containerize it: ## Problems When you try to deploy Skyvern to Coolify with the existing docker-compose, you'll encounter the following problems: 1. **Missing `secrets.toml`:** The UI container crashes on boot because it expects a local file from the git repo to be mounted. 2. **Wrong Database Driver:** The default `DATABASE_STRING` uses a synchronous driver (`psycoph2`) that fails with Skyvern's async engine. 3. **Docker Networking/Port Conflicts:** Coolify's internal reverse proxy conflicts with the default `ports:` definitions. 4. **Skyvern UI Service hosts on Localhost:** We can't access it from the web this way. 5. **No UI Access Control:** The Skyvern UI requires no authentication to access, and must be secured before being exposed to the web. > Discovering and solving these problems was a deeply frustrating experience, taking an unreasonable amount of effort and all-day to get it working. In the end, it only works without the ability to stream the browser - e.g. the equivalent of headless. > > I don't presume that their intent is to make self-hosting difficult in order to sell the cloud hosted service - it's also a new product and maybe they're planning to improve these issues. Regardless, I am sharing what I solved here in the hope it gets someone else closer - if you don't need to stream the view from the browser, this will do what you need. ## Solution and Guide Follow these steps to get Skyvern working on Coolify (sans ability to stream): ### A) Generate a HTTP Auth Hash 1. Open a new terminal and use this command to generate a hash of a username and password: `htpasswd -nb your-username your-password` 2. Take note of the result, which will look like `your-username:$apr1$PNUAc/iN$I4qSGXrNCLSheezFmtCV8.` ### B) Create The Service 1. Create a new Coolify service/resource with the `Docker Compose Empty` template. 2. Paste in the below docker-compose. 3. Replace `YOUR_KEY_HASH_HERE` with the exact output from the previous step. ```yaml services: db: image: 'postgres:14.1' container_name: skyvern-db restart: always environment: POSTGRES_USER: skyvern POSTGRES_PASSWORD: '${DB_PASSWORD:-skyvern}' POSTGRES_DB: skyvern volumes: - 'skyvern-data:/var/lib/postgresql/data' healthcheck: test: - CMD-SHELL - 'pg_isready -U skyvern' interval: 5s timeout: 5s retries: 5 skyvern: image: 'skyvern/skyvern:latest' container_name: skyvern-api restart: always shm_size: 2gb depends_on: db: condition: service_healthy volumes: - 'skyvern-data:/app/.skyvern' environment: - 'DATABASE_STRING=postgresql+asyncpg://skyvern:${DB_PASSWORD:-skyvern}@db:5432/skyvern' - BROWSER_TYPE=chromium-headful - ENABLE_OPENAI=false - ENABLE_OPENAI_COMPATIBLE=true - LLM_KEY=OPENAI_COMPATIBLE - 'OPENAI_COMPATIBLE_API_BASE=${LLM_API_BASE}' - 'OPENAI_COMPATIBLE_API_KEY=${LLM_API_KEY}' - 'OPENAI_COMPATIBLE_MODEL_NAME=${LLM_MODEL_NAME}' extra_hosts: - "None:127.0.0.1" skyvern-ui: image: 'skyvern/skyvern-ui:latest' container_name: skyvern-ui restart: always depends_on: - skyvern user: root volumes: - 'skyvern-ui-data:/app/.streamlit' environment: - 'VITE_API_BASE_URL=${API_PUBLIC_URL}' - 'VITE_WSS_BASE_URL=${WS_PUBLIC_URL}' - 'VITE_SKYVERN_API_KEY=${API_KEY}' command: - /bin/bash - '-c' - "mkdir -p /app/.streamlit\nif [ -z \"${API_KEY}\" ]; then\n touch /app/.streamlit/secrets.toml\nelse\n echo \"cred = \\\"${API_KEY}\\\"\" > /app/.streamlit/secrets.toml\nfi\n/bin/bash /app/entrypoint-skyvernui.sh\n" labels: - traefik.http.middlewares.skyvern-auth.basicauth.users=YOUR_KEY_HASH_HERE volumes: skyvern-data: null skyvern-ui-data: null ``` ## C) Update Service URLS 1. Enable "Connect to Predefined Network" 2. Enter your intended URL for the Skyvern service, with ending `:8000`. 3. Turn off `Enable Gzip Compression` for the Skyvern service. 4. Enter your intended URL for the Skyvern UI service, with ending `:8080`. ![[skyvern_coolify_service_stack.png]] ### D) Update Environment Variables 1. Skip `API_KEY` for now (we do this later). 2. Fill in `API_PUBLIC_URL` with `https://your.domain.com/api/v1`. 3. Paste your hashed username and password from the previous step into `BASIC_AUTH_HASH` and check `Is Literal?`. 4. Set any random password in `DB_PASSWORD` (you won't need this later). 5. Enter the `LLM_API_BASE`, `LLM_API_KEY` and `LLM_MODEL_NAME` you'd like to use Skyvern with. 6. Fill in WS_PUBLIC_URL with `wss://your.domain.com/api/v1`. ![[skyvern_coolify_env_vars.png]] ### E) Deploy and Regenerate API Key 1. Deploy the service and wait for it to report `Running`. 2. Visit the Skyvern UI service URL and login with your username and password. 3. Press the `Regenerate API Key` button. 4. Visit Skyvern `Settings` and copy the newly generated `API_KEY` 5. Return to Coolify, and set the `API_KEY` env var to the newly generated key, and check `Is Literal`. 6. Save changes and restart the service. ![[skyvern_regenerate_api_key_dialog.png]] ## Voila! Your Skyvern instance is up and running on Coolify - Enjoy! > **Except, what I recommend now, is uninstalling Skyvern and installing something that doesn't fight so hard against containerization.**