There are a lot of different ways to host a server, but the absolute easiest is to start up a Docker Compose stack with everything in it.
🔗Docker Compose
The example below will set up a minimal server:
# Create the stack directory
mkdir refrain
cd refrain
mkdir tls jwks
touch docker-compose.yml
Next, copy the YAML below into refrain/docker-compose.yml file:
volumes:
postgres-data:
rabbitmq-data:
minio-data:
services:
postgres:
image: postgres:18.3
shm_size: 128mb
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: refrain
PGDATA: /var/lib/postgresql
volumes:
- postgres-data:/var/lib/postgresql
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U postgres -d refrain" ]
interval: 5s
timeout: 5s
retries: 5
start_period: 5s
rabbitmq:
image: rabbitmq:4.3-management
environment:
RABBITMQ_DEFAULT_USER: rabbitmq
RABBITMQ_DEFAULT_PASS: refrain
volumes:
- rabbitmq-data:/var/lib/rabbitmq
healthcheck:
test: [ "CMD-SHELL", "rabbitmq-diagnostics -q check_running && rabbitmq-diagnostics -q check_local_alarms" ]
interval: 10s
timeout: 10s
retries: 5
start_period: 5s
minio:
image: pgsty/minio:RELEASE.2026-04-17T00-00-00Z
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin-secret
command: server /data --console-address ":9001"
volumes:
- minio-data:/data
healthcheck:
test: [ "CMD", "mc", "ready", "local" ]
interval: 5s
timeout: 5s
retries: 10
init-minio:
image: pgsty/mc:RELEASE.2026-04-17T00-00-00Z
entrypoint: >
/bin/bash -c "
while true; do
mc alias set local http://minio:9000 minioadmin minioadmin-secret
if [[ $? == 0 ]]; then
break
fi
sleep 1
done
mc mb --ignore-existing local/refrain
mc admin user add local refrain-client refrain-client-secret
mc admin policy attach local readwrite --user refrain-client
echo 'Bucket and client user created successfully.'
"
refrain:
image: monitorjbl/refrain
restart: always
command:
- standalone
depends_on:
postgres:
condition: service_healthy
rabbitmq:
condition: service_healthy
minio:
condition: service_healthy
ports:
- "8443:8443/tcp"
- "8443:8443/udp"
environment:
REFRAIN__DATABASE__URL: "postgres://postgres:postgres@postgres:5432/refrain"
REFRAIN__RABBITMQ__URL: "amqp://rabbitmq:refrain@rabbitmq:5672"
REFRAIN__OBJECT_STORAGE__URL: "http://minio:9000"
volumes:
# Mount your configuration file into the server (optional, omitting it will use the default config)
# - ./refrain.toml:/opt/refrain/refrain.toml
# Mount your JWKS dir into the server (optional, but not doing this means your server will have a different signing key at each startup)
- ./jwks:/opt/refrain/jwks
# Mount your TLS dir into the server (optional, but not doing this means your server will have a different TLS key at each boot)
- ./tls:/opt/refrain/tls
Now, start your server!
docker compose up
This will start a server with the default configuration and self-signed keys. Once everything boots up, you can access your server at https://localhost:8443. The default username/password is "admin/refrain1234!".
More example deployments with Docker can be found here.
🔗Kubernetes
Kubernetes is a great deployment platform, though not too many people have it in their homelab these days. If you are one of the crazy, brilliant few that both want to host your
own services and maintain a k8s installation, you can use the example deployments found here. No Helm chart
yet, but good ol' kubectl apply -f still works just fine!
🔗Barebones
This is an example of starting the refrain-server binary yourself. The external dependencies are still required, and in this example we are going to start them with Docker. However, the configuration TOML can be updated to point to any properly-configured Postgres/RabbitMQ/S3 service. There isn't much of a good reason to do this in most cases, but it is a useful illustration of how the service actually runs. For more customized deployments, hopefully this helps!
curl -o refrain-server.zip -L https://s3.us-east-1.amazonaws.com/refrain.gg/releases/latest/server/refrain-server-linux-amd64.zip
unzip refrain-server.zip -d ./refrain
cd ./refrain
touch docker-compose.yml
Now, copy the following into the docker-compose.yml file:
volumes:
postgres-data:
rabbitmq-data:
minio-data:
services:
postgres:
image: postgres:18.3
shm_size: 128mb
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: refrain
PGDATA: /var/lib/postgresql
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql
rabbitmq:
image: rabbitmq:4.3-management
environment:
RABBITMQ_DEFAULT_USER: rabbitmq
RABBITMQ_DEFAULT_PASS: refrain
ports:
- "5672:5672"
volumes:
- rabbitmq-data:/var/lib/rabbitmq
minio:
image: pgsty/minio:RELEASE.2026-04-17T00-00-00Z
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin-secret
ports:
- "9000:9000"
command: server /data --console-address ":9001"
volumes:
- minio-data:/data
healthcheck:
test: [ "CMD", "mc", "ready", "local" ]
interval: 5s
timeout: 5s
retries: 10
init-minio:
image: pgsty/mc:RELEASE.2026-04-17T00-00-00Z
entrypoint: >
/bin/bash -c "
while true; do
mc alias set local http://minio:9000 minioadmin minioadmin-secret
if [[ $? == 0 ]]; then
break
fi
sleep 1
done
mc mb --ignore-existing local/refrain
mc admin user add local refrain-client refrain-client-secret
mc admin policy attach local readwrite --user refrain-client
echo 'Bucket and client user created successfully.'
"
Boot up the dependencies with docker compose up -d and wait for them to finish starting. Finally, start the server:
./refrain-server standalone
You can now access Refrain at https://localhost:8443! This is not a great way to host refrain, but it can be done relatively painlessly.