diff --git a/source/_static/images/healthchecks.svg b/source/_static/images/healthchecks.svg new file mode 100644 index 00000000..7cc6a6c8 --- /dev/null +++ b/source/_static/images/healthchecks.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/source/guide_healthchecks.rst b/source/guide_healthchecks.rst new file mode 100644 index 00000000..67f58862 --- /dev/null +++ b/source/guide_healthchecks.rst @@ -0,0 +1,742 @@ +.. highlight:: console + +.. author:: MetroMarv + +.. categorize your guide! refer to the current list of tags: https://lab.uberspace.de/tags +.. tag:: lang-python +.. tag:: web +.. tag:: django +.. tag:: monitoring + +.. sidebar:: About + + .. image:: _static/images/healthchecks.svg + :align: center + +########## +Healthchecks +########## + +.. tag_list:: + +`Healthchecks `_ allows you to monitor your periodically run jobs (e.g. CronJobs). It will inform you via different channels (mail, Mattermost, +Slack, Signal, ...) if your job didn't execute on time. To track execution HTTP request or mails may be used. + +It offers a web interface to manage your jobs to be monitored. + +---- + +.. note:: For this guide you should be familiar with the basic concepts of + + * :manual:`Python ` + * :manual:`MySQL ` or :manual:`PostgreSQL ` (not used in this guide) + * :manual:`supervisord ` + * :manual:`domains ` + +License +======= + +All relevant legal information can be found here + + * https://github.com/healthchecks/healthchecks/blob/master/LICENSE + +Prerequisites +============= + +First of all we create a new :manual:`MySQL ` database, that our Healthchecks instance will use: + +:: + + [isabell@stardust ~]$ mysql -e "CREATE DATABASE isabell_healthchecks" + [isabell@stardust ~]$ + +If you'd like to use :manual:`PostgreSQL ` instead. Please see the respective +:manual:`manual entry `. + +.. include:: includes/my-print-defaults.rst + +Second we create a :manual_anchor:`new mailbox `, that we'll use to send alerts to our private email +address if one of our jobs failed to run. You'll have to interactively provide a password. Please choose a secure one and remember the +password, you'll need it later. + +:: + + [isabell@stardust ~]$ uberspace mail user add healthchecks + Enter a password for the mailbox: + Please confirm your password: + New mailbox created for user: 'healthchecks', it will be live in a few minutes... + [isabell@stardust ~]$ + +Third of all your URL needs to be setup: + +.. include:: includes/web-domain-list.rst + + +We're using :manual:`Python ` in the currently latest version 3.11: + +:: + + [isabell@stardust ~]$ python3.11 --version + Python 3.11.7 + [isabell@stardust ~]$ + +Installation +============ + +Download the source +------------------- + +In the following steps we'll create a separate folder for this app and future apps, download the :manual:`Python ` source code +from GitHub and select the latest version using git tags: + +.. code-block:: console + :emphasize-lines: 21 + + [isabell@stardust ~]$ mkdir ~/apps + [isabell@stardust ~]$ cd ~/apps + [isabell@stardust ~]$ git clone https://github.com/healthchecks/healthchecks.git + Cloning into 'healthchecks'... + remote: Enumerating objects: 28393, done. + remote: Counting objects: 100% (3677/3677), done. + remote: Compressing objects: 100% (448/448), done. + remote: Total 28393 (delta 3420), reused 3349 (delta 3229), pack-reused 24716 + Receiving objects: 100% (28393/28393), 22.57 MiB | 14.09 MiB/s, done. + Resolving deltas: 100% (22120/22120), done. + [isabell@stardust ~]$ cd healthchecks + [isabell@stardust ~]$ git tag + 1.0.2 + v1.0 + v1.0.1 + v1.0.2 + [...] + v2.9.2 + v3.0 + v3.0.1 + v3.2 + v3.1 + [isabell@stardust ~]$ git checkout v3.2 + Note: switching to 'v3.2'. + + You are in 'detached HEAD' state. You can look around, make experimental + changes and commit them, and you can discard any commits you make in this + state without impacting any branches by switching back to a branch. + + If you want to create a new branch to retain commits you create, you may + do so (now or later) by using -c with the switch command. Example: + + git switch -c + + Or undo this operation with: + + git switch - + + Turn off this advice by setting config variable advice.detachedHead to false + + HEAD is now at c99b644a Update CHANGELOG for v3.2 release + [isabell@stardust ~]$ + +The note of the ``git checkout`` command can be ignored as we do not plan to do any commits in this git repository. + +Set up the virtual environment +----------------- + +Next we will setup a :manual:`Python ` virtual environment where all dependencies are encapsulated. Then we +install the required dependencies and on top of that also `gunicorn `_ which will be our HTTP server +later. + +:: + + [isabell@stardust ~]$ python3.11 -m venv venv + [isabell@stardust ~]$ source venv/bin/activate + (venv) [isabell@stardust ~]$ pip3.11 install -r requirements.txt + Collecting aiosmtpd==1.4.4.post2 (from -r requirements.txt (line 1)) + Obtaining dependency information for aiosmtpd==1.4.4.post2 from https://files.pythonhosted.org/packages/ef/b3/f4cce9da53b02aa7d4c0662ca344421023feefc5c8f815b90d1c7514702e/aiosmtpd-1.4.4.post2-py3-none-any.whl.metadata + Downloading aiosmtpd-1.4.4.post2-py3-none-any.whl.metadata (6.8 kB) + Collecting cronsim==2.5 (from -r requirements.txt (line 2)) + Using cached cronsim-2.5-py3-none-any.whl + Collecting Django==5.0.2 (from -r requirements.txt (line 3)) + Obtaining dependency information for Django==5.0.2 from https://files.pythonhosted.org/packages/50/1b/7536019fd20654919dcd81b475fee1e54f21bd71b2b4e094b2ab075478b2/Django-5.0.2-py3-none-any.whl.metadata + Using cached Django-5.0.2-py3-none-any.whl.metadata (4.1 kB) + Collecting django-compressor==4.4 (from -r requirements.txt (line 4)) + Obtaining dependency information for django-compressor==4.4 from https://files.pythonhosted.org/packages/a0/b5/3c000d6d7b8ffa8831d2ef5bcbbe5780de172024e226ec89391853d4b759/django_compressor-4.4-py2.py3-none-any.whl.metadata + Using cached django_compressor-4.4-py2.py3-none-any.whl.metadata (5.0 kB) + Collecting django-stubs-ext==4.2.7 (from -r requirements.txt (line 5)) + Obtaining dependency information for django-stubs-ext==4.2.7 from https://files.pythonhosted.org/packages/21/be/e87631afa766a101877758495bec4108fdaa20ba65a2e80bc02cfa874985/django_stubs_ext-4.2.7-py3-none-any.whl.metadata + Using cached django_stubs_ext-4.2.7-py3-none-any.whl.metadata (3.6 kB) + Collecting fido2==1.1.2 (from -r requirements.txt (line 6)) + Obtaining dependency information for fido2==1.1.2 from https://files.pythonhosted.org/packages/e3/99/68bab31fbb49e8b3a58ce31cfde5ed9aede6efe5eebbece2eaf93ade75c0/fido2-1.1.2-py3-none-any.whl.metadata + Using cached fido2-1.1.2-py3-none-any.whl.metadata (1.4 kB) + Collecting oncalendar==1.0 (from -r requirements.txt (line 7)) + Using cached oncalendar-1.0-py3-none-any.whl + Collecting psycopg2==2.9.9 (from -r requirements.txt (line 8)) + Using cached psycopg2-2.9.9-cp311-cp311-linux_x86_64.whl + Collecting pycurl==7.45.2 (from -r requirements.txt (line 9)) + Using cached pycurl-7.45.2-cp311-cp311-linux_x86_64.whl + Collecting pydantic==2.5.3 (from -r requirements.txt (line 10)) + Obtaining dependency information for pydantic==2.5.3 from https://files.pythonhosted.org/packages/dd/b7/9aea7ee6c01fe3f3c03b8ca3c7797c866df5fecece9d6cb27caa138db2e2/pydantic-2.5.3-py3-none-any.whl.metadata + Using cached pydantic-2.5.3-py3-none-any.whl.metadata (65 kB) + Collecting pyotp==2.9.0 (from -r requirements.txt (line 11)) + Obtaining dependency information for pyotp==2.9.0 from https://files.pythonhosted.org/packages/c3/c0/c33c8792c3e50193ef55adb95c1c3c2786fe281123291c2dbf0eaab95a6f/pyotp-2.9.0-py3-none-any.whl.metadata + Using cached pyotp-2.9.0-py3-none-any.whl.metadata (9.8 kB) + Collecting segno==1.6.0 (from -r requirements.txt (line 12)) + Obtaining dependency information for segno==1.6.0 from https://files.pythonhosted.org/packages/f7/06/3613899162a62ff307c07ad3214e6a1772f946c34f25ccd79f6549dd2e69/segno-1.6.0-py3-none-any.whl.metadata + Using cached segno-1.6.0-py3-none-any.whl.metadata (9.7 kB) + Collecting statsd==4.0.1 (from -r requirements.txt (line 13)) + Obtaining dependency information for statsd==4.0.1 from https://files.pythonhosted.org/packages/f4/d0/c9543b52c067a390ae6ae632d7fd1b97a35cdc8d69d40c0b7d334b326410/statsd-4.0.1-py2.py3-none-any.whl.metadata + Downloading statsd-4.0.1-py2.py3-none-any.whl.metadata (2.9 kB) + Collecting whitenoise==6.6.0 (from -r requirements.txt (line 14)) + Obtaining dependency information for whitenoise==6.6.0 from https://files.pythonhosted.org/packages/67/16/bb488ac8230f1bce94943b6654f2aad566d18aae575c8b6d8a99c78c489e/whitenoise-6.6.0-py3-none-any.whl.metadata + Using cached whitenoise-6.6.0-py3-none-any.whl.metadata (3.7 kB) + Collecting atpublic (from aiosmtpd==1.4.4.post2->-r requirements.txt (line 1)) + Obtaining dependency information for atpublic from https://files.pythonhosted.org/packages/42/d5/f3c7110d3763af646150203b8bfe6932ab05a9b3e228c27d138babeb92ae/atpublic-4.0-py3-none-any.whl.metadata + Using cached atpublic-4.0-py3-none-any.whl.metadata (1.8 kB) + Collecting attrs (from aiosmtpd==1.4.4.post2->-r requirements.txt (line 1)) + Obtaining dependency information for attrs from https://files.pythonhosted.org/packages/e0/44/827b2a91a5816512fcaf3cc4ebc465ccd5d598c45cefa6703fcf4a79018f/attrs-23.2.0-py3-none-any.whl.metadata + Using cached attrs-23.2.0-py3-none-any.whl.metadata (9.5 kB) + Collecting asgiref<4,>=3.7.0 (from Django==5.0.2->-r requirements.txt (line 3)) + Obtaining dependency information for asgiref<4,>=3.7.0 from https://files.pythonhosted.org/packages/9b/80/b9051a4a07ad231558fcd8ffc89232711b4e618c15cb7a392a17384bbeef/asgiref-3.7.2-py3-none-any.whl.metadata + Using cached asgiref-3.7.2-py3-none-any.whl.metadata (9.2 kB) + Collecting sqlparse>=0.3.1 (from Django==5.0.2->-r requirements.txt (line 3)) + Obtaining dependency information for sqlparse>=0.3.1 from https://files.pythonhosted.org/packages/98/5a/66d7c9305baa9f11857f247d4ba761402cea75db6058ff850ed7128957b7/sqlparse-0.4.4-py3-none-any.whl.metadata + Downloading sqlparse-0.4.4-py3-none-any.whl.metadata (4.0 kB) + Collecting django-appconf>=1.0.3 (from django-compressor==4.4->-r requirements.txt (line 4)) + Obtaining dependency information for django-appconf>=1.0.3 from https://files.pythonhosted.org/packages/c0/98/1cb3d9e8b1c6d0a74539b998474796fc5c0c0888b6201e5c95ba2f7a0677/django_appconf-1.0.6-py3-none-any.whl.metadata + Using cached django_appconf-1.0.6-py3-none-any.whl.metadata (5.4 kB) + Collecting rcssmin==1.1.1 (from django-compressor==4.4->-r requirements.txt (line 4)) + Obtaining dependency information for rcssmin==1.1.1 from https://files.pythonhosted.org/packages/70/61/3f129d34981d1d7eb46cd9ba20a73720d99a64bfa0cf10c4dbddd1b9c2b7/rcssmin-1.1.1-cp311-cp311-manylinux1_x86_64.whl.metadata + Downloading rcssmin-1.1.1-cp311-cp311-manylinux1_x86_64.whl.metadata (4.5 kB) + Collecting rjsmin==1.2.1 (from django-compressor==4.4->-r requirements.txt (line 4)) + Obtaining dependency information for rjsmin==1.2.1 from https://files.pythonhosted.org/packages/29/be/427af5875f63e6ca4f717285a36fd3f377665dacc0a57d3ea68a937296a4/rjsmin-1.2.1-cp311-cp311-manylinux1_x86_64.whl.metadata + Downloading rjsmin-1.2.1-cp311-cp311-manylinux1_x86_64.whl.metadata (4.3 kB) + Collecting typing-extensions (from django-stubs-ext==4.2.7->-r requirements.txt (line 5)) + Obtaining dependency information for typing-extensions from https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl.metadata + Downloading typing_extensions-4.10.0-py3-none-any.whl.metadata (3.0 kB) + Collecting cryptography!=35,<44,>=2.6 (from fido2==1.1.2->-r requirements.txt (line 6)) + Obtaining dependency information for cryptography!=35,<44,>=2.6 from https://files.pythonhosted.org/packages/d4/fa/057f9d7a5364c86ccb6a4bd4e5c58920dcb66532be0cc21da3f9c7617ec3/cryptography-42.0.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata + Downloading cryptography-42.0.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (5.3 kB) + Collecting annotated-types>=0.4.0 (from pydantic==2.5.3->-r requirements.txt (line 10)) + Obtaining dependency information for annotated-types>=0.4.0 from https://files.pythonhosted.org/packages/28/78/d31230046e58c207284c6b2c4e8d96e6d3cb4e52354721b944d3e1ee4aa5/annotated_types-0.6.0-py3-none-any.whl.metadata + Using cached annotated_types-0.6.0-py3-none-any.whl.metadata (12 kB) + Collecting pydantic-core==2.14.6 (from pydantic==2.5.3->-r requirements.txt (line 10)) + Obtaining dependency information for pydantic-core==2.14.6 from https://files.pythonhosted.org/packages/e7/84/2dc88180fc6f0d13aab2a47a53b89c2dbc239e2a87d0a58e31077e111e82/pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata + Using cached pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.5 kB) + Collecting cffi>=1.12 (from cryptography!=35,<44,>=2.6->fido2==1.1.2->-r requirements.txt (line 6)) + Obtaining dependency information for cffi>=1.12 from https://files.pythonhosted.org/packages/9b/89/a31c81e36bbb793581d8bba4406a8aac4ba84b2559301c44eef81f4cf5df/cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata + Using cached cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (1.5 kB) + Collecting pycparser (from cffi>=1.12->cryptography!=35,<44,>=2.6->fido2==1.1.2->-r requirements.txt (line 6)) + Obtaining dependency information for pycparser from https://files.pythonhosted.org/packages/62/d5/5f610ebe421e85889f2e55e33b7f9a6795bd982198517d912eb1c76e1a53/pycparser-2.21-py2.py3-none-any.whl.metadata + Downloading pycparser-2.21-py2.py3-none-any.whl.metadata (1.1 kB) + Using cached aiosmtpd-1.4.4.post2-py3-none-any.whl (154 kB) + Using cached Django-5.0.2-py3-none-any.whl (8.2 MB) + Using cached django_compressor-4.4-py2.py3-none-any.whl (148 kB) + Using cached django_stubs_ext-4.2.7-py3-none-any.whl (8.9 kB) + Using cached fido2-1.1.2-py3-none-any.whl (203 kB) + Using cached pydantic-2.5.3-py3-none-any.whl (381 kB) + Using cached pyotp-2.9.0-py3-none-any.whl (13 kB) + Using cached segno-1.6.0-py3-none-any.whl (74 kB) + Using cached statsd-4.0.1-py2.py3-none-any.whl (13 kB) + Using cached whitenoise-6.6.0-py3-none-any.whl (19 kB) + Using cached pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.1 MB) + Using cached rcssmin-1.1.1-cp311-cp311-manylinux1_x86_64.whl (48 kB) + Using cached rjsmin-1.2.1-cp311-cp311-manylinux1_x86_64.whl (31 kB) + Using cached annotated_types-0.6.0-py3-none-any.whl (12 kB) + Using cached asgiref-3.7.2-py3-none-any.whl (24 kB) + Downloading cryptography-42.0.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.6 MB) + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.6/4.6 MB 42.2 MB/s eta 0:00:00 + Using cached django_appconf-1.0.6-py3-none-any.whl (6.4 kB) + Using cached sqlparse-0.4.4-py3-none-any.whl (41 kB) + Downloading typing_extensions-4.10.0-py3-none-any.whl (33 kB) + Using cached atpublic-4.0-py3-none-any.whl (4.9 kB) + Using cached attrs-23.2.0-py3-none-any.whl (60 kB) + Using cached cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (464 kB) + Using cached pycparser-2.21-py2.py3-none-any.whl (118 kB) + Installing collected packages: statsd, rjsmin, rcssmin, whitenoise, typing-extensions, sqlparse, segno, pyotp, pycurl, pycparser, psycopg2, oncalendar, cronsim, attrs, atpublic, asgiref, annotated-types, pydantic-core, Django, cffi, aiosmtpd, pydantic, django-stubs-ext, django-appconf, cryptography, fido2, django-compressor + Successfully installed Django-5.0.2 aiosmtpd-1.4.4.post2 annotated-types-0.6.0 asgiref-3.7.2 atpublic-4.0 attrs-23.2.0 cffi-1.16.0 cronsim-2.5 cryptography-42.0.5 django-appconf-1.0.6 django-compressor-4.4 django-stubs-ext-4.2.7 fido2-1.1.2 oncalendar-1.0 psycopg2-2.9.9 pycparser-2.21 pycurl-7.45.2 pydantic-2.5.3 pydantic-core-2.14.6 pyotp-2.9.0 rcssmin-1.1.1 rjsmin-1.2.1 segno-1.6.0 sqlparse-0.4.4 statsd-4.0.1 typing-extensions-4.10.0 whitenoise-6.6.0 + + [notice] A new release of pip is available: 23.2.1 -> 24.0 + [notice] To update, run: pip install --upgrade pip + [isabell@stardust ~]$ pip3.11 install mysql + Collecting mysql + Obtaining dependency information for mysql from https://files.pythonhosted.org/packages/9a/52/8d29c58f6ae448a72fbc612955bd31accb930ca479a7ba7197f4ae4edec2/mysql-0.0.3-py3-none-any.whl.metadata + Downloading mysql-0.0.3-py3-none-any.whl.metadata (746 bytes) + Collecting mysqlclient (from mysql) + Using cached mysqlclient-2.2.4-cp311-cp311-linux_x86_64.whl + Downloading mysql-0.0.3-py3-none-any.whl (1.2 kB) + Installing collected packages: mysqlclient, mysql + Successfully installed mysql-0.0.3 mysqlclient-2.2.4 + + [notice] A new release of pip is available: 23.2.1 -> 24.0 + [notice] To update, run: pip install --upgrade pip + [isabell@stardust ~]$ pip3.11 install gunicorn + Collecting gunicorn + Obtaining dependency information for gunicorn from https://files.pythonhosted.org/packages/0e/2a/c3a878eccb100ccddf45c50b6b8db8cf3301a6adede6e31d48e8531cab13/gunicorn-21.2.0-py3-none-any.whl.metadata + Using cached gunicorn-21.2.0-py3-none-any.whl.metadata (4.1 kB) + Collecting packaging (from gunicorn) + Obtaining dependency information for packaging from https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl.metadata + Downloading packaging-24.0-py3-none-any.whl.metadata (3.2 kB) + Using cached gunicorn-21.2.0-py3-none-any.whl (80 kB) + Downloading packaging-24.0-py3-none-any.whl (53 kB) + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 53.5/53.5 kB 2.9 MB/s eta 0:00:00 + Installing collected packages: packaging, gunicorn + Successfully installed gunicorn-21.2.0 packaging-24.0 + + [notice] A new release of pip is available: 23.2.1 -> 24.0 + [notice] To update, run: pip install --upgrade pip + [isabell@stardust ~]$ + +Configuration +============= + +Configure the app +------------------------ + +Edit the file ``./hc/local_settings.py`` and set your host specific settings: + +.. code-block:: python + + DEBUG = False + + SITE_ROOT = 'https://isabell.uber.space' + SITE_NAME = 'My Monitoring Project' + PING_ENDPOINT='https://isabell.uber.space/ping/' + DEFAULT_FROM_EMAIL = 'healthchecks@isabell.uber.space' + ALLOWED_HOSTS=['isabell.uber.space'] + CSRF_TRUSTED_ORIGINS=['https://isabell.uber.space'] + SECRET_KEY = '' + REGISTRATION_OPEN = False # True if you'd like to allow user registrations of anyone from the internet + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'HOST': 'localhost', + 'PORT': '3306', + 'NAME': 'isabell_healthchecks', + 'USER': 'isabell', + 'PASSWORD': 'MySuperSecretPassword', + 'TEST': {'CHARSET': 'UTF8'} + } + } + + # Email + EMAIL_HOST = 'stardust.uberspace.de' + EMAIL_PORT = 465 + EMAIL_HOST_USER = 'healthchecks@isabell.uber.space' + EMAIL_HOST_PASSWORD = 'MySuperSecretPassword' + EMAIL_USE_TLS = False + EMAIL_USE_SSL = True + + + +Initialize the database +----------------- + +Once we set the correct settings we can initialize the database: + +:: + + (venv) [isabell@stardust ~]$ python3.11 ./manage.py migrate + System check identified some issues: + + WARNINGS: + ?: (mysql.W002) MariaDB Strict Mode is not set for database connection 'default' + HINT: MariaDB's Strict Mode fixes many data integrity problems in MariaDB, such as data truncation upon insertion, by escalating warnings into errors. It is strongly recommended you activate it. See: https://docs.djangoproject.com/en/5.0/ref/databases/#mysql-sql-mode + api.Check: (models.W037) MariaDB does not support indexes with conditions. + HINT: Conditions will be ignored. Silence this warning if you don't care about it. + api.Flip: (models.W037) MariaDB does not support indexes with conditions. + HINT: Conditions will be ignored. Silence this warning if you don't care about it. + Operations to perform: + Apply all migrations: accounts, admin, api, auth, contenttypes, logs, payments, sessions + Running migrations: + Applying contenttypes.0001_initial... OK + Applying auth.0001_initial... OK + Applying accounts.0001_initial... OK + Applying accounts.0002_profile_ping_log_limit... OK + Applying accounts.0003_profile_token... OK + Applying accounts.0004_profile_api_key... OK + Applying accounts.0005_auto_20160509_0801... OK + Applying accounts.0006_profile_current_team... OK + Applying accounts.0007_profile_check_limit... OK + Applying accounts.0008_profile_bill_to... OK + Applying accounts.0009_auto_20170714_1734... OK + Applying accounts.0010_profile_team_limit... OK + Applying accounts.0011_profile_sort... OK + Applying accounts.0012_auto_20171014_1002... OK + Applying accounts.0013_remove_profile_team_access_allowed... OK + Applying accounts.0014_auto_20171227_1530... OK + Applying accounts.0015_auto_20181029_1858... OK + Applying accounts.0016_remove_profile_bill_to... OK + Applying accounts.0017_auto_20190112_1426... OK + Applying accounts.0018_auto_20190112_1426... OK + Applying accounts.0019_project_badge_key... OK + Applying accounts.0020_auto_20190112_1950... OK + Applying accounts.0021_auto_20190112_2005... OK + Applying accounts.0022_auto_20190114_0857... OK + Applying accounts.0023_auto_20190117_1419... OK + Applying accounts.0024_auto_20190119_1540... OK + Applying accounts.0025_remove_member_team... OK + Applying accounts.0026_auto_20190204_2042... OK + Applying accounts.0027_profile_deletion_notice_date... OK + Applying accounts.0028_auto_20191119_1346... OK + Applying accounts.0029_remove_profile_current_project... OK + Applying accounts.0030_member_transfer_request_date... OK + Applying accounts.0031_auto_20200803_1413... OK + Applying accounts.0032_auto_20200819_0757... OK + Applying accounts.0033_member_rw... OK + Applying accounts.0034_credential... OK + Applying accounts.0035_profile_reports... OK + Applying accounts.0036_fill_profile_reports... OK + Applying accounts.0037_profile_tz... OK + Applying accounts.0038_profile_theme... OK + Applying accounts.0039_remove_profile_reports_allowed... OK + Applying accounts.0040_auto_20210722_1244... OK + Applying accounts.0041_fill_role... OK + Applying accounts.0042_remove_member_rw... OK + Applying accounts.0043_add_role_manager... OK + Applying accounts.0044_auto_20210730_0942... OK + Applying accounts.0045_auto_20210908_1257... OK + Applying accounts.0046_profile_deletion_scheduled_date... OK + Applying accounts.0047_profile_over_limit_date... OK + Applying accounts.0048_alter_profile_user... OK + Applying admin.0001_initial... OK + Applying admin.0002_logentry_remove_auto_add... OK + Applying admin.0003_logentry_add_action_flag_choices... OK + Applying api.0001_initial... OK + Applying api.0002_auto_20150616_0732... OK + Applying api.0003_auto_20150616_1249... OK + Applying api.0004_auto_20150616_1319... OK + Applying api.0005_auto_20150630_2021... OK + Applying api.0006_check_grace... OK + Applying api.0007_ping... OK + Applying api.0008_auto_20150801_1213... OK + Applying api.0009_auto_20150801_1250... OK + Applying api.0010_channel... OK + Applying api.0011_notification... OK + Applying api.0012_auto_20150930_1922... OK + Applying api.0013_auto_20151001_2029... OK + Applying api.0014_auto_20151019_2039... OK + Applying api.0015_auto_20151022_1008... OK + Applying api.0016_auto_20151030_1107... OK + Applying api.0017_auto_20151117_1032... OK + Applying api.0018_remove_ping_body... OK + Applying api.0019_check_tags... OK + Applying api.0020_check_n_pings... OK + Applying api.0021_ping_n... OK + Applying api.0022_auto_20160130_2042... OK + Applying api.0023_auto_20160131_1919... OK + Applying api.0024_auto_20160203_2227... OK + Applying api.0025_auto_20160216_1214... OK + Applying api.0026_auto_20160415_1824... OK + Applying api.0027_auto_20161213_1059... OK + Applying api.0028_auto_20170305_1907... OK + Applying api.0029_auto_20170507_1251... OK + Applying api.0030_check_last_ping_body... OK + Applying api.0031_auto_20170509_1320... OK + Applying api.0032_auto_20170608_1158... OK + Applying api.0033_auto_20170714_1715... OK + Applying api.0034_auto_20171227_1530... OK + Applying api.0035_auto_20171229_2008... OK + Applying api.0036_auto_20180116_2243... OK + Applying api.0037_auto_20180127_1215... OK + Applying api.0038_auto_20180318_1306... OK + Applying api.0039_remove_check_last_ping_body... OK + Applying api.0040_auto_20180517_1336... OK + Applying api.0041_check_desc... OK + Applying api.0042_auto_20181029_1522... OK + Applying api.0043_channel_name... OK + Applying api.0044_auto_20181120_2004... OK + Applying api.0045_flip... OK + Applying api.0046_auto_20181218_1245... OK + Applying api.0047_auto_20181225_2315... OK + Applying api.0048_auto_20190102_0737... OK + Applying api.0049_auto_20190102_0743... OK + Applying api.0050_ping_kind... OK + Applying api.0051_auto_20190104_0908... OK + Applying api.0052_auto_20190104_1122... OK + Applying api.0053_check_subject... OK + Applying api.0054_auto_20190112_1427... OK + Applying api.0055_auto_20190112_1427... OK + Applying api.0056_auto_20190114_0857... OK + Applying api.0057_auto_20190118_1319... OK + Applying api.0058_auto_20190312_1716... OK + Applying api.0059_auto_20190314_1744... OK + Applying api.0060_tokenbucket... OK + Applying api.0061_webhook_values... OK + Applying api.0062_auto_20190720_1350... OK + Applying api.0063_auto_20190903_0901... OK + Applying api.0064_auto_20191119_1346... OK + Applying api.0065_auto_20191127_1240... OK + Applying api.0066_channel_last_error... OK + Applying api.0067_last_error_values... OK + Applying api.0068_auto_20200117_1023... OK + Applying api.0069_auto_20200117_1227... OK + Applying api.0070_auto_20200411_1310... OK + Applying api.0071_check_manual_resume... OK + Applying api.0072_auto_20200701_1007... OK + Applying api.0073_auto_20200721_1000... OK + Applying api.0074_auto_20200803_1411... OK + Applying api.0075_auto_20200805_1004... OK + Applying api.0076_auto_20201128_0951... OK + Applying api.0077_auto_20210506_0755... OK + Applying api.0078_sms_values... OK + Applying api.0079_auto_20210907_0918... OK + Applying api.0080_fill_slug... OK + Applying api.0081_channel_last_notify... OK + Applying api.0082_fill_last_notify... OK + Applying api.0083_channel_disabled... OK + Applying api.0084_ping_body_raw... OK + Applying api.0085_ping_object_size... OK + Applying api.0086_remove_check_last_ping_was_fail_and_more... OK + Applying api.0087_check_failure_kw_check_filter_body_and_more... OK + Applying api.0088_fill_kw... OK + Applying api.0089_remove_check_subject_remove_check_subject_fail... OK + Applying api.0090_alter_check_filter_subject... OK + Applying api.0091_alter_check_filter_body... OK + Applying api.0092_alter_check_success_kw... OK + Applying api.0093_alter_check_failure_kw... OK + Applying api.0094_ping_rid_alter_channel_kind... OK + Applying api.0095_check_last_start_rid... OK + Applying api.0096_check_start_kw_alter_channel_kind... OK + Applying api.0097_alter_channel_kind... OK + Applying api.0098_channel_last_notify_duration... OK + Applying api.0099_alter_channel_disabled... OK + Applying api.0100_opsgenie_values... OK + Applying api.0101_alter_channel_kind... OK + Applying api.0102_alter_check_kind... OK + Applying contenttypes.0002_remove_content_type_name... OK + Applying auth.0002_alter_permission_name_max_length... OK + Applying auth.0003_alter_user_email_max_length... OK + Applying auth.0004_alter_user_username_opts... OK + Applying auth.0005_alter_user_last_login_null... OK + Applying auth.0006_require_contenttypes_0002... OK + Applying auth.0007_alter_validators_add_error_messages... OK + Applying auth.0008_alter_user_username_max_length... OK + Applying auth.0009_alter_user_last_name_max_length... OK + Applying auth.0010_alter_group_name_max_length... OK + Applying auth.0011_update_proxy_permissions... OK + Applying auth.0012_alter_user_first_name_max_length... OK + Applying logs.0001_initial... OK + Applying payments.0001_initial... OK + Applying payments.0002_subscription_plan_id... OK + Applying payments.0003_subscription_address_id... OK + Applying payments.0004_subscription_send_invoices... OK + Applying payments.0005_subscription_plan_name... OK + Applying payments.0006_subscription_invoice_email... OK + Applying payments.0007_auto_20200727_1430... OK + Applying payments.0008_subscription_setup_date... OK + Applying payments.0009_alter_subscription_user... OK + Applying sessions.0001_initial... OK + +Set up a superuser +----------------- + +To access the healthchecks web interface also Django’s admin interface, you need to create a superuser account. + +You have to interactively supply a username, email, and password. Usually, you can just accept the suggested (i.e. your) username and skip +the email, if you do not plan to use it inside Django. You should pick a decent password though! + +.. code-block:: console + :emphasize-lines: 2,3,4 + + (venv) [isabell@stardust ~]$ python3.11 ./manage.py createsuperuser + Email address:isabell@uber.space + Password: + Password (again): + Superuser created successfully. + (venv) [isabell@stardust ~]$ + +Generate static files +----------------- + +Healthchecks uses a couple of static files. We need to generate this as follows: + +:: + + (venv) [isabell@stardust ~]$ python3.11 ./manage.py collectstatic + 347 static files copied to '/home/isabell/apps/healthchecks/static-collected'. + (venv) [isabell@stardust ~]$ python3.11 ./manage.py compress + Compressing... done + Compressed 26 block(s) from 147 template(s) for 1 context(s). + (venv) [isabell@stardust ~]$ + +Set up the daemons +----------------- + +Healthchecks requires two daemons to be running. One is for the web interface and another is for the alert. Optionally you can create a +third daemon to send monthly reports. We'll manage this daemons using :manual:`supervisord `: + +Create the file ``~/etc/services.d/healthchecks.ini`` with following content: + +.. code-block:: ini + + [program:healthchecks] + directory=/home/isabell/apps/healthchecks + command=/bin/bash -c 'venv/bin/gunicorn --bind 0.0.0.0:8000 hc.wsgi:application' + autostart=true + autorestart=true + stopsignal=INT + # `startsecs` is set by Uberspace monitoring team, to prevent a broken service from looping + startsecs=30 + +Then create the file ``~/etc/services.d/healthchecks-sendalert.ini`` with following content: + +.. code-block:: ini + + [program:healthchecks-sendalert] + directory=/home/isabell/apps/healthchecks + command=/bin/bash -c 'venv/bin/python3.11 manage.py sendalerts' + autostart=true + autorestart=true + stopsignal=INT + # `startsecs` is set by Uberspace monitoring team, to prevent a broken service from looping + startsecs=30 + +Optionally create the third file ``~/etc/services.d/healthchecks-sendreport.ini`` to activate monthly reports with following content: + +.. code-block:: ini + + [program:healthchecks-sendreport] + directory=/home/isabell/apps/healthchecks + command=/bin/bash -c 'venv/bin/python manage.py sendreports --loop' + autostart=true + autorestart=true + stopsignal=INT + # `startsecs` is set by Uberspace monitoring team, to prevent a broken service from looping + startsecs=30 + +After creating the files ask :manual:`supervisord ` to reload it's config files and start the services: + +:: + + [isabell@stardust ~]$ supervisorctl reread + healthchecks: available + healthchecks-sendalert: available + healthchecks-sendreport: available + [isabell@stardust ~]$ supervisorctl update + healthchecks: updated process group + healthchecks-sendalert: updated process group + healthchecks-sendreport: updated process group + [isabell@stardust ~]$ supervisorctl status + healthchecks RUNNING pid 13331, uptime 0:03:14 + healthchecks-sendalert RUNNING pid 19516, uptime 0:03:14 + healthchecks-sendreport RUNNING pid 19517, uptime 0:03:14 + [isabell@stardust ~]$ + +Configure web backend +----------------- + +.. note:: + + Gunicorn is running Django on port 8000 (as configured in the service file). + So make sure to replace ```` in the example below with ``8000``. + +.. include:: includes/web-backend.rst + +Your backend should now point to the service; let's check it: + +.. code-block:: console + :emphasize-lines: 1 + + [isabell@stardust ~]$ uberspace web backend list + / http:8000 => OK, listening: PID 23161, /usr/bin/python3.11 /home/isabell/.local/bin/gunicorn --error-logfile - --reload --bind 0.0.0.0:8000 mysite.wsgi:application + + [isabell@stardust ~]$ + +Finishing installation +====================== + +Point your browser to the configured URL and login with your superuser account. + +Best practices +============== + +Security +-------- + +Change all default passwords. Look at folder permissions. Don't get hacked! + +Updates +======= + +.. note:: Check the `releases feed `_ regularly to stay informed about the newest + version. Alternatively check the `releases page `_ regularly. + +If we'd like upgrade to a newer release, we'll first stop the running services, pull the latest source files and repeat the database +migration and static file generation steps before we start the services again. + +:: + + [isabell@stardust ~]$ supervisorctl stop healthchecks healthchecks-sendalert healthchecks-sendreport + [isabell@stardust ~]$ git pull + remote: Enumerating objects: 286, done. + remote: Counting objects: 100% (286/286), done. + remote: Compressing objects: 100% (137/137), done. + remote: Total 286 (delta 187), reused 241 (delta 149), pack-reused 0 + Receiving objects: 100% (286/286), 337.52 KiB | 14.67 MiB/s, done. + Resolving deltas: 100% (187/187), completed with 35 local objects. + From https://github.com/healthchecks/healthchecks + c99b644a..0a7744c3 master -> origin/master + You are not currently on a branch. + Please specify which branch you want to merge with. + See git-pull(1) for details. + + git pull + + [isabell@stardust ~]$ git checkout + Note: switching to ''. + + You are in 'detached HEAD' state. You can look around, make experimental + changes and commit them, and you can discard any commits you make in this + state without impacting any branches by switching back to a branch. + + If you want to create a new branch to retain commits you create, you may + do so (now or later) by using -c with the switch command. Example: + + git switch -c + + Or undo this operation with: + + git switch - + + Turn off this advice by setting config variable advice.detachedHead to false + + HEAD is now at + [isabell@stardust ~]$ source venv/bin/activate + [isabell@stardust ~]$ python3.11 ./manage.py migrate + [isabell@stardust ~]$ python3.11 ./manage.py collectstatic + [isabell@stardust ~]$ python3.11 ./manage.py compress + [isabell@stardust ~]$ supervisorctl start healthchecks healthchecks-sendalert healthchecks-sendreport + healthchecks: started + healthchecks-sendalert: started + healthchecks-sendreport: started + +Debugging +========= + +If something fails you can check the :manual:`supervisord ` logs. E.g. for the web interface service you can do this as +follows: + +:: + + [isabell@stardust ~]$ supervisorctl tail healthchecks stderr + [2024-03-03 19:05:14 +0100] [13331] [INFO] Starting gunicorn 21.2.0 + [2024-03-03 19:05:14 +0100] [13331] [INFO] Listening at: http://0.0.0.0:8000 (13331) + [2024-03-03 19:05:14 +0100] [13331] [INFO] Using worker: sync + [2024-03-03 19:05:14 +0100] [13332] [INFO] Booting worker with pid: 13332 + [2024-03-10 18:11:55 +0100] [13331] [INFO] Handling signal: int + [2024-03-10 17:11:55 +0000] [13332] [INFO] Worker exiting (pid: 13332) + [2024-03-10 18:11:56 +0100] [13331] [INFO] Shutting down: Master + [2024-03-10 18:13:46 +0100] [10587] [INFO] Starting gunicorn 21.2.0 + [2024-03-10 18:13:46 +0100] [10587] [INFO] Listening at: http://0.0.0.0:8000 (10587) + [2024-03-10 18:13:46 +0100] [10587] [INFO] Using worker: sync + [2024-03-10 18:13:46 +0100] [10588] [INFO] Booting worker with pid: 10588 + +Backup +====== + +All generated data you should backup regularly is saved to the database and the database is regularly backed up by Uberspace. + +---- + +Tested with Healthchecks 3.2.0, Python 3.11, Uberspace 7.1.1 + +.. author_list::