A robust, lightweight Python-based server health monitoring solution with HTTP and ICMP ping checks, smart email alerting, and state persistence. Designed for reliable execution as a scheduled task (cron job).
- Multiple Check Types: HTTP/HTTPS requests and ICMP ping support
- Smart Alerting:
- Sends alerts only on status changes (server down → server recovered)
- Prevents duplicate alerts for continuous failures
- Configurable retry logic before alerting
- State Persistence: Tracks server status between runs with file locking
- Comprehensive Logging: Rotating logs with configurable levels
- Security Hardened:
- Command injection prevention for ping checks
- Credentials stored in environment variables
- Input validation for all user-provided data
- Modular Design: Clean separation of concerns (Strategy pattern for health checks)
- Email Notifications: HTML and plain text email alerts via SMTP
- Python 3.8 or higher
- Linux (for ICMP ping functionality with
fcntlfile locking) - Email account with SMTP access (Gmail or Outlook/Microsoft 365 supported)
cd /home/eo37/PycharmProjects/Server_Live_Testpython3 -m venv .venv
source .venv/bin/activatepip install -r requirements.txt# Copy example configuration
cp .env.example .env
# Edit configuration with your settings
nano .env # or your preferred editor
# Protect credentials
chmod 600 .envEdit the .env file with your settings:
LOG_LEVEL=INFO # DEBUG, INFO, WARNING, ERROR, CRITICAL
RETRY_COUNT=3 # Failures before alerting
# Optional: Override default paths (defaults to ./logs and ./state in project directory)
# LOG_FILE=/custom/path/to/logs/monitor.log
# STATE_FILE=/custom/path/to/state/server_status.jsonHTTP_TIMEOUT=30 # HTTP request timeout (seconds)
PING_TIMEOUT=5 # Ping timeout (seconds)
PING_COUNT=3 # Number of ping packetsThe system supports Gmail and Outlook/Microsoft 365 for sending alerts.
Option 1: Gmail
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=xxxx-xxxx-xxxx-xxxx # 16-character app-specific password
FROM_EMAIL=your-email@gmail.com
TO_EMAILS=recipient@example.com
USE_TLS=trueGmail Setup Requirements:
- Enable 2-Step Verification on your Google Account
- Generate app-specific password at myaccount.google.com/apppasswords
- Use the 16-character password (not your regular Gmail password)
- Limit: 500 emails/day
Option 2: Outlook/Microsoft 365
SMTP_HOST=smtp-mail.outlook.com
SMTP_PORT=587
SMTP_USER=your-email@outlook.com
SMTP_PASSWORD=your-regular-password # Use your normal account password
FROM_EMAIL=your-email@outlook.com
TO_EMAILS=recipient@example.com
USE_TLS=trueOutlook Setup Requirements:
- Works with @outlook.com, @hotmail.com, @live.com
- Also works with Office 365 business accounts
- Use your regular account password (no app password needed)
- Limit: 300 emails/day (free), 10,000/day (Office 365)
Format: url|check_type|timeout|name
SERVERS=http://example.com|http|30|Example Site,8.8.8.8|ping|5|Google DNS,https://api.mysite.com/health|http|15|API HealthParameters:
- url: URL to check (HTTP) or hostname/IP (ping)
- check_type:
httporping - timeout: Timeout in seconds for this server
- name: Friendly name for alerts (optional but recommended)
Test the monitoring script:
# Activate virtual environment
source .venv/bin/activate
# Run the monitor
python main.pyCheck logs:
tail -f logs/monitor.logSet up cron to run every 15 minutes:
# Edit crontab
crontab -e
# Add this line (adjust path as needed):
*/15 * * * * cd /home/eo37/PycharmProjects/Server_Live_Test && .venv/bin/python main.py >> logs/cron.log 2>&1Cron Schedule Options:
*/15 * * * *- Every 15 minutes*/5 * * * *- Every 5 minutes0 * * * *- Every hour*/30 * * * *- Every 30 minutes
Verify Cron Setup:
# List current cron jobs
crontab -l
# Check cron logs
tail -f logs/cron.logThe monitoring system uses smart state tracking to prevent alert spam:
- Initial State: All servers start as "healthy" (prevents false alerts on first run)
- First Failure: Counter increments to 1, no alert sent (might be transient network issue)
- Second Failure: Counter increments to 2, no alert sent (default RETRY_COUNT=3)
- Third Failure (Threshold): Counter reaches 3, sends DOWN alert via email
- Continued Failures: Counter increments but no duplicate alerts sent
- Server Recovery: When check succeeds, sends RECOVERY alert and resets counter to 0
Example Timeline (with RETRY_COUNT=3):
10:00 - Check succeeds → is_healthy=True, failures=0
10:15 - Check fails → is_healthy=True, failures=1 (no alert)
10:30 - Check fails → is_healthy=True, failures=2 (no alert)
10:45 - Check fails → is_healthy=False, failures=3 (DOWN ALERT SENT)
11:00 - Check fails → is_healthy=False, failures=4 (no alert - already down)
11:15 - Check succeeds → is_healthy=True, failures=0 (RECOVERY ALERT SENT)
This prevents hundreds of duplicate alerts if a server is down for hours or days.
Server state is stored in state/server_status.json with file locking to prevent corruption:
{
"http://example.com": {
"server_url": "http://example.com",
"server_name": "Example Site",
"is_healthy": false,
"last_check": "2026-01-16T10:30:00",
"consecutive_failures": 3,
"last_alert_sent": "2026-01-16T10:15:00",
"last_status": "timeout"
}
}Key State Fields:
is_healthy: Boolean flag - prevents duplicate alerts when Falseconsecutive_failures: Counter for retry threshold logiclast_alert_sent: Timestamp of last alert (for debugging)last_status: Most recent check result (success/failure/timeout/error)
State persists between cron runs, enabling smart alerting across monitoring cycles.
Logs are stored in logs/monitor.log with daily rotation:
- Current log:
logs/monitor.log - Archived logs:
logs/monitor.log.2026-01-16,logs/monitor.log.2026-01-15, etc. - Retention: 30 days of logs kept automatically
- Rotation time: Midnight each day
- Format:
[2026-01-16 10:30:00] INFO [server_monitor.main] - Server recovered: Example Site
-
Ping Command Injection Prevention:
- Whitelist validation (IP/hostname format)
- Rejects shell metacharacters (
;,|,&, etc.) - Uses subprocess without shell=True
- Additional shlex.quote() escaping
-
Credential Security:
- Stored in .env file (gitignored)
- File permissions: chmod 600
- Never logged or exposed in error messages
-
Input Validation:
- Email addresses validated with regex
- URLs validated with regex
- IP addresses validated with regex
# Install test dependencies (already in requirements.txt)
source .venv/bin/activate
# Run all tests with coverage
pytest tests/ --cov=. --cov-report=html --cov-report=term
# Run specific test file
pytest tests/test_monitor.py -v
# Run tests matching pattern
pytest tests/ -k "test_http" -v# Open HTML coverage report
open htmlcov/index.html # macOS
xdg-open htmlcov/index.html # LinuxTest individual components:
# Test configuration loading
from config import ConfigLoader
loader = ConfigLoader()
app_config, email_config, servers = loader.load()
print(f"Loaded {len(servers)} servers")
# Test SMTP connection
from notifier import EmailNotifier
notifier = EmailNotifier(email_config)
notifier.test_connection()
# Test HTTP check
from monitor import HttpCheckStrategy
strategy = HttpCheckStrategy(timeout=30)
result = strategy.check("http://example.com")
print(f"Status: {result.status.value}")-
Check SMTP credentials:
python -c "from config import ConfigLoader; from notifier import EmailNotifier; loader = ConfigLoader(); _, email_config, _ = loader.load(); EmailNotifier(email_config).test_connection()" -
Verify SMTP settings: Ensure SMTP_HOST, SMTP_PORT are correct for your provider
-
Check spam folder: Initial alerts might be marked as spam
-
Review logs: Check
logs/monitor.logfor SMTP errors
-
Check permissions: ICMP ping may require elevated privileges on some systems
# Grant ping capability (Linux) sudo setcap cap_net_raw+ep /usr/bin/ping -
Test ping manually:
ping -c 3 8.8.8.8
-
Check host format: Ensure hostname/IP is valid in SERVERS config
If state file becomes corrupted:
# Backup corrupted state
mv state/server_status.json state/server_status.json.bak
# System will create new state on next run
python main.pyCommon issues:
- Missing .env: Copy from
.env.example - Invalid format: Check SERVERS format (pipe-separated:
url|type|timeout|name) - Type errors: Ensure numeric values (timeouts, ports) are valid integers
- Email validation: Check email addresses match required format
-
Check cron service:
sudo systemctl status cron # or crond -
Verify cron entry:
crontab -l
-
Check cron logs:
grep CRON /var/log/syslog # Ubuntu/Debian grep CRON /var/log/cron # CentOS/RHEL
-
Test script path:
cd /home/eo37/PycharmProjects/Server_Live_Test && .venv/bin/python main.py
Adjust RETRY_COUNT in .env:
- Increase value (e.g., 5) for more tolerance to transient failures
- Decrease value (e.g., 2) for faster alerting
main.py: Orchestrator with state management and alert logicmonitor.py: Health check strategies (HTTP and ICMP ping)notifier.py: Email composition and SMTP sendingconfig.py: Configuration loading and validationlogger.py: Centralized logging with file rotation
- Strategy Pattern: Pluggable health check strategies (easy to add new types)
- State Pattern: Server state transitions drive alert logic
- Dependency Injection: Components receive dependencies via constructor
1. Load Configuration (.env) → ConfigLoader
2. Setup Logging → MonitorLogger
3. Load State → StateManager
4. For each server:
a. Create Strategy → HealthCheckFactory
b. Perform Check → ServerMonitor
c. Update State → StateManager
d. Send Alert if needed → EmailNotifier
5. Save State → StateManager
Server_Live_Test/
├── main.py # Entry point and orchestration
├── monitor.py # Health check strategies
├── notifier.py # Email alerting
├── config.py # Configuration management
├── logger.py # Logging setup
├── requirements.txt # Python dependencies
├── .env.example # Configuration template
├── .env # Actual configuration (gitignored)
├── .gitignore # Git ignore rules
├── README.md # This file
├── logs/ # Log files (created automatically)
│ └── monitor.log
├── state/ # State persistence (created automatically)
│ └── server_status.json
└── tests/ # Test suite
├── test_config.py
├── test_logger.py
├── test_monitor.py
├── test_notifier.py
├── test_main.py
└── test_integration.py
- Execution Time: ~5s for 10 healthy servers, up to 250s worst case (all timeouts)
- Memory Usage: <50MB
- Disk Usage: Minimal (small log and state files)
- Network: One request per server per check
This is a self-contained operational tool. For modifications:
- Follow PEP 8 style guidelines
- Add tests for new functionality
- Update documentation
- Ensure >80% test coverage
MIT License - feel free to use and modify for your needs.
For issues or questions:
- Check logs:
logs/monitor.log - Review configuration:
.env - Verify server accessibility manually
- Test SMTP connection
- Check cron execution logs
- Initial release
- HTTP and ICMP ping health checks
- Smart alerting with duplicate prevention
- State persistence with file locking
- Comprehensive test suite
- Full documentation
