Přeskočit obsah

Zprovoznění aplikace Healthchecks na vlastním serveru

Cíl

Na Ubuntu 24.04 chci rozběhnout open-source aplikaci Healthchecks.

K čemu je to dobré

Cituju z dokumentace:

Healthchecks.io is a service for monitoring cron jobs and similar periodic processes:

  • Healthchecks.io listens for HTTP requests ("pings") from your cron jobs and scheduled tasks.
  • It keeps silent as long as pings arrive on time.
  • It raises an alert as soon as a ping does not arrive on time.

Healthchecks.io works as a dead man's switch for processes that need to run continuously or on a regular, known schedule. Some examples of jobs that would benefit from Healthchecks.io monitoring:

  • filesystem backups, database backups
  • task queues
  • database replication monitoring scripts

Healthchecks.io is not the right tool for:

  • monitoring website uptime by probing it with HTTP requests
  • collecting application performance metrics

Zprovoznění aplikace

Vycházím z:

Zdrojový kód, virtuální prostředí a instalace závislostí

git clone https://github.com/healthchecks/healthchecks.git healthchecks && cd healthchecks
git checkout v3.9 # viz https://github.com/healthchecks/healthchecks/releases
uv venv
source .venv/bin/activate
uv pip install -r requirements.txt
uv pip install gunicorn
# uv pip list

cat << EOF > .env
# https://healthchecks.io/docs/self_hosted_configuration/
[email protected]
ALLOWED_HOSTS=health.example.com,localhost
DEBUG=False
[email protected]

EMAIL_HOST='live.smtp.mailtrap.io'
EMAIL_HOST_USER='api'
EMAIL_HOST_PASSWORD='insert the email password here'
EMAIL_PORT=587
# Note that EMAIL_USE_TLS (587) / EMAIL_USE_SSL (465) are mutually exclusive, so only set one of those settings to True.
EMAIL_USE_TLS=True
EMAIL_USE_SSL=False

EMAIL_USE_VERIFICATION=False
REGISTRATION_OPEN=False
SECRET_KEY='$(tr -dc 'a-zA-Z0-9!@#$%^&*()-_=+' < /dev/urandom | head -c 64)'
[email protected]
SHELL_ENABLED=False
SITE_NAME='Mychecks'
SITE_ROOT='https://health.example.com'
EOF

chmod 0600 .env
./manage.py migrate
./manage.py createsuperuser
# ./manage.py test
# ./manage.py runserver

Stalo se mi, že ./manage.py … hlásí settings.EMAIL_HOST is not set, cannot send email, přestože je proměnná EMAIL_HOST v .env nastavená.

Znamená to, že si ./manage.py nevyzvedává nastavení z .env. To je pitomé, ale řešitelné pomocí set -a; source .env; set +a;.

Pro danou terminálovou relaci (~session) pak ./manage.py … funguje podle očekávání.

systemd a nginx

Tyhle kroky provádím jako root.

Vytvoření a spuštění systemd služby.

cd /etc/systemd/system/

cat << EOF > healthchecks.service
[Unit]
Description=Healthchecks App
After=network.target

[Service]
Type=simple
User=web
Group=web
WorkingDirectory=/home/web/p/healthchecks/
# Bez následujícího řádku se proměnné prostředí nastavené v .env nepoužijí!
EnvironmentFile=/home/web/p/healthchecks/.env
ExecStart=/home/web/p/healthchecks/.venv/bin/gunicorn --workers 3 --bind 0.0.0.0:8000 --timeout 120 hc.wsgi:application

Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable healthchecks.service
systemctl start healthchecks.service

# systemctl status healthchecks.service
# journalctl -u healthchecks.service -f
# systemctl restart healthchecks.service

Pro odesílání upozornění z aplikace je potřeba ještě systemd služba healthchecks-sendalerts.service:

[Unit]
Description=Healthchecks Sendalerts
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=web
Group=web
WorkingDirectory=/home/web/p/healthchecks/
EnvironmentFile=/home/web/p/healthchecks/.env
ExecStart=/home/web/p/healthchecks/.venv/bin/python -u /home/web/p/healthchecks/manage.py sendalerts

Restart=always

# během 120 sekund může dojít k maximálně 5 pokusům o restart
RestartSec=20
StartLimitInterval=120
StartLimitBurst=5

[Install]
WantedBy=multi-user.target

Následně tedy:

systemctl daemon-reload
systemctl enable healthchecks-sendalerts.service
systemctl start healthchecks-sendalerts.service

Volitelně je možné vytvořit ještě dvě další systemd služby pro:

./manage.py sendreports # sends out monthly reports, weekly reports, and the daily or hourly reminders
./manage.py smtpd --port 2525 # https://github.com/healthchecks/healthchecks/#receiving-emails

Instalace a konfigurace nginx, vystavení TLS certifikátu.

apt install nginx
systemctl status nginx

ufw allow 'Nginx HTTP'
ufw allow 'Nginx HTTPS'
ufw status

cd /etc/nginx/sites-available/

cat << 'EOF' > health.example.com
# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name health.example.com;
    return 301 https://$server_name$request_uri;
}

# HTTPS server
server {
    listen 443;
    server_name health.example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Timeout settings
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}
EOF

ln -s /etc/nginx/sites-available/health.example.com /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx

# apt install certbot python3-certbot-nginx
certbot --nginx -d health.example.com
# certbot renew --dry-run
# systemctl status certbot.timer

Následné aktualizace

Každá aktualizace pak probíhá takhle:

# Stáhne informace o "tags" a pak přepne na nejnovější tag.
# git fetch --all --tags
# git checkout $(git describe --tags $(git rev-list --tags --max-count=1))
# git status
set -a; source .env; set +a;
./manage.py compress --force
./manage.py collectstatic
./manage.py migrate
# Následně "systemctl restart healthchecks.service healthchecks-sendalerts.service" jako root.

Postgres

Kdybych chtěl místo výchozí SQLite použít databázi Postgres, hodí se tyto návody pro její zprovoznění:

Vlastně je to docela jednoduché:

apt install -y postgresql-common
/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
apt-cache depends postgresql
apt install postgresql
sudo -u postgres psql
    CREATE USER healthchecks WITH PASSWORD 'tajne_heslo';
    CREATE DATABASE healthchecks OWNER healthchecks;
    GRANT ALL PRIVILEGES ON DATABASE healthchecks TO healthchecks;
    \q

Databázi chci přístupnou jen z localhostu, ne zvenku. Že to tak je, můžu zkontrolovat takhle:

netstat -tulpn | grep postgres
psql "postgresql://healthchecks:tajne_heslo@localhost:5432/healthchecks" -c "show listen_addresses;"

Vzhledem k tomu, že databáze není přístupná zvenku, není - myslím - potřeba:

ALTER USER postgres with encrypted password 'strong_password';

Pak je ještě nutné do .env přidat:

DB="postgres"

DB_HOST="localhost"
DB_PORT="5432"
DB_NAME="healthchecks"
DB_USER="healthchecks"
DB_PASSWORD="tajne_heslo"

Smyčka přesměrování

Po provedení výše uvedeného mi prohlížeč hlásil ERR_TOO_MANY_REDIRECTS.

S debugováním mi pomohlo:

curl -I http://127.0.0.1:8000
curl -IL http://127.0.0.1:8000

Příčina byla v nastavení SSL/TLS encryption na Cloudflare. Bylo potřeba přepnout encryption mode z Flexible na Full (strict).

Víc tu:

Redirect loops will occur if your origin server automatically redirects all HTTP requests to HTTPS.

A tu:

The reason for “too many redirects” is if you have an http->https redirect on your origin server. The client connects over https, but Cloudflare connects to your origin on http, which returns a redirect to https, which connects over http to be redirected to https and so on forever until the browser gives up.

Není to specifické pro Healthchecks, došlo by k tomu u libovolné služby s výše uvedenou nginx konfigurací a nastavením Cloudflare.

Alternativa k Healthchecks

Uptime Kuma.

Nabízí více typů monitorů:

Monitoring uptime for HTTP(s) / TCP / HTTP(s) Keyword / HTTP(s) Json Query / Ping / DNS Record / Push / Steam Game Server / Docker Containers.

Z výše uvedených monitorů nabízí Healthchecks vlastně jen Push.

Na druhou stranu má Uptime Kuma výrazně horší dokumentaci. Aplikace je napsaná v JavaScriptu, takže pro provoz bez Dockeru je nutné mít na serveru Node.js a npm. Já dávám přednost kombinaci Python a uv, i proto raději použiju Healthchecks.

Uptime Kuma také neumí - stejně jako Healthchecks - hledat řetězec na „SPA webu“:

The website is most likely an SPA, meaning content is loaded by JavaScript after initial page load. Currently you cannot check the content of such a website.

Závěr

Aplikace běží, můžeme se přihlásit s údaji vytvořenými pomocí ./manage.py createsuperuser na https://health.example.com.

Může se hodit: