# mithal-space-monitor A lightweight, stdlib-only uptime/latency/SSL monitor with a single-page Chart.js dashboard, packaged into one container. ## What's inside | File | Purpose | |---|---| | `monitor.py` | Standard-library-only Python script. Every `CHECK_INTERVAL` seconds it checks DNS resolution time, HTTP status + latency, search-endpoint latency, and SSL cert expiry, then writes a rolling `RETENTION_HOURS` window to a JSON file. | | `index.html` | Single-page dashboard (HTML/CSS/JS + Chart.js via CDN). Polls the JSON file every 30s and renders 24h uptime %, a 60-minute latency line chart, SSL expiry, and a table of the last 10 checks. | | `entrypoint.sh` | Starts `monitor.py` and `python -m http.server` side by side, forwards signals, and exits the container if either process dies (so the orchestrator restarts it). | | `Dockerfile` | `python:3.12-alpine` base, non-root user, healthcheck, no external Python deps. | ## Configuration (environment variables) | Variable | Default | Description | |---|---|---| | `TARGET_URL` | `https://mithal.space` | URL to monitor | | `SEARCH_PATH` | `/search?q=test` | Path appended to the target's origin for the search-latency check | | `CHECK_INTERVAL` | `60` | Seconds between checks | | `RETENTION_HOURS` | `24` | Rolling window kept in the JSON log | | `REQUEST_TIMEOUT` | `10` | Per-request timeout (seconds) | | `PORT` | `8080` | Dashboard HTTP server port | ## Build & run locally ```bash docker build -t mithal-space-monitor . docker run -d \ --name mithal-monitor \ -p 8080:8080 \ -e TARGET_URL="https://mithal.space" \ -e SEARCH_PATH="/search?q=test" \ -v mithal_monitor_data:/app/data \ mithal-space-monitor # open http://localhost:8080 ``` The `-v mithal_monitor_data:/app/data` volume is optional but recommended so your 24h history survives a container restart/redeploy. ## Push to a registry ```bash docker tag mithal-space-monitor registry.example.com/yourorg/mithal-space-monitor:latest docker push registry.example.com/yourorg/mithal-space-monitor:latest ``` ## Deploy This image is a single process group exposing one HTTP port, so it runs as-is on most container platforms: - **Cloud Run / Container Apps / Fly.io**: deploy the image, set `PORT` to match the platform's expected port (Cloud Run injects `PORT` automatically - the entrypoint already respects it), mount a persistent volume if the platform supports one (otherwise history resets on redeploy, which is fine - it just rebuilds over the next `RETENTION_HOURS`). - **Kubernetes**: run as a `Deployment` with 1 replica, a `Service` of type `ClusterIP`/`LoadBalancer`, and optionally a `PersistentVolumeClaim` mounted at `/app/data`. The built-in `HEALTHCHECK` maps naturally to a liveness probe on `GET /`. - **Plain VM / docker-compose**: use the `docker run` command above behind your existing reverse proxy / TLS terminator. ## Notes & extension points - Everything in `monitor.py` uses only the Python standard library (`urllib`, `socket`, `ssl`, `json`) - no `pip install` step, no dependency surface in the image. - Data is written atomically (`write → temp file → os.replace`) so the dashboard never reads a half-written JSON file. - To monitor multiple targets, run one container per target (each with its own `TARGET_URL`/port), or extend `monitor.py` to loop over a list of targets and extend `index.html` with a target selector. - Add basic auth / IP allowlisting at your reverse proxy if the dashboard shouldn't be public.