Developer Tools Azure

Healthchecks on Ubuntu 24.04 on Azure User Guide

| Product: Healthchecks on Ubuntu 24.04 LTS on Azure

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:8000 only, never exposed directly to the network
  • A dedicated Azure data disk at /opt/healthchecks for the application, the Python venv and the SQLite database
  • nginx.service, healthchecks.service and healthchecks-sendalerts.service as 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'

The nginx, healthchecks and healthchecks-sendalerts services active, with nginx on port 80 and the gunicorn application server bound to loopback 127.0.0.1:8000

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/

The Healthchecks instance info note showing the resolved site URL and the create-admin instruction, with the sign-in page returning HTTP 200 - no default password ships

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.

The Healthchecks sign-in page, reached at the instance address, where you sign in with the administrator you created; open registration is disabled and no default account ships

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.

The Healthchecks My Checks dashboard listing monitored jobs with their period, last ping and current up, late or down status at a glance

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.

A Healthchecks check detail page showing its unique ping URL, the period and grace schedule, and the log of received pings

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.

The Healthchecks notification methods page listing the available integrations such as email, Slack, Discord, Telegram, PagerDuty and webhooks

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

The enabled nginx, healthchecks and healthchecks-sendalerts units, the sign-in page returning HTTP 200 through nginx, and the dedicated ext4 data disk mounted at /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 certbot with your-domain on a front end proxy.
  • The application server listens on 127.0.0.1:8000 only 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.