Monit is a lightweight process monitoring and management utility that can automatically repair services and send alerts. As a tool with the ability to execute commands and restart services, Monit requires careful security configuration. This guide covers security measures for production Monit deployments.
Monit architecture includes these security-sensitive components:
Key security concerns include web interface protection, command execution security, credential management, and preventing unauthorized service manipulation.
Configure firewall rules for Monit:
# Monit HTTP interface (default port 2812)
ufw allow from 10.0.0.0/8 to any port 2812 proto tcp
ufw allow from 192.168.1.0/24 to any port 2812 proto tcp
# Block external access
ufw deny from any to any port 2812 proto tcp
# For localhost-only access (recommended)
ufw deny from any to any port 2812 proto tcp
# SSH tunnel for Monit access
ssh -L 2812:localhost:2812 admin@monit-server
# Then access http://localhost:2812
Configure Monit to bind to localhost:
# /etc/monit/monitrc
# HTTP interface - localhost only (recommended)
set httpd port 2812
address localhost
allow localhost
allow admin:password
ssl enable
pemfile /etc/monit/monit.pem
signature disable
# For remote access (use with caution)
# set httpd port 2812
# address 10.0.1.100
# allow 10.0.0.0/255.0.0.0
# allow admin:password
Configure strong authentication:
# /etc/monit/monitrc
set httpd port 2812
address localhost
allow admin:${HASHED_PASSWORD}
allow @admins readwrite
allow @users readonly
allow @operators restart
ssl enable
pemfile /etc/monit/monit.pem
# Define user groups
set group admins users admin,ops-lead
set group users users viewer1,viewer2
set group operators users operator1,operator2
Generate hashed password:
# Generate password hash
monit -v # Shows hash format
# Or use htpasswd
htpasswd -nb admin secure_password
Configure access levels:
# /etc/monit/monitrc
# Read-only access
allow @viewers readonly
# Full access
allow @admins readwrite
# Restart only
allow @operators restart
# Specific service access
allow @webteam service nginx,apache
allow @dbteam service mysql,postgresql
Secure local CLI access:
# Restrict monit binary permissions
chown root:root /usr/bin/monit
chmod 755 /usr/bin/monit
# Restrict configuration file
chown root:root /etc/monit/monitrc
chmod 700 /etc/monit/monitrc
# Use sudo for non-root users
# /etc/sudoers.d/monit
%ops ALL=(ALL) NOPASSWD: /usr/bin/monit status
%admins ALL=(ALL) NOPASSWD: /usr/bin/monit *
Configure PAM authentication:
# /etc/monit/monitrc
set httpd port 2812
address localhost
allow @pam-admins readwrite
pam service "monit"
# /etc/pam.d/monit
@include common-auth
@include common-account
@include common-session
Enable TLS for Monit HTTP interface:
# /etc/monit/monitrc
set httpd port 2812
address localhost
allow admin:password
ssl enable
pemfile /etc/monit/monit.pem
signature disable
# Generate self-signed certificate
# openssl req -new -x509 -days 365 -nodes \
# -out /etc/monit/monit.pem \
# -keyout /etc/monit/monit.pem \
# -subj "/CN=localhost"
# chmod 600 /etc/monit/monit.pem
Generate and manage certificates:
# Generate self-signed certificate
openssl req -new -x509 -days 365 -nodes \
-out /etc/monit/monit.crt \
-keyout /etc/monit/monit.key \
-subj "/CN=monit.company.com/O=Company/C=US"
# Combine into PEM file
cat /etc/monit/monit.key /etc/monit/monit.crt > /etc/monit/monit.pem
chmod 600 /etc/monit/monit.pem
# For CA-signed certificates
openssl req -new -nodes \
-keyout /etc/monit/monit.key \
-out /etc/monit/monit.csr \
-subj "/CN=monit.company.com/O=Company/C=US"
# Submit CSR to CA, then combine
cat /etc/monit/monit.key /etc/monit/monit.crt /etc/monit/ca-bundle.crt > /etc/monit/monit.pem
Use reverse proxy for TLS termination:
# /etc/nginx/sites-available/monit
server {
listen 443 ssl http2;
server_name monit.company.com;
ssl_certificate /etc/nginx/certs/monit.crt;
ssl_certificate_key /etc/nginx/certs/monit.key;
ssl_protocols TLSv1.2 TLSv1.3;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
location / {
auth_basic "Monit Access";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://localhost:2812;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Secure service check configurations:
# /etc/monit/conf.d/services
check process nginx with pidfile /var/run/nginx.pid
start program = "/usr/sbin/service nginx start"
stop program = "/usr/sbin/service nginx stop"
if failed host 127.0.0.1 port 80 protocol http then restart
if 5 restarts within 5 cycles then timeout
group webserver
check process mysql with pidfile /var/run/mysqld/mysqld.pid
start program = "/usr/sbin/service mysql start"
stop program = "/usr/sbin/service mysql stop"
if failed host 127.0.0.1 port 3306 protocol mysql then restart
if 5 restarts within 5 cycles then timeout
group database
Restrict command execution:
# /etc/monit/monitrc
# Limit which commands can be executed
# Monit runs as root, so be careful with scripts
# Use wrapper scripts with validation
check process myapp with pidfile /var/run/myapp.pid
start program = "/usr/local/bin/safe-start-myapp.sh"
stop program = "/usr/local/bin/safe-stop-myapp.sh"
restart program = "/usr/local/bin/safe-restart-myapp.sh"
Secure wrapper scripts:
#!/bin/bash
# /usr/local/bin/safe-start-myapp.sh
set -euo pipefail
# Validate environment
if [ "$(whoami)" != "root" ]; then
echo "Error: Must run as root" >&2
exit 1
fi
# Execute with limited environment
exec /usr/bin/myapp --config /etc/myapp/config.yml
Secure file integrity monitoring:
# /etc/monit/conf.d/files
check file nginx_config with path /etc/nginx/nginx.conf
if failed checksum then alert
if failed permission then alert
if failed uid then alert
if failed gid then alert
check file sshd_config with path /etc/ssh/sshd_config
if failed checksum then alert
if failed permission then alert
Secure network monitoring:
# /etc/monit/conf.d/network
check host webserver with address 10.0.1.50
if failed port 80 protocol http then alert
if failed port 443 protocol https then alert
if icmp type echo with timeout 5 seconds then alert
check host database with address 10.0.1.60
if failed port 3306 protocol mysql with timeout 5 seconds then alert
Protect Monit configuration:
# Set restrictive permissions
chown root:root /etc/monit/monitrc
chmod 700 /etc/monit/monitrc
chown root:root /etc/monit/conf.d/
chmod 750 /etc/monit/conf.d/
# Encrypt sensitive configuration
# Use GPG for files with credentials
gpg -c /etc/monit/conf.d/credentials.conf
Never store plaintext credentials:
# Bad - Never do this
# check host database with address 10.0.1.60
# if failed port 3306 protocol mysql username "root" password "SecretPass123" then alert
# Good - Use environment variables or external secrets
check host database with address 10.0.1.60
if failed port 3306 protocol mysql then alert
# Credentials in secure wrapper script
Use external credential storage:
#!/bin/bash
# /usr/local/bin/check-mysql-secure.sh
MYSQL_PASSWORD=$(cat /etc/monit/.mysql_password | gpg -d 2>/dev/null)
/usr/bin/mysqladmin -u monitor -p${MYSQL_PASSWORD} ping
Secure Monit logs:
# Set restrictive permissions on logs
chown root:adm /var/log/monit.log
chmod 640 /var/log/monit.log
# Configure log rotation
cat > /etc/logrotate.d/monit << EOF
/var/log/monit.log {
weekly
rotate 4
compress
delaycompress
missingok
notifempty
create 640 root adm
}
EOF
Secure Monit state file:
# /etc/monit/monitrc
set statefile /var/lib/monit/monit.state
# Secure state file
chown root:root /var/lib/monit/monit.state
chmod 600 /var/lib/monit/monit.state
Enable logging:
# /etc/monit/monitrc
set log /var/log/monit.log
set logfacility LOG_DAEMON
# Log format
# Monit logs to syslog or file
Configure syslog:
# /etc/monit/monitrc
set log syslog
Log HTTP interface access:
# /etc/monit/monitrc
# Access is logged to Monit log file
set log /var/log/monit.log
# For reverse proxy, configure Nginx/Apache logging
Create alerts for security events:
# /etc/monit/conf.d/security
check file monit_config with path /etc/monit/monitrc
if failed checksum then exec "/usr/local/bin/alert-security.sh"
if failed permission then exec "/usr/local/bin/alert-security.sh"
check file monit_state with path /var/lib/monit/monit.state
if failed checksum then exec "/usr/local/bin/alert-security.sh"
# Alert on service failures
check process monit with pidfile /var/run/monit.pid
if failed port 2812 then exec "/usr/local/bin/alert-monit-down.sh"
Forward logs to SIEM:
# /etc/rsyslog.d/monit.conf
:programname, isequal, "monit" /var/log/monit/syslog.log
:programname, isequal, "monit" @siem.company.com:514