Documentation Index
Fetch the complete documentation index at: https://docs.rxresu.me/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Reactive Resume can be self-hosted using Docker in a matter of minutes, and this guide will walk you through the process. Here are some of the services you’ll need to get started:PostgreSQL
Printer
Email (optional)
Storage (optional)
/app/data.- Docker Hub:
amruthpillai/reactive-resume:latest - GitHub Container Registry:
ghcr.io/amruthpillai/reactive-resume:latest
Minimum requirements
Docker + Docker Compose
Compute
Storage
Quickstart using Docker Compose
Create a new folder (for examplereactive-resume/) with:
compose.yml.env- a persistent data directory for uploads (for example
./data)
Create compose.yml
chromedp/headless-shell:PRINTER_ENDPOINT to http://chrome:9222 (or http://localhost:9222 if running outside Docker Compose). This provides the same PDF/screenshot generation functionality with a smaller image footprint.How startup works (database migrations)
Environment variables
Required
APP_URLDATABASE_URLPRINTER_ENDPOINTAUTH_SECRET
Optional
- SMTP (
SMTP_*) - Social auth (
GOOGLE_*,GITHUB_*,LINKEDIN_*,OAUTH_*) - S3 storage (
S3_*) - AI URL allowlist (
AI_ALLOWED_BASE_URLS) - Feature flags (
FLAG_*)
Server
Server
TZ: Sets the container timezone (affects logs and server-side timestamps). Recommended:Etc/UTC.APP_URL: Canonical/public URL for your instance (used for absolute URLs, redirects, and auth flows). If behind a reverse proxy, set this to your public HTTPS URL (for example,https://resume.example.com).PRINTER_APP_URL(optional): Overrides the base URL used when rendering the print route for the printer. Defaults toAPP_URL. Useful when the printer must access the app via a different internal URL (for example,http://host.docker.internal:3000).
Printer
Printer
PRINTER_ENDPOINT: Endpoint where Reactive Resume connects to the printer browser.- Recommended (Browserless):
ws://printer:3000?token=...and keep the token value in sync with BrowserlessTOKEN. - Also supported:
http://chrome:9222for Chrome DevTools Protocol endpoints.
chromedp/headless-shell:PRINTER_ENDPOINT to http://chrome:9222 (in Docker Compose) or http://localhost:9222 (if running externally). This provides the same PDF/screenshot generation with a smaller image footprint.Database (PostgreSQL)
Database (PostgreSQL)
DATABASE_URL: Postgres connection string in the formatpostgresql://USER:PASSWORD@HOST:PORT/DATABASE. - In Docker Compose, setHOSTto the Postgres service name (e.g.postgres), notlocalhost. - If your password contains special characters (@,#,:), URL-encode it. - For managed Postgres, add provider-specific params (for example?sslmode=require) when needed.
Authentication
Authentication
AUTH_SECRET: Secret used to secure authentication. Changing it invalidates existing sessions.Generate with:GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET (optional): Enables Google sign-in.GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET (optional): Enables GitHub sign-in.LINKEDIN_CLIENT_ID / LINKEDIN_CLIENT_SECRET (optional): Enables LinkedIn sign-in.BETTER_AUTH_API_KEY (optional): Enables Better Auth dashboard integrations.BETTER_AUTH_URL (optional, advanced): Overrides auth base URL if it must differ from APP_URL (for split-host deployments).BETTER_AUTH_SECRET (optional, advanced): Overrides AUTH_SECRET for Better Auth internals.Custom OAuth provider (optional):OAUTH_PROVIDER_NAME: Display name in the UIOAUTH_CLIENT_ID/OAUTH_CLIENT_SECRET: Required for any custom OAuth providerOAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS: Comma-separated allowlist for extra dynamic OAuth redirect hosts/origins (HTTPS only, non-private hosts).OAUTH_SCOPES: Space-separated scopes (defaults toopenid profile email)
- Option A — OIDC Discovery (preferred): Set
OAUTH_DISCOVERY_URLto your provider’s.well-known/openid-configurationURL - Option B — Manual URLs: Set all three:
OAUTH_AUTHORIZATION_URL,OAUTH_TOKEN_URL, andOAUTH_USER_INFO_URL
Email (SMTP, optional)
Email (SMTP, optional)
- Email delivery is enabled only when all of
SMTP_HOST,SMTP_USER,SMTP_PASS, andSMTP_FROMare set. SMTP_HOST: SMTP host (if empty, email sending is disabled).SMTP_PORT: Defaults to587in the app.SMTP_USER/SMTP_PASS: SMTP credentials.SMTP_FROM: Default from address (for example,Reactive Resume <[email protected]>).SMTP_SECURE:"true"or"false"(string). Match your provider settings.
Storage (S3 or local)
Storage (S3 or local)
- Default (local): If all
S3_*values are empty, uploads are stored under<cwd>/data(usually/app/datain the official image). - Mount local uploads to persistent storage (for example
./data:/app/data) or uploads can be lost on container recreation. - S3/S3-compatible: Configure
S3_ACCESS_KEY_ID,S3_SECRET_ACCESS_KEY,S3_REGION,S3_ENDPOINT, andS3_BUCKET. S3_FORCE_PATH_STYLEcontrols bucket addressing (defaults to"false"):"true"for path-style URLs (https://endpoint/bucket) common with MinIO/SeaweedFS."false"for virtual-hosted-style URLs (https://bucket.endpoint) common with AWS S3 / Cloudflare R2.
AI (optional)
AI (optional)
AI_ALLOWED_BASE_URLS: Comma-separated hosts or origins allowed as custom AI API base URLs. - Use this when routing AI requests through your own gateway/proxy. - Example:api.openai.com,https://gateway.ai.vercel.com
Feature Flags
Feature Flags
FLAG_DEBUG_PRINTER: Bypasses the printer-only access restriction (useful when debugging/printer/{resumeId}). Recommended: keep"false"in production.FLAG_DISABLE_SIGNUPS: Disables new signups (web app and server). Useful for private instances.FLAG_DISABLE_EMAIL_AUTH: Disables email/password login entirely. Also disables email verification, forgot password, and reset password flows. Users can still sign up via social auth (Google/GitHub/LinkedIn/Custom OAuth), unless FLAG_DISABLE_SIGNUPS is also set to true. Useful when only SSO is required.FLAG_DISABLE_IMAGE_PROCESSING: Disables image processing. This is useful if you are using a machine with limited resources, like a Raspberry Pi.
Updating your installation
To update your Reactive Resume installation to the latest available version, follow these steps:- Back up your database and uploads first (highly recommended before every update).
-
Pull the latest images for all services defined in your Docker Compose file.
-
Restart the containers to run the new images.
-
Check migration/startup logs after deploy.
-
(Optional) Remove old, unused Docker images to free up disk space.
Backups (recommended)
Regular backups are essential to protect your data. Reactive Resume stores data in two places: the PostgreSQL database and file uploads (either local storage or S3).Database backups
Your PostgreSQL database contains all user accounts, resumes, and application data. For self-hosted deployments, you can usepg_dump to create periodic backups of your database and store them in a secure location. Many hosting providers also offer automated backup solutions for managed PostgreSQL instances, which handle scheduling, retention, and restoration for you.
Upload backups
If you’re using local storage (the./data directory), include this directory in your regular backup routine. A simple approach is to use rsync or a similar tool to copy the directory to a remote server or cloud storage.
If you’re using S3-compatible storage, consider enabling versioning on your bucket to protect against accidental deletions. Most S3 providers also support lifecycle rules for automatic cleanup of old versions and cross-region replication for disaster recovery.
Health Checks
Reactive Resume exposes a health check endpoint at/api/health that verifies the application and its dependencies. It checks database, printer, and storage; if any one is unhealthy, the endpoint returns HTTP 503.
How it works
The Docker Compose configuration includes a health check that periodically calls the/api/health endpoint:
docker compose ps or docker ps.
Reverse proxy integration
Most reverse proxies (such as Traefik, Caddy, or nginx with upstream health checks) can use Docker’s health status to make routing decisions:- Healthy containers receive traffic as normal
- Unhealthy containers are automatically removed from the load balancer pool
Manually checking health
You can manually verify the health of your Reactive Resume instance:Troubleshooting
The app container exits immediately
The app container exits immediately
- Common cause: database migrations failed (often a bad
DATABASE_URL). - What to do:
Check logs for migration errors and database connectivity details:
Can't sign in / redirects loop / cookies don't stick
Can't sign in / redirects loop / cookies don't stick
PDF export fails / printing is stuck
PDF export fails / printing is stuck
- Common cause: Reactive Resume can’t reach the printer, token mismatch, or the printer can’t reach your app. -
Checks: -
PRINTER_ENDPOINTshould usually bews://printer:3000?token=...in Compose. - BrowserlessTOKENand the token inPRINTER_ENDPOINTmust match. - If you usePRINTER_APP_URL="http://host.docker.internal:3000"on Linux, setextra_hosts: ["host.docker.internal:host-gateway"]for the printer service.
/api/health returns 503 even though Postgres is up
/api/health returns 503 even though Postgres is up
- Common cause: printer or storage health failed (not only database). - Fix: inspect the endpoint response
payload and check
printer/storagefields:bash curl -s http://localhost:3000/api/health
Uploads disappear after restart
Uploads disappear after restart
- Cause: local upload storage wasn’t mounted to a persistent volume. - Fix: add a volume mount like
./data:/app/dataand redeploy.
Emails aren't being delivered
Emails aren't being delivered
- Expected behavior: if SMTP isn’t fully configured, the app logs emails to the console. - Fix: set
SMTP_HOST,SMTP_USER,SMTP_PASS, andSMTP_FROM, then verifySMTP_PORTandSMTP_SECURE.
Dynamic OAuth redirect URI is rejected
Dynamic OAuth redirect URI is rejected
- Common cause: redirect host is not trusted for dynamic client registration. - Fix: add trusted HTTPS
hosts/origins to
OAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS.
S3 storage error: ENOTFOUND bucket.endpoint
S3 storage error: ENOTFOUND bucket.endpoint
- Common cause: The S3 client is using virtual-hosted-style addressing (prepending the bucket name to the endpoint), but your S3-compatible storage expects path-style addressing.
- Symptom: Error message like
getaddrinfo ENOTFOUND mybucket.s3-server.comwhen your endpoint iss3-server.com. - Fix: Set
S3_FORCE_PATH_STYLE="true"in your environment. This is required for most self-hosted S3-compatible services like MinIO, SeaweedFS, etc.