linux 安全

fail2ban 安装与配置

sudo apt update
sudo apt install fail2ban

基本配置

fail2ban 的主要配置文件位于:

/etc/fail2ban/jail.conf - 主配置文件(不建议直接修改) /etc/fail2ban/jail.local - 用户自定义配置(推荐在此修改)

fail2ban 常用命令

启动/停止/重启服务

sudo systemctl start fail2ban # 启动服务
sudo systemctl stop fail2ban # 停止服务
sudo systemctl restart fail2ban # 重启服务
sudo systemctl enable fail2ban # 设置开机自启

查看服务状态

sudo systemctl status fail2ban

查看 fail2ban-client 的状态,如启用了对哪些服务的保护

sudo fail2ban-client status
// 默认情况下只开启了对 ssh 的保护
Status
|- Number of jail: 1
`- Jail list: sshd

查看被封禁的 IP

sudo fail2ban-client status sshd

解封特定 IP

sudo fail2ban-client set sshd unbanip 192.168.1.100

手动封禁 IP

sudo fail2ban-client set sshd banip 192.168.1.100

常见filter及其位置

ls /etc/fail2ban/filter.d

查看日志

tail -f /var/log/fail2ban.log

添加自定义filter,注意filter 的名字不能太长

遇到的一个filter 长度问题
iptables v1.8.7 (nf_tables): chain name `f2b-nginx-botsearch-oneinstack' too long (must be under 29 chars)

如自定义filter 名称为 nginx-404
vim /etc/fail2ban/filter.d/nginx-404.conf
填入如下,表示匹配 404 的访问
[Definition]
failregex = ^<HOST> - - \[.*\] "(GET|POST|HEAD) /.* HTTP/\d\.\d" 404
ignoreregex =
然后编辑, 表示 5分钟内有10404 的访问即禁止访问 一个小时
vim /etc/fail2ban/jail.local
[nginx-404]
enabled = true
filter = nginx-404
logpath = /data/wwwlogs/*_nginx.log
backend = polling
port = http,https
maxretry = 10
findtime = 120
bantime = 3600
然后重启
sudo systemctl restart fail2ban
查看自定义filter nginx-404 的状态
sudo fail2ban-client status nginx-404

针对wordpress 的filter

Block XML-RPC brute force

vim /etc/fail2ban/filter.d/wordpress-xmlrpc.conf
[Definition]
failregex = ^<HOST> .*"POST\s+/{1,}xmlrpc\.php
vim /etc/fail2ban/jail.local
[wordpress-xmlrpc]
enabled = true
filter = wordpress-xmlrpc
logpath = /data/wwwlogs/*_nginx.log
backend = polling
maxretry = 3
findtime = 300
bantime = 3600
action = iptables[name=wordpress-xmlrpc, port=http, protocol=tcp]

wordpress-login (Protect /wp-login.php)

vim /etc/fail2ban/filter.d/wordpress-login.conf
[Definition]
failregex = <HOST> -.*"(GET|POST) \/*wp-login\.php
ignoreregex =
vim /etc/fail2ban/jail.local
[wordpress-login]
enabled = true
filter = wordpress-login
logpath = /data/wwwlogs/*_nginx.log
backend = polling
maxretry = 5
findtime = 600
bantime = 3600
action = iptables[name=wordpress-login, port=http, protocol=tcp]
常见问题:
如果设置了具体的 logpath
需要设置
backend = polling
使其生效
backend = polling — this disables the systemd journal reading and enables direct file reading

针对频繁请求的filter

Create the filter
vim /etc/fail2ban/filter.d/nginx-req-limit.conf
[Definition]
# Match any GET/POST request from an IP
failregex = ^<HOST> -.*"(GET|POST|HEAD) .* HTTP/1\.[01]" \d+ .*$
ignoreregex =
# Add the jail in
vim /etc/fail2ban/jail.local
[nginx-req-limit]
enabled = true
port = http,https
filter = nginx-req-limit
logpath = /data/wwwlogs/*_nginx.log
maxretry = 100
findtime = 60
bantime = 3600
# Escalation: each repeat offense multiplies ban time
bantime.increment = true
bantime.multiplier = 2
bantime.maxtime = 604800

Apply CPU Quota to PHP-FPM

  1. Find your PHP-FPM service name
systemctl list-units | grep fpm
// it will show services like:
// php-fpm-83.service
  1. Create a systemd override file
sudo systemctl edit php-fpm-83.service
  1. This opens an empty override file in your editor. Add:
[Service]
CPUAccounting=true
CPUQuota=160%

CPUAccounting=true enables CPU tracking.
CPUQuota=160% caps PHP-FPM at 1.6 cores worth of CPU.

  1. Reload systemd and restart PHP-FPM
sudo systemctl daemon-reexec
sudo systemctl restart php-fpm-83.service
  1. Verify Quota is Active
systemd-cgtop

restart services if load or memory usage is too high

vim /usr/local/bin/server-watchdog.sh
#!/bin/bash
# Simple watchdog for high load or memory usage
# Logs to /var/log/watchdog.log
LOG_FILE="/var/log/watchdog.log"
MAX_LOAD=5 # if load avg > 10 , 1 core:2-3, 2 cores: 4-5, 4 cores: 8-10, 8 cores: 15-20
MAX_MEM=85 # if memory usage > 85%, 12 GB: 80, 4 GB: 85, 8+ GB: 90
SERVICES=("nginx" "mysql" "php-fpm-84" "php-fpm-83" "php-fpm-82")
# Ensure log file exists and has correct permissions
if [ ! -f "$LOG_FILE" ]; then
touch "$LOG_FILE"
chmod 644 "$LOG_FILE"
fi
while true; do
LOAD=$(awk '{print int($1)}' /proc/loadavg)
MEM=$(free | awk '/Mem:/ {printf("%.0f", $3/$2 * 100)}')
if [ "$LOAD" -gt "$MAX_LOAD" ] || [ "$MEM" -gt "$MAX_MEM" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - ⚠️ High load detected (Load=$LOAD, Mem=$MEM%)" >> "$LOG_FILE"
# Restart critical services
for svc in "${SERVICES[@]}"; do
if systemctl is-active --quiet "$svc"; then
systemctl restart "$svc"
echo "$(date '+%Y-%m-%d %H:%M:%S') - Restarted service: $svc" >> "$LOG_FILE"
fi
done
sleep 60
# Recheck load after restart
LOAD_NOW=$(awk '{print int($1)}' /proc/loadavg)
if [ "$LOAD_NOW" -gt "$MAX_LOAD" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - ❗ Load still high after restart, rebooting..." >> "$LOG_FILE"
/sbin/reboot
fi
fi
sleep 30
done
Make it executable:
sudo chmod +x /usr/local/bin/server-watchdog.sh
vim /etc/systemd/system/server-watchdog.service
[Unit]
Description=Simple watchdog for high load recovery
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/server-watchdog.sh
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target

Then reload and start the service:

sudo systemctl daemon-reload
sudo systemctl enable server-watchdog
sudo systemctl start server-watchdog

查看pid程序是由哪个php文件开始执行的

sudo lsof -p pid | grep "\.php"
sudo lsof -p 340314 | grep "\.php"

使用nginx 和 GeoIP2 阻止某地区ip访问

Install GeoIP2 for Nginx

// 争对如下系统级安装的nginx,如果是使用nginx 安装的,需要另外编译geoip2模块
sudo apt update
sudo apt install nginx libnginx-mod-http-geoip2

Download MaxMind GeoLite2 database

如果没有 MaxMind GeoLite2 账号,创建license-key
Create an account at MaxMind and get a license key.
https://www.maxmind.com/en/accounts/current/license-key
mkdir -p /usr/share/GeoIP
cd /usr/share/GeoIP
wget -O GeoLite2-Country.tar.gz \
"https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=YOUR_KEY&suffix=tar.gz"
tar -xzf GeoLite2-Country.tar.gz
会得到文件夹如:
GeoLite2-Country_20260102
里面会有
GeoLite2-Country.mmdb
将其移到/usr/share/GeoIP下
mv /usr/share/GeoIP/GeoLite2-Country_20260102/GeoLite2-Country.mmdb /usr/share/GeoIP

Configure GeoIP2 in Nginx

编辑总nginx 配置文件,具体位置视情况而定
vim /usr/local/nginx/conf/nginx.conf
Inside http {} add:
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
$geoip2_country_code country iso_code;
}

Block China only for a.com

位置视情况而定
vim /usr/local/nginx/conf/vhost/a.com
做如下修改
map $geoip2_country_code $block_china {
default 0;
CN 1;
}
server {
server_name a.com www.a.com;
if ($block_china) {
return 403;
}
...
}