The $14 Alternative to $500/Month Monitoring Stacks
You don't need Datadog, New Relic, AND PagerDuty. You need a script and a cron job.
I audited a startup's monitoring stack last month. They were paying:
- Datadog: $300/month (5 hosts, custom metrics)
- PagerDuty: $99/month (5 users)
- StatusPage: $99/month
- Total: $498/month
They had 12 employees. Their infrastructure was 5 servers and a managed database. They were paying more for monitoring than for their actual infrastructure.
Here's what I set up instead for $14/month.
The $14 Stack
| Component | Tool | Cost |
|---|---|---|
| Monitoring | Custom script + UptimeRobot free | $0 |
| Alerting | Slack webhooks + custom script | $0 |
| Status page | GitHub Pages + custom script | $0 |
| Log aggregation | Loki (self-hosted) | $0 |
| VPS for scripts | Cheapest DigitalOcean droplet | $14 |
| Total | $14/month |
Annual savings: $5,808
Component 1: Monitoring (Replaces Datadog)
#!/usr/bin/env python3
"""monitor.py - Lightweight monitoring that covers 90% of needs"""
import requests
import time
import json
from datetime import datetime
import subprocess
class Monitor:
def __init__(self, config_file='monitor_config.json'):
with open(config_file) as f:
self.config = json.load(f)
self.history = []
def check_http(self, url, expected_code=200):
start = time.time()
try:
r = requests.get(url, timeout=10)
return {
'type': 'http',
'target': url,
'status': r.status_code,
'healthy': r.status_code == expected_code,
'latency_ms': round((time.time() - start) * 1000, 2),
'timestamp': datetime.now().isoformat()
}
except Exception as e:
return {
'type': 'http', 'target': url,
'status': 0, 'healthy': False,
'error': str(e),
'timestamp': datetime.now().isoformat()
}
def check_disk(self, threshold=80):
result = subprocess.run(['df', '-h', '/'], capture_output=True, text=True)
usage = int(result.stdout.split('\n')[1].split()[4].replace('%', ''))
return {
'type': 'disk', 'target': '/',
'usage_pct': usage,
'healthy': usage < threshold,
'timestamp': datetime.now().isoformat()
}
def check_memory(self, threshold=90):
with open('/proc/meminfo') as f:
lines = f.readlines()
total = int(lines[0].split()[1])
available = int(lines[2].split()[1])
usage = ((total - available) / total) * 100
return {
'type': 'memory', 'usage_pct': round(usage, 1),
'healthy': usage < threshold,
'timestamp': datetime.now().isoformat()
}
def check_cpu(self, threshold=90):
result = subprocess.run(['top', '-bn1'], capture_output=True, text=True)
cpu_line = [l for l in result.stdout.split('\n') if 'Cpu(s)' in l][0]
idle = float(cpu_line.split(',')[3].strip().replace(' id', ''))
usage = 100 - idle
return {
'type': 'cpu', 'usage_pct': round(usage, 1),
'healthy': usage < threshold,
'timestamp': datetime.now().isoformat()
}
def run_all(self):
results = []
for check in self.config.get('checks', []):
if check['type'] == 'http':
results.append(self.check_http(check['url']))
elif check['type'] == 'disk':
results.append(self.check_disk(check.get('threshold', 80)))
elif check['type'] == 'memory':
results.append(self.check_memory(check.get('threshold', 90)))
elif check['type'] == 'cpu':
results.append(self.check_cpu(check.get('threshold', 90)))
return results
if __name__ == '__main__':
monitor = Monitor()
results = monitor.run_all()
unhealthy = [r for r in results if not r.get('healthy')]
if unhealthy:
alert(f'{len(unhealthy)} checks failed!')
print(json.dumps(results, indent=2))
Component 2: Alerting (Replaces PagerDuty)
#!/usr/bin/env python3
"""alert.py - Multi-channel alerting"""
import requests
import os
from datetime import datetime
class Alerter:
def __init__(self):
self.slack_webhook = os.environ.get('SLACK_WEBHOOK')
self.sms_key = os.environ.get('TWILIO_KEY') # Optional
def slack(self, message, channel='#alerts'):
if not self.slack_webhook:
return
payload = {
'channel': channel,
'text': message,
'attachments': [{
'color': 'danger' if 'FAILED' in message else 'good',
'fields': [
{'title': 'Timestamp', 'value': datetime.now().isoformat(), 'short': True}
]
}]
}
requests.post(self.slack_webhook, json=payload)
def escalate(self, message, primary, secondary, delay_min=5):
"""Page primary, escalate to secondary after delay"""
self.slack(f'🚨 {message}')
# Wait and escalate if not acknowledged
time.sleep(delay_min * 60)
if not check_acknowledged():
self.slack(f'⏰ ESCALATION: {message}')
self.sms(primary, message)
Component 3: Status Page (Replaces StatusPage)
<!-- status.html - Host on GitHub Pages for free -->
<!DOCTYPE html>
<html>
<head>
<title>System Status</title>
<meta http-equiv="refresh" content="60">
</head>
<body>
<h1>System Status</h1>
<div id="status"></div>
<script>
fetch('/status.json')
.then(r => r.json())
.then(data => {
const html = data.map(check => `
<div style="padding: 10px; border: 1px solid #ddd; margin: 5px;">
<span style="color: ${check.healthy ? 'green' : 'red'}">
${check.healthy ? '✅' : '❌'}
</span>
<strong>${check.target || check.type}</strong>
${check.latency_ms ? `(${check.latency_ms}ms)` : ''}
</div>
`).join('');
document.getElementById('status').innerHTML = html;
});
</script>
</body>
</html>
The Cron Setup
# /etc/crontab
* * * * * root /opt/monitor/monitor.py >> /var/log/monitor.log
*/5 * * * * root /opt/monitor/check_alerts.py
0 * * * * root /opt/monitor/update_status_page.py
What You Get vs What You Lose
What you GET:
- Full control over your monitoring data
- No vendor lock-in
- Customizable alerts and thresholds
- All data stays on your infrastructure
- $5,808/year in savings
What you LOSE:
- Beautiful pre-built dashboards (you build your own with Grafana — free)
- AI-powered anomaly detection (you set static thresholds)
- One-click integrations (you write 10 lines of code per integration)
- 24/7 support (you're on your own)
When to Keep the $500 Stack
Keep paying if:
- You have 50+ servers (the script doesn't scale well past that)
- You need SOC2/HIPAA compliance reporting (Datadog handles this)
- Your team is non-technical (the UI is worth the cost)
- You have budget and no time (the $500 buys convenience)
When to Switch
Switch if:
- You have fewer than 20 servers
- You have a technical team member who can maintain scripts
- You're pre-revenue or bootstrapped
- You want to understand your infrastructure (not just monitor it)
Want the complete $14 monitoring stack? The Ops Starter Kit includes all the monitoring scripts, alert templates, status page code, and setup instructions — everything you need to replace your $500/month stack.
How much are you paying for monitoring? Could $14/month work for you?
Top comments (0)