keepcalculator

06 Numbers and Powers

Self-Host Reactive Resume on a VPS: Step-by-Step

Card No. 06·35618 · Updated · Standard formula, shown below

This guide walks you through deploying Reactive Resume — a free, open-source resume builder — on your own VPS. By the end, you’ll have a private, self-hosted instance accessible via your domain, with your data under your control. You’ll need a VPS (any Linux distribution works, Ubuntu 22.04/24.04 recommended), a domain name pointing to your server’s IP, and basic comfort with the command line.

What You’ll Need

  • A VPS with at least 1 GB RAM and 10 GB storage (any provider).
  • A domain name with an A record pointing to your VPS’s public IP.
  • SSH access to the VPS (root or a user with sudo privileges).
  • Optional but recommended: a Cloudflare account for free SSL and proxy.

Step-by-Step

  1. SSH into your VPS
    Open a terminal and run: ssh user@your_server_ip. Update the system: sudo apt update && sudo apt upgrade -y.
  2. Install Docker and Docker Compose
    Reactive Resume is easiest to run with Docker. Install prerequisites: sudo apt install apt-transport-https ca-certificates curl software-properties-common -y. Add Docker’s official GPG key and repository, then install: curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - and sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable". Then sudo apt install docker-ce docker-compose-plugin -y. Enable Docker to start on boot: sudo systemctl enable docker.
  3. Create a directory for Reactive Resume
    Run mkdir -p ~/reactive-resume && cd ~/reactive-resume.
  4. Create a docker-compose.yml file
    Use a text editor (e.g., nano docker-compose.yml) and paste the following:
    version: '3.8'
    services:
      reactive-resume:
        image: amruthpillai/reactive-resume:latest
        container_name: reactive-resume
        ports:
          - "3000:3000"
        environment:
          - NODE_ENV=production
          - PUBLIC_URL=https://yourdomain.com
          - DATABASE_URL=postgresql://postgres:postgres@db:5432/postgres
          - JWT_SECRET=your_strong_secret_here
        depends_on:
          - db
        restart: unless-stopped
      db:
        image: postgres:16-alpine
        container_name: reactive-resume-db
        environment:
          - POSTGRES_USER=postgres
          - POSTGRES_PASSWORD=postgres
          - POSTGRES_DB=postgres
        volumes:
          - pgdata:/var/lib/postgresql/data
        restart: unless-stopped
    volumes:
      pgdata:

    Replace yourdomain.com with your actual domain and your_strong_secret_here with a long random string (generate one with openssl rand -hex 32).

  5. Start the containers
    Run sudo docker compose up -d. This pulls the images and starts both services. Check status with sudo docker compose ps — both should show “Up”.
  6. Set up a reverse proxy (Nginx)
    Install Nginx: sudo apt install nginx -y. Create a site config: sudo nano /etc/nginx/sites-available/reactive-resume and paste:
    server {
        listen 80;
        server_name yourdomain.com;
    
        location / {
            proxy_pass http://localhost:3000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
    }

    Enable the site: sudo ln -s /etc/nginx/sites-available/reactive-resume /etc/nginx/sites-enabled/. Test config: sudo nginx -t, then reload: sudo systemctl reload nginx.

  7. Enable HTTPS with Let’s Encrypt
    Install Certbot: sudo apt install certbot python3-certbot-nginx -y. Run sudo certbot --nginx -d yourdomain.com and follow the prompts. This auto-configures SSL and renews it automatically.
  8. Access your instance
    Visit https://yourdomain.com. You should see the Reactive Resume login page. The default admin credentials are admin@admin.com / admin — change them immediately after first login (go to Profile → Settings → Change Password).

Common Mistakes

  • Forgetting to change the default admin password — leaving it as admin/admin is a severe security risk.
  • Using a weak JWT_SECRET — a short or guessable secret allows session forgery.
  • Not opening port 3000 — if you skip the reverse proxy and try to access directly, ensure your firewall allows port 3000, but using Nginx on port 80/443 is safer.
  • Pointing the domain to the wrong IP — make sure the A record points to your VPS’s IPv4 address, not IPv6 unless you’ve configured that.
  • Running Docker commands without sudo — if your user isn’t in the docker group, you’ll get permission errors. Add yourself with sudo usermod -aG docker $USER and log out/in.

Tips

  • Back up the PostgreSQL data volume regularly. Use docker run --rm -v reactive-resume_pgdata:/data -v $(pwd):/backup alpine tar czf /backup/pgdata.tar.gz -C /data . from the project directory.
  • Use a firewall like UFW: sudo ufw allow OpenSSH, sudo ufw allow 'Nginx Full', sudo ufw enable.
  • Set up automatic updates for Docker images with a cron job, but test before applying.
  • If you want to use a subdomain like resume.example.com, just point that subdomain to your VPS and use it in the config.
  • Consider using a dedicated non-root user for Docker to reduce risk.

Troubleshooting

  • Site doesn’t load — Check sudo docker compose logs reactive-resume for errors. Verify Nginx is running: sudo systemctl status nginx. Ensure your domain resolves: dig yourdomain.com.
  • Database connection error — Ensure the DATABASE_URL matches the Postgres credentials in the compose file. The host should be db (the service name), not localhost.
  • Port 3000 already in use — Change the left side of the port mapping in compose (e.g., "3001:3000") and update Nginx’s proxy_pass to http://localhost:3001.
  • SSL certificate fails — Make sure port 80 is reachable from the internet. Temporarily disable UFW if needed, then re-enable after certbot.
  • Can’t log in after changing password — Clear browser cookies and cache. If still stuck, reset the admin password via the database: sudo docker exec -it reactive-resume-db psql -U postgres -d postgres -c "UPDATE users SET password = 'new_hash' WHERE email = 'admin@admin.com';" — but this requires generating a bcrypt hash, so it’s easier to reinstall or use the forgot-password flow if available.

Frequently Asked Questions

Is Reactive Resume free to self-host?

Yes, it’s open-source (MIT license) and completely free to self-host. You only pay for your VPS and domain.

Can I use SQLite instead of PostgreSQL?

Reactive Resume officially supports PostgreSQL. SQLite is not recommended because the app expects a relational database with specific features.

How do I update Reactive Resume?

In the project directory, run sudo docker compose pull then sudo docker compose up -d. This pulls the latest image and recreates the container.

Can I use a different reverse proxy like Caddy or Traefik?

Yes, any reverse proxy works. Caddy automatically handles SSL, so you could skip Certbot. Just make sure to proxy to port 3000.

What if I don’t have a domain name?

You can access via IP, but you’ll need to set PUBLIC_URL to http://your_server_ip and use HTTP (not HTTPS) unless you set up a self-signed cert. Many features like OAuth won’t work properly without a domain.

Is it safe to expose this to the internet?

With HTTPS, a strong admin password, and regular updates, it’s reasonably safe. However, consider adding basic authentication via Nginx or using a VPN if you’re the only user.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →