Reactive Resume on AWS User Guide
Overview
Reactive Resume is a free and open source, privacy friendly resume and CV builder. Create and maintain as many resumes and cover letters as you like, keep earlier versions, organise them with tags, preview changes live as you type, choose from a range of templates and typography, share a resume with a public link, and export a finished PDF. The cloudimg image runs Reactive Resume the officially supported way, as the upstream container alongside a bundled PostgreSQL and Redis, orchestrated by Docker Compose under systemd and fronted by nginx. Every image is pinned by digest and captured into the AMI, so your instance starts in seconds. A unique owner account password, session signing key, encryption secret, database password and cache password are generated for each instance on first boot, before the web port is reachable, and public sign up is switched off in the application so nobody can self register on your instance. Backed by 24/7 cloudimg support.
Reactive Resume is a trademark of its respective owner. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by Reactive Resume. It ships the free and open source MIT licensed release, unmodified.

What is included:
- Reactive Resume v5.2.3 (the MIT licensed open source release), pinned by image digest
- A bundled PostgreSQL database and a bundled Redis, both pinned by image digest and reachable only inside a private Docker network (never published to a host port)
- Docker Engine (Docker CE) with the application published to the loopback interface only, fronted by nginx on port
80 reactive-resume.service,reactive-resume-firstboot.serviceandnginx.serviceas systemd units, enabled and active on boot- A unique owner account password, session signing key, encryption secret, database password and cache password generated per instance on first boot, never baked into the image
- Public sign up disabled in the application, so no one can self register on your instance
- A clean, empty database on first boot: no default account, no shipped secret, no prior data
- A dedicated gp3 data volume mounted at
/var/lib/docker, holding the images, database, cache and uploads, resizable independently of the OS disk - PDF export generated in process, so there is no separate browser or rendering service to run
- 24/7 cloudimg support
Connecting to your instance
Connect over SSH as the default login user for your operating system variant, using the EC2 key pair you selected at launch:
| OS variant | SSH login user | Connect |
|---|---|---|
| Ubuntu 24.04 | ubuntu |
ssh -i your-key.pem ubuntu@<public-ip> |
Prerequisites
An active AWS account, an EC2 key pair in the target region, and a VPC with a subnet. m5.large (2 vCPU / 8 GiB RAM) is the recommended size; increase it if many people will use the instance at once. Security group inbound: allow 22/tcp from your management network and 80/tcp (and 443/tcp once you add TLS) for the web interface. Reactive Resume serves plain HTTP on port 80; for production, put it behind TLS with your own domain (see the final section).
Step 1 - Launch from AWS Marketplace
- Open the product in AWS Marketplace and choose Continue to Subscribe, then Continue to Configuration and Continue to Launch.
- Pick the region, the m5.large instance type (or larger), your VPC and subnet.
- Select or create a security group that allows inbound
22/tcpfrom your management network and80/tcpfor the web interface. - Choose your EC2 key pair and launch. When the instance is running, note its public IPv4 address.
Step 2 - Launch from the AWS CLI
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name your-key \
--security-group-ids <security-group-id> \
--subnet-id <subnet-id> \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=reactive-resume}]'
Subscribe to the listing in AWS Marketplace first so the AMI id is available in your account.
Step 3 - Connect to your instance
ssh -i your-key.pem ubuntu@<public-ip>
First boot generates every secret for this instance and creates your owner account before the web port answers, so give it a moment to settle after the instance reports running.
Step 4 - Confirm the services are running
Three systemd units matter: docker, reactive-resume (the Compose stack) and nginx (the reverse proxy on port 80).
sudo systemctl is-active docker reactive-resume nginx
active
active
active
The stack itself is three containers: the application, PostgreSQL and Redis.
sudo docker compose --env-file /etc/reactive-resume/reactive-resume.env -f /etc/reactive-resume/compose.yaml ps --format 'table {{.Service}}\t{{.Status}}'
SERVICE STATUS
postgres Up 14 minutes (healthy)
reactive-resume Up 2 minutes (healthy)
redis Up 14 minutes (healthy)
Step 5 - Secure by default
On a self hosted resume builder the two classic exposures are an open sign up form and a shipped default login. This image has neither.
Before nginx ever opened port 80, first boot generated a unique session signing key, encryption secret, database password and cache password for this instance, created your owner account with a random password, and then switched public sign up off in the application. You can prove it from the command line. A sign up attempt is refused:
curl -s -o /dev/null -w 'HTTP %{http_code}\n' -X POST http://127.0.0.1/api/auth/sign-up/email \
-H 'Content-Type: application/json' \
-d '{"name":"probe","email":"probe@example.com","password":"Pr0be-Guide-123","username":"probeguide"}'
HTTP 400
The bundled database and cache are never published to a host port, and the application itself listens only on loopback behind nginx:
ss -tln | awk 'NR==1 || /:80 |127.0.0.1:3000|:5432|:6379/'
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:3000 0.0.0.0:*
LISTEN 0 511 [::]:80 [::]:*
Only 22 and 80 are reachable from outside the instance.
Step 6 - Get your sign in details
Your owner email and the password generated for this instance are in a root owned file, readable only with sudo:
sudo cat /root/reactive-resume-credentials.txt
REACTIVE_RESUME_URL=http://<public-ip>
REACTIVE_RESUME_ADMIN_EMAIL=admin@reactive-resume.local
REACTIVE_RESUME_ADMIN_PASSWORD=********************
Change that password from Settings, Profile once you are signed in.
Step 7 - Sign in
Browse to http://<public-ip>/ and sign in with the email and password from the previous step.

Step 8 - Create your first resume
From the dashboard choose Create, give the resume a name, and the builder opens. Sections such as basics, experience, education, skills and projects are edited on the left, the resume renders live in the centre, and the template, layout, typography and export controls are on the right.

When the resume is ready, use Download in the builder header to export a PDF. Rendering happens inside the application, so there is no extra service to install or keep running.
Step 9 - Check the stack health from the command line
The application exposes an unauthenticated liveness endpoint that also reports on the database and the upload store:
curl -s http://127.0.0.1/api/health
{
"service": "reactive-resume",
"status": "healthy",
"database": {
"status": "healthy",
"latencyMs": 11
},
"storage": {
"type": "local",
"status": "healthy",
"message": "Local filesystem storage is accessible and has read/write permission.",
"latencyMs": 1
}
}
A healthy status means the application started, its database migrations were applied, PostgreSQL answered, and uploads can be written. It returns HTTP 503 otherwise, which makes it a good target for an Application Load Balancer health check.
Step 10 - Letting other people sign up (optional)
Public sign up is off by default. If you want colleagues to register their own accounts, set the flag and restart the service:
sudo sed -i 's/^FLAG_DISABLE_SIGNUPS=.*/FLAG_DISABLE_SIGNUPS=false/' /etc/reactive-resume/reactive-resume.env
sudo systemctl restart reactive-resume.service
Each account keeps its own resumes; accounts cannot see one another's documents. Only enable this if the instance is on a trusted network or behind an authenticating proxy, and set it back to true to close registration again.
Step 11 - Production: your own domain with TLS
Reactive Resume derives sign in callbacks and share links from APP_URL, so when you put a domain name in front of the instance, update that value too:
sudo sed -i 's|^APP_URL=.*|APP_URL=https://resume.example.com|' /etc/reactive-resume/reactive-resume.env
sudo systemctl restart reactive-resume.service
Then terminate TLS in front of it. The simplest route is certbot with the bundled nginx:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d resume.example.com
Point the DNS record at the instance's public IP first, allow 443/tcp in the security group, and restrict 22/tcp to your management network. All application data lives on the dedicated data volume mounted at /var/lib/docker; take regular EBS snapshots of it, or back up the reactive_resume_pgdata and reactive_resume_data Docker volumes, which hold your resumes and uploads.
Support
Email support@cloudimg.co.uk for help with this image. For questions about Reactive Resume itself, see the upstream documentation.