Install with Docker Compose
This guide installs the ReputeCast Docker Compose stack, PostgreSQL and the app, on a server and prepares it for a reverse proxy. For a ten-minute trial on your own computer, follow the quickstart instead.
Before you begin
Section titled “Before you begin”- A server that meets the system requirements, with Docker Engine and the Docker Compose
plugin (
docker compose). - A DNS name for ReputeCast, such as
news.example.com, pointing at the server. - A reverse proxy that terminates TLS, or a plan for one: reverse proxy and TLS has configurations for Caddy, nginx and Traefik.
Install ReputeCast
Section titled “Install ReputeCast”-
Create a folder for ReputeCast and download the Compose file into it:
Terminal window mkdir -p /opt/reputecast && cd /opt/reputecastcurl -fsSL https://raw.githubusercontent.com/hostrepute/reputecast/main/deploy/docker-compose.yml -o docker-compose.yml -
Create a
.envfile next to it with at least your public URL, the first Owner’s email and a database password (see production settings in .env). -
Start the stack:
Terminal window docker compose up -dCompose starts PostgreSQL, waits until it is healthy, then starts the app. On its first start the app creates its secret key, applies the database migrations and creates the first Owner.
-
Read the first Owner’s temporary password from the logs:
Terminal window docker compose logs app | grep -A4 "ReputeCast is installed"Output app-1 | ReputeCast is installed.app-1 |app-1 | Sign in at https://news.example.comapp-1 | Email [email protected]app-1 | Password SHLn-zHfR-cf6j-NEm5 (temporary: you'll replace it at first sign-in)The banner is printed once, when the first Owner is created.
-
Put your reverse proxy in front of port 8080, open the public URL and sign in. The first sign-in asks you to replace the temporary password, add a passkey or an authenticator app, save recovery codes, confirm the instance basics and create the first workspace.
The Compose file, line by line
Section titled “The Compose file, line by line”This is deploy/docker-compose.yml as published:
# Production-style stack: `docker compose -f deploy/docker-compose.yml up -d`# Set REPUTECAST_PUBLIC_URL and REPUTECAST_ADMIN_EMAIL (in .env next to this# file or your shell) before the first start; the first Owner's temporary# password is printed in the logs: docker compose logs app | grep Passwordname: reputecast
services: postgres: image: postgres:18-alpine restart: unless-stopped environment: POSTGRES_USER: reputecast POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-reputecast} POSTGRES_DB: reputecast volumes: - pgdata:/var/lib/postgresql healthcheck: test: ["CMD-SHELL", "pg_isready -U reputecast -d reputecast"] interval: 5s timeout: 3s retries: 20
app: # REPUTECAST_IMAGE=reputecast with REPUTECAST_VERSION=local runs an image # built from a checkout (make docker VERSION=local). image: ${REPUTECAST_IMAGE:-ghcr.io/hostrepute/reputecast}:${REPUTECAST_VERSION:-latest} restart: unless-stopped depends_on: postgres: condition: service_healthy ports: - "${REPUTECAST_PORT:-8080}:8080" environment: REPUTECAST_DATABASE__URL: postgres://reputecast:${POSTGRES_PASSWORD:-reputecast}@postgres:5432/reputecast?sslmode=disable REPUTECAST_HTTP__PUBLIC_URL: ${REPUTECAST_PUBLIC_URL:-http://localhost:8080} REPUTECAST_AUTO_MIGRATE: "true" REPUTECAST_AUTO_INSTALL: "true" # Set when ReputeCast runs behind a reverse proxy (CIDRs or IPs): # REPUTECAST_HTTP__TRUSTED_PROXIES: 172.16.0.0/12 volumes: - appdata:/var/lib/reputecast
volumes: pgdata: appdata:- Header comment.
grep Passwordprints only the password line;grep -A4 "ReputeCast is installed"shows the whole banner with the sign-in address and email. name: reputecastfixes the project name, whatever the folder is called. Docker names the volumesreputecast_pgdataandreputecast_appdataand the networkreputecast_default.postgresruns PostgreSQL 18 with a database and user both calledreputecast.restart: unless-stoppedbrings it back after a reboot. The password comes fromPOSTGRES_PASSWORD(defaultreputecast: change it).pgdata:/var/lib/postgresqlis where PostgreSQL 18 images keep their data (older images used/var/lib/postgresql/data).healthcheckrunspg_isreadyevery 5 seconds, up to 20 times.depends_on … condition: service_healthymakes the app wait for it.imageisghcr.io/hostrepute/reputecast:latestunless you setREPUTECAST_IMAGEorREPUTECAST_VERSION. Image tags are the release tags (with their leadingv) andlatest.portspublishes the app’s port 8080 on the host port inREPUTECAST_PORT(default8080).REPUTECAST_DATABASE__URLpoints the app at thepostgresservice with the same password.REPUTECAST_HTTP__PUBLIC_URLis set fromREPUTECAST_PUBLIC_URL. ReputeCast uses it for provider webhooks, SSO redirects, passkeys, public pages and every link in emails. With the defaulthttp://localhost:8080, none of these work from outside the server.REPUTECAST_ADMIN_EMAILis the first Owner’s email, used only while the database has no users.REPUTECAST_AUTO_MIGRATEandREPUTECAST_AUTO_INSTALLturn on migrations at start and the creation of the first Owner. The image’s command,serve --auto-migrate --auto-install, already passes both flags.REPUTECAST_HTTP__TRUSTED_PROXIESis commented out; see trusted proxies.appdata:/var/lib/reputecastkeeps the secret key (secret.key) and uploaded files (files/). The image pointsREPUTECAST_SECRETS__KEY_FILEthere, logs as JSON (REPUTECAST_LOG__FORMAT=json) and runs as usernonroot(uid 65532).
Production settings in .env
Section titled “Production settings in .env”Compose reads .env from the project folder to fill the ${…} placeholders in the file:
# The address people and sending providers use, without a trailing slash.REPUTECAST_PUBLIC_URL=https://news.example.com# The first Owner (used only on the first start).# Database password: letters and digits only, because it is part of a URL.POSTGRES_PASSWORD=replace-with-the-output-of-openssl-rand-hex-24# Listen on the loopback interface only, for a reverse proxy on this server.REPUTECAST_PORT=127.0.0.1:8080# Pin the release you run instead of latest.REPUTECAST_VERSION=v1.4.2- Generate the database password with
openssl rand -hex 24. Set it before the first start: the PostgreSQL image appliesPOSTGRES_PASSWORDonly when it creates an empty data volume (postgres image documentation, checked October 2026). REPUTECAST_PORT=127.0.0.1:8080publishes127.0.0.1:8080:8080, so only a proxy on the same server reaches the app. Leave it unset when the proxy runs as another service in this Compose project..envonly fills the placeholders. A variable the Compose file doesn’t mention, such asREPUTECAST_LOG__LEVEL, never reaches the container from.env. Add those todocker-compose.override.ymlinstead.
Other settings in docker-compose.override.yml
Section titled “Other settings in docker-compose.override.yml”Compose merges a docker-compose.override.yml in the same folder into docker-compose.yml automatically
(merge rules, checked October 2026). Keeping
your changes there lets you replace docker-compose.yml with a newer copy without editing it again:
services: app: environment: REPUTECAST_HTTP__TRUSTED_PROXIES: 172.18.0.0/16 REPUTECAST_DNS__SERVERS: 10.0.0.53:53Every setting has an environment variable: see the configuration reference and configure ReputeCast.
Trusted proxies
Section titled “Trusted proxies”ReputeCast uses the client’s IP address for sign-in rate limits, lockouts, sessions and the audit log. Behind a proxy
every request arrives from the proxy, so ReputeCast reads X-Forwarded-For (or X-Real-IP), but only from addresses
in http.trusted_proxies. From anyone else the header is ignored, so it can’t be spoofed.
-
Find the subnet of the project’s network:
Terminal window docker network inspect reputecast_default --format '{{(index .IPAM.Config 0).Subnet}}'A proxy that runs as a container in this network connects from an address in it. A proxy on the server itself reaches the published port through Docker’s gateway, which is in the same subnet.
-
Set it as
REPUTECAST_HTTP__TRUSTED_PROXIESindocker-compose.override.yml(several values: separate them with commas, such as172.18.0.0/16,10.0.0.5). -
Apply it with
docker compose up -d.
Check that it worked
Section titled “Check that it worked”docker compose psshowspostgresashealthyandappas running.curl http://127.0.0.1:8080/readyzanswersready(503 database unavailablewhen PostgreSQL can’t be reached).docker compose exec app /usr/local/bin/reputecast migrate statuslists no migration aspending.- The public URL opens the ReputeCast sign-in page through your proxy.
Troubleshooting
Section titled “Troubleshooting”- The banner says
Sign in at http://localhost:8080:REPUTECAST_PUBLIC_URLwas not set. Add it to.envand rundocker compose up -d; you can also correct the public URL during the first sign-in, in the Instance basics step. grepfinds no banner: the database already had users, for example because thereputecast_pgdatavolume is from an earlier install. Reset the Owner’s password from the server instead:docker compose exec app /usr/local/bin/reputecast user reset-password --email [email protected](recover access).- The app container stops with
Error: owner email: missing (pass --email or set REPUTECAST_ADMIN_EMAIL): the database is empty and no Owner email reached the container. SetREPUTECAST_ADMIN_EMAILand start it again. - The app can’t connect to PostgreSQL after you changed
POSTGRES_PASSWORD: the volume still has the old password. Put the old value back, or change the user’s password in PostgreSQL to match (docker compose exec postgres psql -U reputecast -c "ALTER USER reputecast PASSWORD '…'"). Bind for 0.0.0.0:8080 failed: port is already allocated: another service uses port 8080. SetREPUTECAST_PORTto a free port and point the proxy at it.- Every visitor shows the proxy’s address in sessions and the audit log: set trusted proxies.
Related
Section titled “Related”- Reverse proxy and TLS
- First sign-in and instance setup
- Back up and restore and upgrade ReputeCast
- Install the binary to run ReputeCast without Docker