Nginx 安装与配置
Nginx 基础知识-安装与配置。
nginx配置文件优化
sudo yum install yum-utils
sudo vim /etc/yum.repos.d/nginx.repo
添加:
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
启用 nginx 源
sudo yum-config-manager --enable nginx-mainline
安装 nginx
sudo yum install nginx
开机启动 nginx
systemctl enable nginx
nginx 开机启动
通过上面的操作就自动将 nginx 开机启动了,所以下面的操作可不用执行:
sudo vim /usr/lib/systemd/system/nginx.service
添加:
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
[Install]
WantedBy=multi-user.target
开机启动 nginx: sudo systemctl enable nginx
配置 nginx
下面贴上完整的 nginx.conf 配置文件:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
worker_rlimit_nofile 65535;
events {
use epoll;
worker_connections 65535;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server_names_hash_bucket_size 128;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 50m;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
#fastcgi_intercept_errors on;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 4;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
server_tokens off;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
include /etc/nginx/conf.d/default.conf;
}
下面的是虚拟主机配置文件内容:
server {
listen 80;
server_name api.echoxu.cn;
rewrite ^/(.*)$ https://api.echoxu.cn/$1 permanent;
}
server {
listen 443 ssl;
server_name api.echoxu.cn;
root /usr/share/nginx/html/iweb;
index index.php index.html index.htm;
ssl_certificate /etc/nginx/ssl/api.echoxu.cn.pem;
ssl_certificate_key /etc/nginx/ssl/api.echoxu.cn.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
access_log /usr/share/nginx/logs/Access.log;
error_log /usr/share/nginx/logs/Error.log;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~* \.php$ {
root /usr/share/nginx/html/iweb;
fastcgi_index index.php;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /xmlrpc.php {
deny all;
access_log off;
log_not_found off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location ~ /\. {
deny all;
}
location ~* \.(sh|docx|txt|doc|php|php5|pl|py|zip|gz|bx|)$ {
deny all;
}
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 30d;
log_not_found off;
}
}
分析 nginx 日志
打开 nginx 日志你会看到有很多进行破解的 ip,我们需要找到他们并封禁其 ip:
cat nginx.log | cut -d ' ' -f 1 | sort | uniq -c | awk '{if ($1 > 5) print $0}' | sort -nr | less > ip.txt
通过上面的命令我们找到了进行 5 次尝试破解的 ip 地址.下面我们对其 ip 进行封禁:
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address="181.174.83.226" drop'
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address="129.213.59.142" drop'
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address="60.248.159.139" drop'
重启防火墙firewall-cmd --reload
,可通过firewall-cmd --zone=public --list-rich-rules
查看刚添加的规则.
如果发现误封了 ip,可通过sudo firewall-cmd --permanent --remove-rich-rule='rule family=ipv4 source address="181.174.83.226" drop'
进行解封 ip。
下面是自动化封禁 ip 的脚本 (分析 Error.log 日志也能得到相同的效果) :
#!/bin/bash
# drop ip
# author: echoxu
# todo: 异步执行,提高运行效率
ip_lock_file=/root/ip_lock_file.txt
ip_arr=()
ip_limit_count=5
ip_from_firewall_rules=`firewall-cmd --zone=public --list-rich-rules |awk -F ' ' '{print $4}' |grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"`
ip_from_nginx_log=`cat /usr/share/nginx/logs/Access.log | awk -F ' ' '{if ($9 == 404 || $9 == 403 || $9 == 400) print $1}' | sort -rn |uniq -c | awk -F ' ' '{if ($1 > $ip_limit_count) print $2}'`
ip_from_secure_log=`cat /var/log/secure-20231119 |grep -E 'Did not|Bad protocol' | grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" |sort -u`
getIPFromFirewallRules(){
for firewallip in $ip_from_firewall_rules
do
echo "$(date +'%F %T') 已封禁入侵ip: $firewallip " >> $ip_lock_file
done
}
getIPFromNginxLog(){
for nginxlogip in $ip_from_nginx_log
do
ip_arr[${#ip_arr[*]}]=${nginxlogip}
done
#echo "从 Nginx log 中获得 ${#ip_arr[*]} 个 ip,分别为:${ip_arr[*]}"
}
# kill ip from /var/log/secure
getIPFromSecureLog(){
for securelogip in $ip_from_secure_log
do
ip_arr[${#ip_arr[*]}]=${securelogip}
done
#echo "从 secure log 中获得 ${#ip_arr[*]} 个 ip,分别为:${ip_arr[*]}"
}
generateBaseData(){
if [ ! -f $ip_lock_file ];then
getIPFromFirewallRules # 将 firewall rules 里的数据导入到 ip_lock_file (程序首次运行时执行此函数)
fi
}
killIP(){
for ip in ${ip_arr[*]}
do
ip_is_exist=`cat $ip_lock_file |grep $ip|wc -l`
if [ $ip_is_exist -eq 0 ];then
firewall-cmd --permanent --add-rich-rule="rule family=ipv4 source address=$ip drop"
echo "$(date +'%F %T') 已封禁入侵ip: $ip " >> $ip_lock_file
fi
#echo "入侵ip: $ip 已在黑名单中存在。 "
done
}
main(){
generateBaseData
getIPFromNginxLog
getIPFromSecureLog
killIP
firewall-cmd --reload
}
main
添加定时任务,让其每半小时执行一次脚本并封禁破解次数>7 的 ip 地址:
crontab -e 然后添加如下:
0 0 * * * /usr/sbin/logrotate -f /etc/logrotate.daily.0/nginx >/dev/null 2>&1
*/30 * * * * sh /root/killIP.sh > /dev/null 2>&1 &
最好对 nginx 的日志进行一些切割处理,让其每天产生一个日志:
sudo vim /etc/logrotate.daily.0/nginx
添加如下内容:
/usr/share/nginx/logs/*.log {
daily
missingok
rotate 30
compress
dateext
delaycompress
notifempty
create 640 root root
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
添加定时任务,每天 00:00 产生新的日志文件:
0 0 * * * /usr/sbin/logrotate -f /etc/logrotate.daily.0/nginx >/dev/null 2>&1
根据偏移量读取 Nginx logs,请参考:使用偏移量读取 nginx logs
nginx 日志切割,请参考:nginx 日志切割
nginx 配置文件
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name example.com;
rewrite ^/(.*)$ https://www.example.com/$1 permanent;
}
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=15r/s;
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name www.example.com;
root /usr/share/nginx/html/example;
index index.html index.htm;
ssl_certificate /etc/nginx/ssl/9705728_www.example.com.pem;
ssl_certificate_key /etc/nginx/ssl/9705728_www.example.com.key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
# intermediate configuration
ssl_protocols TLSv1.2;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/ssl/9705728_www.example.com.pem;
resolver 127.0.0.1 223.5.5.5 8.8.8.8 8.8.4.4 valid=60s ipv6=off; #设置OCSP请求的DNS服务器地址
resolver_timeout 5s;
access_log /usr/share/nginx/logs/Access.log;
error_log /usr/share/nginx/logs/Error.log;
location / {
limit_req zone=mylimit;
# 只接受 GET 请求
add_header Allow "GET" always;
if ( $request_method !~ ^(GET)$ ){
return 444;
}
# 如果是空user_agent 直接返回444
if ($http_user_agent ~ ^$){
return 444;
}
# 访问的文件不存在时直接返回 444,因为我只需要开放那几个文件能访问就行
if (!-e $request_filename){
return 444;
}
#userAgent中如果包含下面的关键字,直接返回444
if ($http_user_agent ~* "Scrapy|python|curl|wget|httpclient|MJ12bot|Expanse*|DnBCrawler-Analytics|ahrefsbot|seznambot|serpstatbot|sindresorhus|zgrab|python-requests*|Go-http-client|serpstatbot|abuse.xmco.fr"){
return 444;
}
# 只接受指定的请求,其它请求全部拒绝访问
if ($request_uri ~* "\/|index.html|aboutUS.html|docDetail.html|doc.html|getStart.html|index.html|medicalTesting.html|price.html|researchService.html|favicon.ico|favicon.svg") {
break;
}
# 允许访问 favicon.ico
location ~ ^/favicon* {
log_not_found off;
access_log off;
expires 90d;
break;
}
# 允许通过域名访问
location ~ ^/$ {
break;
}
# 限制 \x00\x01 这样的请求访问,参考: https://github.com/mariusv/nginx-badbot-blocker/issues/157
if ($request_uri ~* ".*\\x.*"){
return 444;
}
# 屏蔽恶意访问
# if ($request_uri ~* \.(php|php5|asp|aspx|jsp|sh|swp|git|env|yaml|yml|conf|ini|txt|pl|py|json|sql|db|bak|ini|docx|doc|rar|tar|gz|zip|log|aws)$) {
# return 444;
# }
# 屏蔽指定关键词
# if ($request_uri ~* (wordpress|wp-content|wp-*|nextcloud|owncloud|credentials|phpinfo|wlwmanifest|tmp|credentials|phpMyAdmin|xmlrpc|wcm|shell|login|admin)) {
# return 444;
# }
# 当请求不是上面开放的路径时直接拒绝访问,达到了只能访问特定路径的目的
return 444;
}
}
nginx 支持 http1.2
nginx 开启 OCSP Stapling : https://developer.aliyun.com/article/764381
strings /usr/sbin/nginx | grep _module | grep -v configure| sort | grep ngx_http_v2_module
- --with-http_v2_module和--with-http_ssl_module用于支持HTTP2和ssl加密,
- --with-openssl=用于指定openssl库的安装目录
- --with-openssl-opt=enable-tls1_3用于开启openssl库的tls1.3支持,但是现在的新版本已经默认开启,无需额外添加这个参数
nginx 支持 http2,tls1.3 需要将 openssl 升级到 1.1.1
可通过 https://ssl-config.mozilla.org 查看配置 tls1.2/tls1.3 的参数
通过 https://www.ssllabs.com/ssltest/analyze.html 可查看是否已启用了 tls1.2/tls1.3
参考: - https://blog.csdn.net/qq_42287535/article/details/126040255
# generated 2023-12-05, Mozilla Guideline v5.7, nginx 1.24.0, OpenSSL 1.0.2k-fips, intermediate configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.24.0&config=intermediate&openssl=1.0.2k-fips&guideline=5.7
# https://www.ssllabs.com/ssltest/analyze.html 检查是否支持 tls1.2
# links: https://blog.csdn.net/qq_42287535/article/details/126040255
# links: https://zhuanlan.zhihu.com/p/223304805
server {
listen 80 default_server;
listen [::]:80 default_server;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /path/to/signed_cert_plus_intermediates;
ssl_certificate_key /path/to/private_key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
ssl_dhparam /path/to/dhparam;
# intermediate configuration
ssl_protocols TLSv1.2;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;
# replace with the IP address of your resolver
resolver 127.0.0.1;
}
检查 nginx 是否开启 ocsp: openssl s_client -connect www.digitalocean.com:443 -status 2> /dev/null | grep -A 17 'OCSP response:' | grep -B 17 'Next Update'
nginx 配置 ocsp: how-to-configure-ocsp-stapling-on-apache-and-nginx
nginx 日志出现 "\x15\x03\x01\x00\x02\x02P"
Nginx 400错误归因于随机IP地址中以“ \ x”开头的随机编码字符串,request_body中含有中文时,nginx日志会转换为十六进制这个其实很难防住,不过可尝试以下方法:
部分日志:
35.203.211.189 - - [01/Dec/2023:15:15:19 +0800] "\x00\x00\x001\xFFSMBr\x00\x00\x00\x00\x18Eh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xB5}\x00\x00\x01\x00\x00\x0E\x00\x02NT LM 0.12\x00\x02\x00" 400 150 "-" "-"
35.203.211.189 - - [01/Dec/2023:15:15:19 +0800] "\x00\x00\x00f\xFESMB@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001234567890123456$\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x001234567890123456\x00\x00\x00\x00\x00\x00\x00\x00\x02\x02" 400 150 "-" "-"
35.203.211.189 - - [01/Dec/2023:15:15:19 +0800] "\x00\x00\x00f\xFESMB@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001234567890123456$\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x001234567890123456\x00\x00\x00\x00\x00\x00\x00\x00\x10\x02" 400 150 "-" "-"
35.203.211.189 - - [01/Dec/2023:15:15:20 +0800] "\x00\x00\x00f\xFESMB@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001234567890123456$\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x001234567890123456\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03" 400 150 "-" "-"
35.203.211.189 - - [01/Dec/2023:15:15:20 +0800] "\x00\x00\x00f\xFESMB@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001234567890123456$\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x001234567890123456\x00\x00\x00\x00\x00\x00\x00\x00\x02\x03" 400 150 "-" "-"
35.203.211.189 - - [01/Dec/2023:15:15:21 +0800] "\x00\x00\x00\xAC\xFESMB@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001234567890123456$\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x001234567890123456h\x00\x00\x00\x02\x00\x00\x00\x11\x03\x00\x00\x02\x00\x06\x00\x00\x00\x00\x00\x02\x00\x02\x00\x01\x00\x00\x00\x01\x00,\x00\x00\x00\x00\x00\x02\x00\x02\x00\x01\x00\x01\x00 \x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 400 150 "-" "-"
54.91.91.71 - - [01/Dec/2023:15:23:55 +0800] "\x15\x03\x01\x00\x02\x02P" 400 150 "-" "-"
54.91.91.71 - - [01/Dec/2023:15:24:17 +0800] "\x15\x03\x01\x00\x02\x02P" 400 150 "-" "-"
- 你最有可能看到此消息,因为你正在向HTTP端点发出HTTPS请求。例如,你将HTTPS请求发送到Web服务器的端口80而不是443。因此,HTTP端点获得了一堆加密数据,不费力气地解密它(因为HTTP应该是纯文本) ,因此你在日志文件中会看到一堆乱码。
- https://bbs.csdn.net/topics/398495210
- https://www.openssl.org/source/openssl-1.1.1w.tar.gz
- https://blog.csdn.net/abccyz/article/details/128748255
- https://github.com/mariusv/nginx-badbot-blocker/issues/157
- https://blog.csdn.net/weixin_45122740/article/details/121189540