---
title: "Deploy Healthchecks"
description: "Monitor cron jobs, backups and scheduled tasks; alert when a ping is late"
category: "Observability"
url: https://railway.com/deploy/healthchecks-monitoring
---

# Deploy Healthchecks

Monitor cron jobs, backups and scheduled tasks; alert when a ping is late

**[Deploy Healthchecks on Railway](https://railway.com/template/healthchecks-monitoring)**

- **Creator:** A3A
- **Category:** Observability
- **Total deploys:** 1

## Template content

### Postgres https://devicons.railway.app/i/postgresql.svg

- **Image:** ghcr.io/railwayapp-templates/postgres-ssl:18

### healthchecks https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/healthchecks.svg

- **Image:** healthchecks/healthchecks:latest
- **Start command:** `/bin/sh -c 'mkdir -p /tmp/hcconf; printf "%s\n" "from hc.settings import *" "SESSION_COOKIE_SECURE = True" "CSRF_COOKIE_SECURE = True" "SECURE_HSTS_SECONDS = 31536000" > /tmp/hcconf/railway_settings.py; export PYTHONPATH="/tmp/hcconf:$PYTHONPATH" DJANGO_SETTINGS_MODULE=railway_settings; if [ -n "$S3_ENDPOINT" ]; then case "$S3_ENDPOINT" in https://*) S3_ENDPOINT=${S3_ENDPOINT#https://}; S3_SECURE=True;; http://*) S3_ENDPOINT=${S3_ENDPOINT#http://}; S3_SECURE=False;; esac; export S3_ENDPOINT S3_SECURE; echo "bootstrap: s3 endpoint=$S3_ENDPOINT secure=$S3_SECURE"; fi; for i in 1 2 3 4 5 6 7 8 9 10 11 12; do ./manage.py migrate --noinput && break; echo "bootstrap: database not ready, retry $i"; sleep 5; done; if [ -n "$SUPERUSER_EMAIL" ] && [ -n "$SUPERUSER_PASSWORD" ]; then ./manage.py createsuperuser --email "$SUPERUSER_EMAIL" --password "$SUPERUSER_PASSWORD" || echo "bootstrap: superuser already present, skipping"; fi; ./manage.py shell -c "from django.conf import settings; from hc.api.models import Channel; qs = Channel.objects.filter(kind=\"email\"); n = 0 if settings.EMAIL_HOST else qs.count(); n and qs.delete(); print(f\"bootstrap: removed {n} email notification channel(s); set EMAIL_HOST to enable email alerts\")"; exec uwsgi /opt/healthchecks/docker/uwsgi.ini'`
- **Health check:** /api/v3/status/
- **Public domain:** Yes

## Buckets

- **pings**

## Documentation

![Healthchecks logo](https://opengraph.githubassets.com/a4f763bd1e3e35dd3005f7dc38cf212c8e8907a63df77f2b861b99c3acc76beb/healthchecks/healthchecks)

# Deploy and Host Healthchecks on Railway

Healthchecks is an open-source monitor for cron jobs, backups and any scheduled task meant to run quietly in the background. Instead of polling your servers, it waits: each job sends an HTTP request to a unique ping URL when it finishes, and if that ping does not arrive on schedule, Healthchecks alerts you through email, Slack, Telegram, PagerDuty, ntfy or webhooks. It is what sysadmins reach for after discovering a nightly database dump stopped running three weeks ago. Self-host Healthchecks and every ping, schedule and alert stays on infrastructure you control.

This template runs Healthchecks on Railway with the pieces a real deployment needs. The main service runs the Django app under uWSGI plus the two background senders from upstream's official image: `sendalerts`, which watches for late and failed checks, and `sendreports`, which sends periodic summaries. Managed PostgreSQL stores accounts, checks and the ping log, and an object storage bucket holds captured job output. Traffic arrives on the public Railway domain; the database and bucket stay private.

![Healthchecks Railway architecture](https://res.cloudinary.com/rroe4rtk/image/upload/v1786895545/0f86eeeb-8b4d-40cf-bb6f-f9a7a6253dec.png)

## Getting Started with Healthchecks on Railway

When the deploy finishes, open the public URL and you land on the sign-in page. The first administrator is created on first boot from `SUPERUSER_EMAIL` and `SUPERUSER_PASSWORD` — open the Healthchecks service in Railway, go to the Variables tab and copy the generated password. Sign in, then use Account → Settings to change both to your own. Public registration is closed by default (`REGISTRATION_OPEN=False`), so the instance is not open to strangers; invite teammates from Project → Settings instead.

Inside you get a starter project with one check. Click it to reveal its ping URL, then call that URL from the job you want to watch:

```
0 3 * * * /usr/local/bin/backup.sh &amp;&amp; curl -fsS -m 10 --retry 5 https://your-app.up.railway.app/ping/
```

Reload the dashboard and the check turns green with a "Last Ping" timestamp — confirmation the deployment works end to end. Add `/start` before the job and `/fail` in the error path to record run duration and alert on failure, and send stdout as the request body to attach each run's output to its ping. Then open Integrations and add an alert channel.

![Healthchecks dashboard listing three cron checks with live statuses](https://res.cloudinary.com/rroe4rtk/image/upload/v1786838585/healthchecks-checks-dashboard.png)
![Healthchecks ping detail showing captured pg_dump job output](https://res.cloudinary.com/rroe4rtk/image/upload/v1786838586/healthchecks-captured-job-output.png)
![Healthchecks integrations page with a delivered webhook alert](https://res.cloudinary.com/rroe4rtk/image/upload/v1786838588/healthchecks-webhook-delivered.png)

## About Hosting Healthchecks

Healthchecks implements the dead man's switch pattern: a job proves it is alive by checking in, and silence is the alarm. That catches failures HTTP probes miss — a cron entry lost in a migration, a backup that exits zero while writing an empty file. Teams self-host it to keep job metadata in-house, to watch jobs behind a VPN no SaaS probe can reach, and to avoid per-check pricing.

Key features:

- Period-and-grace schedules, cron expressions and systemd OnCalendar syntax, each with its own timezone
- Success, start and failure signals, giving run duration, a searchable event log and captured output per check
- 25+ alert integrations: email, Slack, Discord, Telegram, Mattermost, Teams, PagerDuty, Opsgenie, ntfy, Gotify, Pushover, Signal and webhooks
- Projects, teams and read-only members, plus per-project API keys for the REST management API
- Status badges, uptime summaries, Prometheus metrics, and TOTP and WebAuthn two-factor sign-in

The alert senders run inside the main container as supervised daemons, exactly as upstream's image runs them, so there is no separate worker to keep in sync.

## Why Deploy Healthchecks on Railway

Railway removes the setup work around the app itself:

- Managed PostgreSQL and object storage provisioned and wired up already
- HTTPS on a public domain immediately, custom domains a click away
- Migrations and first-admin creation run automatically on boot
- Private networking keeps the database off the public internet
- Health checks and restart policies configured out of the box

## Common Use Cases for Self-Hosted Healthchecks

- Confirming nightly database dumps and backup syncs ran, and keeping the output when they did not
- Watching scheduled ETL stages, alerting when a step is late instead of waiting for stale dashboards
- Monitoring certificate renewals, log rotation and cache warming — jobs that fail silently for months
- Giving jobs on internal networks an outbound-only way to report health

## Dependencies for Healthchecks

- **Healthchecks** — `healthchecks/healthchecks:latest`, the official image from [github.com/healthchecks/healthchecks](https://github.com/healthchecks/healthchecks). Serves the dashboard and ping API on port 8000 and runs the senders.
- **PostgreSQL** — Railway managed Postgres, storing users, projects, checks, the ping log and notification history. MySQL and SQLite also work upstream; Postgres is what healthchecks.io runs.
- **Object storage bucket** — Railway managed S3-compatible storage for ping bodies. Clear the `S3_*` variables and bodies go into the database.

### Environment Variables Reference

| Variable | Purpose |
|---|---|
| `SITE_ROOT` | Public base URL used in ping URLs, links and emails |
| `SECRET_KEY` | Signs sessions and login links; keep it stable |
| `SUPERUSER_EMAIL` / `SUPERUSER_PASSWORD` | First administrator, created on first boot |
| `REGISTRATION_OPEN` | `False` closes public sign-up |
| `EMAIL_HOST` and friends | SMTP server for email alerts and resets |
| `S3_*` | Object storage credentials for ping bodies |
| `RP_ID` | Domain for WebAuthn keys; update it for a custom domain |

### Deployment Dependencies

- Runtime: Python 3.14, Django 6.0, uWSGI
- Source: [github.com/healthchecks/healthchecks](https://github.com/healthchecks/healthchecks) (BSD-3-Clause); image on [Docker Hub](https://hub.docker.com/r/healthchecks/healthchecks)
- Docs: [healthchecks.io/docs/self_hosted_configuration](https://healthchecks.io/docs/self_hosted_configuration/)

## Hardware Requirements for Self-Hosting Healthchecks

| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 0.5 vCPU | 1–2 vCPU |
| RAM | 512 MB | 1–2 GB |
| Storage | Database only, ~1 GB | 5 GB plus object storage |
| Runtime | Python 3.11+, PostgreSQL 13+ | Python 3.14, PostgreSQL 16+ |

Load scales with ping volume, not check count; four uWSGI workers handle thousands of checks.

## Self-Hosting Healthchecks with Docker

The official image needs a database and a few variables. A minimal Docker Compose file:

```
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: hc-password
  web:
    image: healthchecks/healthchecks:latest
    ports: ["8000:8000"]
    environment:
      DB: postgres
      DB_HOST: db
      DB_PASSWORD: hc-password
      SECRET_KEY: change-me
      SITE_ROOT: https://hc.example.org
      ALLOWED_HOSTS: "*"
```

The image runs migrations and starts the alert senders itself. Create the first administrator with the bundled management command:

```
docker compose exec web ./manage.py createsuperuser --email you@example.org --password s3cret
```

Put a TLS-terminating proxy in front and make sure it sets `X-Forwarded-Proto`, or Django rejects sign-in with a CSRF error. Railway handles both.

## How Much Does Healthchecks Cost to Self-Host?

Healthchecks is free and open source under the BSD-3-Clause license, with no paid edition or feature gates — the self-hosted build is the same code that runs the hosted service. Hosted healthchecks.io is free for 20 checks and $20/month for 100, so self-hosting pays for itself once you watch a few dozen jobs. On Railway you pay only for resources used.

## FAQ

**What is Healthchecks?**
An open-source cron job monitoring service. Jobs send an HTTP ping when they succeed, and Healthchecks alerts you when an expected ping does not arrive on time.

**What does this Railway template deploy?**
The official `healthchecks/healthchecks` image with its dashboard, ping API and alert senders, plus managed PostgreSQL and an object storage bucket. Public domain, health check, migrations and the first admin account are configured for you.

**Why does the template include PostgreSQL and object storage?**
Every account, check and ping event lives in a relational database, so a database is not optional. Object storage holds captured job output; without it those bodies land in the database, which grows quickly.

**How do I enable email alerts in self-hosted Healthchecks?**
Set `EMAIL_HOST`, `EMAIL_PORT`, `EMAIL_HOST_USER`, `EMAIL_HOST_PASSWORD` and `DEFAULT_FROM_EMAIL` to your SMTP provider's values and redeploy. Until then use a webhook, Slack, Telegram or ntfy integration — none need an SMTP server.

**How do I ping a check from a shell script or cron entry?**
Append `curl -fsS -m 10 --retry 5 ` to the job; it stays quiet on success and retries transient network errors. Use `/start` before the work to measure duration and `/fail` in your error handler.

**Can I create checks programmatically with the Healthchecks API?**
Yes. Create an API key under Project → Settings and use the REST management API to list, create, pause and delete checks, keeping monitoring in sync with infrastructure-as-code. If you attach a custom domain, update `SITE_ROOT` and `RP_ID` so ping URLs and sign-in follow it.


## Similar templates

- [Pyroscope profiling](https://railway.com/deploy/pyroscope-profiling) — Protected continuous profiling with durable Pyroscope storage.
- [SigOnly](https://railway.com/deploy/sigonly) — Deploy SigNoz with a working demo app & config in one click
- [Unwrapped Spotify Music Stats](https://railway.com/deploy/wide-bold) — Unwrapped Spotify Music Stats, Estatísticas de músicas disponíveis

Open this page in a browser: https://railway.com/deploy/healthchecks-monitoring
