Healthchecks on Ubuntu 24.04 on Azure User Guide
Overview
Healthchecks is an open source, self hosted monitoring service for cron jobs and scheduled tasks, a dead man's switch for the jobs that run in the background where nobody is watching. Every job, backup script, certificate renewal or batch process gets its own unique ping URL and requests it when it finishes. If a ping does not arrive on schedule, Healthchecks marks the check late or down and notifies you through email, Slack, Discord, Telegram, PagerDuty, webhooks and dozens of other integrations. Unlike active probing that watches a service from the outside, this passive model catches the jobs that silently stopped running.
The cloudimg image serves Healthchecks 4.2 behind an nginx reverse proxy on a hardened, fully patched Ubuntu 24.04 LTS base. The Django application runs under gunicorn on the loopback interface (127.0.0.1:8000), nginx serves it on port 80, and a second service delivers alerts the moment a check changes state. The image is secure by default: it ships with no administrator account and no shared password, so you create your own admin with a single command and no default login ever ships. Backed by 24/7 cloudimg support.
What is included:
- Healthchecks 4.2 served by gunicorn behind nginx, managed by systemd
- The Healthchecks web UI and ping API on
:80 - No default administrator: you create your own admin with one command
- A dedicated alert delivery daemon (
healthchecks-sendalerts.service) for notifications - The application server bound to
127.0.0.1:8000only, never exposed directly to the network - A dedicated Azure data disk at
/opt/healthchecksfor the application, the Python venv and the SQLite database nginx.service,healthchecks.serviceandhealthchecks-sendalerts.serviceas enabled systemd units- 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; size up as your check count grows. NSG inbound: allow 22/tcp from your management network and 80/tcp for the web UI. Healthchecks serves plain HTTP on port 80; for production, terminate TLS in front of it with your own domain. The application server is never exposed directly: it listens on 127.0.0.1:8000 only, so port 8000 stays off the network.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Healthchecks by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Review the dedicated data disk on the Disks tab, then Review + create then Create.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name healthchecks \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Then open port 80 to the web UI:
az vm open-port --resource-group <your-rg> --name healthchecks --port 80
Step 3 - Confirm the services are running
SSH in as azureuser and confirm nginx, the Healthchecks application and the alert daemon are active. Note that the application server listens only on 127.0.0.1:8000 while nginx serves the web UI on port 80.
systemctl is-active nginx healthchecks healthchecks-sendalerts
sudo ss -tlnp | grep -E ':80 |:8000 ' | sed 's/ */ /g'

Step 4 - The first boot info note
Healthchecks ships with no administrator account. On the first boot of every VM a one shot service resolves the instance address, sets it as the site root, and writes an instance info note recording the site URL and the create-admin instruction. There is no password in it, because you set your own. Read it with sudo:
sudo cat /root/healthchecks-credentials.txt
You can confirm the web UI is healthy from the command line; the sign-in page returns 200 and the root path redirects unauthenticated visitors to it (302):
curl -s -o /dev/null -w 'GET /accounts/login/ -> HTTP %{http_code}\n' http://127.0.0.1/accounts/login/

Step 5 - Create your administrator
Because the image ships with no user, you create the first administrator with a single command over SSH. Run the Healthchecks management wrapper and follow the prompts to set your own email and password:
# Enter your own <your-email> and a strong password when prompted.
sudo /usr/local/sbin/hc-manage createsuperuser
Then browse to http://<vm-public-ip>/. Unauthenticated visitors are redirected to the sign-in page, where you enter the email and password you just chose. There are no default credentials to change, because none ship.

Step 6 - Your checks dashboard
After signing in you land on My Checks, the dashboard that lists every check with its current up, late or down state, its schedule and when its last ping arrived. A fresh instance starts empty; this is where your monitored jobs appear as you add them.

Step 7 - Create a check and copy its ping URL
Select Add Check, give it a name, and set its Period (how often the job runs) and Grace (how late a ping may be before the check goes down). Open the check to see its unique ping URL and the log of received pings. You copy that URL into your job.

Step 8 - Wire the ping URL into a cron job
Add a request to the check's ping URL at the end of the job you want to monitor. When the job finishes successfully it pings the URL; if a ping does not arrive within the period plus grace, Healthchecks marks the check down and alerts you. For a nightly backup, for example:
0 2 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 --retry 5 https://<vm-public-ip>/ping/<your-check-uuid>
You can also signal start, success and failure explicitly by appending /start or /fail to the ping URL, which lets Healthchecks measure job duration and catch jobs that begin but never finish.
Step 9 - Notification integrations
Open Notification Methods (the Integrations page) to connect where alerts are delivered. Healthchecks supports email, Slack, Discord, Telegram, PagerDuty, Opsgenie, generic webhooks and dozens more. Add a method, assign it to your checks, and alerts are sent the moment a check changes state by the healthchecks-sendalerts daemon.

Step 10 - Verify the stack
Confirm the services are enabled, the web UI responds through nginx, and the dedicated data disk mount:
systemctl is-enabled nginx healthchecks healthchecks-sendalerts
curl -s -o /dev/null -w 'GET /accounts/login/ -> HTTP %{http_code}\n' http://127.0.0.1/accounts/login/
findmnt -no SOURCE,TARGET,FSTYPE /opt/healthchecks

Step 11 - Where your data lives
The Django application, its Python virtual environment and the SQLite database all live on a dedicated Azure data disk mounted at /opt/healthchecks, separate from the OS disk. This disk is captured into the image and re provisioned on every VM, and you can snapshot and resize it independently. Confirm the mount and the free space:
df -h /opt/healthchecks | tail -1
sudo du -sh /opt/healthchecks/app /opt/healthchecks/venv /opt/healthchecks/data
Step 12 - Enable email notifications
To send email alerts, add your SMTP relay settings to the configuration file and restart the two application services. The file already documents the keys; append your own values (never commit real credentials):
# /opt/healthchecks/hc.env
EMAIL_HOST=smtp.your-provider.example
EMAIL_PORT=587
EMAIL_HOST_USER=<your-email>
EMAIL_HOST_PASSWORD=<your-password>
DEFAULT_FROM_EMAIL=healthchecks@your-domain
Then apply the change:
sudo systemctl restart healthchecks healthchecks-sendalerts
Security notes
- Healthchecks serves plain HTTP on port 80. For production, put it behind your own TLS terminating reverse proxy or an Azure Application Gateway with a certificate for your domain, and restrict port 80 in the NSG to trusted networks. A common approach is
certbotwith your-domain on a front end proxy. - The application server listens on
127.0.0.1:8000only and is never exposed directly; only nginx on port 80 faces the network. - The image ships with no administrator and no shared password. You create the first admin with one command, so there are no default credentials to rotate, and open web sign-up stays disabled (
REGISTRATION_OPEN=False) until you choose to enable it. - Keep the VM patched. The image ships fully patched with unattended security upgrades enabled.
Support
cloudimg images come with 24/7 support. If you have any questions about this Healthchecks image or need help with your deployment, contact us through the cloudimg website.