Hc
Applications Azure

HotCRP Conference Management on Ubuntu 24.04 on Azure User Guide

| Product: HotCRP 3.4 Conference Management on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of HotCRP on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. HotCRP is the conference management system behind many of the most selective conferences in computer science and beyond, developed by Eddie Kohler and published at github.com/kohler/hotcrp. It runs the full life cycle of academic peer review: authors register and submit papers and declare conflicts, the program committee bids on and is assigned reviews, reviewers write structured reviews and discuss them, and the chairs run discussion and record accept or reject decisions — all from one web application.

The image installs HotCRP 3.4 (pinned to the upstream release tag v3.4, commit fd942dabf918377e3ed529e4a9c15fb86aacec73) served by nginx and PHP 8.3 FPM, with MariaDB holding the conference database and a loopback Postfix instance providing the outgoing mail path. Unattended security upgrades are configured to keep the server patched on your running VM.

One appliance, one web application. HotCRP is a front-controller application: nginx and php8.3-fpm serve the whole site on port 80 and route every request through HotCRP's index.php. mariadb holds the conference database and postfix provides the local sendmail path for notification email. MariaDB (127.0.0.1:3306) and Postfix (127.0.0.1:25) are bound to loopback only and are never exposed to the network.

Security by design — there is no administrator account in the image. HotCRP grants system-administrator rights to the first account created on a fresh site, which would let an unauthenticated visitor register themselves as chair. This image closes that hole completely. It ships no HotCRP account, no database and no configuration at all. On the very first boot of every VM a one shot service generates a unique administrator password and a unique database password, creates the conference database and loads the schema (with the "first user is administrator" behaviour disabled), writes the configuration, seeds the single system-administrator account, and then proves the new password signs in through the real sign-in form and that admin, a blank password and other common guesses do not, before writing /root/hotcrp-credentials.txt (mode 0600, root only).

The site cannot serve an unprovisioned instance. nginx and php8.3-fpm are each gated on a bootstrap marker that first boot writes only after the database, configuration and administrator account are in place. Until that marker exists systemd skips those units entirely, so there is no window in which a half-provisioned site — or an empty site where the first visitor becomes administrator — is reachable. The units are still enabled, so the appliance comes straight back after a reboot.

What is included:

  • HotCRP 3.4 served by nginx and PHP 8.3 FPM, routing every request through the application front controller

  • MariaDB (mariadb.service) holding the conference database, bound to loopback

  • A local Postfix instance (postfix.service) bound to loopback, providing the sendmail path HotCRP uses for notification email — ready to relay through your own SMTP smarthost

  • A first-boot service that mints per-instance secrets, seeds the administrator, and proves the credentials before the site is reachable

  • The bootstrap gate that stops nginx and php-fpm serving until provisioning is complete

Prerequisites

  • An Azure subscription and either the Azure Portal or the Azure CLI (az) signed in
  • An SSH key pair so you can read the generated credentials file
  • Inbound TCP port 80 open to the browsers that will reach the site (and port 22 for administration)

Step 1: Deploy from the Azure Portal

  1. Open the cloudimg HotCRP Conference Management on Ubuntu 24.04 LTS offer in the Azure Marketplace and choose Create.
  2. Pick a resource group and region, keep the recommended Standard_B2s size (2 vCPU / 4 GB is comfortable for a conference), and provide your SSH public key for the azureuser account.
  3. On the Networking step allow inbound 80 (the web application) and 22 (SSH). HotCRP serves everything over port 80; put it behind an Azure Application Gateway or a reverse proxy if you want TLS.
  4. Create the VM and note its public IP address.

Step 2: Deploy from the Azure CLI

RG="hotcrp-prod"; LOCATION="eastus"; VM_NAME="hotcrp"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/hotcrp-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az vm create \
  --resource-group "$RG" --name "$VM_NAME" \
  --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values "$SSH_KEY" \
  --public-ip-sku Standard
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 80 --priority 1001
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1002

Step 3: First boot and your credentials

On first boot the image mints the per-instance database and administrator passwords, creates the conference database, loads the schema, writes the configuration, seeds the administrator account, opens the bootstrap gate, starts nginx and php-fpm, verifies the new credentials work and the common defaults are rejected, and writes /root/hotcrp-credentials.txt. This completes within a minute or two. SSH in as azureuser and read the details:

sudo cat /root/hotcrp-credentials.txt

The file is mode 0600 and owned by root, so only a privileged user can read it. It contains the site URL, the administrator email (admin@hotcrp.local) and password, and the database credentials.

Step 4: Confirm the appliance is running

All four services should report active. ss confirms the web application is on port 80 while MariaDB and Postfix are bound to loopback only.

systemctl is-active mariadb.service php8.3-fpm.service nginx.service postfix.service
sed -n 's/.*HOTCRP_VERSION *= *"\([^"]*\)".*/HotCRP \1/p' /var/www/hotcrp/src/init.php | head -1
php -r 'echo "PHP ".PHP_VERSION."\n";'
ss -tulnp | grep -E ':(80|25|3306) ' | sed 's/users:.*//' | sort

All four services report active, HotCRP 3.4 and PHP 8.3 report their versions, and ss shows the web application on port 80 while Postfix on 25 and MariaDB on 3306 are bound to 127.0.0.1 only

Step 5: Sign in to HotCRP

Browse to http://<your-vm-ip>/. You will see the HotCRP sign-in page. Sign in with the administrator email admin@hotcrp.local and the password from the credentials file.

The HotCRP sign-in page with the email and password fields

Once signed in you land on the conference home with the administration console — search, the paper list, settings, users and the assignment tools are all one click away.

The signed-in HotCRP conference home showing the administration console

Step 6: Change the administrator password

Open the account menu (top right) and choose Profile, then set a new password under the Password section. From then on use your own password; the generated one in the credentials file was only to get you in.

Step 7: Set up your conference

Open Settings and set your conference's short and long name, the submission and review deadlines, the review form fields and rounds, and whether reviewing is anonymous, double blind or open. HotCRP walks you through each stage — submissions, reviewing, discussion and decisions — with its own inline help.

Step 8: The submission and review workflow

This is what HotCRP exists to do. Authors submit papers from the same site; each submission gets an entry you can search, tag, assign reviewers to, and decide on. The Search page lists every submission with its status and review count.

The HotCRP submissions list showing a submitted paper with its status and review count

Opening a paper shows its metadata, the submitted document, the reviewing controls (Write review, Assign reviews), conflict and discussion tools, and the decision field — the whole review surface on one page.

A submitted paper rendered on its HotCRP paper page with the abstract, the submission document and the review and assignment controls

Everything the panel shows is read straight from the conference database, so a submission an author makes or a review your committee writes is reflected immediately:

The Paper table listing a submission with its submitted status, the administrator account with roles, and curl confirming the site serves the sign-in page on port 80

Step 9: Prove the per-VM administrator works and defaults are rejected

The image ships no shared credential. The credentials file is root-only, the configuration is not world-readable, and the real sign-in form accepts only the per-VM administrator password:

ls -l /root/hotcrp-credentials.txt
stat -c 'credentials mode %a owner %U:%G' /root/hotcrp-credentials.txt
stat -c 'options.php  mode %a owner %U:%G' /var/www/hotcrp/conf/options.php
# the per-VM administrator password signs in through the real form:
sudo /usr/local/sbin/hotcrp-login-check.sh admin@hotcrp.local '<HOTCRP_ADMIN_PASSWORD>' \
  && echo "per-VM administrator: SIGNED IN" \
  || echo "per-VM administrator: run this on your VM (the password is substituted from the credentials file)"
# every guessable default is rejected:
for p in admin password hotcrp 123456 ""; do
  if sudo /usr/local/sbin/hotcrp-login-check.sh admin@hotcrp.local "$p"; then
    echo "  '$p' ACCEPTED (unexpected)"
  else
    echo "  '$p' rejected (correct)"
  fi
done
# the database DSN is never web-served:
curl -s -o /dev/null -w '  GET /conf/options.php -> HTTP %{http_code} (404 = not served)\n' http://127.0.0.1/conf/options.php

The credentials file at mode 600 owned by root, conf/options.php at mode 640 owned by root and www-data, the real sign-in form rejecting admin, password, hotcrp, 123456 and a blank password, and conf/options.php returning HTTP 404 over the web

Step 10: Invite your program committee

From Users you can add program committee members and chairs, set their roles, and send them account links. Authors create their own accounts when they submit; program committee members you invite here. HotCRP's automatic and manual assignment tools then let you match reviewers to submissions, honouring conflicts and reviewer preferences.

Step 11: How the first-boot gate protects an unprovisioned instance

The distinguishing security property of this image is that the web tier cannot serve until provisioning is complete. Each web unit carries a ConditionPathExists drop-in on the bootstrap-ready marker, which first boot writes only after the administrator has been seeded — so there is never a moment when an empty site is reachable and the first visitor could become administrator.

grep -E 'ConditionPathExists|After=' /etc/systemd/system/nginx.service.d/cloudimg-bootstrap-gate.conf
for u in php8.3-fpm nginx; do
  printf '%-12s %s\n' "$u" "$(grep -h ConditionPathExists /etc/systemd/system/$u.service.d/cloudimg-bootstrap-gate.conf)"
done
ls -l /var/lib/cloudimg/
systemctl is-enabled php8.3-fpm.service nginx.service

The systemd drop-in for nginx showing ConditionPathExists on the cloudimg hotcrp bootstrap-ready marker, the same condition on php8.3-fpm, the marker and first-boot sentinel present in /var/lib/cloudimg, and both units reported as enabled so they survive a reboot

Step 12: Configure outgoing email

HotCRP sends account, submission and review notifications by email. The image ships a local Postfix that accepts mail on loopback so nothing is lost, but to deliver to the outside world you should point it at your own SMTP smarthost. Set a relayhost and reload Postfix:

sudo postconf -e 'relayhost = [<smtp-host>]:587'
sudo systemctl reload postfix

If your relay requires authentication, configure smtp_sasl_auth_enable and a sasl_passwd map in the usual Postfix way, then run sudo postmap /etc/postfix/sasl_passwd. HotCRP's own From: address is set from the conference contact email in Settings.

Step 13: Back up and restore

The whole conference — accounts, submissions, reviews, settings and the uploaded documents — lives in the MariaDB hotcrp database (documents are also cached under /var/lib/hotcrp/docs). Back it up with a routine dump:

sudo mysqldump --single-transaction hotcrp | gzip > "hotcrp-$(date +%F).sql.gz"

Restore into a fresh instance by piping the decompressed dump back into mysql hotcrp.

Step 14: Security recommendations

  • Put HotCRP behind TLS. The image serves plain HTTP on port 80. Terminate HTTPS at an Azure Application Gateway, a load balancer, or a reverse proxy in front of the VM, and restrict port 80 to that front end.
  • Restrict SSH to your administration network with an NSG rule.
  • Rotate the administrator password (Step 6) and keep the credentials file (/root/hotcrp-credentials.txt) readable only by root.
  • Keep the OS patched. Unattended security upgrades are enabled; reboot periodically to pick up new kernels.
  • Back up regularly (Step 13), especially before opening submissions and before the decision deadline.

Step 15: Support and licensing

HotCRP is distributed under the MIT licence. This cloudimg image bundles HotCRP 3.4 with nginx, PHP, MariaDB and Postfix from Ubuntu 24.04, configured and hardened as described above.

cloudimg provides 24/7 support for this image by email at support@cloudimg.co.uk. We help with conference setup, submission and review deadlines, program committee and reviewer management, review form design, outgoing mail and SMTP relay configuration, database administration, backup and restore, performance tuning and HotCRP version upgrades.

All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.