Reactive Resume on Ubuntu 24.04 on Azure 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 VM, 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 VM 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 VM 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
- PDF export generated in process, so there is no separate browser or rendering service to run
- 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting point; increase the size if many people will use the instance at once. NSG 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 - Deploy from the Azure Marketplace
- In the Azure portal, choose Create a resource and search the Marketplace for the cloudimg Reactive Resume offer.
- Select the plan, then Create.
- On the Basics tab pick your subscription, resource group and region, name the VM, and select Standard_B2s (or larger).
- Choose SSH public key authentication with admin username
azureuserand provide your public key. - On the Networking tab, allow inbound
22/tcpfrom your management network and80/tcpfor the web interface. - Review and create. When the VM is running, note its public IP address.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group my-reactive-resume-rg \
--name reactive-resume \
--image cloudimg:reactive-resume-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Open the port the web interface needs (SSH is opened by default):
az vm open-port --resource-group my-reactive-resume-rg --name reactive-resume --port 80 --priority 900
Step 3 - Connect to your VM
ssh azureuser@<vm-ip>
First boot generates every secret for this VM and creates your owner account before the web port answers, so give it a moment to settle after the VM 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 VM, created your owner account with a random password, and then switched public sign up off in the application. You can prove all of 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:PortProcess
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 VM.

Step 6 - Get your sign in details
Your owner email and the password generated for this VM are in a root owned file, readable only with sudo:
sudo cat /root/reactive-resume-credentials.txt
REACTIVE_RESUME_URL=http://<vm-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://<vm-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 - Track your applications
Applications in the sidebar keeps a record of the roles you have applied for and which resume you sent, so the job search stays in the same place as the documents.

Step 10 - 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 Azure Load Balancer or Application Gateway health probe.
Step 11 - 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 12 - 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 VM, 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 VM's public IP first, allow 443/tcp in the NSG, and restrict 22/tcp to your management network. Take regular backups of 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.