Skip to content

Self-Hosting ReviewInbox

ReviewInbox self-hosting uses Docker Compose with separate web, api, worker, and postgres services. Run it behind your own HTTPS reverse proxy on a VPS.

ReviewInbox is in early alpha. Pin a semver release and read release notes before upgrading.

  • A Linux VPS with Docker and Docker Compose.
  • A domain name pointing to the VPS.
  • An HTTPS reverse proxy such as Traefik, Caddy, or Nginx.
  • A pinned ReviewInbox release version, for example 0.1.0.

Create an application directory:

Terminal window
sudo mkdir -p /opt/reviewinbox
sudo chown "$USER":"$USER" /opt/reviewinbox
cd /opt/reviewinbox

Download the Compose and environment files:

Terminal window
curl -fsSLO https://raw.githubusercontent.com/reviewinbox/reviewinbox/main/docker-compose.self-hosted.yml
curl -fsSLo .env.self-hosted https://raw.githubusercontent.com/reviewinbox/reviewinbox/main/.env.self-hosted.example

Generate secrets:

Terminal window
openssl rand -base64 32 # BETTER_AUTH_SECRET
openssl rand -base64 32 # APP_ENCRYPTION_KEY

Edit .env.self-hosted:

Terminal window
nano .env.self-hosted
chmod 600 .env.self-hosted

Set these required values:

  • REVIEWINBOX_VERSION: the exact semver release to run.
  • APP_PUBLIC_URL: your public HTTPS origin, for example https://reviewinbox.example.com.
  • BETTER_AUTH_URL: the same public HTTPS origin when using one domain.
  • BETTER_AUTH_TRUSTED_ORIGINS: the same public HTTPS origin.
  • BETTER_AUTH_SECRET: one generated base64 value.
  • APP_ENCRYPTION_KEY: one generated base64 value. This encrypts Store Credentials.
  • POSTGRES_PASSWORD: a strong database password.

Do not commit .env.self-hosted, attach it to support tickets, or include it in broad log bundles. It contains credentials for auth, Store Credential encryption, Postgres, SMTP, AI, and object storage.

Start the stack:

Terminal window
docker compose --env-file .env.self-hosted -f docker-compose.self-hosted.yml up -d

Check service status:

Terminal window
docker compose --env-file .env.self-hosted -f docker-compose.self-hosted.yml ps
docker compose --env-file .env.self-hosted -f docker-compose.self-hosted.yml logs -f api

AI drafting is optional. Without it, ReviewInbox still imports Reviews and supports manual Reply Draft editing, but it will not generate autogenerated Reply Drafts.

Enable AI-generated Reply Drafts with an OpenAI-compatible provider:

AI_PROVIDER=openai-compatible
AI_MODEL=gpt-4.1-mini
AI_API_KEY=your-provider-key
AI_BASE_URL=

Set AI_BASE_URL only when your provider requires a custom OpenAI-compatible endpoint.

Use one public domain:

  • Route /api/* to 127.0.0.1:3000.
  • Route all other requests to 127.0.0.1:8080.

This keeps Better Auth cookies and browser requests simple. The web container calls the API through relative /api paths by default.

reviewinbox.example.com {
reverse_proxy /api/* 127.0.0.1:3000
reverse_proxy 127.0.0.1:8080
}

Caddy manages HTTPS automatically when the domain points to the VPS.

server {
listen 80;
server_name reviewinbox.example.com;
location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

Use Certbot or your preferred ACME client to enable HTTPS.

If Traefik runs on the same Docker host, attach ReviewInbox services to your Traefik network and add labels with a compose override:

services:
api:
networks:
- default
- traefik
labels:
traefik.enable: "true"
traefik.http.routers.reviewinbox-api.rule: Host(`reviewinbox.example.com`) && PathPrefix(`/api`)
traefik.http.routers.reviewinbox-api.entrypoints: websecure
traefik.http.routers.reviewinbox-api.tls.certresolver: letsencrypt
traefik.http.services.reviewinbox-api.loadbalancer.server.port: "3000"
web:
networks:
- default
- traefik
labels:
traefik.enable: "true"
traefik.http.routers.reviewinbox-web.rule: Host(`reviewinbox.example.com`)
traefik.http.routers.reviewinbox-web.entrypoints: websecure
traefik.http.routers.reviewinbox-web.tls.certresolver: letsencrypt
traefik.http.services.reviewinbox-web.loadbalancer.server.port: "80"
networks:
traefik:
external: true

Update the version pin in .env.self-hosted:

REVIEWINBOX_VERSION=0.1.1

Pull and restart:

Terminal window
docker compose --env-file .env.self-hosted -f docker-compose.self-hosted.yml pull
docker compose --env-file .env.self-hosted -f docker-compose.self-hosted.yml up -d

The API service runs pending database migrations on startup in the self-hosted compose file. Keep this to one API instance unless migrations are moved to a dedicated deployment job.

Back up Postgres and uploaded files regularly.

Create a database dump:

Terminal window
docker compose --env-file .env.self-hosted -f docker-compose.self-hosted.yml exec -T postgres pg_dump -U reviewinbox reviewinbox > reviewinbox.sql

List named volumes:

Terminal window
docker volume ls | grep reviewinbox

Back up the postgres-data and uploads volumes with your VPS backup tooling.

View logs:

Terminal window
docker compose --env-file .env.self-hosted -f docker-compose.self-hosted.yml logs -f api worker web

Restart one service:

Terminal window
docker compose --env-file .env.self-hosted -f docker-compose.self-hosted.yml restart worker

Stop the stack:

Terminal window
docker compose --env-file .env.self-hosted -f docker-compose.self-hosted.yml down