Deployment guide

Healthchecks

Overview

Healthchecks is an open source, self-hosted monitoring service for cron jobs and scheduled tasks. It works as 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, which watches a service from the outside, this passive model catches the jobs that silently stopped running.

This SecureAnyCloud image serves Healthchecks 4.2 behind an nginx reverse proxy on a hardened Ubuntu 24.04 LTS base that is patched at build time. 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.

What you get:

  • 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 SecureAnyCloud support

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.

Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting size. Size up as your check count grows.

Configure the network security group (NSG) to allow inbound 22/tcp from your management network and 80/tcp for the web UI. Healthchecks serves plain HTTP on port 80, so 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 SecureAnyCloud, and select Create.

On the Basics tab, 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 select Review + create and Create.

Step 2 - Deploy from the Azure CLI

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:healthchecks-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name healthchecks \
  --image sac1647283583153:healthchecks-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

Then open port 80 for 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 that nginx, the Healthchecks application and the alert daemon are active. 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 and sets it as the site root. It also writes an instance info note that records the site URL and the create-admin instruction.

The note contains no password, because you set your own. Read it with sudo:

sudo cat /root/healthchecks-credentials.txt

Confirm from the command line that the web UI is healthy. 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

The image ships with no user, so 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. Enter the email and password you just chose.

There are no default credentials to change, because none ship.

Step 6 - Your checks dashboard

After you sign in, you land on My Checks. This dashboard lists every check with its current up, late or down state, its schedule and when its last ping arrived. A fresh instance starts empty. Your monitored jobs appear here 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. 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. This lets Healthchecks measure job duration and catch jobs that begin but never finish.

Step 9 - Notification integrations

Open Notification Methods (the Integrations page) to choose where alerts are delivered. Healthchecks supports email, Slack, Discord, Telegram, PagerDuty, Opsgenie, generic webhooks and dozens more.

Add a method and assign it to your checks. The healthchecks-sendalerts daemon then sends alerts the moment a check changes state.

Step 10 - Verify the stack

Confirm that the services are enabled, that the web UI responds through nginx, and that the dedicated data disk is mounted:

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, and 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. 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. Open web sign-up stays disabled (REGISTRATION_OPEN=False) until you choose to enable it.
  • Keep the VM patched. The image is patched at build time and ships with unattended security upgrades enabled.

Support

SecureAnyCloud images come with 24/7 support. If you have questions about this Healthchecks image or need help with your deployment, contact us through the SecureAnyCloud website.

Deploy on Azure

Launch Healthchecks on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure