Self-Hosting
Run Crovly on your own infrastructure. Contact us for self-hosting options.
Note: Self-hosting is available as a custom deployment option. Contact us to discuss self-hosting for your organization.
Requirements
- Docker or Node.js 22+
- PostgreSQL 16+
- Redis 7+
- ~256MB RAM, 1 CPU core (handles millions of verifications/day)
Docker Compose
services:
crovly:
image: ghcr.io/crovly/crovly:latest
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://user:pass@db:5432/crovly
REDIS_URL: redis://redis:6379
AUTH_SECRET: your-random-secret-here
AUTH_URL: https://captcha.yourdomain.com
NEXT_PUBLIC_APP_URL: https://captcha.yourdomain.com
NEXT_PUBLIC_APP_NAME: Crovly
depends_on:
- db
- redis
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: crovly
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- redisdata:/data
volumes:
pgdata:
redisdata:Environment Variables
| Variable | Required | Description |
|---|---|---|
DATABASE_URL | Yes | PostgreSQL connection string |
REDIS_URL | Yes | Redis connection string |
AUTH_SECRET | Yes | Random secret for session signing (generate with openssl rand -base64 32) |
AUTH_URL | Yes | Public URL of your instance |
NEXT_PUBLIC_APP_URL | Yes | Same as AUTH_URL — used by the frontend |
NEXT_PUBLIC_APP_NAME | No | Display name (default: Crovly) |
RESEND_API_KEY | No | For transactional emails (password reset, etc.) |
Widget Configuration
Point the widget to your self-hosted API instead of the default:
<script src="https://captcha.yourdomain.com/widget.js"
data-site-key="YOUR_SITE_KEY"
data-api-url="https://captcha.yourdomain.com"></script>
<div id="crovly-captcha"></div>Self-Hosting the Widget
For a fully self-contained setup, host widget.js yourself instead of using the CDN:
- Download
widget.jsfromhttps://get.crovly.com/widget.js - Serve it from your own domain
- Update the script
srcto your domain
<script src="https://captcha.yourdomain.com/widget.js"
data-site-key="YOUR_SITE_KEY"
data-api-url="https://captcha.yourdomain.com"></script>Database Migrations
On first run, the application automatically runs database migrations. No manual setup is required.
Health Check
Verify your instance is running:
curl https://captcha.yourdomain.com/api/health{
"status": "ok",
"checks": { "db": "ok", "redis": "ok" },
"timestamp": "2026-01-01T00:00:00Z"
}Reverse Proxy
If running behind nginx or a load balancer, ensure these headers are forwarded:
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;Crovly uses the client IP for challenge binding and rate limiting. Without proper header forwarding, all requests appear to come from the proxy IP.