Nginx配置文件性能微调
全局的配置
user www-data;
pid /var/run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 100000;
worker_process定义了nginx对外提供Web服务时的worker进程数,起始可以设置为CPU的核数,CPU核数是多少就设置为多少(设置为"auto"将自动检测)
worker_rlimit_nofile更改worker进程的最大打开文件限制,如果没设置的话,这个值为操作系统的限制.设置后你的操作系统和Nginx可以处理比"ulimit -a"更多的文件,所以把这个值设高,这样nginx就不会有"too many open files"问题了
Event模块部分
events {
worker_connections 2048;
multi_accept on;
use epoll;
}
worker_connections设置可由一个worker进程同时打开的最大连接数.如果设置了上面提到的worker_rlimit_nofile,我们可以将这个值设得很高
注意:最大客户数也由系统的可用socket连接数限制(~ 64K),所以设置不切实际的高没什么好处
multi_accept告诉nginx收到一个新连接通知后接受尽可能多的连接
use epoll使用epoll模型,效率更高
HTTP模块部分
http {
server_tokens off;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
...
}
service_tokens隐藏Nginx版本号
sendfile可以让sendfile()发挥作用.sendfile()可以在磁盘和TCP socket之间互相拷贝数据(或任意两个文件描述符)
默认是Pre-sendfile,传送数据之前在用户空间申请数据缓冲区,之后用read()将数据从文件拷贝到这个缓冲区,write()将缓冲区数据写入网络.sendfile()是立即将数据从磁盘读到OS缓存,sendfile()要比组合read()和write()以及打开关闭丢弃缓冲更加有效
tcp_nopush告诉nginx在一个数据包里发送所有头文件,而不一个接一个的发送
tcp_nodelay告诉nginx不要缓存数据,而是一段一段的发送--当需要及时发送数据时,就应该给应用设置这个属性,这样发送一小块数据信息时就不能立即得到返回值
keepalive_timeout 10;
client_header_timeout 10;
client_body_timeout 10;
reset_timedout_connection on;
send_timeout 10;
keepalive_timeout 给客户端分配keep-alive链接超时时间.服务器将在这个超时时间过后关闭链接.我们将它设置低些可以让ngnix持续工作的时间更长
client_header_timeout和client_body_timeout 设置请求头和请求体(各自)的超时时间,在一定时间内收不到客户端的请求头请求体就关闭连接
reset_timedout_connection 告诉nginx关闭不响应的客户端连接.这将会释放那个客户端所占有的内存空间
send_timeout指定客户端的响应超时时间.这个设置不会用于整个转发器,而是在两次客户端读取操作之间.如果在这段时间内,客户端没有读取任何数据,nginx就会关闭连接
limit_conn_zone $binary_remote_addr zone=addr:5m;
limit_conn addr 100;
limit_conn_zone设置用于保存各种key(比如当前连接数)的共享内存的参数.5m就是5兆字节,这个值应该被设置的足够大以存储(32K*5)32byte状态或者(16K*5)64byte状态
limit_conn addr为给定的key设置最大连接数.这里key是addr,我们设置的值是100,也就是说我们允许每一个IP地址最多同时打开有100个连接
include /etc/nginx/mime.types;
default_type text/html;
charset UTF-8;
include只是一个在当前文件中包含另一个文件内容的指令。这里我们使用它来加载稍后会用到的一系列的MIME类型
default_type设置文件使用的默认的MIME-type
charset设置我们的头文件中的默认的字符集
gzip on;
gzip_min_length 1k; #最小1K的文件才启动压缩
gzip_buffers 4 32k; #压缩过程都写到buffer里面,压缩完成才发给客户端
gzip_http_version 1.1;
gzip_comp_level 9; #压缩的级别
gzip_types text/css text/xml application/javascripts; #对什么样的内容压缩
gzip_vary on; #让前边的缓存服务器识别压缩后的文件
gzip是告诉nginx采用gzip压缩的形式发送数据,这将会减少我们发送的数据量
gzip_min_length设置对数据启用压缩的最少字节数.如果一个请求小于1K,我们最好不要压缩它,因为压缩这些小的数据会降低处理此请求的所有进程的速度
gzip_buffers
gzip_http_version是http协议
gzip_comp_level设置数据的压缩等级.这个等级可以是1-9之间的任意数值,9是最慢但是压缩比最大的.我们设置为4,这是一个比较折中的设置
gzip_types设置需要压缩的数据格式
gzip_vary 让前边的缓存服务器识别压缩后的文件
open_file_cache max=100000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
open_file_cache打开缓存的同时也指定了缓存最大数目,以及缓存的时间.我们可以设置一个相对高的最大时间,这样我们可以在它们不活动超过20秒后清除掉
open_file_cache_valid在open_file_cache中指定检测正确信息的间隔时间
open_file_cache_min_uses 定义了open_file_cache中指令参数不活动时间期间里最小的文件数
open_file_cache_errors指定了当搜索一个文件时是否缓存错误信息,也包括再次给配置中添加文件.我们也包括了服务器模块,这些是在不同文件中定义的.如果你的服务器模块不在这些位置,你就得修改这一行来指定正确的位置
Nginx expires缓存
介绍
简单的说,nginx expire功能就是为用户访问的访问内容设定一个过期时间,当用户第一次访问到这些内容时,会把这些内容存储在用户浏览器本地,这样用户第二次访问该网站,浏览器会加载检查已经缓存在用户浏览器恩地的内容,就不去服务器下载了
作用
在网站开发和运营中,对于视频、图片、css、js等不长修改的元素缓存在客户浏览器本地.
图片可以缓存365天,css、js、html等代码缓存10-30天,这样用户第一次打开页面后,会按过期时间在客户浏览器缓存上述内容,下次用户在打开页面的时候重复的元素就无需加载了可放位置:
http server location,我们一般放在location段根据匹配规则设置过期时间
配置
location ~ .*.(gif|jpg|jpeg|png|bmp|swf)${
expires 3650d;
}
location ~ .*.(js|css)?$ {
expires 30d;
}
location image {
expires 1d;
}
Nginx日志相关优化与安全
配置日志切割
编写脚本实现nginx日志轮询
vim cut_nginx_log.sh
#!/bin/bash
cd /application/nginx/log
/bin/mv www_access.log www_access_$(date +%F -d -1day).log
/application/nginx/sbin/nginx -s reload
将脚本加入定时任务定期执行
crontab -e
00 00 * * * /bin/sb /root/cut_nginx_log.sh > /dev/null 2 >&1
不需要记录的日志
比如访问一些图片等是不需要记录日志的
location ~ .*. (js|jpg}JPG|jpeg|css|bmp|gif|GIF|)$ {
access_log off;
}
说明:用location标签匹配不记录日志的元素扩展名,然后关掉日志
Nginx站点目录及文件URL访问控制
根据扩展名限制程序和文件访问
location ~ ^/images/.*.(php|php5|.sh|.pl|.py)$ {
deny all;
}
location ~ ^/static/.*.(php|pph5|.sh|.pl|.py)$ {
deny all;
}
说明:用location标签匹配不被解析的文件,然后关掉访问权限
禁止访问指定目录下所有的文件和目录
单目录
location ~ ^/(static)/ { #写法一
deny all;
}
location ~ ^/static { #写法二
deny all'
}
多目录
location ~ ^/(static|image) {
deny all;
}
禁止访问指定目录,如果访问就返回404
location /admin/ {
return 404;
}
location /templates/ {
return 403;
}
限制来源IP访问
应用场景:网站后台,只允许个别IP或者网段访问
location ~ ^/oldboy/{
allow 192.168.0.20;
deny all;
}
location ~ ^/admin/ {
deny 192.168.0.1;
allow 192.168.0.0/24;
allow 10.1.1.0/16;
deny all; #一旦deny all;下面就不能再接IP或者IP段了
}
Nginx防止恶意解析
什么是恶意解析
假如你们公司里web服务器是多台组成的一个集群,所以IP是不一样的,对方在ping你们域名的时候会出来一个IP,但是这个IP不是万网对应你们域名的IP,然后他们拿到这个IP,在万网上边把他们的域名解析到你这个IP上来,这就造成一个问题:如果他们的域名没备案的话,公安局就会一直找你们公司
解决方案
让使用IP直接访问网站的,或者访问恶意解析到你们公司IP的域名,收到501错误
配置
server { #这个虚拟主机必须放在其他虚拟主机的前边
listen 80 default_server;
server_name _;
return 501;
}
说明:假如nginx多个虚拟主机,如果直接访问IP的话,nginx会默认访问第一个虚拟主机,所以通过IP直接访问的话就是访问第一个虚拟主机,就会报501错误,如果其他域名恶意解析到你这个IP上了也会返回501错误
Nginx配置防盗链
什么是资源盗链
假如把别人网站上的一段视频或一张图片,复制链接,然后放在自己的网站上,用户来自己网站访问这些内容的时候,承受负担和流量的是别人的服务器
常见防盗链解决方案基本原理
根据http referer实现防盗链
在HTTP协议中,有一个表头字段叫referer,使用URL格式来表示从哪里来的链接到当前网页的资源.
通过referer可以检测目标访问的来源网页,如果是资源文件,可以跟踪到显示它的网页地址,一旦检测出来不是本站,马上执行阻止或者返回指定图片、错误信息等
一句话说明:只允许指定的域名使用资源文件,如果其他域名使用则返回指定错误信息
什么是HTTP referer
HTTP referer是header的一部分,当浏览器向Web服务器发送请求的时候,一般会带上referer,告诉我服务器我是从哪个页面链接过来的.
配置通过referer实现防盗链
编辑nginx.conf配置文件,加入第三个location字段部分,可以根据实际情况修改
vim nginx.conf
server {
listen 80;
server_name blog.etiantian.org;
root html/blog;
location / {
index index.php index.html index.htm;
}
location ~ .*.(php|php5)?$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
location ~* .(jpg|gif|png|swf|flv|wma|asf|mp3|mmf|zip|rar)$ {
valid_referers none blocked *.etiantian.org etiantian.org #允许使用资源文件的域名
if ($invalid_referer){ #如果不是上边允许的域名使用资源文件的时候,就返回另一张图片,或者返回403也可以
rewrite ^/http://blog.etiantian.org/img/nolink.jps
}
#通过location匹配需要防盗的资源文件
}
access_log logs/access_blog.log main;
}
Nginx错误页面优雅显示
参数:error_page
可放位置:http,server
原理:如果发现404错误等,也可以是其他错误代码,自动跳转到某个页面(页面自定义)
配置404优雅显示
编辑nginx.conf配置文件,放在server下面就是针对某个虚拟主机的404做优雅显示,放在http就是对所有虚拟主机的404做优雅显示
vim nginx.conf
server {
listen 80;
server_name blog.etiantian.org;
root html/blog;
location / {
index index.php index.html index.htm;
}
location ~ .*.(php|php5)?$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
#方法一
error_page 404 /error/404.html #如果发现404错误就跳转到html/blog/error/404.html页面
#方法二
error_page 404 www.baidu.com #如果发现404错误就跳转到www.baidu.com
方法三
error_page 404 403 /error/404.html #如果发现404、403错误就跳转指定页面
access_log logs/access_blog.log main;
}
Nginx站点目录文件及目录权限优化
单机LNMP环境,站点目录和文件属性设置如下
所有目录权限755 所有文件权限644 所有目录和文件属主属组都是root 用户上传资源的目录权限755,属主属组都是nginx服务用户
集群参考
Nginx限制HTTP请求
我们可以通过nginx限制http请求的方法来达到提升服务器安全的目的,例如:让http只能使用GET、HEAD、POST放的配置如下
if (request_method !~ ^T|HEAD|POST)$) {
return 501;
}
还可以通过限制上传服务器的Web服务(可以具体到文件)使用GET方法,来达到防止用户通过上传服务器访问存储内容,让访问存储渠道只能从静态或图片服务器入口进入,例如在上传上限制HTTP的GET方法
if ($request_method ~* ^(GET)$) {
return 501;
}
#请参考专业的nginx架构逻辑图
基于nginx Web服务linux系统内核参数优化
http://oldboy.blog.51cto.com/2561410/1336488
http://yangrong.blog.51cto.com/6945369/1321594
Nginx程序架构优化
为网站程序解耦
简单的说就是把一堆程序代码按照业务员用途分开,然后提供方服务,例如:注册登录、上传、下载、浏览列表、商品内容页面、订单支付等都应该是独立的程序服务,只不过在客户端看来是一个整体
中小公司必须做到以下几个程序模块独立
- 网页页面服务
- 图片附件及下载服务
- 上传图片服务
使用普通用户启动Nginx
为什么让Nginx服务使用普通用户
默认情况下,Nignx的master进程使用的是root用户,worker进程使用的是nginx指定的普通用户,使用root用户跑nginx进程有两个最大的问题
- 管理权限必须是root,
- 使用root跑nginx服务,一旦网站出现漏洞,用户就可以很容易的获得服务器的root权限
给nginx服务降权解决方案
- 给nginx服务降权,用inca用户跑nginx服务,给开发及运维设置普通账号,只要和inca同组即可管理nginx,该方案解决了nginx管理问题,防止root分配权限过大
- 开发人员使用普通账号即可管理nginx服务及其站点下的程序,看日志
给nginx服务降权实战
安装nginx使用root用户装到/application/nginx下
创建用来跑nginx的普通用户
[root@lnmp02 ~]# useradd inca
配置inca用户的nginx
[root@lnmp02 ~]# su - inca
[inca@lnmp02 ~]$ mkdir conf www logs
[inca@lnmp02 ~]$ touch conf/nginx.conf
[inca@lnmp02 ~]$ vim nginx.conf
worker_processes 1;
error_log /home/inca/logs/error.log;
user inca inca;
pid /home/inca/logs/nginx.pid;
events {
worker_connections 1024;
use epoll;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
server {
listen 8080;
server_name www.etiantian.org;
root /home/inca/www;
location / {
index index.html index.htm;
}
access_log /home/inca/logs/www_access.log main;
}
}
[inca@lnmp02 ~]$ cp /application/nginx/conf/mime.types /home/inca/conf/.
启动Nginx
[inca@lnmp02 ~]$ /application/nginx/sbin/nginx -c /home/inca/conf/nginx.conf
测试Nginx进程是否是inca用户
[inca@lnmp02 ~]$ ps -ef |grep nginx
inca 28697 1 0 02:50 ? 00:00:00 nginx: master process /application/nginx/sbin/nginx -c /home/inca/conf/nginx.conf #可以看到nginx进程已经是inca账户了
inca 28698 28697 0 02:50 ? 00:00:00 nginx: worker process
Nginx页面缓存
模块:proxy_cache
缓存静态的文件,例如:CSS、JS、图片等
无缓存时用户访问流程
有缓存时用户访问流程
应用场景:Nginx作为反向代理的时候做Web页面缓存
作用
Web缓存位于Web服务器和客户端之间,当用户访问一个URL时,Web缓存服务器会去后端服务器取回要输出的内容,当下一个请求到来时,如果访问的是相同的URL,Web缓存服务器直接输出内容给客户端,就不再次向后端服务器发出请求了,从而降低了Web服务器、数据库的负载,减少了网络延迟,提高了用户访问速度
proxy_cache相关指令集
proxy_cache_path
可放位置:http段
语法:proxy_cache_path path [levels=number] keys_zone=zone_name:zone_size[inactive=time] [max_size=size];
实例:proxy_cache_path /tmp/ngx_cache levels=1:2 keys_zone=cache_one:500m inactive=1d max_size=5g;
path:存放目录
levels:指定该缓存空间有两层目录hash目录,第一层目录为一个字母,第二层目录为两个字母,例如:/tmp/ngx_cache/c/29/xxxxxxxxxxxx
keys_zone:指定该缓存区的名字
500m:指内存缓存空间大小为500m
inactive:指定过期时间,如果缓存数据在1天内没有被访问就删除
max_size:的5g是指硬盘缓存空间为30G
作用:用于设置缓存文件的存放路径
proxy_cache_methods
可放位置:
语法:proxy_cache_methods[GET HEAD POST];
实例:proxy_cache_methods[GET HEAD];
作用:用于设置缓存哪些HTTP方法,默认缓存HTTP的GET/HEAD方法,不缓存POST方法
proxy_cache_min_uses
可放位置
语法:proxy_cache_min_uses the_number
实例:语法:proxy_cache_min_uses 1
作用:用于设置缓存最小使用次数,默认值为1
proxy_cache_valid
可放位置:location
语法:proxy_cache_valid reply_code [reply_code...] time ;
实例:proxy_cache_valid 200 304 12h;
实例:proxy_cache_valid 301 302 1m;
实例:proxy_cache_valid any 1m;
作用:设置200、304状态的URL缓存12h,301、302状态的URL缓存1m,其他的都缓存1m
proxy_cache_key
可放位置:location
语法:proxy_cache_key line ;
实例:proxy_cache_key $host$uri$is_args$args;
作用:用来设置Web缓存的key值,Nginx根据Key值md5哈希存储缓存,一般根据$host(域名),$request_uri(请求的路径)等变量组合成proxy_cache_key
proxy_cache
可放位置:location
语法:proxy_cache [name]
实例:proxy_cache cache_one
作用:调用http段定义的proxy_cache_path
proxy_set_header
可放位置:location
实例:roxy_set_header HOST $host;
实例:proxy_set_header X-Forwarded-For $remote_addr;
作用:记录host主机名和客户端IP地址
配置Nginx Web缓存
环境说明
nginx-proxy 192.168.0.93 nginx
realserver 192.168.0.94 nginx
配置realserver
安装Nginx省略
配置nginx虚拟主机
[root@realserver ~]# vim /application/nginx/conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 8080;
location / {
root html/test;
index index.html index.htm;
}
}
}
配置网站程序
[root@realserver ~]# vim /application/nginx/html/test/index.html
<img src="/root/test.jpg" />
启动nginx
[root@realserver ~]# /application/nginx/sbin/nginx
测试此虚拟主机
[root@realserver ~]# curl 192.168.0.94:8080/index.html #出来一张图片则为成功
配置Nginx Web缓存
安装Nginx省略
配置Nginx Web缓存
[root@nginx-proxy ~]# vim /application/nginx/conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
'"addr:$upstream_addr-status:$upstream_status- cachestatus:$upstream_cache_status"' ;
sendfile on;
keepalive_timeout 65;
proxy_cache_path /tmp/ngx_cache levels=1:2 keys_zone=cache:500m inactive=1d max_size=5g;
upstream server_pool{
server 192.168.0.194:8080;
}
server {
listen 80;
server_name www.etiantian.org;
location / {
proxy_pass http://server_pool;
proxy_cache cache;
proxy_cache_valid 200 304 12h;
proxy_cache_valid 301 302 1m;
proxy_cache_valid any 1m;
proxy_cache_key $host$uri$is_args$args;
proxy_set_header HOST $host;
proxy_set_header X-Forwarded-For $remote_addr;
expires 1d;
add_header Nginx-Cache "$upstream_cache_status"; #curl -I的时候可以查看是否命中
}
access_log logs/www_access.log main;
}
}
测试Nginx Web缓存
[root@nginx-proxy ~]# curl -I 192.168.0.93
HTTP/1.1 200 OK
Server: nginx/1.6.3
Date: Sun, 06 Nov 2016 00:25:20 GMT
Content-Type: text/html
Content-Length: 29
Connection: keep-alive
Last-Modified: Sat, 05 Nov 2016 23:37:38 GMT
ETag: "581e6d42-1d"
Expires: Mon, 07 Nov 2016 00:25:20 GMT
Cache-Control: max-age=86400
Nginx-Cache: MISS #可以看到第一次是MISS的,因为第一次请求Nginx还没缓存
Accept-Ranges: bytes
[root@nginx-proxy ~]# curl -I 192.168.0.93
HTTP/1.1 200 OK
Server: nginx/1.6.3
Date: Sun, 06 Nov 2016 00:25:23 GMT
Content-Type: text/html
Content-Length: 29
Connection: keep-alive
Last-Modified: Sat, 05 Nov 2016 23:37:38 GMT
ETag: "581e6d42-1d"
Expires: Mon, 07 Nov 2016 00:25:23 GMT
Cache-Control: max-age=86400
Nginx-Cache: HIT #可以看到第二次就命中了
Accept-Ranges: bytes