Browse Source

Add a section in Docs about running self-hosted instances

Fixes: #467
pull/470/head
Pēteris Caune 4 years ago
parent
commit
b7c769fc0e
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
25 changed files with 1034 additions and 139 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +16
    -14
      hc/front/views.py
  3. +1
    -1
      hc/settings.py
  4. +22
    -43
      templates/docs/api.html
  5. +4
    -8
      templates/docs/attaching_logs.html
  6. +4
    -7
      templates/docs/bash.html
  7. +1
    -1
      templates/docs/cloning_checks.html
  8. +1
    -2
      templates/docs/configuring_prometheus.html
  9. +1
    -1
      templates/docs/csharp.html
  10. +1
    -1
      templates/docs/go.html
  11. +12
    -23
      templates/docs/http_api.html
  12. +2
    -3
      templates/docs/javascript.html
  13. +1
    -2
      templates/docs/measuring_script_run_time.html
  14. +5
    -9
      templates/docs/monitoring_cron_jobs.html
  15. +2
    -4
      templates/docs/php.html
  16. +3
    -5
      templates/docs/powershell.html
  17. +3
    -5
      templates/docs/python.html
  18. +2
    -4
      templates/docs/reliability_tips.html
  19. +1
    -1
      templates/docs/ruby.html
  20. +86
    -0
      templates/docs/self_hosted.html
  21. +81
    -0
      templates/docs/self_hosted.md
  22. +301
    -0
      templates/docs/self_hosted_configuration.html
  23. +476
    -0
      templates/docs/self_hosted_configuration.md
  24. +3
    -5
      templates/docs/signaling_failures.html
  25. +4
    -0
      templates/front/base_docs.html

+ 1
- 0
CHANGELOG.md View File

@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file.
- Improve the crontab snippet in the "Check Details" page (#465)
- Add Signal integration (#428)
- Change Zulip onboarding, ask for the zuliprc file (#202)
- Add a section in Docs about running self-hosted instances
## Bug Fixes
- Fix unwanted HTML escaping in SMS and WhatsApp notifications


+ 16
- 14
hc/front/views.py View File

@ -325,21 +325,23 @@ def serve_doc(request, doc="introduction"):
if not os.path.exists(path):
raise Http404("not found")
replaces = {
"{{ default_timeout }}": str(int(DEFAULT_TIMEOUT.total_seconds())),
"{{ default_grace }}": str(int(DEFAULT_GRACE.total_seconds())),
"SITE_NAME": settings.SITE_NAME,
"SITE_ROOT": settings.SITE_ROOT,
"SITE_HOSTNAME": site_hostname(),
"SITE_SCHEME": site_scheme(),
"PING_ENDPOINT": settings.PING_ENDPOINT,
"PING_URL": settings.PING_ENDPOINT + "your-uuid-here",
"IMG_URL": os.path.join(settings.STATIC_URL, "img/docs"),
}
content = open(path, "r", encoding="utf-8").read()
for placeholder, value in replaces.items():
content = content.replace(placeholder, value)
if not doc.startswith("self_hosted"):
replaces = {
"{{ default_timeout }}": str(int(DEFAULT_TIMEOUT.total_seconds())),
"{{ default_grace }}": str(int(DEFAULT_GRACE.total_seconds())),
"SITE_NAME": settings.SITE_NAME,
"SITE_ROOT": settings.SITE_ROOT,
"SITE_HOSTNAME": site_hostname(),
"SITE_SCHEME": site_scheme(),
"PING_ENDPOINT": settings.PING_ENDPOINT,
"PING_URL": settings.PING_ENDPOINT + "your-uuid-here",
"IMG_URL": os.path.join(settings.STATIC_URL, "img/docs"),
}
for placeholder, value in replaces.items():
content = content.replace(placeholder, value)
ctx = {
"page": "docs",


+ 1
- 1
hc/settings.py View File

@ -27,7 +27,7 @@ def envint(s, default):
return int(v)
SECRET_KEY = os.getenv("SECRET_KEY", "---")
SECRET_KEY = os.getenv("SECRET_KEY", "")
METRICS_KEY = os.getenv("METRICS_KEY")
DEBUG = envbool("DEBUG", "True")
ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "*").split(",")


+ 22
- 43
templates/docs/api.html View File

@ -103,12 +103,11 @@ specified value.</p>
<dd>The API key is either missing or invalid.</dd>
</dl>
<h3>Example Request</h3>
<div class="bash highlight"><pre><span></span><code>curl --header <span class="s2">&quot;X-Api-Key: your-api-key&quot;</span> SITE_ROOT/api/v1/checks/
<div class="highlight"><pre><span></span><code>curl --header <span class="s2">&quot;X-Api-Key: your-api-key&quot;</span> SITE_ROOT/api/v1/checks/
</code></pre></div>
<h3>Example Response</h3>
<div class="json highlight"><pre><span></span><code><span class="p">{</span>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">&quot;checks&quot;</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;Filesystem Backup&quot;</span><span class="p">,</span>
@ -149,14 +148,13 @@ specified value.</p>
<span class="p">}</span>
</code></pre></div>
<p>When using the read-only API key, SITE_NAME omits the following fields from responses:
<code>ping_url</code>, <code>update_url</code>, <code>pause_url</code>, <code>channels</code>. It adds an extra
<code>unique_key</code> field. The <code>unique_key</code> identifier is stable across API calls, and
you can use it in the <a href="#get-check">Get a single check</a>
and <a href="#list-flips">Get a list of check's status changes</a> API calls.</p>
<p>Example:</p>
<div class="json highlight"><pre><span></span><code><span class="p">{</span>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">&quot;checks&quot;</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;Filesystem Backup&quot;</span><span class="p">,</span>
@ -191,7 +189,6 @@ and <a href="#list-flips">Get a list of check's status changes</a> API calls.</p
<span class="p">}</span>
</code></pre></div>
<h2 class="rule" id="get-check">Get a Single Check</h2>
<p><code>GET SITE_ROOT/api/v1/checks/&lt;uuid&gt;</code><br>
<code>GET SITE_ROOT/api/v1/checks/&lt;unique_key&gt;</code></p>
@ -210,12 +207,11 @@ using the read-only API key) as an identifier.</p>
<dd>The specified check does not exist.</dd>
</dl>
<h3>Example Request</h3>
<div class="bash highlight"><pre><span></span><code>curl --header <span class="s2">&quot;X-Api-Key: your-api-key&quot;</span> SITE_ROOT/api/v1/checks/&lt;uuid&gt;
<div class="highlight"><pre><span></span><code>curl --header <span class="s2">&quot;X-Api-Key: your-api-key&quot;</span> SITE_ROOT/api/v1/checks/&lt;uuid&gt;
</code></pre></div>
<h3>Example Response</h3>
<div class="json highlight"><pre><span></span><code><span class="p">{</span>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;Database Backup&quot;</span><span class="p">,</span>
<span class="nt">&quot;tags&quot;</span><span class="p">:</span> <span class="s2">&quot;production db&quot;</span><span class="p">,</span>
<span class="nt">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;Runs ~/db-backup.sh&quot;</span><span class="p">,</span>
@ -235,7 +231,6 @@ using the read-only API key) as an identifier.</p>
<span class="p">}</span>
</code></pre></div>
<h3>Example Read-Only Response</h3>
<p>When using the read-only API key, SITE_NAME omits the following fields from responses:
<code>ping_url</code>, <code>update_url</code>, <code>pause_url</code>, <code>channels</code>. It adds an extra
@ -243,7 +238,7 @@ using the read-only API key) as an identifier.</p>
<p>Note: although API omits the <code>ping_url</code>, <code>update_url</code>, and <code>pause_url</code> in read-only
API responses, the client can easily construct these URLs themselves <em>if</em> they know the
check's unique UUID.</p>
<div class="json highlight"><pre><span></span><code><span class="p">{</span>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;Database Backup&quot;</span><span class="p">,</span>
<span class="nt">&quot;tags&quot;</span><span class="p">:</span> <span class="s2">&quot;production db&quot;</span><span class="p">,</span>
<span class="nt">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;Runs ~/db-backup.sh&quot;</span><span class="p">,</span>
@ -260,7 +255,6 @@ check's unique UUID.</p>
<span class="p">}</span>
</code></pre></div>
<h2 class="rule" id="create-check">Create a Check</h2>
<p><code>POST SITE_ROOT/api/v1/checks/</code></p>
<p>Creates a new check and returns its ping URL.
@ -395,20 +389,18 @@ field values.</dd>
the limit is 20 checks per account.</dd>
</dl>
<h3>Example Request</h3>
<div class="bash highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/ <span class="se">\</span>
<div class="highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/ <span class="se">\</span>
--header <span class="s2">&quot;X-Api-Key: your-api-key&quot;</span> <span class="se">\</span>
--data <span class="s1">&#39;{&quot;name&quot;: &quot;Backups&quot;, &quot;tags&quot;: &quot;prod www&quot;, &quot;timeout&quot;: 3600, &quot;grace&quot;: 60}&#39;</span>
</code></pre></div>
<p>Or, alternatively:</p>
<div class="bash highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/ <span class="se">\</span>
<div class="highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/ <span class="se">\</span>
--data <span class="s1">&#39;{&quot;api_key&quot;: &quot;your-api-key&quot;, &quot;name&quot;: &quot;Backups&quot;, &quot;tags&quot;: &quot;prod www&quot;, &quot;timeout&quot;: 3600, &quot;grace&quot;: 60}&#39;</span>
</code></pre></div>
<h3>Example Response</h3>
<div class="json highlight"><pre><span></span><code><span class="p">{</span>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">&quot;channels&quot;</span><span class="p">:</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
<span class="nt">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
<span class="nt">&quot;grace&quot;</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span>
@ -427,7 +419,6 @@ the limit is 20 checks per account.</dd>
<span class="p">}</span>
</code></pre></div>
<h2 class="rule" id="update-check">Update an Existing Check</h2>
<p><code>POST SITE_ROOT/api/v1/checks/&lt;uuid&gt;</code></p>
<p>Updates an existing check. All request parameters are optional. If you omit any
@ -540,20 +531,18 @@ field values.</dd>
<dd>The specified check does not exist.</dd>
</dl>
<h3>Example Request</h3>
<div class="bash highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc <span class="se">\</span>
<div class="highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc <span class="se">\</span>
--header <span class="s2">&quot;X-Api-Key: your-api-key&quot;</span> <span class="se">\</span>
--data <span class="s1">&#39;{&quot;name&quot;: &quot;Backups&quot;, &quot;tags&quot;: &quot;prod www&quot;, &quot;timeout&quot;: 3600, &quot;grace&quot;: 60}&#39;</span>
</code></pre></div>
<p>Or, alternatively:</p>
<div class="bash highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc <span class="se">\</span>
<div class="highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc <span class="se">\</span>
--data <span class="s1">&#39;{&quot;api_key&quot;: &quot;your-api-key&quot;, &quot;name&quot;: &quot;Backups&quot;, &quot;tags&quot;: &quot;prod www&quot;, &quot;timeout&quot;: 3600, &quot;grace&quot;: 60}&#39;</span>
</code></pre></div>
<h3>Example Response</h3>
<div class="json highlight"><pre><span></span><code><span class="p">{</span>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">&quot;channels&quot;</span><span class="p">:</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
<span class="nt">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
<span class="nt">&quot;grace&quot;</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span>
@ -572,7 +561,6 @@ field values.</dd>
<span class="p">}</span>
</code></pre></div>
<h2 class="rule" id="pause-check">Pause Monitoring of a Check</h2>
<p><code>POST SITE_ROOT/api/v1/checks/&lt;uuid&gt;/pause</code></p>
<p>Disables monitoring for a check without removing it. The check goes into a "paused"
@ -590,16 +578,15 @@ state. You can resume monitoring of the check by pinging it.</p>
<dd>The specified check does not exist.</dd>
</dl>
<h3>Example Request</h3>
<div class="bash highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/0c8983c9-9d73-446f-adb5-0641fdacc9d4/pause <span class="se">\</span>
<div class="highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/0c8983c9-9d73-446f-adb5-0641fdacc9d4/pause <span class="se">\</span>
--request POST --header <span class="s2">&quot;X-Api-Key: your-api-key&quot;</span> --data <span class="s2">&quot;&quot;</span>
</code></pre></div>
<p>Note: the <code>--data ""</code> argument forces curl to send a <code>Content-Length</code> request header
even though the request body is empty. For HTTP POST requests, the <code>Content-Length</code>
header is sometimes required by some network proxies and web servers.</p>
<h3>Example Response</h3>
<div class="json highlight"><pre><span></span><code><span class="p">{</span>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">&quot;channels&quot;</span><span class="p">:</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
<span class="nt">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
<span class="nt">&quot;grace&quot;</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span>
@ -618,7 +605,6 @@ header is sometimes required by some network proxies and web servers.</p>
<span class="p">}</span>
</code></pre></div>
<h2 class="rule" id="delete-check">Delete Check</h2>
<p><code>DELETE SITE_ROOT/api/v1/checks/&lt;uuid&gt;</code></p>
<p>Permanently deletes the check from the user's account. Returns JSON representation of the
@ -636,13 +622,12 @@ check that was just deleted.</p>
<dd>The specified check does not exist.</dd>
</dl>
<h3>Example Request</h3>
<div class="bash highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc <span class="se">\</span>
<div class="highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc <span class="se">\</span>
--request DELETE --header <span class="s2">&quot;X-Api-Key: your-api-key&quot;</span>
</code></pre></div>
<h3>Example Response</h3>
<div class="json highlight"><pre><span></span><code><span class="p">{</span>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">&quot;channels&quot;</span><span class="p">:</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
<span class="nt">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
<span class="nt">&quot;grace&quot;</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span>
@ -661,7 +646,6 @@ check that was just deleted.</p>
<span class="p">}</span>
</code></pre></div>
<h2 class="rule" id="list-pings">Get a list of check's logged pings</h2>
<p><code>GET SITE_ROOT/api/v1/checks/&lt;uuid&gt;/pings/</code></p>
<p>Returns a list of pings this check has received.</p>
@ -680,13 +664,12 @@ number of returned pings depends on the account's billing plan: 100 for free acc
<dd>The specified check does not exist.</dd>
</dl>
<h3>Example Request</h3>
<div class="bash highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc/pings/ <span class="se">\</span>
<div class="highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc/pings/ <span class="se">\</span>
--header <span class="s2">&quot;X-Api-Key: your-api-key&quot;</span>
</code></pre></div>
<h3>Example Response</h3>
<div class="json highlight"><pre><span></span><code><span class="p">{</span>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">&quot;pings&quot;</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;success&quot;</span><span class="p">,</span>
@ -730,7 +713,6 @@ number of returned pings depends on the account's billing plan: 100 for free acc
<span class="p">}</span>
</code></pre></div>
<h2 class="rule" id="list-flips">Get a list of check's status changes</h2>
<p><code>GET SITE_ROOT/api/v1/checks/&lt;uuid&gt;/flips/</code><br>
<code>GET SITE_ROOT/api/v1/checks/&lt;unique_key&gt;/flips/</code></p>
@ -771,13 +753,12 @@ number of returned pings depends on the account's billing plan: 100 for free acc
<dd>The specified check does not exist.</dd>
</dl>
<h3>Example Request</h3>
<div class="bash highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc/flips/ <span class="se">\</span>
<div class="highlight"><pre><span></span><code>curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc/flips/ <span class="se">\</span>
--header <span class="s2">&quot;X-Api-Key: your-api-key&quot;</span>
</code></pre></div>
<h3>Example Response</h3>
<div class="json highlight"><pre><span></span><code><span class="p">[</span>
<div class="highlight"><pre><span></span><code><span class="p">[</span>
<span class="p">{</span>
<span class="nt">&quot;timestamp&quot;</span><span class="p">:</span> <span class="s2">&quot;2020-03-23T10:18:23+00:00&quot;</span><span class="p">,</span>
<span class="nt">&quot;up&quot;</span><span class="p">:</span> <span class="mi">1</span>
@ -793,7 +774,6 @@ number of returned pings depends on the account's billing plan: 100 for free acc
<span class="p">]</span>
</code></pre></div>
<h2 class="rule" id="list-channels">Get a List of Existing Integrations</h2>
<p><code>GET SITE_ROOT/api/v1/channels/</code></p>
<p>Returns a list of integrations belonging to the project.</p>
@ -805,12 +785,11 @@ number of returned pings depends on the account's billing plan: 100 for free acc
<dd>The API key is either missing or invalid.</dd>
</dl>
<h3>Example Request</h3>
<div class="bash highlight"><pre><span></span><code>curl --header <span class="s2">&quot;X-Api-Key: your-api-key&quot;</span> SITE_ROOT/api/v1/channels/
<div class="highlight"><pre><span></span><code>curl --header <span class="s2">&quot;X-Api-Key: your-api-key&quot;</span> SITE_ROOT/api/v1/channels/
</code></pre></div>
<h3>Example Response</h3>
<div class="json highlight"><pre><span></span><code><span class="p">{</span>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="nt">&quot;channels&quot;</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">&quot;id&quot;</span><span class="p">:</span> <span class="s2">&quot;4ec5a071-2d08-4baa-898a-eb4eb3cd6941&quot;</span><span class="p">,</span>


+ 4
- 8
templates/docs/attaching_logs.html View File

@ -7,32 +7,29 @@ it later.</p>
<h2>Logging Command Output</h2>
<p>In this example, we run <code>certbot renew</code>, capture its output (both the stdout
and stderr streams), and submit the captured output to SITE_NAME:</p>
<div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<span class="nv">m</span><span class="o">=</span><span class="k">$(</span>/usr/bin/certbot renew <span class="m">2</span>&gt;<span class="p">&amp;</span><span class="m">1</span><span class="k">)</span>
curl -fsS -m <span class="m">10</span> --retry <span class="m">5</span> --data-raw <span class="s2">&quot;</span><span class="nv">$m</span><span class="s2">&quot;</span> PING_URL
</code></pre></div>
<h2>In Combination with the <code>/fail</code> and <code>/{exit-status}</code> Endpoints</h2>
<p>We can extend the previous example and signal either success or failure
depending on the exit code:</p>
<div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<span class="nv">m</span><span class="o">=</span><span class="k">$(</span>/usr/bin/certbot renew <span class="m">2</span>&gt;<span class="p">&amp;</span><span class="m">1</span><span class="k">)</span>
curl -fsS -m <span class="m">10</span> --retry <span class="m">5</span> --data-raw <span class="s2">&quot;</span><span class="nv">$m</span><span class="s2">&quot;</span> PING_URL/<span class="nv">$?</span>
</code></pre></div>
<h2>Using Runitor</h2>
<p><a href="https://github.com/bdd/runitor">Runitor</a> is a third party utility that runs the
supplied command, captures its output and reports to SITE_NAME.
It also measures the execution time and retries HTTP requests on transient errors.
Best of all, the syntax is simple and clean:</p>
<div class="bash highlight"><pre><span></span><code>runitor -uuid your-uuid-here -- /usr/bin/certbot renew
<div class="highlight"><pre><span></span><code>runitor -uuid your-uuid-here -- /usr/bin/certbot renew
</code></pre></div>
<h2>Handling More Than 10KB of Logs</h2>
<p>While SITE_NAME can store a small amount of logs in a pinch, it is not specifically
designed for that. If you run into the issue of logs getting cut off, consider
@ -44,13 +41,12 @@ the totals instead.</li>
<li>If the important content is usually at the end, submit the <strong>last 10KB</strong> instead
of the first. Here is an example that submits the last 10KB of <code>dmesg</code> output:</li>
</ul>
<div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<span class="nv">m</span><span class="o">=</span><span class="k">$(</span>dmesg <span class="p">|</span> tail --bytes<span class="o">=</span><span class="m">10000</span><span class="k">)</span>
curl -fsS -m <span class="m">10</span> --retry <span class="m">5</span> --data-raw <span class="s2">&quot;</span><span class="nv">$m</span><span class="s2">&quot;</span> PING_URL
</code></pre></div>
<ul>
<li>Finally, if it is critical to capture the entire log output,
consider using a dedicated log aggregation service for capturing the logs.</li>

+ 4
- 7
templates/docs/bash.html View File

@ -4,14 +4,13 @@ have to do is make an HTTP request at an appropriate place in the script.
<a href="https://curl.haxx.se/docs/manpage.html">curl</a> and
<a href="https://www.gnu.org/software/wget/manual/wget.html">wget</a>
are two common command-line HTTP clients you can use.</p>
<div class="bash highlight"><pre><span></span><code><span class="c1"># Sends an HTTP GET request with curl:</span>
<div class="highlight"><pre><span></span><code><span class="c1"># Sends an HTTP GET request with curl:</span>
curl -m <span class="m">10</span> --retry <span class="m">5</span> PING_URL
<span class="c1"># Silent version (no stdout/stderr output unless curl hits an error):</span>
curl -fsS -m <span class="m">10</span> --retry <span class="m">5</span> -o /dev/null PING_URL
</code></pre></div>
<p>Here's what each curl parameter does:</p>
<dl>
<dt><strong>-m &lt;seconds&gt;</strong></dt>
@ -36,7 +35,7 @@ to actively signal a failure. The exit status should be a 0-255 integer.
SITE_NAME will interpret exit status 0 as success and all non-zero values as failures.</p>
<p>The following example runs <code>/usr/bin/certbot renew</code>, and uses the <code>$?</code> variable to
look up its exit status:</p>
<div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<span class="c1"># Payload here:</span>
/usr/bin/certbot renew
@ -44,25 +43,23 @@ look up its exit status:</p>
curl -m <span class="m">10</span> --retry <span class="m">5</span> PING_URL/<span class="nv">$?</span>
</code></pre></div>
<h2>Logging Command Output</h2>
<p>When pinging with HTTP POST, you can put extra diagnostic information in the request
body. If the request body looks like a valid UTF-8 string, SITE_NAME
will accept and store the first 10KB of the request body.</p>
<p>In the below example, certbot's output is captured and submitted via HTTP POST:</p>
<div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<span class="nv">m</span><span class="o">=</span><span class="k">$(</span>/usr/bin/certbot renew <span class="m">2</span>&gt;<span class="p">&amp;</span><span class="m">1</span><span class="k">)</span>
curl -fsS -m <span class="m">10</span> --retry <span class="m">5</span> --data-raw <span class="s2">&quot;</span><span class="nv">$m</span><span class="s2">&quot;</span> PING_URL
</code></pre></div>
<h2>Auto-provisioning New Checks</h2>
<p>This example uses SITE_NAME <a href="../api/">Management API</a> to create a check "on the fly"
(if it does not already exist) and retrieve its ping URL.
Using this technique, you can write services that automatically
register with SITE_NAME the first time they run.</p>
<div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/bash</span>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/bash</span>
<span class="nv">API_KEY</span><span class="o">=</span>your-api-key-here


+ 1
- 1
templates/docs/cloning_checks.html View File

@ -16,7 +16,7 @@ an existing deployment in a new region. The SITE_NAME web interface does
not have a function to clone an entire project, but you can clone all checks in the
project relatively easily using the <a href="../api/">Management API</a> calls.
Below is an example using Python and the <a href="https://requests.readthedocs.io/en/master/">requests</a> library:</p>
<div class="python highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">requests</span>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">requests</span>
<span class="n">API_URL</span> <span class="o">=</span> <span class="s2">&quot;SITE_ROOT/api/v1/checks/&quot;</span>
<span class="n">SOURCE_PROJECT_READONLY_KEY</span> <span class="o">=</span> <span class="s2">&quot;...&quot;</span>


+ 1
- 2
templates/docs/configuring_prometheus.html View File

@ -7,7 +7,7 @@ the Prometheus endpoint:</p>
<p><img alt="Project's API Keys" src="IMG_URL/prometheus_endpoint.png" /></p>
<h2>Update the prometheus.yml</h2>
<p>You can copy the Prometheus endpoint URL and add it to the Prometheus configuration:</p>
<div class="yaml highlight"><pre><span></span><code> <span class="p p-Indicator">-</span> <span class="nt">job_name</span><span class="p">:</span> <span class="s">&quot;healthchecks&quot;</span>
<div class="highlight"><pre><span></span><code> <span class="p p-Indicator">-</span> <span class="nt">job_name</span><span class="p">:</span> <span class="s">&quot;healthchecks&quot;</span>
<span class="nt">scrape_interval</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">60s</span>
<span class="nt">scheme</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">SITE_SCHEME</span>
<span class="nt">metrics_path</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">/projects/45sd78-eeee-dddd-8888-b25a9887ecfd/metrics/NXyGzks4s8xcF1J-wzoaioyoqXIANGD0</span>
@ -15,6 +15,5 @@ the Prometheus endpoint:</p>
<span class="p p-Indicator">-</span> <span class="nt">targets</span><span class="p">:</span> <span class="p p-Indicator">[</span><span class="s">&quot;SITE_HOSTNAME&quot;</span><span class="p p-Indicator">]</span>
</code></pre></div>
<p>Notice how we split up the URL and paste in the scheme, domain, and path separately.</p>
<p>Reload Prometheus, and your changes should be live, coming in under the <code>hc_</code> prefix.</p>

+ 1
- 1
templates/docs/csharp.html View File

@ -1,6 +1,6 @@
<h1>C#</h1>
<p>Below is an example of making an HTTP request to SITE_NAME from C#.</p>
<div class="csharp highlight"><pre><span></span><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">client</span> <span class="p">=</span> <span class="k">new</span> <span class="n">System</span><span class="p">.</span><span class="n">Net</span><span class="p">.</span><span class="n">WebClient</span><span class="p">())</span>
<div class="highlight"><pre><span></span><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">client</span> <span class="p">=</span> <span class="k">new</span> <span class="n">System</span><span class="p">.</span><span class="n">Net</span><span class="p">.</span><span class="n">WebClient</span><span class="p">())</span>
<span class="p">{</span>
<span class="n">client</span><span class="p">.</span><span class="n">DownloadString</span><span class="p">(</span><span class="s">&quot;PING_URL&quot;</span><span class="p">);</span>
<span class="p">}</span>

+ 1
- 1
templates/docs/go.html View File

@ -1,6 +1,6 @@
<h1>Go</h1>
<p>Below is an example of making an HTTP request to SITE_NAME from Go.</p>
<div class="go highlight"><pre><span></span><code><span class="kn">package</span> <span class="nx">main</span>
<div class="highlight"><pre><span></span><code><span class="kn">package</span> <span class="nx">main</span>
<span class="kn">import</span> <span class="s">&quot;fmt&quot;</span>
<span class="kn">import</span> <span class="s">&quot;net/http&quot;</span>


+ 12
- 23
templates/docs/http_api.html View File

@ -15,20 +15,18 @@ If the request body looks like a UTF-8 string, SITE_NAME stores the request body
<p>Successful responses will have the "200 OK" HTTP response status code and a short
"OK" string in the response body.</p>
<h2>Send a "success" Signal</h2>
<div class="text highlight"><pre><span></span><code>HEAD|GET|POST PING_ENDPOINT{uuid}
<div class="highlight"><pre><span></span><code>HEAD|GET|POST PING_ENDPOINT{uuid}
</code></pre></div>
<p>Signals to SITE_NAME that the job has completed successfully (or,
continuously running processes are still running and healthy). The <code>uuid</code> parameter
is unique for each check.</p>
<p><strong>Example</strong></p>
<div class="http highlight"><pre><span></span><code><span class="nf">GET</span> <span class="nn">/5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.0</span>
<div class="highlight"><pre><span></span><code><span class="nf">GET</span> <span class="nn">/5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.0</span>
<span class="na">Host</span><span class="o">:</span> <span class="l">hc-ping.com</span>
</code></pre></div>
<div class="http highlight"><pre><span></span><code><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<div class="highlight"><pre><span></span><code><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="na">Server</span><span class="o">:</span> <span class="l">nginx</span>
<span class="na">Date</span><span class="o">:</span> <span class="l">Wed, 29 Jan 2020 09:58:23 GMT</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">text/plain; charset=utf-8</span>
@ -39,21 +37,18 @@ is unique for each check.</p>
OK
</code></pre></div>
<h2>Send a "fail" Signal</h2>
<div class="text highlight"><pre><span></span><code>HEAD|GET|POST PING_ENDPOINT{uuid}/fail
<div class="highlight"><pre><span></span><code>HEAD|GET|POST PING_ENDPOINT{uuid}/fail
</code></pre></div>
<p>Signals to SITE_NAME that the job has failed. Actively signaling a failure
minimizes the delay from your monitored service failing to you receiving an alert.</p>
<p><strong>Example</strong></p>
<div class="http highlight"><pre><span></span><code><span class="nf">GET</span> <span class="nn">/5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278/fail</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.0</span>
<div class="highlight"><pre><span></span><code><span class="nf">GET</span> <span class="nn">/5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278/fail</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.0</span>
<span class="na">Host</span><span class="o">:</span> <span class="l">hc-ping.com</span>
</code></pre></div>
<div class="http highlight"><pre><span></span><code><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<div class="highlight"><pre><span></span><code><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="na">Server</span><span class="o">:</span> <span class="l">nginx</span>
<span class="na">Date</span><span class="o">:</span> <span class="l">Wed, 29 Jan 2020 09:58:23 GMT</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">text/plain; charset=utf-8</span>
@ -64,12 +59,10 @@ minimizes the delay from your monitored service failing to you receiving an aler
OK
</code></pre></div>
<h2>Send a "start" Signal</h2>
<div class="text highlight"><pre><span></span><code>HEAD|GET|POST PING_ENDPOINT{uuid}/start
<div class="highlight"><pre><span></span><code>HEAD|GET|POST PING_ENDPOINT{uuid}/start
</code></pre></div>
<p>Sends a "job has started!" message to SITE_NAME. Sending a "start" signal is
optional, but it enables a few extra features:</p>
<ul>
@ -77,12 +70,11 @@ optional, but it enables a few extra features:</p>
<li>SITE_NAME will detect if the job runs longer than its configured grace time</li>
</ul>
<p><strong>Example</strong></p>
<div class="http highlight"><pre><span></span><code><span class="nf">GET</span> <span class="nn">/5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278/start</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.0</span>
<div class="highlight"><pre><span></span><code><span class="nf">GET</span> <span class="nn">/5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278/start</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.0</span>
<span class="na">Host</span><span class="o">:</span> <span class="l">hc-ping.com</span>
</code></pre></div>
<div class="http highlight"><pre><span></span><code><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<div class="highlight"><pre><span></span><code><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="na">Server</span><span class="o">:</span> <span class="l">nginx</span>
<span class="na">Date</span><span class="o">:</span> <span class="l">Wed, 29 Jan 2020 09:58:23 GMT</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">text/plain; charset=utf-8</span>
@ -93,22 +85,19 @@ optional, but it enables a few extra features:</p>
OK
</code></pre></div>
<h2>Report Script's Exit Status</h2>
<div class="text highlight"><pre><span></span><code>HEAD|GET|POST PING_ENDPOINT{uuid}/{exit-status}
<div class="highlight"><pre><span></span><code>HEAD|GET|POST PING_ENDPOINT{uuid}/{exit-status}
</code></pre></div>
<p>Sends a success or failure signal depending on the exit status
included in the URL. The exit status is a 0-255 integer. SITE_NAME
interprets 0 as success and all other values as failure.</p>
<p><strong>Example</strong></p>
<div class="http highlight"><pre><span></span><code><span class="nf">GET</span> <span class="nn">/5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278/1</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.0</span>
<div class="highlight"><pre><span></span><code><span class="nf">GET</span> <span class="nn">/5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278/1</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.0</span>
<span class="na">Host</span><span class="o">:</span> <span class="l">hc-ping.com</span>
</code></pre></div>
<div class="http highlight"><pre><span></span><code><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<div class="highlight"><pre><span></span><code><span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="na">Server</span><span class="o">:</span> <span class="l">nginx</span>
<span class="na">Date</span><span class="o">:</span> <span class="l">Wed, 29 Jan 2020 09:58:23 GMT</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">text/plain; charset=utf-8</span>


+ 2
- 3
templates/docs/javascript.html View File

@ -1,15 +1,14 @@
<h1>Javascript</h1>
<p>Below is an example of making an HTTP request to SITE_NAME from Node.js.</p>
<div class="js highlight"><pre><span></span><code><span class="kd">var</span> <span class="nx">https</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;https&#39;</span><span class="p">);</span>
<div class="highlight"><pre><span></span><code><span class="kd">var</span> <span class="nx">https</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;https&#39;</span><span class="p">);</span>
<span class="nx">https</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;PING_URL&#39;</span><span class="p">).</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Ping failed: &#39;</span> <span class="o">+</span> <span class="nx">err</span><span class="p">)</span>
<span class="p">});</span>
</code></pre></div>
<p>You can also send pings from a browser environment. SITE_NAME sets the
<code>Access-Control-Allow-Origin:*</code> CORS header, so cross-domain AJAX requests work.</p>
<div class="js highlight"><pre><span></span><code><span class="kd">var</span> <span class="nx">xhr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">();</span>
<div class="highlight"><pre><span></span><code><span class="kd">var</span> <span class="nx">xhr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">();</span>
<span class="nx">xhr</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="s1">&#39;GET&#39;</span><span class="p">,</span> <span class="s1">&#39;PING_URL&#39;</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="nx">xhr</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
</code></pre></div>

+ 1
- 2
templates/docs/measuring_script_run_time.html View File

@ -7,7 +7,7 @@
<p>Signaling a start kicks off a separate timer: the job now <strong>must</strong> signal a
success within its configured "Grace Time," or it will get marked as "down."</p>
<p>Below is a code example in Python:</p>
<div class="python highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">requests</span>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">requests</span>
<span class="n">URL</span> <span class="o">=</span> <span class="s2">&quot;PING_URL&quot;</span>
@ -29,7 +29,6 @@ success within its configured "Grace Time," or it will get marked as "down."</p>
<span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">URL</span><span class="p">)</span>
</code></pre></div>
<h2>Viewing Measured Run Times</h2>
<p>When SITE_NAME receives a "start" signal followed by a regular ping or a "fail"
signal, and the two events are less than 24 hours apart,


+ 5
- 9
templates/docs/monitoring_cron_jobs.html View File

@ -3,12 +3,11 @@
update your cron job command to send an HTTP request to SITE_NAME
after completing the job.</p>
<p>Let's look at an example:</p>
<div class="bash highlight"><pre><span></span><code>$ crontab -l
<div class="highlight"><pre><span></span><code>$ crontab -l
<span class="c1"># m h dom mon dow command</span>
<span class="m">8</span> <span class="m">6</span> * * * /home/user/backup.sh
</code></pre></div>
<p>The above job runs <code>/home/user/backup.sh</code> every day at 6:08. The backup
script is presumably a headless, background process. Even if it works
correctly currently, it can start silently failing in the future without
@ -40,12 +39,11 @@ increasingly important as you add more checks to your account.</p>
</ol>
<p>Finally, edit your cron job definition and append a curl or wget call
after the command:</p>
<div class="bash highlight"><pre><span></span><code>$ crontab -e
<div class="highlight"><pre><span></span><code>$ crontab -e
<span class="c1"># m h dom mon dow command</span>
<span class="m">8</span> <span class="m">6</span> * * * /home/user/backup.sh <span class="o">&amp;&amp;</span> curl -fsS --retry <span class="m">5</span> -o /dev/null PING_URL
</code></pre></div>
<p>Now, each time your cron job runs, it will send an HTTP request to the ping URL.
Since SITE_NAME knows your cron job's schedule, it can calculate
the dates and times when the job should run. As soon as your cron job doesn't
@ -84,7 +82,7 @@ the likely cause is a timezone mismatch: your machine may be using a timezone
different from what you have configured on SITE_NAME.</p>
<p>On modern GNU/Linux systems, you can look up the time zone using the
<code>timedatectl status</code> command and looking for "Time zone" in its output:</p>
<div class="text highlight"><pre><span></span><code>$ timedatectl status
<div class="highlight"><pre><span></span><code>$ timedatectl status
Local time: C  2020-01-23 12:35:50 EET
Universal time: C  2020-01-23 10:35:50 UTC
@ -95,15 +93,13 @@ different from what you have configured on SITE_NAME.</p>
RTC in local TZ: no
</code></pre></div>
<h2>Viewing Cron Logs Using <code>journalctl</code></h2>
<p>On a systemd-based system, you can use the <code>journalctl</code> utility to see system logs,
including logs from the cron daemon.</p>
<p>To see live logs:</p>
<div class="bash highlight"><pre><span></span><code>journalctl -f
<div class="highlight"><pre><span></span><code>journalctl -f
</code></pre></div>
<p>To see the logs from e.g. the last hour, and only from the cron daemon:</p>
<div class="bash highlight"><pre><span></span><code>journalctl --since <span class="s2">&quot;1 hour ago&quot;</span> -t CRON
<div class="highlight"><pre><span></span><code>journalctl --since <span class="s2">&quot;1 hour ago&quot;</span> -t CRON
</code></pre></div>

+ 2
- 4
templates/docs/php.html View File

@ -1,13 +1,12 @@
<h1>PHP</h1>
<p>Below is an example of making an HTTP request to SITE_NAME from PHP.</p>
<div class="php highlight"><pre><span></span><code><span class="nb">file_get_contents</span><span class="p">(</span><span class="s1">&#39;PING_URL&#39;</span><span class="p">);</span>
<div class="highlight"><pre><span></span><code><span class="nb">file_get_contents</span><span class="p">(</span><span class="s1">&#39;PING_URL&#39;</span><span class="p">);</span>
</code></pre></div>
<p>If you would like to setup timeout and retry options, as discussed in the
<a href="../reliability_tips/">reliability tips section</a>, there is a
<a href="https://www.phpcurlclass.com/">curl package</a> available that lets you do that easily:</p>
<div class="php highlight"><pre><span></span><code><span class="k">use</span> <span class="nx">Curl\Curl</span><span class="p">;</span>
<div class="highlight"><pre><span></span><code><span class="k">use</span> <span class="nx">Curl\Curl</span><span class="p">;</span>
<span class="nv">$curl</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Curl</span><span class="p">();</span>
<span class="nv">$curl</span><span class="o">-&gt;</span><span class="na">setRetry</span><span class="p">(</span><span class="mi">20</span><span class="p">);</span>
@ -15,5 +14,4 @@
<span class="nv">$curl</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">(</span><span class="s1">&#39;PING_URL&#39;</span><span class="p">);</span>
</code></pre></div>
<p>Note: this code does not throw any exceptions.</p>

+ 3
- 5
templates/docs/powershell.html View File

@ -5,19 +5,17 @@
<p>Here is a simple PowerShell script that pings SITE_NAME. When scheduled to
run with Task Scheduler, it will essentially just send regular "I'm alive" messages.
Of course, you can extend it to do more things.</p>
<div class="powershell highlight"><pre><span></span><code><span class="c"># inside a PowerShell script:</span>
<div class="highlight"><pre><span></span><code><span class="c"># inside a PowerShell script:</span>
<span class="nb">Invoke-RestMethod</span> <span class="n">PING_URL</span>
</code></pre></div>
<p>Save the above to e.g., <code>C:\Scripts\healthchecks.ps1</code>.
Then use the following command in a Scheduled Task to run the script:</p>
<div class="bat highlight"><pre><span></span><code>powershell.exe -ExecutionPolicy bypass -File C:\Scripts\healthchecks.ps1
<div class="highlight"><pre><span></span><code>powershell.exe -ExecutionPolicy bypass -File C:\Scripts\healthchecks.ps1
</code></pre></div>
<p>In simple cases, you can also pass the script to PowerShell directly,
using the "-command" argument:</p>
<div class="bat highlight"><pre><span></span><code># Without an underlying script, passing the command to PowerShell directly:
<div class="highlight"><pre><span></span><code># Without an underlying script, passing the command to PowerShell directly:
powershell.exe -command <span class="p">&amp;</span>{Invoke-RestMethod PING_URL}
</code></pre></div>

+ 3
- 5
templates/docs/python.html View File

@ -1,7 +1,7 @@
<h1>Python</h1>
<p>If you are already using the <a href="https://requests.readthedocs.io/en/master/">requests</a>
library, it is convenient to also use it here:</p>
<div class="python highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">requests</span>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">requests</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;PING_URL&quot;</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
@ -10,10 +10,9 @@ library, it is convenient to also use it here:</p>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Ping failed: </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">e</span><span class="p">)</span>
</code></pre></div>
<p>Otherwise, you can use the <a href="https://docs.python.org/3/library/urllib.request.html">urllib.request</a>
module from Python 3 standard library:</p>
<div class="python highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">socket</span>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">socket</span>
<span class="kn">import</span> <span class="nn">urllib.request</span>
<span class="k">try</span><span class="p">:</span>
@ -23,9 +22,8 @@ module from Python 3 standard library:</p>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Ping failed: </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">e</span><span class="p">)</span>
</code></pre></div>
<p>You can include additional diagnostic information in the in the request body (for POST requests):</p>
<div class="python highlight"><pre><span></span><code><span class="c1"># Passing diagnostic information in the POST body:</span>
<div class="highlight"><pre><span></span><code><span class="c1"># Passing diagnostic information in the POST body:</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">&quot;PING_URL&quot;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="s2">&quot;temperature=-7&quot;</span><span class="p">)</span>
</code></pre></div>

+ 2
- 4
templates/docs/reliability_tips.html View File

@ -12,21 +12,19 @@ request could block the whole process. An explicit per-request time limit mitiga
this problem.</p>
<p>Specifying the timeout depends on the tool you use. curl, for example, has the
<code>--max-time</code> (shorthand: <code>-m</code>) parameter:</p>
<div class="bash highlight"><pre><span></span><code><span class="c1"># Send an HTTP request, 10 second timeout:</span>
<div class="highlight"><pre><span></span><code><span class="c1"># Send an HTTP request, 10 second timeout:</span>
curl -m <span class="m">10</span> PING_URL
</code></pre></div>
<h2>Use Retries</h2>
<p>To minimize the amount of false alerts you get from SITE_NAME, instruct your HTTP
client to retry failed requests several times.</p>
<p>Specifying the retry policy depends on the tool you use. curl, for example, has the
<code>--retry</code> parameter:</p>
<div class="bash highlight"><pre><span></span><code><span class="c1"># Retry up to 5 times, uses an increasing delay between each retry (1s, 2s, 4s, 8s, ...)</span>
<div class="highlight"><pre><span></span><code><span class="c1"># Retry up to 5 times, uses an increasing delay between each retry (1s, 2s, 4s, 8s, ...)</span>
curl --retry <span class="m">5</span> PING_URL
</code></pre></div>
<h2>Handle Exceptions</h2>
<p>Make sure you know how your HTTP client handles failed requests. For example,
if you use an HTTP library that raises exceptions, decide if you want to

+ 1
- 1
templates/docs/ruby.html View File

@ -1,6 +1,6 @@
<h1>Ruby</h1>
<p>Below is an example of making an HTTP request to SITE_NAME from Ruby.</p>
<div class="ruby highlight"><pre><span></span><code><span class="nb">require</span> <span class="s1">&#39;net/http&#39;</span>
<div class="highlight"><pre><span></span><code><span class="nb">require</span> <span class="s1">&#39;net/http&#39;</span>
<span class="nb">require</span> <span class="s1">&#39;uri&#39;</span>
<span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="no">URI</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s1">&#39;PING_URL&#39;</span><span class="p">))</span>

+ 86
- 0
templates/docs/self_hosted.html View File

@ -0,0 +1,86 @@
<h1>Self-Hosted Healthchecks</h1>
<p>Healthchecks is open-source, and is licensed under the BSD 3-clause license.</p>
<p>Rather than using the hosted service at
<a href="https://healthchecks.io">https://healthchecks.io</a>, you have the option to host an
instance yourself.</p>
<p>The building blocks are:</p>
<ul>
<li>Python 3.6+</li>
<li>Django 3</li>
<li>PostgreSQL or MySQL</li>
</ul>
<h2>Setting Up for Development</h2>
<p>You can set up a development environment in a Python
<a href="https://docs.python.org/3/tutorial/venv.html">virtual environment</a>
on your local system to develop a new feature, write a new integration
or test a bugfix.</p>
<p>The following instructions assume you are using a Debian-based OS.</p>
<ul>
<li>
<p>Install dependencies:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get update
$ sudo apt-get install -y gcc python3-dev python3-venv
</code></pre></div>
</li>
<li>
<p>Prepare directory for project code and virtualenv. Feel free to use a
different location:</p>
<div class="highlight"><pre><span></span><code>$ mkdir -p ~/webapps
$ <span class="nb">cd</span> ~/webapps
</code></pre></div>
</li>
<li>
<p>Prepare virtual environment
(with virtualenv you get pip, we'll use it soon to install requirements):</p>
<div class="highlight"><pre><span></span><code>$ python3 -m venv hc-venv
$ <span class="nb">source</span> hc-venv/bin/activate
</code></pre></div>
</li>
<li>
<p>Check out project code:</p>
<div class="highlight"><pre><span></span><code>$ git clone https://github.com/healthchecks/healthchecks.git
</code></pre></div>
</li>
<li>
<p>Install requirements (Django, ...) into virtualenv:</p>
<div class="highlight"><pre><span></span><code>$ pip install wheel
$ pip install -r healthchecks/requirements.txt
</code></pre></div>
</li>
<li>
<p>Create database tables and a superuser account:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> ~/webapps/healthchecks
$ ./manage.py migrate
$ ./manage.py createsuperuser
</code></pre></div>
</li>
</ul>
<p>With the default configuration, Healthchecks stores data in a SQLite file
<code>hc.sqlite</code> in the checkout directory (<code>~/webapps/healthchecks</code>).</p>
<ul>
<li>
<p>Run tests:</p>
<div class="highlight"><pre><span></span><code>$ ./manage.py <span class="nb">test</span>
</code></pre></div>
</li>
<li>
<p>Run development server:</p>
<div class="highlight"><pre><span></span><code>$ ./manage.py runserver
</code></pre></div>
</li>
</ul>
<p>At this point, the site should now be running at <code>http://localhost:8000</code>.</p>
<p>To access Django administration site, log in as a superuser, then
visit <code>http://localhost:8000/admin/</code>.</p>
<p>FIXME note about no email configuration, no sendalerts, and the devserver</p>
<h2>Next Steps</h2>
<p>Get the <a href="https://github.com/healthchecks/healthchecks">source code</a>.</p>
<p>See <a href="../self_hosted_configuration/">Configuration</a> for a list of configuration options.</p>

+ 81
- 0
templates/docs/self_hosted.md View File

@ -0,0 +1,81 @@
# Self-Hosted Healthchecks
Healthchecks is open-source, and is licensed under the BSD 3-clause license.
Rather than using the hosted service at
[https://healthchecks.io](https://healthchecks.io), you have the option to host an
instance yourself.
The building blocks are:
* Python 3.6+
* Django 3
* PostgreSQL or MySQL
## Setting Up for Development
You can set up a development environment in a Python
[virtual environment](https://docs.python.org/3/tutorial/venv.html)
on your local system to develop a new feature, write a new integration
or test a bugfix.
The following instructions assume you are using a Debian-based OS.
* Install dependencies:
$ sudo apt-get update
$ sudo apt-get install -y gcc python3-dev python3-venv
* Prepare directory for project code and virtualenv. Feel free to use a
different location:
$ mkdir -p ~/webapps
$ cd ~/webapps
* Prepare virtual environment
(with virtualenv you get pip, we'll use it soon to install requirements):
$ python3 -m venv hc-venv
$ source hc-venv/bin/activate
* Check out project code:
$ git clone https://github.com/healthchecks/healthchecks.git
* Install requirements (Django, ...) into virtualenv:
$ pip install wheel
$ pip install -r healthchecks/requirements.txt
* Create database tables and a superuser account:
$ cd ~/webapps/healthchecks
$ ./manage.py migrate
$ ./manage.py createsuperuser
With the default configuration, Healthchecks stores data in a SQLite file
`hc.sqlite` in the checkout directory (`~/webapps/healthchecks`).
* Run tests:
$ ./manage.py test
* Run development server:
$ ./manage.py runserver
At this point, the site should now be running at `http://localhost:8000`.
To access Django administration site, log in as a superuser, then
visit `http://localhost:8000/admin/`.
FIXME note about no email configuration, no sendalerts, and the devserver
## Next Steps
Get the [source code](https://github.com/healthchecks/healthchecks).
See [Configuration](../self_hosted_configuration/) for a list of configuration options.

+ 301
- 0
templates/docs/self_hosted_configuration.html View File

@ -0,0 +1,301 @@
<h1>Server Configuration</h1>
<p>Healthchecks prepares its configuration in <code>hc/settings.py</code>. It reads configuration
from environment variables. Below is a list of variables it reads and uses:</p>
<h2><code>ALLOWED_HOSTS</code></h2>
<p>Default: <code>*</code></p>
<p>A list of strings representing the host/domain names that this site can serve.
You can specify multiple domain names by separating them with commas:</p>
<div class="highlight"><pre><span></span><code><span class="na">ALLOWED_HOSTS</span><span class="o">=</span><span class="s">my-hc.example.org,alternative-name.example.org</span>
</code></pre></div>
<p>Aside from the comma-separated syntax, this is a standard Django setting.
Read more about it in the
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#allowed-hosts">Django documentation</a>.</p>
<h2><code>APPRISE_ENABLED</code></h2>
<p>Default: <code>False</code></p>
<p>A boolean that turns on/off the <a href="https://github.com/caronc/apprise">Apprise</a>
integration.</p>
<p>Before enabling the Apprise integration, make sure the <code>apprise</code> package is installed:</p>
<div class="highlight"><pre><span></span><code>pip install apprise
</code></pre></div>
<h2><code>DEBUG</code></h2>
<p>Default: <code>True</code></p>
<p>A boolean that turns on/off debug mode.</p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#debug">Django documentation</a>.</p>
<h2><code>DEFAULT_FROM_EMAIL</code></h2>
<p>Default: <code>[email protected]</code></p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#default-from-email">Django documentation</a>.</p>
<h2><code>DB</code></h2>
<p>Default: <code>sqlite</code></p>
<p>The database enginge to use. Possible values: <code>sqlite</code>, <code>postgres</code>, <code>mysql</code>.</p>
<h2><code>DB_CONN_MAX_AGE</code></h2>
<p>Default: <code>0</code></p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#conn-max-age">Django documentation</a>.</p>
<h2><code>DB_HOST</code></h2>
<p>Default: <code>""</code> (empty string)</p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#host">Django documentation</a>.</p>
<h2><code>DB_NAME</code></h2>
<p>Default: <code>hc</code> (PostgreSQL, MySQL) or <code>{project-path}/hc.sqlite</code> (SQLite)</p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#name">Django documentation</a>.</p>
<h2><code>DB_PASSWORD</code></h2>
<p>Default: <code>""</code> (empty string)</p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#password">Django documentation</a>.</p>
<h2><code>DB_PORT</code></h2>
<p>Default: <code>""</code> (empty string)</p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#port">Django documentation</a>.</p>
<h2><code>DB_SSLMODE</code></h2>
<p>Default: <code>prefer</code></p>
<p>PostgreSQL-specific, <a href="https://www.postgresql.org/docs/10/libpq-connect.html#LIBPQ-CONNECT-SSLMODE">details</a></p>
<h2><code>DB_TARGET_SESSION_ATTRS</code></h2>
<p>Default: <code>read-write</code></p>
<p>PostgreSQL-specific, <a href="https://www.postgresql.org/docs/10/libpq-connect.html#LIBPQ-CONNECT-TARGET-SESSION-ATTRS">details</a></p>
<h2><code>DB_USER</code></h2>
<p>Default: <code>postgres</code> (PostgreSQL) or <code>root</code> (MySQL)</p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#user">Django documentation</a>.</p>
<h2><code>DISCORD_CLIENT_ID</code></h2>
<p>Default: <code>None</code></p>
<p>The Discord Client ID, required by the Discord integration.</p>
<p>To set up the Discord integration:</p>
<ul>
<li>Register a new application at
<a href="https://discordapp.com/developers/applications/me">https://discordapp.com/developers/applications/me</a></li>
<li>Add a Redirect URI to your Discord application. The URI format is
<code>SITE_ROOT/integrations/add_discord/</code>. For example, if <code>your SITE_ROOT</code>
is <code>https://my-hc.example.org</code> then the Redirect URI would be
<code>https://my-hc.example.org/integrations/add_discord/</code></li>
<li>Look up your Discord app's <em>Client ID</em> and <em>Client Secret</em>. Put them
in the <code>DISCORD_CLIENT_ID</code> and <code>DISCORD_CLIENT_SECRET</code> environment
variables.</li>
</ul>
<h2><code>DISCORD_CLIENT_SECRET</code></h2>
<p>Default: <code>None</code></p>
<p>The Discord Client Secret, required by the Slack integration. Look it up at
<a href="https://discordapp.com/developers/applications/me">https://discordapp.com/developers/applications/me</a>.</p>
<h2><code>EMAIL_HOST</code></h2>
<p>Default: <code>""</code> (empty string)</p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#email-host">Django documentation</a>.</p>
<h2><code>EMAIL_HOST_PASSWORD</code></h2>
<p>Default: <code>""</code> (empty string)</p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#email-host-password">Django documentation</a>.</p>
<h2><code>EMAIL_HOST_USER</code></h2>
<p>Default: <code>""</code> (empty string)</p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#email-host-user">Django documentation</a>.</p>
<h2><code>EMAIL_PORT</code></h2>
<p>Default: <code>587</code></p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#email-port">Django documentation</a>.</p>
<h2><code>EMAIL_USE_TLS</code></h2>
<p>Default: <code>True</code></p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#email-use-tls">Django documentation</a>.</p>
<h2><code>EMAIL_USE_VERIFICATION</code></h2>
<p>Default: <code>True</code></p>
<p>A boolean that turns on/off a verification step when adding an email integration.</p>
<p>If enabled, whenever an user adds an email integration, Healthchecks emails a
verification link to the new address. The new integration becomes active only
after user clicks the verification link.</p>
<p>If you are setting up a private healthchecks instance where
you trust your users, you can opt to disable the verification step. In that case,
set <code>EMAIL_USE_VERIFICATION</code> to <code>False</code>.</p>
<h2><code>LINENOTIFY_CLIENT_ID</code></h2>
<p>Default: <code>None</code></p>
<h2><code>LINENOTIFY_CLIENT_SECRET</code></h2>
<p>Default: <code>None</code></p>
<h2><code>MASTER_BADGE_LABEL</code></h2>
<p>Default: same as <code>SITE_NAME</code></p>
<h2><code>MATRIX_ACCESS_TOKEN</code></h2>
<p>Default: <code>None</code></p>
<p>The <a href="https://matrix.org/">Matrix</a> bot user's access token, required by the Matrix
integration.</p>
<p>To set up the Matrix integration:</p>
<ul>
<li>Register a bot user (for posting notifications) in your preferred Matrix homeserver.</li>
<li>Use the <a href="https://www.matrix.org/docs/guides/client-server-api#login">Login API call</a>
to retrieve bot user's access token. You can run it as shown in the documentation,
using curl in command shell.</li>
<li>Set the <code>MATRIX_</code> environment variables. Example:</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="na">MATRIX_ACCESS_TOKEN</span><span class="o">=</span><span class="s">[a long string of characters returned by the login call]</span>
<span class="na">MATRIX_HOMESERVER</span><span class="o">=</span><span class="s">https://matrix.org</span>
<span class="na">MATRIX_USER_ID</span><span class="o">=</span><span class="s">@mychecks:matrix.org</span>
</code></pre></div>
<h2><code>MATRIX_HOMESERVER</code></h2>
<p>Default: <code>None</code></p>
<p>The Matrix bot's homeserver address, required by the Matrix integration.</p>
<h2><code>MATRIX_USER_ID</code></h2>
<p>Default: <code>None</code></p>
<p>The Matrix bot's user identifier, required by the Matrix integration.</p>
<h2><code>PD_VENDOR_KEY</code></h2>
<p>Default: <code>None</code></p>
<p><a href="https://www.pagerduty.com/">PagerDuty</a> vendor key,
required by the PagerDuty integration.</p>
<h2><code>PING_BODY_LIMIT</code></h2>
<p>Default: <code>10000</code></p>
<p>The upper size limit in bytes for logged ping request bodies.
The default value is 10000 (10 kilobytes). You can adjust the limit or you can remove
the it altogether by setting this value to <code>None</code>.</p>
<h2><code>PING_EMAIL_DOMAIN</code></h2>
<p>Default: <code>localhost</code></p>
<h2><code>PING_ENDPOINT</code></h2>
<p>Default: <code>http://localhost:8000/ping/</code></p>
<h2><code>PUSHBULLET_CLIENT_ID</code></h2>
<p>Default: <code>None</code></p>
<h2><code>PUSHBULLET_CLIENT_SECRET</code></h2>
<p>Default: <code>None</code></p>
<h2><code>PUSHOVER_API_TOKEN</code></h2>
<p>Default: <code>None</code></p>
<p>The <a href="https://pushover.net/">Pushover</a> API token, required by the Pushover integration.</p>
<p>To enable the Pushover integration:</p>
<ul>
<li>Register a new Pushover application at
<a href="https://pushover.net/apps/build">https://pushover.net/apps/build</a>.</li>
<li>Within the Pushover application configuration, enable subscriptions.
Make sure the subscription type is set to "URL". Also make sure the redirect
URL is configured to point back to the root of the Healthchecks instance
(e.g., <code>https://my-hc.example.org/</code>).</li>
<li>Put the Pushover application's <em>API Token</em> and the <em>Subscription URL</em> in
<code>PUSHOVER_API_TOKEN</code> and <code>PUSHOVER_SUBSCRIPTION_URL</code> environment
variables. The Pushover subscription URL should look similar to
<code>https://pushover.net/subscribe/yourAppName-randomAlphaNumericData</code>.</li>
</ul>
<h2><code>PUSHOVER_EMERGENCY_EXPIRATION</code></h2>
<p>Default: <code>86400</code> (24 hours)</p>
<p>Specifies how many seconds an emergency Pushoover notification
will continue to be retried for.</p>
<p>More information in <a href="https://pushover.net/api#priority">Pushover API documentation</a>.</p>
<h2><code>PUSHOVER_EMERGENCY_RETRY_DELAY</code></h2>
<p>Default: <code>300</code> (5 minutes)</p>
<p>Specifies how often (in seconds) the Pushover servers will send the same notification
to the user.</p>
<p>More information in <a href="https://pushover.net/api#priority">Pushover API documentation</a>.</p>
<h2><code>PUSHOVER_SUBSCRIPTION_URL</code></h2>
<p>Default: <code>None</code></p>
<p>The Pushover Subscription URL, required by the Pushover integration.</p>
<h2><code>REGISTRATION_OPEN</code></h2>
<p>Default: <code>True</code></p>
<p>A boolean that controls whether site visitors can create new accounts.
Set it to <code>False</code> if you are setting up a private Healthchecks instance, but
it needs to be publicly accessible (so, for example, your cloud services
can send pings to it).</p>
<p>If you close new user registration, you can still selectively invite users
to your team account.</p>
<h2><code>REMOTE_USER_HEADER</code></h2>
<p>Default: <code>None</code></p>
<p>Specifies the request header to use for external authentication.</p>
<p>Healthchecks supports external authentication by means of HTTP headers set by
reverse proxies or the WSGI server. This allows you to integrate it into your
existing authentication system (e.g., LDAP or OAuth) via an authenticating proxy. When this option is enabled, <strong>Healtchecks will trust the header's value implicitly</strong>, so it is <strong>very important</strong> to ensure that attackers cannot set the value themselves (and thus impersonate any user). How to do this varies by your chosen proxy, but generally involves configuring it to strip out headers that normalize to the same name as the chosen identity header.</p>
<p>To enable this feature, set the <code>REMOTE_USER_HEADER</code> value to a header you wish to authenticate with. HTTP headers will be prefixed with <code>HTTP_</code> and have any dashes converted to underscores. Headers without that prefix can be set by the WSGI server itself only, which is more secure.</p>
<p>When <code>REMOTE_USER_HEADER</code> is set, Healthchecks will:
- assume the header contains user's email address
- look up and automatically log in the user with a matching email address
- automatically create an user account if it does not exist
- disable the default authentication methods (login link to email, password)</p>
<h2><code>RP_ID</code></h2>
<p>Default: <code>None</code></p>
<p>The <a href="https://www.w3.org/TR/webauthn-2/#relying-party-identifier">Relying Party identifier</a>,
required by the WebAuthn second-factor authentication feature.</p>
<p>Healthchecks optionally supports two-factor authentication using the WebAuthn
standard. To enable WebAuthn support, set the <code>RP_ID</code> setting to a non-null value.
Set its value to your site's domain without scheme and without port. For example,
if your site runs on <code>https://my-hc.example.org</code>, set <code>RP_ID</code> to <code>my-hc.example.org</code>.</p>
<p>Note that WebAuthn requires HTTPS, even if running on localhost. To test WebAuthn
locally with a self-signed certificate, you can use the <code>runsslserver</code> command
from the <code>django-sslserver</code> package.</p>
<h2><code>SECRET_KEY</code></h2>
<p>Default: <code>""</code> (empty string)</p>
<p>A secret key used for cryptographic signing.</p>
<p>This is a standard Django setting, read more in
<a href="https://docs.djangoproject.com/en/3.1/ref/settings/#secret-key">Django documentation</a>.</p>
<h2><code>SHELL_ENABLED</code></h2>
<p>Default: <code>False</code></p>
<p>A boolean that turns on/off the "Shell Commands" integration.</p>
<p>The "Shell Commands" integration runs user-defined local shell commands when checks
go up or down. This integration is disabled by default, and can be enabled by setting
the <code>SHELL_ENABLED</code> environment variable to <code>True</code>.</p>
<p>Note: be careful when using "Shell Commands" integration, and only enable it when
you fully trust the users of your Healthchecks instance. The commands will be executed
by the <code>manage.py sendalerts</code> process, and will run with its system permissions.</p>
<h2><code>SIGNAL_CLI_ENABLED</code></h2>
<p>Default: <code>False</code></p>
<p>A boolean that turns on/off the <a href="https://signal.org/">Signal</a> integration.</p>
<p>Healthchecks uses <a href="https://github.com/AsamK/signal-cli">signal-cli</a> to send Signal
notifications. Healthcecks interacts with signal-cli over DBus.</p>
<p>To enable the Signal integration:</p>
<ul>
<li>Set up and configure signal-cli to listen on DBus system bus
(<a href="https://github.com/AsamK/signal-cli/wiki/DBus-service">instructions</a>).
Make sure you can send test messages from command line, using the <code>dbus-send</code>
example given in the signal-cli instructions.</li>
<li>Set the <code>SIGNAL_CLI_ENABLED</code> environment variable to <code>True</code>.</li>
</ul>
<h2><code>SITE_ROOT</code></h2>
<p>Default: <code>http://localhost:8000</code></p>
<h2><code>SITE_NAME</code></h2>
<p>Default: <code>Mychecks</code></p>
<h2><code>SLACK_CLIENT_ID</code></h2>
<p>Default: <code>None</code></p>
<p>The Slack Client ID, required by the Slack integration.</p>
<p>Go to <a href="https://api.slack.com/apps/">https://api.slack.com/apps/</a>
to create a <em>Slack app</em>, and look up its <em>Client ID</em> and <em>Client Secret</em>.</p>
<p>When setting up the Slack app, make sure to:</p>
<ul>
<li>Add the <a href="https://api.slack.com/scopes/incoming-webhook">incoming-webhook</a>
scope to the Bot Token Scopes.</li>
<li>Add a <em>Redirect URL</em> in the format <code>SITE_ROOT/integrations/add_slack_btn/</code>.
For example, if your <code>SITE_ROOT</code> is <code>https://my-hc.example.org</code> then the
Redirect URL would be <code>https://my-hc.example.org/integrations/add_slack_btn/</code>.</li>
</ul>
<h2><code>SLACK_CLIENT_SECRET</code></h2>
<p>Default: <code>None</code></p>
<p>The Slack Client Secret, required by the Slack integration.
Look it up at <a href="https://api.slack.com/apps/">https://api.slack.com/apps/</a>.</p>
<h2><code>TELEGRAM_BOT_NAME</code></h2>
<p>Default: <code>ExampleBot</code></p>
<p>The <a href="https://telegram.org/">Telegram</a> bot name, required by the Telegram integration.</p>
<p>To set up the Telegram integration:</p>
<ul>
<li>Create a Telegram bot by talking to the
<a href="https://core.telegram.org/bots#6-botfather">BotFather</a>. Set the bot's name,
description, user picture, and add a "/start" command.</li>
<li>After creating the bot you will have the bot's name and token. Put them
in <code>TELEGRAM_BOT_NAME</code> and <code>TELEGRAM_TOKEN</code> environment variables.</li>
<li>Run the <code>settelegramwebhook</code> management command. This command tells Telegram
where to forward channel messages by invoking Telegram's
<a href="https://core.telegram.org/bots/api#setwebhook">setWebhook</a> API call:</li>
</ul>
<div class="highlight"><pre><span></span><code>$ ./manage.py settelegramwebhook
Done, Telegram<span class="err">&#39;</span>s webhook <span class="nb">set</span> to: https://my-monitoring-project.com/integrations/telegram/bot/
</code></pre></div>
<p>For this to work, your <code>SITE_ROOT</code> must be publicy accessible and use the "https://"
scheme.</p>
<h2><code>TELEGRAM_TOKEN</code></h2>
<p>Default: <code>None</code></p>
<p>The Telegram bot user's authentication token, required by the Telegram integration.</p>
<h2><code>TRELLO_APP_KEY</code></h2>
<p>Default: <code>None</code></p>
<h2><code>TWILIO_ACCOUNT</code></h2>
<p>Default: <code>None</code></p>
<h2><code>TWILIO_AUTH</code></h2>
<p>Default: <code>None</code></p>
<h2><code>TWILIO_FROM</code></h2>
<p>Default: <code>None</code></p>
<h2><code>TWILIO_USE_WHATSAPP</code></h2>
<p>Default: <code>False</code></p>
<h2><code>USE_PAYMENTS</code></h2>
<p>Default: <code>False</code></p>
<p>A boolean that turns on/off billing features.</p>

+ 476
- 0
templates/docs/self_hosted_configuration.md View File

@ -0,0 +1,476 @@
# Server Configuration
Healthchecks prepares its configuration in `hc/settings.py`. It reads configuration
from environment variables. Below is a list of variables it reads and uses:
## `ALLOWED_HOSTS`
Default: `*`
A list of strings representing the host/domain names that this site can serve.
You can specify multiple domain names by separating them with commas:
```ini
ALLOWED_HOSTS=my-hc.example.org,alternative-name.example.org
```
Aside from the comma-separated syntax, this is a standard Django setting.
Read more about it in the
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#allowed-hosts).
## `APPRISE_ENABLED`
Default: `False`
A boolean that turns on/off the [Apprise](https://github.com/caronc/apprise)
integration.
Before enabling the Apprise integration, make sure the `apprise` package is installed:
```bash
pip install apprise
```
## `DEBUG`
Default: `True`
A boolean that turns on/off debug mode.
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#debug).
## `DEFAULT_FROM_EMAIL`
Default: `[email protected]`
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#default-from-email).
## `DB`
Default: `sqlite`
The database enginge to use. Possible values: `sqlite`, `postgres`, `mysql`.
## `DB_CONN_MAX_AGE`
Default: `0`
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#conn-max-age).
## `DB_HOST`
Default: `""` (empty string)
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#host).
## `DB_NAME`
Default: `hc` (PostgreSQL, MySQL) or `{project-path}/hc.sqlite` (SQLite)
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#name).
## `DB_PASSWORD`
Default: `""` (empty string)
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#password).
## `DB_PORT`
Default: `""` (empty string)
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#port).
## `DB_SSLMODE`
Default: `prefer`
PostgreSQL-specific, [details](https://www.postgresql.org/docs/10/libpq-connect.html#LIBPQ-CONNECT-SSLMODE)
## `DB_TARGET_SESSION_ATTRS`
Default: `read-write`
PostgreSQL-specific, [details](https://www.postgresql.org/docs/10/libpq-connect.html#LIBPQ-CONNECT-TARGET-SESSION-ATTRS)
## `DB_USER`
Default: `postgres` (PostgreSQL) or `root` (MySQL)
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#user).
## `DISCORD_CLIENT_ID`
Default: `None`
The Discord Client ID, required by the Discord integration.
To set up the Discord integration:
* Register a new application at
[https://discordapp.com/developers/applications/me](https://discordapp.com/developers/applications/me)
* Add a Redirect URI to your Discord application. The URI format is
`SITE_ROOT/integrations/add_discord/`. For example, if `your SITE_ROOT`
is `https://my-hc.example.org` then the Redirect URI would be
`https://my-hc.example.org/integrations/add_discord/`
* Look up your Discord app's _Client ID_ and _Client Secret_. Put them
in the `DISCORD_CLIENT_ID` and `DISCORD_CLIENT_SECRET` environment
variables.
## `DISCORD_CLIENT_SECRET`
Default: `None`
The Discord Client Secret, required by the Slack integration. Look it up at
[https://discordapp.com/developers/applications/me](https://discordapp.com/developers/applications/me).
## `EMAIL_HOST`
Default: `""` (empty string)
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#email-host).
## `EMAIL_HOST_PASSWORD`
Default: `""` (empty string)
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#email-host-password).
## `EMAIL_HOST_USER`
Default: `""` (empty string)
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#email-host-user).
## `EMAIL_PORT`
Default: `587`
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#email-port).
## `EMAIL_USE_TLS`
Default: `True`
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#email-use-tls).
## `EMAIL_USE_VERIFICATION`
Default: `True`
A boolean that turns on/off a verification step when adding an email integration.
If enabled, whenever an user adds an email integration, Healthchecks emails a
verification link to the new address. The new integration becomes active only
after user clicks the verification link.
If you are setting up a private healthchecks instance where
you trust your users, you can opt to disable the verification step. In that case,
set `EMAIL_USE_VERIFICATION` to `False`.
## `LINENOTIFY_CLIENT_ID`
Default: `None`
## `LINENOTIFY_CLIENT_SECRET`
Default: `None`
## `MASTER_BADGE_LABEL`
Default: same as `SITE_NAME`
## `MATRIX_ACCESS_TOKEN`
Default: `None`
The [Matrix](https://matrix.org/) bot user's access token, required by the Matrix
integration.
To set up the Matrix integration:
* Register a bot user (for posting notifications) in your preferred Matrix homeserver.
* Use the [Login API call](https://www.matrix.org/docs/guides/client-server-api#login)
to retrieve bot user's access token. You can run it as shown in the documentation,
using curl in command shell.
* Set the `MATRIX_` environment variables. Example:
```ini
MATRIX_ACCESS_TOKEN=[a long string of characters returned by the login call]
MATRIX_HOMESERVER=https://matrix.org
MATRIX_USER_ID=@mychecks:matrix.org
```
## `MATRIX_HOMESERVER`
Default: `None`
The Matrix bot's homeserver address, required by the Matrix integration.
## `MATRIX_USER_ID`
Default: `None`
The Matrix bot's user identifier, required by the Matrix integration.
## `PD_VENDOR_KEY`
Default: `None`
[PagerDuty](https://www.pagerduty.com/) vendor key,
required by the PagerDuty integration.
## `PING_BODY_LIMIT`
Default: `10000`
The upper size limit in bytes for logged ping request bodies.
The default value is 10000 (10 kilobytes). You can adjust the limit or you can remove
the it altogether by setting this value to `None`.
## `PING_EMAIL_DOMAIN`
Default: `localhost`
## `PING_ENDPOINT`
Default: `http://localhost:8000/ping/`
## `PUSHBULLET_CLIENT_ID`
Default: `None`
## `PUSHBULLET_CLIENT_SECRET`
Default: `None`
## `PUSHOVER_API_TOKEN`
Default: `None`
The [Pushover](https://pushover.net/) API token, required by the Pushover integration.
To enable the Pushover integration:
* Register a new Pushover application at
[https://pushover.net/apps/build](https://pushover.net/apps/build).
* Within the Pushover application configuration, enable subscriptions.
Make sure the subscription type is set to "URL". Also make sure the redirect
URL is configured to point back to the root of the Healthchecks instance
(e.g., `https://my-hc.example.org/`).
* Put the Pushover application's _API Token_ and the _Subscription URL_ in
`PUSHOVER_API_TOKEN` and `PUSHOVER_SUBSCRIPTION_URL` environment
variables. The Pushover subscription URL should look similar to
`https://pushover.net/subscribe/yourAppName-randomAlphaNumericData`.
## `PUSHOVER_EMERGENCY_EXPIRATION`
Default: `86400` (24 hours)
Specifies how many seconds an emergency Pushoover notification
will continue to be retried for.
More information in [Pushover API documentation](https://pushover.net/api#priority).
## `PUSHOVER_EMERGENCY_RETRY_DELAY`
Default: `300` (5 minutes)
Specifies how often (in seconds) the Pushover servers will send the same notification
to the user.
More information in [Pushover API documentation](https://pushover.net/api#priority).
## `PUSHOVER_SUBSCRIPTION_URL`
Default: `None`
The Pushover Subscription URL, required by the Pushover integration.
## `REGISTRATION_OPEN`
Default: `True`
A boolean that controls whether site visitors can create new accounts.
Set it to `False` if you are setting up a private Healthchecks instance, but
it needs to be publicly accessible (so, for example, your cloud services
can send pings to it).
If you close new user registration, you can still selectively invite users
to your team account.
## `REMOTE_USER_HEADER`
Default: `None`
Specifies the request header to use for external authentication.
Healthchecks supports external authentication by means of HTTP headers set by
reverse proxies or the WSGI server. This allows you to integrate it into your
existing authentication system (e.g., LDAP or OAuth) via an authenticating proxy. When this option is enabled, **Healtchecks will trust the header's value implicitly**, so it is **very important** to ensure that attackers cannot set the value themselves (and thus impersonate any user). How to do this varies by your chosen proxy, but generally involves configuring it to strip out headers that normalize to the same name as the chosen identity header.
To enable this feature, set the `REMOTE_USER_HEADER` value to a header you wish to authenticate with. HTTP headers will be prefixed with `HTTP_` and have any dashes converted to underscores. Headers without that prefix can be set by the WSGI server itself only, which is more secure.
When `REMOTE_USER_HEADER` is set, Healthchecks will:
- assume the header contains user's email address
- look up and automatically log in the user with a matching email address
- automatically create an user account if it does not exist
- disable the default authentication methods (login link to email, password)
## `RP_ID`
Default: `None`
The [Relying Party identifier](https://www.w3.org/TR/webauthn-2/#relying-party-identifier),
required by the WebAuthn second-factor authentication feature.
Healthchecks optionally supports two-factor authentication using the WebAuthn
standard. To enable WebAuthn support, set the `RP_ID` setting to a non-null value.
Set its value to your site's domain without scheme and without port. For example,
if your site runs on `https://my-hc.example.org`, set `RP_ID` to `my-hc.example.org`.
Note that WebAuthn requires HTTPS, even if running on localhost. To test WebAuthn
locally with a self-signed certificate, you can use the `runsslserver` command
from the `django-sslserver` package.
## `SECRET_KEY`
Default: `""` (empty string)
A secret key used for cryptographic signing.
This is a standard Django setting, read more in
[Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#secret-key).
## `SHELL_ENABLED`
Default: `False`
A boolean that turns on/off the "Shell Commands" integration.
The "Shell Commands" integration runs user-defined local shell commands when checks
go up or down. This integration is disabled by default, and can be enabled by setting
the `SHELL_ENABLED` environment variable to `True`.
Note: be careful when using "Shell Commands" integration, and only enable it when
you fully trust the users of your Healthchecks instance. The commands will be executed
by the `manage.py sendalerts` process, and will run with its system permissions.
## `SIGNAL_CLI_ENABLED`
Default: `False`
A boolean that turns on/off the [Signal](https://signal.org/) integration.
Healthchecks uses [signal-cli](https://github.com/AsamK/signal-cli) to send Signal
notifications. Healthcecks interacts with signal-cli over DBus.
To enable the Signal integration:
* Set up and configure signal-cli to listen on DBus system bus
([instructions](https://github.com/AsamK/signal-cli/wiki/DBus-service)).
Make sure you can send test messages from command line, using the `dbus-send`
example given in the signal-cli instructions.
* Set the `SIGNAL_CLI_ENABLED` environment variable to `True`.
## `SITE_ROOT`
Default: `http://localhost:8000`
## `SITE_NAME`
Default: `Mychecks`
## `SLACK_CLIENT_ID`
Default: `None`
The Slack Client ID, required by the Slack integration.
Go to [https://api.slack.com/apps/](https://api.slack.com/apps/)
to create a _Slack app_, and look up its _Client ID_ and _Client Secret_.
When setting up the Slack app, make sure to:
* Add the [incoming-webhook](https://api.slack.com/scopes/incoming-webhook)
scope to the Bot Token Scopes.
* Add a _Redirect URL_ in the format `SITE_ROOT/integrations/add_slack_btn/`.
For example, if your `SITE_ROOT` is `https://my-hc.example.org` then the
Redirect URL would be `https://my-hc.example.org/integrations/add_slack_btn/`.
## `SLACK_CLIENT_SECRET`
Default: `None`
The Slack Client Secret, required by the Slack integration.
Look it up at [https://api.slack.com/apps/](https://api.slack.com/apps/).
## `TELEGRAM_BOT_NAME`
Default: `ExampleBot`
The [Telegram](https://telegram.org/) bot name, required by the Telegram integration.
To set up the Telegram integration:
* Create a Telegram bot by talking to the
[BotFather](https://core.telegram.org/bots#6-botfather). Set the bot's name,
description, user picture, and add a "/start" command.
* After creating the bot you will have the bot's name and token. Put them
in `TELEGRAM_BOT_NAME` and `TELEGRAM_TOKEN` environment variables.
* Run the `settelegramwebhook` management command. This command tells Telegram
where to forward channel messages by invoking Telegram's
[setWebhook](https://core.telegram.org/bots/api#setwebhook) API call:
```bash
$ ./manage.py settelegramwebhook
Done, Telegram's webhook set to: https://my-monitoring-project.com/integrations/telegram/bot/
```
For this to work, your `SITE_ROOT` must be publicy accessible and use the "https://"
scheme.
## `TELEGRAM_TOKEN`
Default: `None`
The Telegram bot user's authentication token, required by the Telegram integration.
## `TRELLO_APP_KEY`
Default: `None`
## `TWILIO_ACCOUNT`
Default: `None`
## `TWILIO_AUTH`
Default: `None`
## `TWILIO_FROM`
Default: `None`
## `TWILIO_USE_WHATSAPP`
Default: `False`
## `USE_PAYMENTS`
Default: `False`
A boolean that turns on/off billing features.

+ 3
- 5
templates/docs/signaling_failures.html View File

@ -4,30 +4,28 @@ ping URL: append either <code>/fail</code> or <code>/{exit-status}</code> to you
The exit status should be a 0-255 integer. SITE_NAME will interpret
exit status 0 as success and all non-zero values as failures.</p>
<p>Examples:</p>
<div class="bash highlight"><pre><span></span><code><span class="c1"># Reports failure by appending the /fail suffix:</span>
<div class="highlight"><pre><span></span><code><span class="c1"># Reports failure by appending the /fail suffix:</span>
curl --retry <span class="m">3</span> PING_URL/fail
<span class="c1"># Reports failure by appending a non-zero exit status:</span>
curl --retry <span class="m">3</span> PING_URL/1
</code></pre></div>
<p>By actively signaling failures to SITE_NAME, you can minimize the delay from your
monitored service encountering a problem to you getting notified about it.</p>
<h2>Shell Scripts</h2>
<p>The below shell script appends <code>$?</code> (a special variable which contains the
exit status of the last executed command) to the ping URL:</p>
<div class="bash highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
/usr/bin/certbot renew
curl --retry <span class="m">3</span> PING_URL/<span class="nv">$?</span>
</code></pre></div>
<h2>Python</h2>
<p>Below is a skeleton code example in Python which signals a failure when the
work function returns an unexpected value or throws an exception:</p>
<div class="python highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">requests</span>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">requests</span>
<span class="n">URL</span> <span class="o">=</span> <span class="s2">&quot;PING_URL&quot;</span>
<span class="k">def</span> <span class="nf">do_work</span><span class="p">():</span>


+ 4
- 0
templates/front/base_docs.html View File

@ -42,6 +42,10 @@
<li class="nav-header">Developer Tools</li>
{% include "front/docs_nav_item.html" with slug="resources" title="Third-party resources" %}
<li class="nav-header">Self-hosted</li>
{% include "front/docs_nav_item.html" with slug="self_hosted" title="Overview" %}
{% include "front/docs_nav_item.html" with slug="self_hosted_configuration" title="Configuration" %}
<li class="nav-header">Reference</li>
<li><a href="{% url 'hc-docs-cron' %}">Cron syntax cheatsheet</a></li>
</ul>


Loading…
Cancel
Save