Applications Azure

Reactive Resume on Ubuntu 24.04 on Azure User Guide

| Product: Reactive Resume on Ubuntu 24.04 LTS on Azure

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.

The Reactive Resume dashboard listing your resumes, with the signed in owner account and the version shown in the sidebar

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.service and nginx.service as 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

  1. In the Azure portal, choose Create a resource and search the Marketplace for the cloudimg Reactive Resume offer.
  2. Select the plan, then Create.
  3. On the Basics tab pick your subscription, resource group and region, name the VM, and select Standard_B2s (or larger).
  4. Choose SSH public key authentication with admin username azureuser and provide your public key.
  5. On the Networking tab, allow inbound 22/tcp from your management network and 80/tcp for the web interface.
  6. 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)

systemctl reporting docker, reactive-resume and nginx active, and the three containers running healthy under Docker Compose

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.

Public sign up returns HTTP 400, a wrong password returns HTTP 401, the per VM owner password returns HTTP 200, and only ports 80 and loopback 3000 are listening

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=********************

The per VM access notes, with the application URL, the owner email and the owner password masked

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.

The Reactive Resume sign in page asking for an email address and password

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.

The Reactive Resume builder with the section editor on the left, the live resume preview in the centre, and the template and layout panel 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.

The Reactive Resume applications tracker in its empty state, ready to record job applications

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.