apps/web/content/docs/self-hosting.mdx
Cap Web is our web application for uploading and sharing Caps - it's what runs right here on Cap.so. You can upload videos to it from the dashboard or from Cap Desktop.
<CapEmbed src="https://cap.so/embed/k310v2vf41d6ffp" />The fastest way to self-host Cap is with Docker Compose. This single command will start everything you need:
git clone https://github.com/CapSoftware/Cap.git
cd Cap
docker compose up -d
That's it! Cap will be available at http://localhost:3000.
Login links will appear in the logs since email isn't configured:
docker compose logs cap-web
Best for VPS, home servers, or any Docker-capable host.
What's included:
Steps:
docker compose up -dhttp://localhost:3000Note: The main
docker-compose.ymlbuilds the media server from source, so a full clone of the repository is required. The Coolify compose file uses a pre-built image fromghcr.ioinstead.
Custom configuration:
Create a .env file to customize your deployment:
# Public URL (required for production)
CAP_URL=https://cap.yourdomain.com
# S3 public URL (for video playback)
S3_PUBLIC_URL=https://s3.yourdomain.com
# Optional: Custom ports
CAP_PORT=3000
MINIO_PORT=9000
# Optional: Custom passwords (auto-generated if not set)
MYSQL_PASSWORD=your-secure-password
MINIO_ROOT_PASSWORD=your-minio-password
Railway provides a fully managed deployment with automatic SSL and scaling. Login credentials appear in Railway's Deploy Logs after deployment.
For Coolify users, use docker-compose.coolify.yml which includes environment variable placeholders:
docker-compose.coolify.ymlNote: The Coolify compose file uses slightly different environment variable names:
WEB_URLinstead ofCAP_URL, andS3_PUBLIC_ENDPOINTinstead ofS3_PUBLIC_URL.
https://cap.yourdomain.com)By default, login links are printed to the server logs. To send emails:
RESEND_API_KEY=re_xxxxx
RESEND_FROM_DOMAIN=yourdomain.com
For video transcription and AI summaries:
DEEPGRAM_API_KEY=your-key # Transcription
GROQ_API_KEY=your-key # AI summaries (preferred)
OPENAI_API_KEY=your-key # AI summaries (fallback)
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-secret
NEXTAUTH_SECRET)DATABASE_ENCRYPTION_KEY)MEDIA_SERVER_WEBHOOK_SECRET)This is fine for local development or testing on a private network, but you must generate unique secrets before exposing Cap to the internet. </Warning>
Generate secure secrets:
openssl rand -hex 32
Run this command three times to generate values for:
NEXTAUTH_SECRETDATABASE_ENCRYPTION_KEYMEDIA_SERVER_WEBHOOK_SECRETFull production checklist:
MYSQL_PASSWORD, MINIO_ROOT_PASSWORDDATABASE_ENCRYPTION_KEY, NEXTAUTH_SECRET, MEDIA_SERVER_WEBHOOK_SECRETCAP_URL to your public URLS3_PUBLIC_URL to your MinIO/S3 public URL┌─────────────────┐ ┌─────────────────┐
│ Cap Desktop │────▶│ Cap Web │
└─────────────────┘ │ (port 3000) │
└────────┬────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ MySQL │ │ MinIO │ │ Media │
│ (3306) │ │ (9000) │ │ Server │
└──────────┘ └──────────┘ └──────────┘
See packages/env/server.ts for all available options.
Can't access Cap after starting:
docker compose logs cap-web
Database migration issues:
docker compose down -v # Warning: deletes data
docker compose up -d
Reset everything:
docker compose down -v
docker compose up -d
If you encounter issues with self-hosting:
We do not offer direct support for self-hosted deployments.