Step 7: Schedule everything
Stagger your maintenance jobs so they don't overlap and cause I/O contention:
# /etc/cron.d/security-maintenance
# 2:00 AM — Inbound firewall blacklist update (nftables)
0 2 * * * root /usr/local/bin/update-abuse-blacklist.sh > /dev/null 2>&1
# 3:00 AM — Outbound threat intelligence update (Squid)
0 3 * * * root /etc/squid/update_blacklist.sh > /dev/null 2>&1
# 6:45 AM — SSL certificate renewal
45 6 * * * root certbot renew -a webroot --webroot-path /usr/share/nginx/html --quiet --renew-hook "systemctl reload nginx"
Inbound protection at 2 AM. Outbound protection at 3 AM. SSL at 6:45 AM. No overlap, no spike.
The inbound blacklist update script — which fetches AbuseIPDB, Bitwire, and Spamhaus feeds and loads them into nftables — is covered in Fail2ban with nftables and Crowd-Sourced Blacklists. That guide also covers the fail2ban jails for SSH and Nginx forbidden requests, which complement the outbound monitoring described here. Together they close the loop: inbound attacks get blocked at the firewall, outbound compromise attempts get logged and flagged.
What this won't catch
This setup monitors PHP's outbound connections that go through HTTP/HTTPS — cURL, file_get_contents(), stream wrappers, SOAP. It won't catch:
- Raw socket connections that bypass HTTP entirely (
fsockopen(),socket_create()) - DNS lookups (PHP resolves hostnames before Squid sees the connection)
- Connections from non-PHP processes running on the same server
Those are separate problems with separate solutions. What this does catch is the 95% of outbound PHP traffic that uses the standard HTTP layer — and it catches it with enough detail to know exactly which file on which site made the call.
This guide is maintained as part of a modular, SSL-first framework. Each configuration is audited for production stability and modern security standards.
Compatibility: Tested against current stable releases. While optimized for the stack above, core logic remains relevant for Nginx 1.26+ and PHP 8.2+ environments.