tutorial

How to Monitor Docker Containers with Vigilmon (HTTP, TCP, and Alerts)

Running services in Docker containers gives you isolation and reproducibility — but containers also introduce new failure modes that traditional monitoring m...

Running services in Docker containers gives you isolation and reproducibility — but containers also introduce new failure modes that traditional monitoring misses. A container can crash silently, expose a port that goes unreachable, or fail its own health check without anyone noticing for hours.

In this tutorial you'll set up end-to-end monitoring for Docker services using Vigilmon — free tier, no credit card.


Why containers need dedicated monitoring

Docker containers fail in ways that VM-era monitoring tools weren't built to catch:

  • Silent crash and restart loops — a container restarts every 30 seconds (crash-loop), appears "running" at the Docker level, but never serves traffic
  • Port-binding failures — the container starts but the host port binding silently drops; curl localhost:3000 hangs indefinitely
  • Health check mismatches — you define a HEALTHCHECK in your Dockerfile but never alert on a unhealthy status
  • Dependency failures — your app container is up but the database container it depends on is down, making your /health endpoint return 500

External monitoring — something probing your service from outside the Docker network — is the only way to catch all of these reliably.


What you'll need

  • A running Docker service (we'll use a sample docker-compose.yml)
  • A free Vigilmon account (sign up takes 30 seconds)

Step 1: Add a health endpoint to your Docker service

Before setting up a monitor, give Vigilmon something to check. Add a /health route to your app that returns HTTP 200 when the service is operational.

Here's an example for a Node.js/Express app already in your container:

// Add to your Express app
app.get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

For a Go service:

http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    w.Write([]byte(`{"status":"ok"}`))
})

Expose the port in your docker-compose.yml:

version: "3.9"

services:
  web:
    image: your-app:latest
    build: .
    ports:
      - "3000:3000"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s
    restart: unless-stopped

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db_data:/var/lib/postgresql/data
    restart: unless-stopped

volumes:
  db_data:

The healthcheck block tells Docker when your container is healthy — but Docker doesn't alert you when it goes unhealthy. That's where Vigilmon comes in.


Step 2: Set up HTTP monitoring in Vigilmon

  1. Log in to vigilmon.online and go to Monitors → New Monitor
  2. Choose HTTP / HTTPS as the type
  3. Set the URL to your health endpoint, e.g. https://your-server.example.com/health
  4. Set the check interval to 1 minute (the free tier supports 1-minute checks)
  5. Under Expected response, set:
    • Status code: 200
    • (Optional) Response body contains: "status":"ok"
  6. Save the monitor

Vigilmon will now probe your /health endpoint from multiple regions every minute. If it returns anything other than 200 — or if it times out — an incident is triggered.


Step 3: Set up TCP port monitoring

HTTP checks verify that your app is responding correctly. TCP port checks verify that the port is reachable at all — useful for databases, message queues, or any service that doesn't speak HTTP.

  1. In Vigilmon, go to Monitors → New Monitor
  2. Choose TCP Port as the type
  3. Enter your server hostname and the port, e.g. your-server.example.com / 5432
  4. Save the monitor

Now you'll know immediately if the PostgreSQL container loses its port binding, even before any HTTP-level check would fire.


Step 4: Configure webhook alerts for container downtime

When a container goes down, you want to know in seconds — not when a user reports it. Vigilmon supports webhooks for real-time alerts.

  1. Go to Alert Channels → Add Channel → Webhook
  2. Enter your webhook URL (Slack, Discord, PagerDuty, or any custom endpoint)
  3. Assign the channel to your monitors

Example Slack webhook payload Vigilmon sends on an incident:

{
  "monitor_name": "web /health",
  "status": "down",
  "url": "https://your-server.example.com/health",
  "started_at": "2024-01-15T10:23:00Z",
  "duration_seconds": 45
}

You can also use email alerts if you don't need real-time Slack notifications — just add an email alert channel and assign it the same way.


Step 5: Create a public status page for your Docker services

If you're running production services, a public status page lets your customers self-serve instead of emailing support when something's down.

  1. In Vigilmon, go to Status Pages → New Status Page
  2. Give it a name (e.g. "Production Services")
  3. Add your monitors — web /health, TCP postgres:5432, etc.
  4. Publish the page

You'll get a public URL like https://status.vigilmon.online/your-page that shows real-time uptime for each monitored service. Share it in your README, your app's footer, or your support docs.


Putting it all together

Here's the complete docker-compose.yml with health checks for all services:

version: "3.9"

services:
  web:
    image: your-app:latest
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://app:${DB_PASSWORD}@db:5432/app
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 15s
    restart: unless-stopped

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      web:
        condition: service_healthy
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    restart: unless-stopped

volumes:
  db_data:

And the corresponding Vigilmon monitors to set up:

| Monitor | Type | What it catches | |---------|------|-----------------| | https://your-domain/health | HTTP | App crashes, 5xx errors, DB connection failures | | your-server:80 | TCP | nginx port binding failures | | your-server:443 | TCP | TLS/HTTPS port issues | | your-server:5432 | TCP | Postgres port binding (if exposed) |


What's next

  • SSL expiry monitoring — Vigilmon also checks your TLS certificate expiry date and alerts you before it lapses
  • Heartbeat monitoring — if you run cron jobs or batch tasks inside containers, Vigilmon's heartbeat monitors will alert you when a scheduled job stops reporting in

Get started free at vigilmon.online — no credit card, monitors start 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 →