Files
uptime-monitor/README.md
T
2026-08-20 08:23:32 +02:00

118 lines
4.1 KiB
Markdown

# uptime-monitor
A small single-container Python 3 uptime monitor.
- Monitors a configurable list of HTTP/HTTPS endpoints.
- Each endpoint independently specifies: scheme (http/https), port, the
DNS server used to resolve it, and the expected HTTP status code.
- **DNS resolution never uses the system/router-provided resolver** —
every lookup is sent explicitly and only to the DNS server configured
for that endpoint (see "How DNS enforcement works" below).
- Runs a full rolling pass over all endpoints every 10 minutes (configurable).
- If any endpoint fails, all endpoints are immediately re-checked once,
instead of waiting for the next scheduled pass.
- Writes every check result to an InfluxDB 2.x bucket (`uptime`) over
HTTPS, with certificate verification disabled for InfluxDB specifically
(self-signed cert).
- Everything — endpoint list, InfluxDB URL/token/org/bucket, intervals —
lives in one YAML file that's bind-mounted into the container. Edit it
and restart the container; no image rebuild required.
## Setup
```bash
cp config.example.yaml config.yaml
# edit config.yaml: fill in your InfluxDB url/token/org, and your endpoints
docker compose up -d --build
```
## Editing endpoints / InfluxDB settings later
```bash
vim config.yaml
docker compose restart uptime-monitor
```
No rebuild needed — `config.yaml` is bind-mounted (`docker-compose.yml`),
never baked into the image (see `.dockerignore`).
## Config reference (`config.yaml`)
```yaml
influx:
url: "https://influxdb.example.local:8086"
token: "..." # InfluxDB 2.x API token with write access
org: "..."
bucket: "uptime"
verify_ssl: false # keep false: influx uses a self-signed cert
check:
interval_seconds: 600 # 10 min rolling interval
timeout_seconds: 10 # default per-check timeout
immediate_recheck_delay_seconds: 5 # pause before the failure-triggered recheck
endpoints:
- name: "my-service"
host: "service.example.com"
scheme: "https"
port: 443
dns_server: "1.1.1.1" # required, per-endpoint — no default DNS is ever used
expected_status: 200
path: "/" # optional, default "/"
timeout_seconds: 5 # optional, overrides check.timeout_seconds
verify_tls: true # optional, set false if THIS endpoint has a self-signed cert
```
Add/remove/edit entries under `endpoints:` freely.
## How DNS enforcement works
For each check:
1. A fresh `dnspython` resolver is created with `configure=False` (so it
never reads `/etc/resolv.conf`) and pointed at only the endpoint's
`dns_server`.
2. That resolver performs the A-record lookup.
3. The resulting IP is pinned for the single outgoing HTTP(S) request via
a scoped patch of `socket.getaddrinfo` — so `requests`/urllib3 connects
directly to that IP instead of resolving the hostname itself. The
hostname in the URL is left untouched, so the `Host` header and TLS
SNI/certificate checks behave exactly as they normally would.
At no point is the container's own (router-provided) DNS resolver
consulted for endpoint hostnames.
## What gets written to InfluxDB
Measurement `uptime_check`, one point per endpoint per check:
- tags: `endpoint`, `host`, `scheme`, `port`
- fields: `success` (0/1), `expected_status`, `status_code` (if a response
was received), `response_time_ms`, `resolved_ip`, `error` (if any)
Example Flux query:
```flux
from(bucket: "uptime")
|> range(start: -24h)
|> filter(fn: (r) => r._measurement == "uptime_check")
|> filter(fn: (r) => r._field == "success")
```
## Failure / immediate recheck behavior
- Every `check.interval_seconds`, all endpoints are checked in sequence.
- If any endpoint fails that pass, after `immediate_recheck_delay_seconds`
all endpoints are checked again immediately (one extra pass).
- The monitor then returns to the normal `interval_seconds` schedule.
If the outage continues, the next scheduled pass will detect it again
and trigger another single immediate recheck — it does not hammer the
endpoint in a tight loop.
## Local dev (without Docker)
```bash
pip install -r requirements.txt
CONFIG_PATH=./config.yaml python -m app.main
```