Docker Compose
The recommended way to run ravyn. Three containers, prebuilt images, no Rust toolchain required on the host.
1. Prerequisites
A Linux server with Docker and the Compose plugin:
docker --version docker compose version
If either is missing, follow Docker's own install guide for your distro first.
2. Get the compose file
mkdir ravyn && cd ravyn curl -O https://tryravyn.com/docker-compose.yml
It looks like this:
services: db: image: postgres:16-alpine environment: POSTGRES_PASSWORD: change-me POSTGRES_DB: ravyn volumes: - db-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 2s timeout: 5s retries: 15 api: image: ghcr.io/officialaudite/ravyn-api:latest environment: DATABASE_URL: postgres://postgres:change-me@db:5432/ravyn STORAGE_ROOT: /data THUMBNAIL_ROOT: /data/thumbnails LISTEN_ADDR: 0.0.0.0:3000 # the domain people will actually see, not the container's own address RAVYN_PUBLIC_API_URL: https://files.example.com ports: - "3000:3000" volumes: - storage:/data depends_on: db: condition: service_healthy web: image: ghcr.io/officialaudite/ravyn-web:latest environment: RAVYN_API_URL: http://api:3000 RAVYN_PUBLIC_API_URL: https://files.example.com ports: - "3001:3001" depends_on: - api volumes: db-data: storage:
change-me placeholders to a real password
before starting this anywhere reachable from the internet.
3. Point it at your domain
Edit RAVYN_PUBLIC_API_URL on both services to
the domain you'll actually use. This is what gets embedded in
share links and Discord/Slack webhook payloads, and it has to
match what a visitor's browser can reach - not the internal
api:3000 container address.
4. Start it
docker compose up -d
ravyn-web is on port 3001,
ravyn-api on 3000. Put a reverse proxy in
front of both for TLS - see the Caddy snippet below.
5. Create the first account
Open the site and register. The very first account on a fresh
instance always becomes admin automatically - there's no separate
setup step. From /admin that account decides whether
anyone else can sign up.
Reverse proxy with Caddy
A minimal Caddyfile for two subdomains, one for the
app and one for direct file/API links:
files.example.com {
reverse_proxy localhost:3001
}
api.example.com {
reverse_proxy localhost:3000
}
Caddy issues and renews TLS certificates automatically. If you'd
rather run everything off one domain, proxy /api/*
and file routes to :3000 and everything else to
:3001 - ravyn-web already proxies most of what a
browser needs, so a single domain works too; see the README's
Docker section for the exact route list.
S3-compatible storage
Local disk is the default. To use S3, R2, MinIO, or anything
S3-compatible, add these to the api service instead
of (or alongside) STORAGE_ROOT:
| Variable | Meaning |
|---|---|
STORAGE_BACKEND | s3 |
S3_BUCKET | bucket name |
S3_REGION | region, or auto for R2/most others |
S3_ENDPOINT | custom endpoint URL, unset for real AWS S3 |
S3_ACCESS_KEY_ID | access key |
S3_SECRET_ACCESS_KEY | secret key |
Updating
docker compose pull docker compose up -d
Backing up
Two things need backing up: the db-data volume
(a pg_dump is easiest) and either your
storage volume (local disk) or your S3 bucket's own
backup/versioning, depending which you picked.
docker compose exec db pg_dump -U postgres ravyn > backup.sql