sudo apt-get install libapache2-mod-geoip
sudo a2enmod geoip
sudo apt-get install geoip-database
Add to your Apache virtual host configuration or .htaccess:
# Enable GeoIP
GeoIPEnable On
GeoIPDBFile /usr/share/GeoIP/GeoIP.dat
# Block specific countries (example: CN for China, RU for Russia)
SetEnvIf GEOIP_COUNTRY_CODE ^(CN|RU)$ BlockCountry
Order Allow,Deny
Allow from all
Deny from env=BlockCountry
# Custom error page
ErrorDocument 403 /blocked.html
Create blocked.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Access Denied</title>
</head>
<body>
<h1>Access Denied</h1>
<p>We apologize, but access to this website is not available in your region.</p>
</body>
</html>
sudo a2enmod ratelimit
Add to your Apache configuration:
# Enable rate limiting module
<IfModule mod_ratelimit.c>
# Limit bandwidth to 400KB/s per IP
SetOutputFilter RATE_LIMIT
SetEnv rate-limit 400
</IfModule>
# Limit requests per minute
<IfModule mod_evasive20.c>
DOSHashTableSize 3097
DOSPageCount 2
DOSSiteCount 50
DOSPageInterval 1
DOSSiteInterval 1
DOSBlockingPeriod 10
DOSLogDir "/var/log/mod_evasive"
</IfModule>
sudo apt-get install fail2ban
Create /etc/fail2ban/jail.local:
[php-saas]
enabled = true
filter = php-saas
logpath = /var/log/apache2/access.log
maxretry = 3
findtime = 300
bantime = 3600
[php-api]
enabled = true
filter = php-api
logpath = /var/log/apache2/access.log
maxretry = 100
findtime = 60
bantime = 3600
Create /etc/fail2ban/filter.d/php-saas.conf:
[Definition]
failregex = ^<HOST> .* "POST /login.*" .* 401
^<HOST> .* "POST /auth.*" .* 401
^<HOST> .* "(GET|POST) /admin.*" .* 403
ignoreregex =
Create /etc/fail2ban/filter.d/php-api.conf:
[Definition]
failregex = ^<HOST> .* "(GET|POST|PUT|DELETE) /api/.*" .* (429|403)
ignoreregex =
[WordPress and Joomla configurations remain the same...]
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
[Previous ModSecurity installation steps remain the same...]
Add to /etc/modsecurity/modsecurity.conf:
# PHP SaaS API Rate Limiting
SecRule &ARGS "@eq 0" "phase:2,id:4000,nolog,pass"
SecRule REQUEST_URI "@beginsWith /api/" \
"phase:1,id:4001,nolog,pass,setvar:ip.api_count=+1,expirevar:ip.api_count=60"
SecRule IP:API_COUNT "@gt 100" \
"phase:1,id:4002,deny,status:429,msg:'API rate limit exceeded'"
# Block PHP information disclosure
SecRule REQUEST_URI "@contains phpinfo.php" \
"id:4100,phase:1,deny,status:403,msg:'PHP info access denied'"
# Protect configuration files
SecRule REQUEST_URI "@rx .*\.(?:php|ini|conf)$" \
"chain,phase:2,id:4200,deny,status:403,msg:'Configuration file access denied'"
SecRule REQUEST_URI "@contains /config/"
# API Authentication Check
SecRule REQUEST_URI "@beginsWith /api/" \
"chain,phase:1,id:4300,deny,status:401,msg:'API authentication required'"
SecRule REQUEST_HEADERS:Authorization "^$"
# JSON/XML Content-Type Validation for API
SecRule REQUEST_URI "@beginsWith /api/" \
"chain,phase:1,id:4400,deny,status:415,msg:'Invalid Content-Type'"
SecRule REQUEST_HEADERS:Content-Type "!@rx ^application/(json|xml)"
# CORS Protection
Header always set Access-Control-Allow-Origin "https://your-domain.com"
Header always set Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE"
Header always set Access-Control-Allow-Headers "Authorization, Content-Type"
Add to your Apache configuration or .htaccess:
# Security Headers
Header set X-Frame-Options "SAMEORIGIN"
Header set X-XSS-Protection "1; mode=block"
Header set X-Content-Type-Options "nosniff"
Header set Referrer-Policy "strict-origin-when-cross-origin"
Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"
Header set Permissions-Policy "geolocation=(), midi=(), sync-xhr=(), microphone=(), camera=(), magnetometer=(), gyroscope=(), fullscreen=(self), payment=()"
# PHP Handler Security
<FilesMatch ".+\.ph(ar|p|tml)$">
SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch ".+\.phps$">
Require all denied
</FilesMatch>
Add to .htaccess:
# Protect application directories
<DirectoryMatch "^/.*/(?:config|vendor|logs|temp)/">
Require all denied
</DirectoryMatch>
# API Rate Limiting
<LocationMatch "^/api/">
Header set X-RateLimit-Limit "100"
Header set X-RateLimit-Remaining "%{remain}e"
Header set X-RateLimit-Reset "%{reset}e"
</LocationMatch>
# Protect uploaded files
<Directory "/path/to/uploads">
php_flag engine off
Options -ExecCGI
AllowOverride None
# Allow only specific file types
<FilesMatch "\.(?i:(jpe?g|gif|png|pdf))$">
Order Allow,Deny
Allow from all
</FilesMatch>
</Directory>
Add to php.ini:
session.cookie_httponly = 1
session.cookie_secure = 1
session.cookie_samesite = "Strict"
session.use_strict_mode = 1
session.use_only_cookies = 1
session.cache_limiter = 'nocache'
Essential php.ini settings:
# Error handling
display_errors = Off
log_errors = On
error_reporting = E_ALL
# File upload settings
upload_max_filesize = 10M
max_file_uploads = 5
file_uploads = On
# Memory limits
memory_limit = 256M
max_execution_time = 30
# Request limits
max_input_time = 60
max_input_vars = 1000
post_max_size = 10M
# Security settings
expose_php = Off
allow_url_fopen = Off
allow_url_include = Off
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_multi_exec,parse_ini_file,show_source
# Update GeoIP database
sudo geoipupdate
# Update ModSecurity rules
cd /etc/modsecurity/owasp-crs
sudo git pull
# Check Fail2ban status
sudo fail2ban-client status
sudo fail2ban-client status php-saas
sudo fail2ban-client status php-api
# Monitor Apache access logs
sudo tail -f /var/log/apache2/access.log | grep "403\|401\|429"
# Monitor ModSecurity logs
sudo tail -f /var/log/modsec_audit.log
# Monitor Fail2ban logs
sudo tail -f /var/log/fail2ban.log
# Monitor PHP error logs
sudo tail -f /var/log/php/error.log
Create a monitoring script (monitor_api.php):
<?php
function checkApiEndpoints() {
$endpoints = [
'/api/health',
'/api/status',
// Add your critical endpoints
];
$results = [];
foreach ($endpoints as $endpoint) {
$ch = curl_init('https://your-domain.com' . $endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
$response = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$results[$endpoint] = [
'status' => $httpcode,
'response_time' => curl_getinfo($ch, CURLINFO_TOTAL_TIME)
];
curl_close($ch);
}
return $results;
}
$results = checkApiEndpoints();
file_put_contents(
'/var/log/api_monitor.log',
date('Y-m-d H:i:s') . ' ' . json_encode($results) . "\n",
FILE_APPEND
);
After implementing these measures, test your application:
- Use a VPN to test country blocking
- Test API rate limiting:
# Test API rate limits for i in {1..110}; do curl -H "Authorization: Bearer test" https://your-domain.com/api/endpoint done
- Test Fail2ban:
# Test login protection for i in {1..5}; do curl -X POST https://your-domain.com/login -d "invalid data" done
- Use security scanning tools:
- OWASP ZAP
- Nikto
- API Security Checklist
- Always backup your configuration files before making changes
- Test in a staging environment first
- Monitor logs regularly for false positives
- Keep all security modules and rules updated
- Document any custom rules or modifications
- Implement proper API versioning
- Use proper authentication (JWT, OAuth2)
- Implement request signing for critical endpoints
- Use HTTPS everywhere
- Implement proper CORS policies
- Use prepared statements for all database queries
- Implement proper input validation
- Use secure password hashing (bcrypt/Argon2)
- Implement proper session management
- Regular security audits
- DDoS protection services
- Regular backups
- User access control
Need help with implementation? Create an issue in this repository or contact your system administrator.