OpenQAOpenQA
Deployment

Docker Deployment

Deploy OpenQA using Docker — the recommended method for production. The official image is published on Docker Hub at orkalab/openqa.

📌 Default Port: 4242

OpenQA listens on port 4242 by default. You can change this via the WEB_PORT environment variable.

Docker Hub (Recommended)

Pull the pre-built image directly — no need to clone the repository or build anything.

🎯 Quick Start: Minimal Setup

You can start OpenQA with zero environment variables and configure everything via the web interface:

bash
1# Minimal setup - configure via web UI
2docker run -d \
3 -p 4242:4242 \
4 -v openqa-data:/app/data \
5 --name openqa \
6 orkalab/openqa:latest
7 
8# Then open http://localhost:4242 and configure via UI

This is perfect for demos and development. All configuration (API keys, target URL, etc.) can be done through the /config page.

Full Configuration (Environment Variables)

For production deployments with pre-configured settings:

bash
1# Pull the latest image
2docker pull orkalab/openqa:latest
3 
4# Run with your API key
5docker run -d \
6 -p 4242:4242 \
7 -e LLM_PROVIDER=openai \
8 -e OPENAI_API_KEY=sk-xxx \
9 -e OPENQA_JWT_SECRET=$(openssl rand -hex 32) \
10 -e SAAS_URL=https://your-app.com \
11 -e DATA_PATH=/app/data \
12 -e DB_PATH=/app/data/openqa.db \
13 -v openqa-data:/app/data \
14 --name openqa \
15 orkalab/openqa:latest

🗂️ Why DATA_PATH and DB_PATH?

The Docker image uses an entrypoint script that fixes directory permissions before starting the app. It uses DATA_PATH to know which directory to chown for the unprivileged openqa user.

If DATA_PATH is omitted, the entrypoint defaults to /data — but the volume is mounted at /app/data. The result: the database directory is owned by root and the app cannot write to it.

DB_PATH makes the database path explicit and prevents ambiguity across restarts.

Then open http://localhost:4242 — first run will prompt you to create an admin account.

Available tags

  • orkalab/openqa:latest — latest stable release
  • orkalab/openqa:2.x.x — pinned version (recommended for production)

Simple Deployment (Dokploy, VPS, etc.)

For quick deployment on your server, Dokploy, or any Docker-compatible platform, use this ready-to-go configuration:

📦 One-Click Deploy

Download the files from the repository:

  • docker-compose.simple.yml — Production-ready compose file
  • .env.simple.example — Environment template with all options
bash
1# 1. Download the files
2wget https://raw.githubusercontent.com/Orka-Community/OpenQA/main/docker-compose.simple.yml
3wget https://raw.githubusercontent.com/Orka-Community/OpenQA/main/.env.simple.example
4 
5# 2. Create your .env file
6cp .env.simple.example .env
7 
8# 3. Edit .env with your configuration
9nano .env
10# Required: OPENAI_API_KEY, OPENQA_JWT_SECRET, SAAS_URL
11 
12# 4. Start OpenQA
13docker compose -f docker-compose.simple.yml up -d
14 
15# 5. Access at http://your-server:4242

🔐 Security Reminder

Always generate a strong JWT secret: openssl rand -hex 32

bash
1# Create .env with your keys
2cat > .env <<EOF
3LLM_PROVIDER=openai
4OPENAI_API_KEY=sk-xxx
5OPENQA_JWT_SECRET=$(openssl rand -hex 32)
6SAAS_URL=https://your-app.com
7EOF
8 
9# Start
10docker compose up -d

Build from Source

If you prefer to build the image yourself from the repository:

bash
1# 1. Clone the repository
2git clone https://github.com/Orka-Community/OpenQA.git
3cd OpenQA
4 
5# 2. Build the image
6docker build -t orkalab/openqa:latest .
7 
8# 3. Run
9docker run -d -p 4242:4242 --env-file .env --name openqa orkalab/openqa:latest

Docker Compose Configuration

The production Docker Compose file includes:

yaml
1services:
2 openqa:
3 image: orkalab/openqa:latest
4 platform: linux/amd64
5 container_name: openqa
6 restart: unless-stopped
7 ports:
8 - "${EXTERNAL_PORT:-4242}:4242"
9 environment:
10 - NODE_ENV=production
11 - WEB_PORT=4242
12 - WEB_HOST=0.0.0.0
13 - LLM_PROVIDER=${LLM_PROVIDER:-openai}
14 - OPENAI_API_KEY=${OPENAI_API_KEY}
15 - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
16 - OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-}
17 - SAAS_URL=${SAAS_URL}
18 - OPENQA_JWT_SECRET=${OPENQA_JWT_SECRET}
19 - GITHUB_TOKEN=${GITHUB_TOKEN:-}
20 - GITHUB_OWNER=${GITHUB_OWNER:-}
21 - GITHUB_REPO=${GITHUB_REPO:-}
22 volumes:
23 - openqa_data:/app/data
24 healthcheck:
25 test: ["CMD", "wget", "-qO-", "http://localhost:4242/api/health"]
26 interval: 30s
27 timeout: 10s
28 retries: 3
29 start_period: 40s
30 
31volumes:
32 openqa_data:

💡 Custom Port

To use a different port, set both EXTERNAL_PORT (host) and WEB_PORT (container):

bash
1# Example: Run on port 8080
2EXTERNAL_PORT=8080 WEB_PORT=8080 docker compose up -d

With HTTPS (Nginx)

For production with SSL:

bash
1# 1. Update nginx.conf with your domain
2nano nginx.conf
3 
4# 2. Get SSL certificate
5sudo certbot certonly --standalone -d your-domain.com
6 
7# 3. Start with Nginx profile
8docker-compose -f docker-compose.production.yml --profile with-nginx up -d

Production Dockerfile

The multi-stage Dockerfile optimizes for production:

bash
1# Build stage
2FROM node:20-alpine AS builder
3WORKDIR /app
4COPY package*.json ./
5RUN npm ci
6COPY . .
7RUN npm run build
8 
9# Production stage
10FROM node:20-alpine
11WORKDIR /app
12RUN apk add --no-cache chromium
13ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
14COPY --from=builder /app/dist ./dist
15COPY --from=builder /app/node_modules ./node_modules
16COPY package*.json ./
17USER node
18EXPOSE 4242
19CMD ["node", "dist/cli/index.js", "start"]

Useful Commands

bash
1# View logs
2docker logs -f openqa
3# or with Compose:
4docker compose logs -f
5 
6# Restart
7docker compose restart
8 
9# Stop
10docker compose down
11 
12# Update to latest image
13docker pull orkalab/openqa:latest
14docker compose up -d
15 
16# Backup data volume
17docker cp openqa:/app/data ./backup-$(date +%Y%m%d)

Troubleshooting

Container won't start?

  • • Check logs: docker logs openqa
  • • Verify environment variables are set
  • • Ensure port 4242 is not in use

Playwright/Browser issues?

  • • The Dockerfile installs Chromium automatically
  • • For ARM64 (M1/M2), use --platform linux/amd64

🔥 Firewall blocking access?

If you can access the app locally (curl http://localhost:4242) but not from outside, the firewall is blocking the port.

bash
1# UFW (Ubuntu/Debian)
2sudo ufw allow 4242/tcp
3sudo ufw reload
4 
5# iptables
6sudo iptables -A INPUT -p tcp --dport 4242 -j ACCEPT
7 
8# Check if port is open
9sudo netstat -tlnp | grep 4242

Note: Cloud providers (Hetzner, OVH, DigitalOcean, AWS) often have an additional firewall in their control panel. Make sure to open the port there too!

🐳 Dokploy / Traefik Setup

When using Dokploy or Traefik as a reverse proxy, you need to configure the network and labels correctly.

Step 1: Configure Domain in Dokploy UI
  • • Go to Domains tab
  • • Set Container Port to 4242
  • • Enable HTTPS with Let's Encrypt
Step 2: Complete Docker Compose Configuration

If you get a 404 error, you need to add the Traefik network and labels to your compose file:

yaml
1services:
2 openqa:
3 image: orkalab/openqa:latest
4 platform: linux/amd64
5 container_name: openqa
6 restart: unless-stopped
7 ports:
8 - "8080:4242"
9 environment:
10 - NODE_ENV=production
11 - WEB_PORT=4242
12 - WEB_HOST=0.0.0.0
13 - CORS_ORIGINS=https://your-domain.com
14 - LLM_PROVIDER=${LLM_PROVIDER:-openai}
15 - OPENAI_API_KEY=${OPENAI_API_KEY}
16 - SAAS_URL=${SAAS_URL}
17 - OPENQA_JWT_SECRET=${OPENQA_JWT_SECRET}
18 labels:
19 - "traefik.enable=true"
20 - "traefik.http.routers.openqa-app.rule=Host(`your-domain.com`)"
21 - "traefik.http.routers.openqa-app.entrypoints=websecure"
22 - "traefik.http.routers.openqa-app.tls.certresolver=letsencrypt"
23 - "traefik.http.services.openqa-app.loadbalancer.server.port=4242"
24 networks:
25 - dokploy-network
26 volumes:
27 - openqa_data:/app/data
28 
29volumes:
30 openqa_data:
31 
32networks:
33 dokploy-network:
34 external: true

⚠️ Important: Use openqa-app (not openqa) in Traefik labels to avoid conflicts with Dokploy's auto-generated services.

🔒 CORS: Set CORS_ORIGINS to your domain (e.g., https://your-domain.com) to avoid CORS errors during setup. You can specify multiple origins separated by commas.

Step 3: Verify Traefik Routing
bash
1# Check if Traefik sees the container
2docker logs dokploy-traefik --tail 100 | grep openqa
3 
4# Should NOT show errors like "cannot be linked automatically with multiple Services"
5# If you see this error, rename your router/service in labels (e.g., openqa-app)
6 
7# Restart Traefik if needed
8docker restart dokploy-traefik

⚠️ 404 Page Not Found?

This usually means the reverse proxy is routing to the wrong port. Verify:

  • • Container Port in Dokploy/Traefik is set to 4242 (not 3000)
  • • Check logs: docker logs openqa should show "url":"http://0.0.0.0:4242"
  • • Test locally: curl http://localhost:4242 should return HTML

🔧 Quick Diagnostic Commands

bash
1# Check container is running with correct port mapping
2docker ps | grep openqa
3# Should show: 0.0.0.0:4242->4242/tcp
4 
5# Test from inside the server
6curl http://localhost:4242
7# Should return: Found. Redirecting (or HTML)
8 
9# Check what port the app is listening on
10docker logs openqa | grep "running"
11# Should show: "url":"http://0.0.0.0:4242"

🚫 CORS Error: origin not allowed?

If you see Error: CORS: origin https://your-domain.com not allowed in the logs when creating an account:

bash
1# Add CORS_ORIGINS environment variable (note the S at the end!)
2# In your docker-compose.yml or Dokploy environment settings:
3CORS_ORIGINS=https://your-domain.com
4 
5# Multiple origins (comma-separated):
6CORS_ORIGINS=https://your-domain.com,https://www.your-domain.com
7 
8# Then redeploy
9docker compose down && docker compose up -d

Note: The CORS_ORIGINS must match exactly the domain you're accessing the app from (including https://). Use CORS_ORIGINS (with an S), not CORS_ORIGIN.

⚠️ X-Forwarded-For validation error?

If you see ValidationError: The 'X-Forwarded-For' header is set but the Express 'trust proxy' setting is false:

This is fixed in the latest version. Make sure you're using orkalab/openqa:latest and redeploy. The app now correctly handles reverse proxies like Traefik and Nginx.