Reactive Resume logo

Reactive Resume

A free and open-source resume builder that keeps your privacy in mind

Alternative to: canva, resume.io, novoresume, zety


Reactive Resume is a free and open-source resume builder that simplifies the process of creating, updating, and sharing your resume. It offers a real-time preview as you type, professionally designed templates, and multiple export formats, with complete data ownership and no tracking or analytics by default for self-hosted deployments.

Reactive Resume Docker Compose example

Self-host Reactive Resume on your own server, homelab, or VPS starting from this Docker Compose example. It runs Reactive Resume in Docker containers using the official ghcr.io/amruthpillai/reactive-resume:latest, postgres:latest, redis:latest, chrislusf/seaweedfs:latest, quay.io/minio/mc:latest images, with persistent volumes and automatic restarts preconfigured. Review the environment variables and adjust them to your setup, save the file as compose.yml (or docker-compose.yml), and start the stack with docker compose up -d.

services:
  reactive_resume:
    image: ghcr.io/amruthpillai/reactive-resume:latest
    restart: unless-stopped
    volumes:
      - app_data:/app/data
    environment:
      # Port the app listens on inside the container.
      PORT: "3000"
      # Public URL where users reach Reactive Resume. Must match the external hostname
      # (used for auth callbacks, OAuth issuer, email links, OpenGraph and upload URLs).
      APP_URL: "http://localhost:3000"
      # PostgreSQL connection string (points at the bundled postgres service).
      DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/postgres"
      # Secret used by Better Auth to sign sessions. Generate with: openssl rand -hex 32
      AUTH_SECRET: "changeme"
      # Secret used to encrypt saved AI-provider credentials in the agent workspace. Generate with: openssl rand -hex 32
      ENCRYPTION_SECRET: "changeme"
      # Redis connection string (points at the bundled redis service).
      REDIS_URL: "redis://redis:6379"
      # S3-compatible object storage (points at the bundled SeaweedFS service).
      S3_ACCESS_KEY_ID: "seaweedfs"
      S3_SECRET_ACCESS_KEY: "seaweedfs"
      S3_REGION: "us-east-1"
      S3_ENDPOINT: "http://seaweedfs:8333"
      S3_BUCKET: "reactive-resume"
      S3_FORCE_PATH_STYLE: "true"
      # SMTP server for sending verification / password-reset emails.
      # When left blank, emails are logged to the container console instead of sent.
      SMTP_HOST: ""
      SMTP_PORT: ""
      SMTP_USER: ""
      SMTP_PASS: ""
      # Sender identity for outgoing email.
      SMTP_FROM: "Reactive Resume <noreply@rxresu.me>"
      # Use an implicit TLS connection to the SMTP server (true) or STARTTLS/plain (false).
      SMTP_SECURE: "false"
      # Set to "true" to prevent new users from registering.
      FLAG_DISABLE_SIGNUPS: "false"
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
      seaweedfs:
        condition: service_healthy
      seaweedfs_create_bucket:
        condition: service_completed_successfully
    healthcheck:
      test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/api/health').then((r) => { if (!r.ok) process.exit(1); }).catch(() => process.exit(1));"]
      start_period: 60s
      interval: 30s
      timeout: 10s
      retries: 3

  postgres:
    image: postgres:latest
    restart: unless-stopped
    environment:
      POSTGRES_DB: "postgres"
      POSTGRES_USER: "postgres"
      POSTGRES_PASSWORD: "postgres"
    volumes:
      - postgres_data:/var/lib/postgresql
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres", "-d", "postgres"]
      start_period: 10s
      interval: 30s
      timeout: 10s
      retries: 3

  redis:
    image: redis:latest
    restart: unless-stopped
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      start_period: 5s
      interval: 30s
      timeout: 10s
      retries: 3

  seaweedfs:
    image: chrislusf/seaweedfs:latest
    restart: unless-stopped
    command: server -s3 -filer -dir=/data -ip=0.0.0.0
    environment:
      AWS_ACCESS_KEY_ID: "seaweedfs"
      AWS_SECRET_ACCESS_KEY: "seaweedfs"
    volumes:
      - seaweedfs_data:/data
    healthcheck:
      test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://localhost:8888"]
      start_period: 10s
      interval: 30s
      timeout: 10s
      retries: 3

  seaweedfs_create_bucket:
    image: quay.io/minio/mc:latest
    restart: on-failure
    entrypoint: >
      /bin/sh -c "
        sleep 5;
        mc alias set seaweedfs http://seaweedfs:8333 seaweedfs seaweedfs;
        mc mb seaweedfs/reactive-resume;
        exit 0;
      "
    depends_on:
      seaweedfs:
        condition: service_healthy

volumes:
  app_data:
  postgres_data:
  redis_data:
  seaweedfs_data:

Values set to changeme are required — replace them with your own values before starting Reactive Resume.

Prefer a managed setup? WinterFlow installs, configures, and updates Reactive Resume for you using this same Docker Compose configuration.