repos
/ status-django master

status-django

mirror archived upstream

Self-hostable uptime monitor and status page on Django: HTTP checks, Lighthouse audits, SEO crawls, and email and Discord alerts.

djangodockerhandcodedpythonself-hostedsqlitestatus-pageuptime-monitoringvite

7.2 KB · 186 lines · markdown Raw History
  1> **Archived.** This project is no longer in use and no longer maintained. Last updated April 2026.
  2
  3# Status
  4
  5A self-hostable uptime monitor and status page. HTTP checks every 3 minutes,
  6daily Lighthouse audits, weekly in-process SEO crawls, and alerts via email
  7and Discord webhook on state transitions.
  8
  9
 10## Motivation
 11
 12I was bored and felt like writing my own uptime service over the weekend.
 13
 14
 15## Features
 16
 17- HTTP uptime checks with rolling uptime percentages and recent-uptime bars
 18- Lighthouse audits (performance, accessibility, best practices, SEO) with
 19  weighted breakdown and top savings opportunities
 20- In-process SEO crawler (requests + BeautifulSoup) — title, description,
 21  canonical, OG tags, and H1 per page
 22- Security header analysis (HSTS, CSP, X-Frame-Options, Referrer-Policy, etc.)
 23- Alert state machine with debounce on flaps — two consecutive non-200s to
 24  go down, immediate 200 to come back up
 25- Email and Discord webhook alerts on state transitions only
 26- PDF report export per property via a headless Chromium subprocess
 27- Customizable UI with a warm-earth palette and Monaspace Argon
 28
 29
 30## Requirements
 31
 32You need docker + docker-compose installed for a quick production start or you
 33can figure out how we install and run things via the `Dockerfile` and set it up
 34yourself.
 35
 36If you want to install things without docker then you'll need the following
 37dependencies:
 38
 39- python
 40- uv
 41- bun
 42- node (required only for the `lighthouse` npm CLI — Bun doesn't run Lighthouse
 43  correctly; see bun issue #4958)
 44- chromium (used for PDF report generation via a subprocess wrapper)
 45
 46You can also check the `Dockerfile` for an exact list of dependencies and adjust
 47package names for your desired platform.
 48
 49This is a standard Django project. If you know how to run Django, or want to
 50look up any Django tutorial on how to run Django, you shouldn't have a problem
 51getting this project running on almost anything.
 52
 53
 54## Running locally
 55
 56If you have all of the above dependencies installed you can use my Makefile to
 57run and install python and node dependencies locally. Running `make` will check
 58that you have the proper dependencies installed and if not it will try and
 59install them for you. It will then create you a fresh database and run
 60everything.
 61
 62If you want to also run the scheduler you'll have to do so separately. Run
 63`make` in one window/tab and run `make scheduler` in another.
 64
 65
 66## Checking outdated dependencies
 67
 68This can be done in both bun and uv with the following two commands:
 69
 70    uv lock --upgrade --dry-run
 71    bun outdated
 72
 73You can then upgrade all dependencies at once with:
 74
 75    make update
 76
 77I recommend testing everything after this to make sure it's all working.
 78
 79
 80## Optimizing images with webp
 81
 82My development system runs Ubuntu so I installed the official webp utils from
 83Google with `apt install webp`.
 84
 85    cwebp -q 90 -m 6 -o output.webp input.png
 86
 87
 88## Using docker-compose
 89
 90The easiest way to run this project is to run it using
 91`docker-compose up --build -d` if you have `docker-compose` and `docker`
 92installed. This will start the server and have you running at port 8000. The
 93first time you do this make sure you run migrations with
 94`docker-compose run web python manage.py migrate`. Make sure you setup the
 95`.env` file before running, you can copy the sample from
 96`samplefiles/env.sample` into the root of the project as `.env` and change the
 97variables.
 98
 99
100## Default user
101
102The default user is `admin` with the password `admin`. Add your own properties
103from the dashboard after signing in.
104
105
106## Alerts
107
108Each property can be assigned a Discord webhook URL per user (see the account
109settings). Email alerts use the project's configured outbound mailer (the
110direct-to-MX backend by default, see `status/mailer.py`). Alerts fire on state
111transitions only — not on every failing check.
112
113
114## Backups
115
116All data is stored in `/srv/data/status/` and your repo is stored in
117`/srv/git/status.git/`. You can backup both of these folders and you'll have
118a 100% backup of everything except changes you may have made to the `Caddyfile`
119and the `.env` file which should be easy enough to recreate but you can back
120those up too!
121
122
123## Server guide
124
125This quickstart requires that you have an Alpine Linux server running with a
126domain name pointed to it. I'm currently using Linode as my host since they
127support Alpine Linux nicely. If you don't want to use Linode or Alpine Linux
128you can use these instructions and just change the apk commands at the start to
129whatever Linux distro you're using.
130
131**IMPORTANT NOTE**: Change `status.bythewood.me` to your domain name where
132relevant in these instructions.
133
134**TIP**: During the ufw portion to enable the firewall I recommend only allowing
135your IP address or your ISP's IP address range which you can find on whois
136lookups at the top. For example, replace `192.230.176.0/20` with your IP or your
137ISP's IP range.
138
139    ufw allow from 192.230.176.0/20 proto tcp to any port 22
140
141I allow my local ISP's range because I have a DHCP lease from them and I get
142tired of logging into my server from my hosting provider's UI to update it. It's
143good enough security and much better than nothing!
144
145Server:
146
147    apk update && apk upgrade && apk add docker docker-compose caddy git iptables ip6tables ufw
148    ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp && ufw --force enable
149    echo -e "#!/bin/sh\napk upgrade --update | sed \"s/^/[\`date\`] /\" >> /var/log/apk-autoupgrade.log" > /etc/periodic/daily/apk-autoupgrade && chmod 700 /etc/periodic/daily/apk-autoupgrade
150    rc-update add docker boot && service docker start
151    mkdir -p /srv/git/status.git && cd /srv/git/status.git && git init --bare
152
153Local:
154
155    git clone [email protected]:overshard/status-django.git && cd status-django
156    git remote remove origin && git remote add origin [email protected]:/srv/git/status.git
157    git push --set-upstream origin master
158
159Server:
160
161    mkdir -p /srv/docker && cd /srv/docker && git clone /srv/git/status.git status && cd /srv/docker/status
162    cp samplefiles/Caddyfile.sample /etc/caddy/Caddyfile && sed -i 's/status.example.com/status.bythewood.me/g' /etc/caddy/Caddyfile
163    cp samplefiles/env.sample .env && sed -i 's/status.example.com/status.bythewood.me/g' .env
164    cp samplefiles/post-receive.sample /srv/git/status.git/hooks/post-receive
165    mkdir -p /srv/data/status/db && chown -R 1000:1000 /srv/data/status
166    docker-compose up --build --detach && docker-compose run web python3 manage.py migrate --noinput && docker-compose run web sqlite3 db.sqlite3 "PRAGMA journal_mode=WAL;" ".exit"
167    rc-update add caddy boot && service caddy start
168
169
170## Scaling
171
172I choose to use an sqlite3 database since that handles all my usecases just
173fine. My first recommendation for scaling this project would be to use a
174PostgreSQL database. If you want to get fancy then a time-series database like
175Timescale would make a lot of sense. The foundation of this project is pure
176Django so it shouldn't be hard to swap in a different database.
177
178
179## Support
180
181I won't be providing any user support for this project. I'm more than happy to
182accept good pull requests and fix bugs but I don't have the time to help people
183run or use this project. I appologize in advance for this. Maintaining
184mutliple OSS projects has taught me that I need to step back from trying to
185provide support to avoid burnout.