Reactive Resume on a VPS: Self-Hosted Resume Builder with AI Suggestions and PDF Export
Reactive Resume is a free, open-source resume builder with a polished drag-and-drop editor, 20+ templates, AI writing suggestions (optional), PDF export, and one-click public sharing links. It competes with paid services like Canva Resume ($13/month) and Zety ($24/month). Self-hosting on a VPS keeps your employment history, contact details, and career information off third-party servers.
What Reactive Resume Provides
- Templates: 20+ professional templates (modern, classic, creative, ATS-friendly)
- Sections: Work experience, education, skills, certifications, projects, publications, references
- AI suggestions: OpenAI-powered writing improvements for bullet points (optional)
- Multi-resume: Create different resumes for different job types
- PDF export: One-click professional PDF generation
- Public link: Share your resume via a URL without PDF download
- Import: Import from LinkedIn, JSON Resume format
Step 1: Docker Compose Setup
<code">mkdir -p /opt/reactive-resume && cd /opt/reactive-resume nano docker-compose.yml
<code">version: '3.8'
services:
# PostgreSQL database
postgres:
image: postgres:16-alpine
restart: always
environment:
POSTGRES_DB: rxresume
POSTGRES_USER: rxresume
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U rxresume"]
interval: 10s
timeout: 5s
retries: 5
# MinIO for file storage (profile photos, PDF cache)
minio:
image: minio/minio:latest
restart: always
command: server /data
ports:
- "127.0.0.1:9000:9000"
- "127.0.0.1:9001:9001"
environment:
MINIO_ROOT_USER: ${MINIO_USER}
MINIO_ROOT_PASSWORD: ${MINIO_PASSWORD}
volumes:
- minio_data:/data
# Chrome for PDF generation
chrome:
image: browserless/chrome:latest
restart: always
ports:
- "127.0.0.1:3000:3000"
environment:
CONNECTION_TIMEOUT: 10000
MAX_CONCURRENT_SESSIONS: 5
# Reactive Resume backend
server:
image: amruthpillai/reactive-resume:server-latest
restart: always
ports:
- "127.0.0.1:3100:3100"
depends_on:
postgres:
condition: service_healthy
environment:
TZ: UTC
PORT: 3100
NODE_ENV: production
PUBLIC_URL: https://resume.yourdomain.com
PUBLIC_SERVER_URL: https://resume.yourdomain.com/api
STORAGE_URL: https://resume.yourdomain.com/minio
CHROME_URL: ws://chrome:3000
DATABASE_URL: postgresql://rxresume:${POSTGRES_PASSWORD}@postgres/rxresume
ACCESS_TOKEN_SECRET: ${ACCESS_TOKEN_SECRET}
REFRESH_TOKEN_SECRET: ${REFRESH_TOKEN_SECRET}
MINIO_ENDPOINT: minio
MINIO_PORT: 9000
MINIO_BUCKET: reactive-resume
MINIO_ACCESS_KEY: ${MINIO_USER}
MINIO_SECRET_KEY: ${MINIO_PASSWORD}
# Optional: AI writing suggestions
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
# Reactive Resume frontend
client:
image: amruthpillai/reactive-resume:client-latest
restart: always
ports:
- "127.0.0.1:3050:3050"
environment:
PORT: 3050
NODE_ENV: production
PUBLIC_URL: https://resume.yourdomain.com
VITE_SERVER_URL: https://resume.yourdomain.com/api
VITE_STORAGE_URL: https://resume.yourdomain.com/minio
volumes:
postgres_data:
minio_data:
<code">cat > .env << 'EOF' POSTGRES_PASSWORD=StrongResumeDbPassword! MINIO_USER=resumeadmin MINIO_PASSWORD=StrongMinioPassword! ACCESS_TOKEN_SECRET=$(openssl rand -hex 32) REFRESH_TOKEN_SECRET=$(openssl rand -hex 32) OPENAI_API_KEY=sk-your-key # Optional EOF chmod 600 .env docker compose up -d
Step 2: Nginx Reverse Proxy
<code">sudo nano /etc/nginx/sites-available/reactive-resume
<code">server {
listen 443 ssl http2;
server_name resume.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/resume.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/resume.yourdomain.com/privkey.pem;
client_max_body_size 10M;
# Frontend
location / {
proxy_pass http://127.0.0.1:3050;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Backend API
location /api/ {
proxy_pass http://127.0.0.1:3100;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 120s;
}
# MinIO storage
location /minio/ {
proxy_pass http://127.0.0.1:9000/;
proxy_set_header Host $host;
}
}
<code">sudo certbot --nginx -d resume.yourdomain.com sudo systemctl reload nginx
Step 3: Create MinIO Bucket
<code"># Initialize MinIO bucket: docker exec minio mc alias set local http://localhost:9000 resumeadmin StrongMinioPassword! docker exec minio mc mb local/reactive-resume docker exec minio mc anonymous set download local/reactive-resume # Allow public read
Step 4: Using Reactive Resume
- Visit
https://resume.yourdomain.com - Register an account
- Dashboard → Create New Resume → choose template
- Fill in sections: personal info, experience, education, skills
- Drag sections to reorder, customize colors and fonts
- Export PDF → high-quality, ATS-friendly PDF
- Share link → public URL for online viewing
Getting Started
Reactive Resume with all its dependencies uses 500 MB–1 GB RAM total. A 2 GB Ubuntu VPS at VPS.DO handles the full stack. The headless Chrome container for PDF generation is the most RAM-intensive component (~300 MB). For personal or small team use, the free OpenAI API tier (or skipping AI features entirely) keeps operating costs to just VPS and storage.
Conclusion
Self-hosted Reactive Resume provides a professional resume building experience — polished templates, drag-and-drop editing, PDF export, and shareable links — without sending career history, contact information, and employment details to subscription-based services. For job seekers prioritizing privacy, or organizations providing resume tools to employees, self-hosted Reactive Resume delivers full functionality at infrastructure cost only.