Doppler is a secrets management platform that centralises environment variables and secrets across your applications, services, and CI pipelines. Development teams at Stripe, Canva, and Notion use Doppler to sync secrets in real time to their production containers, serverless functions, and Kubernetes clusters. When Doppler's API or sync service goes down, applications cannot fetch updated secrets, new deployments stall, and containers that rely on runtime secret injection fail to start — all without a clear error message pointing back to secrets management.
In this tutorial you'll set up end-to-end monitoring for Doppler using Vigilmon so your team knows the moment secret delivery is impacted — free tier, no credit card required.
Why Doppler needs external monitoring
Doppler operates as both a cloud SaaS and a self-hosted enterprise deployment. Both flavours carry distinct failure modes:
Cloud (SaaS) Doppler:
- API outages — the Doppler CLI and SDKs call
api.doppler.comto fetch secrets; an API outage means fresh container starts fail - Sync delays — secrets updated in Doppler take longer than normal to propagate to your services; your app keeps running with stale values
- Webhook delivery failures — Doppler notifies your CI pipeline when a secret rotates; if webhooks fail silently, your pipeline deploys with the old secret
- Dashboard unavailability — engineers cannot audit secret access or rotate compromised credentials
Self-hosted (Doppler Enterprise):
- Service crashes — the Doppler API server process exits; all secret fetches return 500
- Database connectivity loss — the backend database goes unreachable; secret reads succeed but writes (rotations, new secrets) fail silently
- TLS certificate expiry — the HTTPS endpoint serves a stale certificate; strict clients reject the connection without a clear error
An external monitor probing both the Doppler API and your self-hosted health endpoints surfaces these failures before your applications start returning authentication or configuration errors.
What you'll need
- A Doppler account (cloud or self-hosted)
- A free Vigilmon account — takes 30 seconds to create
Step 1: Monitor the Doppler cloud API status
For cloud Doppler users, the primary API endpoint to monitor is:
GET https://api.doppler.com/v3/me
This endpoint requires a Doppler token, so Vigilmon cannot call it directly without authentication. Instead, monitor the Doppler status page API which is publicly accessible:
GET https://status.doppler.com/api/v2/status.json
This endpoint returns the current operational status of Doppler's infrastructure:
{
"page": { "name": "Doppler Status" },
"status": {
"indicator": "none",
"description": "All Systems Operational"
}
}
Set up a Vigilmon HTTP monitor for this endpoint:
- Log in to vigilmon.online and go to Monitors → New Monitor
- Choose HTTP / HTTPS as the type
- Set the URL to
https://status.doppler.com/api/v2/status.json - Set the check interval to 1 minute
- Under Expected response, configure:
- Status code:
200 - Response body contains:
"indicator":"none"
- Status code:
- Save the monitor
When Doppler has an active incident, the indicator field changes to minor, major, or critical — any of these will trigger your Vigilmon alert.
Step 2: Add an application-level secrets probe
Because the Doppler status page only reflects Doppler's infrastructure health, add a probe from within your own application to verify secrets are being delivered to your services correctly. Create a lightweight health endpoint in your app that confirms secret injection is working:
# Python / FastAPI example
from fastapi import FastAPI
import os
app = FastAPI()
@app.get("/health/secrets")
async def secrets_health():
required_secrets = ["DATABASE_URL", "API_KEY", "STRIPE_SECRET_KEY"]
missing = [s for s in required_secrets if not os.getenv(s)]
if missing:
return {"status": "error", "missing_secrets": missing}, 503
return {
"status": "ok",
"secrets_loaded": len(required_secrets),
"timestamp": datetime.utcnow().isoformat(),
}
// Node.js / Express example
const requiredSecrets = ['DATABASE_URL', 'API_KEY', 'STRIPE_SECRET_KEY'];
app.get('/health/secrets', (req, res) => {
const missing = requiredSecrets.filter(key => !process.env[key]);
if (missing.length > 0) {
return res.status(503).json({ status: 'error', missing_secrets: missing });
}
res.json({
status: 'ok',
secrets_loaded: requiredSecrets.length,
timestamp: new Date().toISOString(),
});
});
// Go example
http.HandleFunc("/health/secrets", func(w http.ResponseWriter, r *http.Request) {
required := []string{"DATABASE_URL", "API_KEY", "STRIPE_SECRET_KEY"}
var missing []string
for _, key := range required {
if os.Getenv(key) == "" {
missing = append(missing, key)
}
}
if len(missing) > 0 {
w.WriteHeader(http.StatusServiceUnavailable)
json.NewEncoder(w).Encode(map[string]interface{}{
"status": "error",
"missing": missing,
})
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
})
Add this endpoint as a second Vigilmon HTTP monitor:
- Create a monitor for
https://your-app.example.com/health/secrets - Set expected status:
200 - Set response body:
"status":"ok"
If the Doppler API is unreachable during container startup, this check will catch it by detecting missing environment variables.
Step 3: Monitor the self-hosted Doppler API server
If you're running Doppler Enterprise self-hosted, monitor the health endpoint directly:
GET https://doppler.yourcompany.com/api/v3/health
Expected healthy response:
{"status":"healthy","database":"connected","version":"3.x.x"}
Set up the monitor:
- Create an HTTP monitor for
https://doppler.yourcompany.com/api/v3/health - Expected status code:
200 - Response body contains:
"status":"healthy"
For the self-hosted database layer, add a TCP port monitor:
- Go to Monitors → New Monitor → TCP Port
- Host:
db.yourcompany.com, Port:5432(PostgreSQL) or3306(MySQL) - Save the monitor
Here's the recommended Docker Compose for a self-hosted Doppler instance with health checks:
version: "3.9"
services:
doppler:
image: dopplerhq/doppler-enterprise:latest
ports:
- "443:443"
environment:
DATABASE_URL: postgres://doppler:${DB_PASSWORD}@db:5432/doppler
SECRET_KEY: ${DOPPLER_SECRET_KEY}
DOMAIN: doppler.yourcompany.com
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/api/v3/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
restart: unless-stopped
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: doppler
POSTGRES_USER: doppler
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- doppler_db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U doppler"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
volumes:
doppler_db:
Step 4: Monitor Doppler webhook delivery
Doppler sends webhooks to your CI pipeline and other integrations when secrets are rotated. If these webhooks fail, your pipeline deploys with outdated secrets. Create a small webhook receiver to verify Doppler can reach your infrastructure:
// Webhook health receiver (Node.js)
const express = require('express');
const app = express();
let lastWebhookAt = null;
app.post('/doppler-webhook', express.json(), (req, res) => {
// Verify Doppler webhook signature
const signature = req.headers['x-doppler-signature'];
if (!verifySignature(signature, req.body, process.env.DOPPLER_WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'invalid signature' });
}
lastWebhookAt = new Date().toISOString();
console.log('Doppler webhook received:', req.body.event);
res.json({ received: true });
});
// Separate health endpoint Vigilmon can probe
app.get('/health/doppler-webhook', (req, res) => {
const staleThresholdMs = 24 * 60 * 60 * 1000; // 24 hours
const isStale = lastWebhookAt
? Date.now() - new Date(lastWebhookAt).getTime() > staleThresholdMs
: false;
res.json({
status: isStale ? 'stale' : 'ok',
last_received: lastWebhookAt,
});
});
app.listen(3001);
Add a Vigilmon monitor for https://your-app.example.com/health/doppler-webhook. If your Doppler webhooks have been silent for longer than expected, this check surfaces it.
Step 5: Configure alerts and escalation
Set up Vigilmon alert channels so the right team is notified when Doppler is impacted:
Slack / Discord webhook alert:
- Go to Alert Channels → Add Channel → Webhook
- Enter your Slack webhook URL
- Assign it to all Doppler-related monitors
Example alert payload Vigilmon sends to Slack:
{
"monitor_name": "Doppler Status API",
"status": "down",
"url": "https://status.doppler.com/api/v2/status.json",
"started_at": "2024-06-10T14:05:00Z",
"duration_seconds": 300
}
Email escalation:
For secrets management, consider adding email alerts to your security team in addition to Slack. A Doppler outage may require manual secret rotation procedures and security runbooks to be activated:
- Go to Alert Channels → Add Channel → Email
- Add your security team's DL
- Assign it to the Doppler monitors with a 5-minute delay (avoids noisy flapping alerts)
Status page for visibility:
- Go to Status Pages → New Status Page
- Name it "Secrets & Config Infrastructure"
- Add your Doppler monitors and application secrets health endpoint
- Share the URL in your engineering runbook
Monitoring checklist
| What to monitor | Type | Endpoint | Alert on |
|---|---|---|---|
| Doppler cloud API | HTTP | status.doppler.com/api/v2/status.json | indicator ≠ none |
| App secrets probe | HTTP | /health/secrets | Non-200 or missing secrets |
| Self-hosted API | HTTP | doppler.yourcompany.com/api/v3/health | Non-200 |
| Self-hosted DB | TCP | db-host:5432 | Connection refused |
| Webhook delivery | HTTP | /health/doppler-webhook | stale status |
Summary
Doppler is the connective tissue between your secret store and your running applications. When it fails — at the SaaS layer or the self-hosted database layer — applications can't start, deployments silently fail, and security incidents go undetected. A layered monitoring setup with Vigilmon covers the Doppler API, your application-level secret injection, the self-hosted database, and webhook delivery in under ten minutes.
Start monitoring your secrets management infrastructure for free at vigilmon.online.