tutorial

Monitoring Your FastHTML Application with Vigilmon (Free, Multi-Region)

FastHTML is the Python web framework from Jeremy Howard that combines HTMX with Python for instant interactivity. Learn how to add a health route, set up external uptime monitoring, and get alerted when your FastHTML app goes down.

Monitoring Your FastHTML Application with Vigilmon (Free, Multi-Region)

FastHTML is the Python web framework from Jeremy Howard (fast.ai) that makes HTMX-powered interactivity feel as natural as writing plain Python. If you've built ML-backed apps, internal tools, or rapid prototypes with FastHTML, you know how fast it goes from idea to deployed app.

What's less exciting is finding out your app has been down for two hours because nobody set up monitoring.

This guide covers how to add a health route to a FastHTML app and set up external uptime monitoring with Vigilmon — so you get alerted the moment your app becomes unreachable.


Why FastHTML apps need external monitoring

FastHTML apps are typically deployed as lightweight Python ASGI processes — on a VPS, on Fly.io, on Railway, or on any platform that runs a Docker container. Like any long-running process, they can:

  • Crash after an unhandled exception in a route
  • Hang when waiting on a blocked database call or external API
  • Become unreachable when the deployment fails silently
  • Run out of memory and get killed by the OS

When any of these happen, the process stops responding to HTTP requests. Your users get a connection error or a timeout. Without external monitoring, you won't find out until someone tells you.


Step 1: Add a health route to your FastHTML app

FastHTML makes this simple. Add a /health route that returns a JSON response:

from fasthtml.common import *
from starlette.responses import JSONResponse
import time

app, rt = fast_app()

@rt('/health')
def get():
    return JSONResponse(
        {'status': 'ok', 'timestamp': time.time()},
        status_code=200
    )

serve()

Verify it locally:

curl http://localhost:5001/health
# {"status":"ok","timestamp":1751280000.0}

Add a database check

If your FastHTML app uses a database (SQLite via MiniDataAPI, or a PostgreSQL/MySQL connection), include a lightweight connectivity check:

from fasthtml.common import *
from starlette.responses import JSONResponse
import time

# Example with MiniDataAPI (built-in SQLite)
db = database('data/app.db')
todos = db.t.todos

app, rt = fast_app()

@rt('/health')
def get():
    try:
        # Lightweight DB probe
        todos.count
        db_status = 'ok'
    except Exception as e:
        return JSONResponse(
            {'status': 'error', 'database': 'error', 'detail': str(e)},
            status_code=503
        )

    return JSONResponse(
        {
            'status': 'ok',
            'database': db_status,
            'timestamp': time.time()
        },
        status_code=200
    )

serve()

For PostgreSQL via asyncpg or psycopg:

import asyncpg

@rt('/health')
async def get():
    try:
        conn = await asyncpg.connect(os.environ['DATABASE_URL'])
        await conn.execute('SELECT 1')
        await conn.close()
        db_status = 'ok'
    except Exception as e:
        return JSONResponse(
            {'status': 'error', 'database': 'error'},
            status_code=503
        )

    return JSONResponse({'status': 'ok', 'database': db_status}, status_code=200)

Step 2: Set up Vigilmon monitoring

With the health route live, point Vigilmon at it:

  1. Sign up at vigilmon.online — free tier, no credit card
  2. Click New Monitor → HTTP
  3. Enter https://your-fasthtml-app.com/health
  4. Set the check interval (5 minutes on free tier)
  5. Save

Vigilmon probes from multiple geographic regions. If your app is unreachable from any region, it opens an incident immediately.

Add a keyword monitor for response validation

Add a second monitor that asserts the response body:

  1. New Monitor → Keyword
  2. URL: https://your-fasthtml-app.com/health
  3. Keyword: "status":"ok"
  4. If absent, Vigilmon treats it as a failure

This catches the case where the ASGI server is running but your health handler returns a database error — HTTP 503 with a body that says "status":"error".

Recommended monitor set for FastHTML

| Monitor | URL | Type | What it catches | |---|---|---|---| | App health | /health | HTTP | Process down, port not responding | | Response check | /health | Keyword | Database error, degraded state | | Main route | / | HTTP | Homepage broken (bad deploy) |


Step 3: Monitor ML model loading (for AI-backed apps)

FastHTML is popular in the Python/ML community for building AI-powered interfaces. If your app loads a model at startup (transformers, scikit-learn, etc.), add a readiness flag so the health check only returns 200 after the model has loaded:

from fasthtml.common import *
from starlette.responses import JSONResponse
import time
import threading

app, rt = fast_app()

model = None
model_ready = False

def load_model():
    global model, model_ready
    # Replace with your actual model loading
    from transformers import pipeline
    model = pipeline('text-generation', model='gpt2')
    model_ready = True

# Load in background so the app starts fast
threading.Thread(target=load_model, daemon=True).start()

@rt('/health')
def get():
    if not model_ready:
        return JSONResponse(
            {'status': 'starting', 'model': 'loading'},
            status_code=503
        )

    return JSONResponse(
        {'status': 'ok', 'model': 'ready', 'timestamp': time.time()},
        status_code=200
    )

serve()

This prevents Vigilmon from alerting during a normal cold start while the model loads. Once the model is ready, /health starts returning 200 and monitoring proceeds normally.


Step 4: Configure alert delivery

Slack:

  1. Create an incoming webhook in Slack
  2. In Vigilmon: Notifications → New Channel → Slack
  3. Enable it on your FastHTML monitors

Email:

  1. In Vigilmon: Notifications → New Channel → Email
  2. Add your address

When your FastHTML app goes down, you'll get:

🔴 DOWN: your-fasthtml-app.com/health
Status: Connection refused
Regions: US-East, EU-West, AP-Southeast
Started: 7 minutes ago

And when it recovers:

✅ RECOVERED: your-fasthtml-app.com/health is back UP
Total downtime: 12 minutes

Step 5: Deploy-time health check

If you deploy via Docker, add a health check so failed containers are restarted automatically:

FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .

HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
  CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:5001/health')" || exit 1

CMD ["python", "main.py"]

Or in docker-compose.yml:

services:
  app:
    build: .
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:5001/health')"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    restart: unless-stopped
    ports:
      - "5001:5001"

Combined with Vigilmon, you get:

  • Docker restarts the container if it fails its health check
  • Vigilmon alerts you if the whole host goes unreachable, or the restart loop isn't resolving the issue

Step 6: Create a public status page

If you're sharing your FastHTML app with users or collaborators:

  1. Status Pages → New Status Page in Vigilmon
  2. Add your health monitor
  3. Share the public URL

A status page lets users check current uptime themselves during an incident instead of emailing you.


What you've built

| What | How | |---|---| | Health route | /health — plain FastHTML route returning JSON | | Database check | Lightweight query inside the health handler | | External monitoring | Vigilmon HTTP monitor (multi-region) | | Body assertion | Vigilmon keyword monitor on "status":"ok" | | ML readiness | Startup flag prevents cold-start false positives | | Container health | Dockerfile / Docker Compose HEALTHCHECK | | Instant alerts | Slack/email on down + recovery |

Your FastHTML app is now externally observable. The next time the ASGI process crashes, the database connection fails, or a deployment goes wrong, you'll know about it in minutes — not hours.


Get started free at vigilmon.online — your first monitor is running in under a minute.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →