A practical walkthrough of the repository's Docker Compose stack: what each service does, which keys you need, how to run without cloud AI, and what to harden before production.
By SupoClip · Updated · 9 min read
SupoClip is the open-source AI video clipper behind the hosted app at supoclip.com. The same repository ships a Docker Compose stack you can run on a laptop, a home server, or a VPS. This guide follows that stack exactly as it exists in the repository. Where a step depends on your provider or hardware, we say so instead of guessing.
docker compose up starts these containers, all defined in docker-compose.yml:
Services in the SupoClip Docker Compose stack
Service
Role
Host port
frontend
Next.js web app, auth, and API proxy
FRONTEND_PORT (3107 in .env.example; 3001 if unset)
backend
FastAPI API; docs at /docs
8000
worker
ARQ worker: download, transcribe, analyze, render
none
postgres
PostgreSQL 15: users, tasks, clips
none
redis
Redis 7: job queue and live progress
6379
mcp
MCP server for AI clients (optional to keep running)
9100
Every published port is bound to 127.0.0.1, so a fresh install is reachable only from the machine itself. Generated clips, uploads, Postgres, and Redis are stored in named Docker volumes, so they survive container restarts. If you don't use MCP, stop that container with docker compose stop mcp.
Requirements
Docker with Compose v2 (docker compose) or the standalone docker-compose, plus Git.
A transcription source, set with TRANSCRIPTION_PROVIDER:assemblyai (default, needs ASSEMBLY_AI_API_KEY), whisper (local, no key), or youtube_captions (YouTube links only).
An LLM for clip selection, set with LLM=provider:model: OpenAI, Google, Anthropic, OpenRouter (each needs its API key), or a local ollama: model.
Optional:PEXELS_API_KEY for B-roll overlays.
The first image build downloads Python and Node dependencies. The quick start estimates 5–10 minutes; it varies with your connection and CPU.
Install with Docker Compose
1. Clone and create your environment file
terminal
git clone https://github.com/FujiwaraChoki/supoclip.git
cd supoclip
cp .env.example .env
2. Pick providers in .env
The template defaults to LLM=openrouter:anthropic/claude-sonnet-5.5. Processing fails unless you set OPENROUTER_API_KEY or point LLM at a provider you have a key for. A minimal cloud setup looks like this:
.env
TRANSCRIPTION_PROVIDER=assemblyai
ASSEMBLY_AI_API_KEY=your_assemblyai_key
LLM=google-gla:gemini-3-flash-preview
GOOGLE_API_KEY=your_google_key
# Replace every placeholder secret, even for local use
BETTER_AUTH_SECRET=generate_with_openssl_rand_base64_32
BACKEND_AUTH_SECRET=generate_another_one
APP_SETTINGS_ENCRYPTION_KEY=and_another_one
Generate each secret with openssl rand -base64 32. SELF_HOST=true (the default) keeps billing off and removes per-account generation limits.
3. Build and start
terminal
docker compose up -d --build
# or: ./start.sh (checks .env and Docker first, then does the same)
Open http://localhost:3107, create an account, and paste a YouTube link or upload a file. API docs are at http://localhost:8000/docs.
Option: fully local transcription and clip selection
To keep transcripts and analysis on your own hardware, combine local Whisper with an Ollama model:
.env
TRANSCRIPTION_PROVIDER=whisper
WHISPER_MODEL_SIZE=medium # tiny | base | small | medium | large | large-v3
LLM=ollama:gpt-oss:20b
# Empty = http://host.docker.internal:11434/v1 inside the containers.
# If you set it yourself, keep the /v1 suffix.
OLLAMA_BASE_URL=
The worker makes the Ollama calls from inside its container, so Ollama must be reachable from there, not just from your shell. How you get there depends on where Ollama runs:
Ollama on the host, with Docker Desktop (macOS, Windows)
No extra setup. Docker Desktop forwards host.docker.internal to the host, so leave OLLAMA_BASE_URL empty and pull the model with ollama pull gpt-oss:20b.
Ollama on the host, with Docker Engine (Linux)
Compose maps host.docker.internal to the Docker bridge gateway, but Ollama listens only on 127.0.0.1 by default, so the worker's connection is refused. Make Ollama listen on all interfaces:
That also exposes port 11434 on your network interfaces. Ollama has no authentication, so block that port from outside the machine with your firewall. If your firewall filters traffic from Docker networks, also allow the containers to reach it.
Ollama in its own container
Add it to the stack with an override file, then point SupoClip at the service name instead of the host:
docker-compose.override.yml (merge into any override you already have)
OLLAMA_BASE_URL=http://ollama:11434/v1
docker compose up -d ollama
docker compose exec ollama ollama pull gpt-oss:20b
docker compose up -d backend worker # pick up the new .env value
Whichever setup you choose, test from inside the worker before submitting a video. The check looks for gpt-oss:20b because that is the model in the example LLM value. If you chose another model, replace it with the exact name after ollama: in your LLM setting. Ollama lists a model pulled without a tag as name:latest, so use that form in the check.
model ready means the worker can reach Ollama and the model you searched for is installed. No output means either the connection failed or the model is missing, so rerun the command without the grep to see which. Smaller Whisper models trade accuracy for speed, and clip quality depends on the LLM. Compare a local model against a hosted one on a recording you know before switching your whole backlog.
Verify the install
terminal
docker compose ps # every service should be "healthy"
curl -f http://localhost:8000/health/db # backend can reach Postgres
docker compose logs -f worker # watch a job move through the pipeline
Create an account and submit a short video first, so a misconfiguration fails fast.
Confirm the task page shows progress updates. If it stays queued, check the worker logs.
Play and download a finished clip.
Stuck tasks are usually a missing provider key or a worker that cannot reach Redis. The troubleshooting guide covers the common cases.
Production checklist
The Compose file is tuned for getting started. Before putting it on a public domain:
Build the production frontend. Compose defaults to the hot-reloading development target and mounts frontend/src into the container. Set FRONTEND_BUILD_TARGET=runner and NODE_ENV=production in .env, then drop the source mounts with the override below.
Terminate HTTPS at a reverse proxy (Caddy, nginx, Traefik) in front of the frontend port.
Expose the backend for uploads. With BACKEND_AUTH_SECRET set, browsers upload video files directly to NEXT_PUBLIC_API_URL. Point that at a public HTTPS backend URL, and add your frontend origin to CORS_ORIGINS.
Set your public origin everywhere:NEXT_PUBLIC_APP_URL, BETTER_AUTH_URL, and CORS_ORIGINS. NEXT_PUBLIC_* values are baked in at build time, so rebuild the frontend after changing them.
Change the database password.docker-compose.yml hardcodes supoclip_password in four places: POSTGRES_PASSWORD in the postgres service and DATABASE_URL in the frontend, backend, and worker services. Editing POSTGRES_PASSWORD in .env alone changes none of them. Override all four, as shown below.
Set REDIS_PASSWORD; the Redis container enables AUTH when it is non-empty.
Close sign-ups with DISABLE_SIGN_UP=true if the instance is just for your team.
Review the limits:MAX_VIDEO_DURATION (default 5400 s, 90 minutes) and MAX_VIDEO_UPLOAD_BYTES (about 12 GB).
docker-compose.override.yml (Compose v2.24+)
services:
frontend:
volumes: !reset [] # the runner image already contains the build
For the database password, put a new value in POSTGRES_PASSWORD in .env. Generate it with openssl rand -hex 24, because hex needs no escaping inside a URL. Then point all four settings at it in the same override file:
docker-compose.override.yml (merge into any override you already have)
Postgres reads POSTGRES_PASSWORD only when it initializes an empty data volume. On an install that already has a database, changing that variable does not change the actual password. Rotate it inside Postgres first, using the same value as in .env. Then recreate the services so they use the new URLs:
init.sql creates the schema only when the Postgres volume is first initialized. After that, nothing updates the schema automatically. If a new version adds files under frontend/prisma/migrations or backend/migrations, apply them yourself before you restart the app. New code running against the old schema fails on missing columns and tables. Back up first, and stop the app services so they don't pick up new code early. The development frontend hot-reloads mounted source.
A database created by init.sql has no Prisma migration history. Don't run prisma migrate deploy against it: Prisma would replay every migration from the first one and fail on tables that already exist. If you want Prisma to manage migrations from now on, first baseline it with prisma migrate resolve --applied <migration>, but only for migrations whose changes are already in your schema. Prisma permanently skips any migration you mark as applied, even if its changes are missing.
Back up the clips and uploads volumes too if you need to keep rendered videos. Never run docker compose down -v on an instance you care about: it deletes every volume, including the database.
Want to customize the output? Drop .ttf fonts into backend/fonts/ and .mp4 transitions into backend/transitions/. They appear in the app automatically. For automation, create an API key in Settings and use the REST API or the bundled MCP server.
Frequently asked questions
Is self-hosted SupoClip free?
The code is free under AGPL-3.0 and self-host mode has no generation limits or paywall. You still pay for your own hardware or server, and for any cloud transcription or LLM usage you configure. A Whisper + Ollama setup avoids per-request AI fees but needs enough local compute.
Can SupoClip run without any cloud AI services?
Yes, for clip analysis. Set TRANSCRIPTION_PROVIDER=whisper to transcribe locally and LLM=ollama:<model> to select clips with a local model. Downloading YouTube links still needs internet access; uploaded files do not. Optional B-roll uses the Pexels API.
Do I need a GPU?
No. The .env.example template sets BACKEND_CPU_ONLY=true, which installs CPU-only PyTorch. CPU-only Whisper transcription is slower than a cloud API, so long videos take longer on modest hardware.
Does it work on Apple Silicon?
Yes, with a caveat: the backend and worker images run as linux/amd64 under emulation. BACKEND_CPU_ONLY=true avoids NVIDIA downloads, but it does not enable Apple GPU acceleration.
How do I keep my instance private?
Create your account, then set DISABLE_SIGN_UP=true and recreate the frontend container. Compose binds every port to 127.0.0.1, so nothing is public until you add a reverse proxy.
Try it on one recording you know well.
Use the hosted app, or run the same open-source code on your own machine.