警告
本文最后更新于 2022-06-28,文中内容可能已过时。
前言
一篇包含tomcat、nginx、php等相关参数及性能的优化文件,看了很多,但却不能完全记住,整理一篇用于备忘。
1. tomcat 服务调优
1.1. 安全优化
-
降权启动
-
telnet
管理端口保护
- 修改配置文件
/pathto/tomcat/conf/server.xml
,22行左右的<Server port="8005" shutdown="SHUTDOWN">
8005
端口和SHUTDOWN
(区分大小写)关键字,防止tomcat
被远程关闭
-
ajp
连接端口保护
ajp
是apache
和tomcat
相互沟通的一个渠道,如果不使用,可以注释掉或者修改端口 /pathto/tomcat/conf/server.xml: 123
。
-
禁用管理端
- 一般管理端用于测试使用,正式使用需要删除
/pathto/tomcat/webapps
下所有目录,新建的站点放到该目录的ROOT
下即可,另删除/pathto/tomcat/conf/tomcat-users.xml
下关于角色的配置(或者删掉这个文件,似乎也没有什么影响)。
-
文件访问列表控制
web.xml: 121
配置listings
值为false
, 默认false
-
隐藏版本信息
- 可修改
conf/web.xml
中关于error-page
的相关配置(实际上个人在5.8
中好像没有找到这块的),也可以修改站点中WEB-INF/web.xml
中的错误页
-
访问控制限制
conf/server.xml: Host
下添加<Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="10.0.2.*"/>
-
启动脚本权限修正744
-
应用自动部署
conf/server.xml: 158
修改参数unpackWARs
和autoDeploy
: <Host name="localhost" appBase="webapps" unpackWARs="false" autoDeploy="false">
1.2. 性能优化
1
2
3
4
|
<Connector executor="tomcatThreadPool" port="8080" enableLookups="false"
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
connectionTimeout="20000"
redirectPort="8443" />
|
2. tmpfs 一种基于内存的文件系统
可用于挂载临时文件存放目录,挂载后操作目录相当于直接操作内存,umount后挂载目录数据会被直接清空。
1
|
mount -t tmpfs -o size=1024M tmpfs /mnt/usb02
|
3. nginx 优化
nginx 规则匹配优先级: =
> 完整路径
> ^~
> ~|~*
> 部分起始路径
> /
防止SQL注入、XSS攻击的实践配置方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
if ($request_method !~* GET|POST) { return 444; }
#使用444错误代码可以更加减轻服务器负载压力。
if ($query_string ~* "(\$|'|--|[+|(%20|%2F)]union[+|(%20|%2F)]|[+|(%20|%2F)]insert[+|(%20|%2F)]|[+|(%20|%2F)]drop[+|(%20|%2F)]|[+|(%20|%2F)]truncate[+|(%20|%2F)]|[+|(%20|%2F)]update[+|(%20|%2F)]|[+|(%20|%2F)]from[+|(%20|%2F)]|[+|(%20|%2F)]grant[+|(%20|%2F)]|[+|(%20|%2F)]exec[+|(%20|%2F)]|[+|(%20|%2F)]where[+|(%20|%2F)]|[+|(%20|%2F)]select[+|(%20|%2F)]|[+|(%20|%2F)]and[+|(%20|%2F)]|[+|(%20|%2F)]or[+|(%20|%2F)]|[+|(%20|%2F)]count[+|(%20|%2F)]|[+|(%20|%2F)]exec[+|(%20|%2F)]|[+|(%20|%2F)]chr[+|(%20|%2F)]|[+|(%20|%2F)]mid[+|(%20|%2F)]|[+|(%20|%2F)]like[+|(%20|%2F)]|[+|(%20|%2F)]iframe[+|(%20|%2F)]|[\<|%3C]script[\>|%3E]|javascript|alert|webscan|dbappsecurity|style|confirm\(|innerhtml|innertext)(.*)$") { return 555; }
if ($uri ~* "(/~).*") { return 501; }
if ($uri ~* "(\\x.)") { return 501; }
if ($query_string ~* "[;'<>].*") { return 509; }
if ($request_uri ~ " ") { return 509; }
if ($request_uri ~ "(\/\.+)") { return 509; }
if ($request_uri ~ "(\.+\/)") { return 509; }
# sql 注入
# if ($uri ~* "(insert|select|delete|update|count|master|truncate|declare|exec|\*|\')(.*)$" ) { return 508; }
if ($query_string ~ "concat.*\(") { return 508; }
if ($query_string ~ "union.*select.*\(") { return 508; }
if ($query_string ~ "union.*all.*select.*") { return 508; }
if ($request_uri ~* "(cost\()|(concat\()") { return 508; }
if ($request_uri ~* "[+|(%20|%2F)]union[+|(%20|%2F)]") { return 508; }
if ($request_uri ~* "[+|(%20|%2F)]and[+|(%20|%2F)]") { return 508; }
if ($request_uri ~* "[+|(%20|%2F)]select[+|(%20|%2F)]") { return 508; }
if ($request_uri ~* "[+|(%20|%2F)]or[+|(%20|%2F)]") { return 508; }
if ($request_uri ~* "[+|(%20|%2F)]delete[+|(%20|%2F)]") { return 508; }
if ($request_uri ~* "[+|(%20|%2F)]update[+|(%20|%2F)]") { return 508; }
if ($request_uri ~* "[+|(%20|%2F)]insert[+|(%20|%2F)]") { return 508; }
## 常见漏洞利用
if ($query_string ~ "(<|%3C).*script.*(>|%3E)") { return 403; }
if ($query_string ~ "GLOBALS(=|\[|\%[0-9A-Z]{0,2})") { return 403; }
if ($query_string ~ "_REQUEST(=|\[|\%[0-9A-Z]{0,2})") { return 403; }
if ($query_string ~ "proc/self/environ") { return 403; }
if ($query_string ~ "mosConfig_[a-zA-Z_]{1,21}(=|\%3D)") { return 403; }
if ($query_string ~ "base64_(en|de)code\(.*\)") { return 403; }
# 垃圾邮件字段
if ($query_string ~ "\b(ultram|unicauca|valium|viagra|vicodin|xanax|ypxaieo)\b") { return 507; }
if ($query_string ~ "\b(erections|hoodia|huronriveracres|impotence|levitra|libido)\b") { return 507; }
if ($query_string ~ "\b(ambien|bluespill|cialis|cocaine|ejaculation|erectile)\b") { return 507; }
if ($query_string ~ "\b(lipitor|phentermin|pro[sz]ac|sandyauer|tramadol|troyhamby)\b") { return 507; }
## 文件注入
if ($query_string ~ "[a-zA-Z0-9_]=http://") { return 444; }
if ($query_string ~ "[a-zA-Z0-9_]=(\.\.//?)+") { return 444; }
if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+") { return 444; }
# if ($http_user_agent ~* "spider") { return 508; }
#if ($http_user_agent ~ "Wget") {
# return 508;
#}
# if ($http_user_agent ~* "~17ce.com") { return 508; }
if ($http_user_agent ~* "(YisouSpider|ApacheBench|Jmeter|JoeDog|Havij|masscan|mail2000|github|Java|python)") { return 508; }
if ($http_user_agent ~* "WebBench*") { return 508; }
if ($http_user_agent ~* "Nmap Scripting Engine") { return 508; }
if ($http_user_agent ~* "Indy Library") { return 508; }
if ($http_user_agent ~ "^$") { return 508; }
if ($http_user_agent ~ "libwww-perl") { return 508; }
if ($http_user_agent ~ "GetRight") { return 508; }
if ($http_user_agent ~ "GetWeb!") { return 508; }
if ($http_user_agent ~ "Go!Zilla") { return 508; }
if ($http_user_agent ~ "Download Demon") { return 508; }
if ($http_user_agent ~ "Go-Ahead-Got-It") { return 508; }
if ($http_user_agent ~ "TurnitinBot") { return 508; }
if ($http_user_agent ~ "GrabNet") { return 508; }
location ~* "(&pws=0|_vti_|\(null\)|\{\$itemURL\}|echo(.*)kae|boot\.ini|etc/passwd|eval\(|self/environ|(wp-)?config\.|cgi-|muieblack)" { return 403; }
location ~* "/(^$|mobiquo|phpinfo|shell|sqlpatch|thumb|thumb_editor|thumbopen|timthumb|webshell|config|configuration)\.php" { return 403; }
location ~* "('|\")(.*)(drop|insert|md5|select|union)" { return 403; }
location ~* "(https?|ftp|php):/" { return 403; }
location ~* "(='|=%27|/'/?)." { return 403; }
|
3.1. 版本号隐藏
- 修改文件: 修改
nginx.conf
,在http
标签中添加server_tokens off;
参数,然后reload
- 编译修改:
- 修改
nginx
源码文件/pathto/nginx-x.xx.x/src/core/nginx.h
,nginx
版本号参数NGINX_VERSION
,软件名称 NGINX_VAR
,NGINX_VER
- 修改
nginx
源码文件49: /pathto/nginx-x.xx.x/src/http/ngx_http_header_filter_module.c
,值 Server: xxxx
(curl 显示的页面)
- 修改
nginx
源码文件36: /pathto/nginx-x.xx.x/src/http/ngx_http_special_response.c
,值 <hr><center>xxxx</center>
(错误页面:例如502)
- 正常编译安装
3.2. 更改nginx默认用户
- 修改配置文件:
/pathto/nginx/conf/nginx.conf
,值 user nobody
为 user <user> <group>
;
- 编译时指定默认用户:
--user=<user> --group=<group>
3.3. 优化wroker进程数
1
2
3
|
# main
worker_processes 8;
worker_cpu_affinity 0001 0010 0100 1000 0001 0010 0100 1000; # 掩码形式 分别代表1-8核
|
3.4. Nginx 事件模型优化
nginx是异步的网络io模型,epoll 工作模型是高性能高并发的设置。
- 修改配置文件:
/pathto/nginx/conf/nginx.conf
1
2
3
4
5
6
7
8
|
# main
events {
use epoll;
# 开启的时候,将会对多个Nginx进程接受连接进行序列化,防止多个进程对连接的争抢,当服务器连接数不多时,开启这个参数会让负载有一定程度的降低. 但是当服务器的吞吐量很大时,为了效率,需要关闭. 并且关闭这个参数的时候也可以让请求在多个worker间的分配更均衡(默认关闭 off)
# accept_mutex on;
multi_accept on; # 告诉nginx收到一个新连接通知后接受尽可能多的连接,默认是on
worker_connections 65535; # 单个worker的连接数(并发等于 worker_connections * worker_processes )
}
|
3.5. Nginx worker 进程最大打开文件数
main
标签下设置worker_rlimit_nofile 65535
,值可为系统优化后设置的ulimit -HSn
的结果 。
3.6. Nginx 服务器域名hash表大小
: main
- 参数1:
server_names_hash_max_size 512;
设置存放域名(server_names)的最大hash表大小(如果nginx发出消息 应首选增大 max size)
- 参数2:
server_names_hash_bucket_size 64;
此设置与server_names_hash_max_size
共同控制保存服务器域名的hash表.
3.7. 开启高效的文件传输模式
; http/server/location/if in location
sendfile on;
, 作用于两个文件描述符之间的数据拷贝函数,这个拷贝操作是在内核中的。
tcp_nopush on;
,允许把http response header和文件的开始放在一个文件里面发布,积极的作用是减少网络报文段的数量。
tcp_nodelay on;
, 提升io性能,默认情况下数据发送时,内核并不会马上发送,可能会等待更多的字节组成一个数据包,这样可以提高I/O性能,但是,每次只发送很少字节的业务场景,使用tcp_nodelay功能,等待时间会比较长.(高并发建议使用)
3.8. 超时连接优化
3.8.1. 作用
- 设置将无用的连接尽快超时,可以保护服务器的系统资源(cpu、内存、磁盘)
- 当连接很多时,及时断掉那些已经建立好但又长时间不做事的连接, 以减少其占用的服务器资源,应为服务器维护连接也是要消耗资源的。
- 有时黑客或恶意用户攻击网站,就会不断的和服务器建立多个连接,消耗连接数,但啥也不干,只是持续建立连接,这就会大量消耗服务器的资源,此时就应该及时断掉这些恶意占用资源的连接。
- LNMP环境中,如果用户请求了动态服务,则Nginx就会建立连接请求fastcgi服务以及mysql服务,此时这个Nginx连接就要设定一个超时时间,在用户容忍的是就按内反回数据,或者在多等一会后端服务器返回数据,具体的策略要具体业务分析。
3.8.2. 问题
- 超时时间若设置太短,并发很大的时候,就会导致服务器无法瞬间响应用户请求,导致体验下降 。
3.8.3. 建议
- php 网站建议短连接,php程序建立连接消耗的资源和时间少
- java网站建议长连接,java程序建立连接消耗的资源和时间多(连接重用,连接池..)
3.8.4. 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# http/server
keepalive_timeout 60; # 默认60秒
# keepalive_time 可以使客户端到服务器端已经建立的连接一直工作而不退出,当服务器有持续请求的时候,keep-alive会使用正在建立的连接提供服务,从而避免服务器重新建立新的连接处理请求。 此参数生效需激活tcp_nodelay选项
client_header_timeout 15; # 用于设置读取客户端请求头数据的超时时间,此处的数值15单位是秒,为经验参考值。如果超过此事件客户端还没有发送完整的header数据,服务端将返回 408错误 ,指定一个时间可以防止客户端利用http协议进行攻击 。
client_body_timeout 15; # 用于设置读取客户端请求主体的超时时间,这个超时仅仅为两次成功的读取操作之间的一个超时,非请求整个主体数据的超时时间,如果在这个超时时间内,客户端没有发送任何数据,则服务端返回 408 。
send_timeout 25; # 设置服务器端传送http响应信息到客户端的超时时间(服务端发给客户端),这个超时时间仅仅为两次成功握手后的一个超时,非请求整个响应数据的超时时间,如果这个超时时间内,客户端没有接受任何数据,连接将会被关闭。
# 上传文件大小
client_max_body_size 8m; # 上传文件大小,超过设置值反会413错误.
|
3.9. 动态参数引擎fastcgi
Nginx Fastcgi参数(http) |
说明 |
fastcgi_connect_timeout |
表示Nginx服务器和后端FastCGI服务器连接的超时时间,默认60s,这个参数通常设置不要超过75s,因为建立的连接诶越多消耗的资源就越多。(Nginx请求php服务器多少时间内要拿到数据,否则断开连接502) |
fastcgi_send_timeout |
设置Nginx允许FastCGI服务端返回数据的超时时间,即在规定时间之内后端服务器必须传完所有数据,否则Nginx将断开这个连接,默认60s(PHP需要在多少时间内将数据全部发送完成给nginx,否则断开) |
fastcgi_read_timeout |
设置Nginx从FastCGI服务端读取响应信息的超时时间,表示连接成功建立后,Nginx等待后端服务器的响应时间,是Nginx已经进入后端的排队之中等候处理的时间。 |
fastcgi_buffer_size |
这个是Nginx fastcgi的缓冲区大小参数,设定用来读取从fastcgi服务端收到的第一部分响应信息的缓冲区大小,这里的第一部分通常会包含一个小的响应头部,默认情况下大小是由fastcgi_buffers 指定的一个缓冲区的大小 |
fastcgi_buffers |
设定用来读取从Fastcgi服务端收到响应信息的缓冲区大小,已经缓冲区的数量。默认值:`fastcg_buffers 8 4 |
fastcgi_busy_buffers_size |
用于设置系统很繁忙的时候可以使用的fastcgi_buffers大小,官方推荐的大小为fastcgi_buffers *2 ,默认值 `fastcgi_busy_buffers_size 8k |
fastcgi_temp_file_write_size |
fastcgi临时文件的大小,可设置128-256k |
fastcgi_cache xxxx |
表示开启fastcgi缓存并为其指定一个名称,开启缓存非常有用,可以有效的降低cpu负载,并且防止502错误的发生,但是开启缓存也有可能会引起其他问题,要根据具体情况来选择。 |
fastcgi_cache_path |
例:fastcgi_cache_path /data/ngx_fcgi_cache levels=2:2 keys_zone=ngx_fcgi_cache:521min active=1d max_size=40g ,fastcgi_cache缓存目录,可以设置hash层级,比如2:2会生成256×256个子目录,keys_zone是这个缓存空间的名字,cache是用多少内存(这样热门的内容nginx直接存放内存,提高访问速度),inactive表示默认失效的时间,max_size 表示最多用多少硬盘空间。需要注意的是fastcgi_cache缓存是先写在fastcgi_temp_path,在转移到fastcgi_cache_path,所以这两个目录最好是放在同一分区 |
fastcgi_cache_valid |
例: fastcgi_cache_valid 200 302 1h; 当状态码是200、302时候缓存一小时;fastcgi_cache_valid 301 1d; 当状态码是301时缓存一天;fastcgi_cache_valid any 1m; 当状态码是其他的时候缓存1分钟 |
fastcgi_cache_min_uses |
设置请求几次响应被缓存 例: fastcgi_cache_min_uses 1; 表示1次请求即被缓存 |
fastcgi_cache_use_stale |
定义那些情况下使用过期缓存 例:fastcgi_cache_use_stale error timeout invalid_header http_500; |
fastcgi_cache_key |
例: fastcgi_cache_key $request_method://$host$request_uri; fastcgi_cache_key http://$host$request_uri; 定义fastcgi_cache的key,示例中就以请求的URI作为缓存的key,Nginx回去这个key的md5作为缓存文件,如果设置了缓存hash目录,nginx会从后向前取相应的位数作为目录。注意 一定要加上$request_method 作为cache key,否则如果HEAD类型的先请求会导致后面的GET请求返回为空。 |
示例配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# fastcgi 缓冲区 和 超时时间 (http标签)
fastcgi_send_timeout 240;
fastcgi_read_timeout 240;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;
fastcgi_temp_path /opt/nginxssl/fastcgi_temp/tmp;
fastcgi_cache_path /opt/nginxssl/fastcgi_temp/cache levels=2:2 keys_zone=cache:128m inactive=1d max_size=6g;
#fastcgi 缓存 (server标签)
fastcgi_cache cache;
fastcgi_cache_valid 200 1h;
fastcgi_cache_valid 301 1d;
fastcgi_cache_valid any 1m;
fastcgi_cache_min_uses 1;
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_cache_key http://$host$request_uri;
|
3.10. gzip
3.10.1. 优点
- 提升网站用户体验,提升网站用户访问速度
- 节约网站宽带成本
3.10.2. 需要和不需要压缩的对象
- 纯文本内容压缩比很高,因此纯文本的内容最好要压缩(例如: html、js、css、xml、shtml等)
- 被压缩的纯文本必须要大于1kb,否则由于压缩算法的原因,可能导致压缩反而是文件增大
- 图片、视频(流媒体)等文件尽量不要压缩,因为这些文件大多都是经过压缩的,如果在压缩可能不会减少太多,或者可能增大,而在压缩还会消耗大量的cpu、内存资源
3.10.3. 配置
参数 |
作用 |
gzip on |
开启gzip压缩功能 |
gzip_min_length 1k |
设置允许压缩页面的最小字节数,页面字节数从header头的Content-Length中获取,默认0,表示不管页面多大都进行压缩 |
gzip_buffers 4 16k |
压缩区缓冲区大小,表示申请4个单位为16k的内存作为压缩结果流缓存,默认值是申请与原始数据大小相同的内存空间来存储gzip压缩结果 |
gzip_http_version 1.1 |
压缩版本,默认1.1,比如说前端访问的并不一定是用户,可能是cdn,这个时候就需要加一个版本,先大部分都支持gzip解压,设置默认即可 |
gzip_comp_level 2; |
用来指定压缩比例,1 压缩最小,处理速度最快;9压缩比例最大,传输快,但处理速度慢,也比较消耗cpu资源 |
gzip_types text/plan application/x-javascript |
指定需要压缩的文件类型 |
gzip_vary on; |
vary header 支持,该选项可以让前端的缓存服务器缓存gzip压缩的页面,(让缓存服务器继续缓存,而不是解压,只有在浏览器的时候在解压) |
3.11. nginx expires 缓存
3.11.1. 优点
- expires 可以降低网站的宽带,节约成本
- 加快用户访问网站的速度,提升用户体验
- 减少服务器访问量,降低服务器压力,节约服务器成本
3.11.2. 缺点
- 当网站被缓存的页面存在更新时,用户看到的可能还是旧的数据
- 解决方案:
- 缩短经常修改页面的缓存时间
- 对于经常修改的页面文件名进行添加,或加上版本号,这样前端cdn以及用户端需要重新更新缓存内容
3.11.3. 配置
如果配置后导致前端无法正常访问,有可能是因为server标签中没有指定root目录有关
示例:
1
2
3
4
5
|
# server / http
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf){
expires 6d;
}
|
3.12. nginx 日志
3.12.1. 切割示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#!/bin/bash
# 40 23 * * * /bin/bash /opt/sh/cut_nginx_all.sh >> /dev/null 2>&1
time=`date +"%Y-%m-%d"`
log_path="/opt/nginxssl/logs"
pid_path="/opt/nginxssl/logs/nginx.pid"
new_dir="/opt/logs/nginxlogs"
# nginx web 日志 (www.log) ,以空格隔开,无需后缀
logs_names=(www www1)
cd $new_dir
num=${#logs_names[@]}
for((i=0;i<num ;i++));do
mv ${log_path}/${logs_names[i]}.log ${new_dir}/${logs_names[i]}_${time}.log
tar czf ${logs_names[i]}_${time}.tar.gz ${logs_names[i]}_${time}.log
rm ${logs_names[i]}_${time}.log
done
/opt/nginxssl/sbin/nginx -s reopen
|
3.12.2. 不记录不需要的日志
- 在实际工作中,对于负载均衡器的健康检查节点或某些特定文件(如图片、js、css等)的日志,一般不需要记录下来,因为在PV时是按照页面计算的。而且日志写入太频繁会大量消耗磁盘IO,降低服务器性能.
- 网络流量度量术语
- 独立(公网)ip数: 指的是不同IP地址的计算机访问网站时被计算的总次数。独立IP书是衡量网站流量的一个重要指标。一般一天内相同IP地址的客户端访问网站页面只被计算为一次,记录独立IP的时间可以为一天或一个月,目前通常标准为一天;
- PV 访问量: 即Page View 页面浏览,即页面浏览量或点击量,不管客户端是不是相同,也不管ip是不是相同,用户每次访问一个网站页面都会被计算一个PV。具体度量方法就是从客户浏览器发出一个对web服务器的请求,web服务器接到这个请求后,将该请求对应的一个网页发给浏览器,就产生了一个pv。但是只要这个请求发送给了浏览器,无论这个页面是否完全打开(或下载完成),那么都会被(服务器日志)计数为一个PV,一般为了防止用户快速刷PV,都是把PV的统计程序放在页面的最下面。
- UV 独立访客数: 同一个客户端(PC或移动端) 访问网站被计算为一个访客,一天内相同的客户端访问同一个网站只计算一次UV,UV一般是以客户端Cookie等计算作为统计依据,实际统计会有误差。一台客户端可能忽悠多人使用的情况,因此,UV实际上并不一定是独立的自然人访问。
- 配置方法:
这里的location标签匹配不记录日志的元素扩展名,然后关掉了日志。
1
2
3
|
location ~ .*\.(js|jpg|JPG|jpeg|JPEG|css|bmp|gif|GIF)$ {
access_log off;
}
|
3.12.3. 访问日志权限设置
- 限制用户及组为root , 修改目录权限 600 ,nginx访问日志的权限即使是root,nginx也是可以读取的
3.13. nginx 站点目录及文件URL控制
3.13.1. 根据文件扩展名限制程序和文件访问
1
2
3
4
5
6
7
8
9
10
11
|
location ~ ^/image/.*\.(php|php5|sh|pl|py)${
deny all;
}
location ~ ^/static/.*\.(php|php5|sh|pl|py)${
deny all;
}
location ~ ^/data/(attachment|avatar)/.*\.(php|php5)${
deny all;
}
|
3.13.2. 限制网站来源IP访问
1
2
3
4
5
6
|
location ~ ^/admin/{
allow xx.xx.xx.xx;
allow xx.xx.xx.xx/xx;
# deny xx.xx.xx.xx;
deny all;
}
|
使用if来限制客户端ip
1
2
3
4
5
6
7
|
if ($remote_addr = 10.0.0.7 ) {
return 403;
}
if ($remote_addr = xx.xx.xx.xx ) {
set $allow_access_root 'true';
}
|
3.13.3. 配置nginx禁止非法域名解析
- 问题: 如何防止用户IP访问网站(恶意域名解析,也相当于ip访问网站)
解决:让使用ip访问网站的用户,或者恶意解析域名的用户,收到501错误。(需要放到所有server之前)
1
2
3
4
5
|
server {
listen 80 default_server;
server_name _;
return 501;
}
|
3.14. 防盗链
3.14.1. 解决方案
- 根据
http_referer
实现防盗链
示例:
1
2
3
4
5
6
7
8
|
# server
location ~* ^.+\.(jpg|png|swf|flv)$ {
valid_referers none bloked *.example.com;
if ($invalid_referer) {
#rewrite ^/ https://www.example.com/daolian.png;
return 403;
}
}
|
- 根据
cookie
防盗链
3.15. 错误页面优雅显示
示例:
1
2
3
4
|
# error_page 可以多行,每行对应一个状态码
error_page 500 502 503 504 404 /50x_error.html;
# 若集群,建议选择域名跳转,统一分配
# error_page 500 502 503 504 404 http://www.example.com/erro_page;
|
fastcgi_intercept_errors on;
默认 off
,这个指令指定的是是否传递 4xx
和 5xx
信息到客户端,或允许nginx
使用error_page
处理错误信息。
3.16. 站点目录权限优化
目录权限755
,文件权限644
,用户及组root
,用户上传目录nginx
服务用户.(减少文件上传目录权限)
3.17. 防爬虫优化
3.17.1. robots.txt 机器人协议
网站通过robots(网站根目录存放robots.txt)协议告诉搜索引擎哪些页面可以抓取,那些页面不能抓取。
示例:
1
2
3
|
User-agent: *
Disallow: /
Sitemap: https://www.example.com/sitemap.xml
|
3.17.2. nginx 防爬虫优化配置
示例:
1
2
3
4
|
# server|location
if ($http_user_agent ~* "LWP::Simple|BBBike|wget") {
return 403;
}
|
3.18. nginx 限制http请求方法
示例:
1
2
3
4
5
|
# 屏蔽非GET|HEAD|POST的请求方法
# server|location
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 501;
}
|
3.19. 使用cdn做网站内容加速
cdn全国或全球的分布式缓存集群
3.20. 网站架构优化
3.20.1. 为网站程序解耦
指的是把一堆程序代码按照业务用途分开,然后提供服务。例如: 注册登陆、上传、下载、浏览列表、商品内容页面、订单支付等都应该是独立的程序服务。
3.21. nginx 监牢模式
3.21.1. nginx 服务降权解决方案
解决方案:
- 给
nginx
服务降权,用普通用户(假设普通用户为www
)跑nginx
服务,给开发和运维设置普通用户帐号,将开发和运维的帐号设置为与www
同组即可管理nginx
,该方案解决了nginx
管理问题,防止root
分配权限过大。
- 开发人员使用普通用户即可管理
nginx
服务及站点下的程序和日志。
- 采取项目负责制度,即谁负责的项目维护出了问题就是谁负责。
3.22. 控制nginx并发连接数
示例:
1
2
3
4
5
|
# 定义
# http
limit_conn_zone $binary_remote_addr zone=addr:10m;
#使用(seerver/location)
limit_conn addr 1;
|
3.23. 控制 nginx请求
1
2
3
4
5
|
# 定义
# http
limit_req_zone $binary_remote_addr zone=one;10m rate=1r/s;
#使用(seerver/location)
limit_req zone=one burst=5;
|
4. php 优化
4.1. php 参数调优
php.ini-development
与php.ini-production
的区别是日志的开启与隐藏
4.1.1. php.ini 安全参数调优
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
; 打开安全模式(防止system()函数可调用系统命令),5.5以上已无该参数
safe_mode = On
; safe_mode 打开时,safe_mode_gid被关闭,那么php脚本能够对文件进行访问,而且同组的用户也能狗对文件进行访问。设置off进行关闭,5.5以上已无该参数
safe_mode_gid = Off
; 关闭危险函数(phpinfo,passthru,exec,shell_exec,system,popen,proc_open,proc_get_status,chroot,scandir,chgrp,chown,readdir,ls_dir,ini_set,ini_alter,ini_restore,dl,pfsockopen,fsocket,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server,rmdir,chmod,closedir,opendir,dir,fileperms,copy,delfile),默认无限制
disable_functions = phpinfo
; 关闭php版本信息(默认On)
expose_php = Off
; 关闭注册全局变量,5.5以上已无该参数
register_globals = Off
; 防止sql注入(打开后自动把用户体检对sql的查询进行转换,例如把'转换为\),默认Off,5.5以上已无该参数
magic_quotes_gpc = On
; 错误信息输出控制,默认On
; 建议在关闭display_errors后能够把错误信息记录下来,便于查找服务器运行的原因:
; log_errors = On
; error_log = /var/log/php_error.log
display_errors = Off
|
4.1.2. php.ini 优化参数调优
1
2
3
4
5
6
7
8
9
10
11
12
|
; 每个脚本最大允许执行时间(s),0 表示没有限制
max_execution_time = 30
; 每个脚本使用的最大内存,要能够使用该指令编译时必须启用 --enable-memory-limit 选项
memory_limit = 128M
; 每个脚本等待输入数据的最长时间 ,-1 表示不限制
max_input_time = 60
; 上传文件的最大许可
upload_max_filesize = 2M
; 最大上传的文件数量(可同时上传多少个文件),默认20
max_file_uploads = 20
; http post 数据的大小 (请求包的大小),默认8M
post_max_size = 8M
|
4.1.3. php.ini 安全优化
1
2
3
4
|
; 禁止打开远程地址,默认On
allow_url_fopen = Off
; 防止nginx文件类型错误解析漏洞,默认1
cgi.fix_pathinfo = 0
|
4.1.4. php session 会话保持
集群环境,一般会将session存放于memcache中,多个集群节点连接同一个memcache,保证用户session处于在线状态
php.ini 修改
1
2
3
4
|
; 调整php session 信息存放类型,默认文件 files
session.save_handler = memcache
; session 保存位置,默认tmp
session.save_path = "tcp://10.0.0.18:11211"
|
4.2. php-fpm 调优
4.2.1. php-fpm.conf 调优
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
; 打开进程pid
pid = run/php-fpm.pid
; 打开php-fpm 进程错误日志
error_log = log/php-fpm.log
; 错误日志级别 , 默认notice
log_level = error
; 最大的php-fpm进程数量(静态),默认128
process.max = 128
; 文件描述符,默认1024
rlimit_files = 10240
; 表示在emergency_restart_interval时间内,出现SIGEGV或者SIGBUS错误的php-cgi进程数如果超过了
; emergency_restart_threshold个,则php-cgi就会优雅重启
emergency_restart_interval = 60s
emergency_restart_threshold = 60
;
; 池定义
; 与nginx用户一样
[www]
user = www
group = www
; 监听
listen = 127.0.0.1:9000
; 控制允许访问的客户端
listen.allowed_clients = 127.0.0.1
; 进程模式,默认动态,开启后需配合pm.max_children,pm.start_servers,pm.min_spare_servers,pm.max_spare_servers参数进行设置
pm = dynamic
; 同一时间,最大可创建的子进程的数量(静态模式下由此参数固定进程数)
pm.max_children = 300
; 设置启动时创建的子进程数目
pm.start_servers = 20
; pm.*_spare_servers 设置空闲服务进程的最低/最大数目
pm.min_spare_servers = 20
pm.max_spare_servers = 300
; 进程的超时时间,当进程不提供服务后,多少秒关闭,默认10s
pm.process_idle_timeout = 10s
; 一个子进程处理多少个请求后退出,默认 0
pm.max_requests = 10240
|