架构师之路(一)Nginx系列之web 服务优化

1、Nginx 基本安全优化

1.1 隐藏服务版本号

位置:http、server、location
代码:server_tokens: off;

1.2 更改源码,修改软件名及版本号

修改三个文件:
nginx-1.6.3/src/core/nginx.h
nginx-1.6.3/src/http/ngx_http_header_filter_module.c
nginx-1.6.3/src/http/ngx_http_special_response.c

1.3 更改nginx的默认用户

useradd nginx -s /sbin/nologin -M
默认为nobody;主配置文件:
user  nginx nginx;
nginx work进程的用户。

2、根据参数优化nginx服务性能

2.1 优化nginx服务的worker进程个数

worker_processes 1;
进程数可以是CPU的核数*2;
# 查看系统有多少核心
 grep processor /proc/cpuinfo | wc -l
# 查看有几颗cpu
 grep 'physical id' /proc/cpuinfo | sort | uniq |wc -l

2.2 绑定不同的nginx进程到不同的cpu上

work_processes  4;
worker_cpu_affinity  0001 0010 0100 1000;

2.3 nginx 事件处理模型优化

events {  # events 指令是设定nginx的工作模式和连接数上限
  use epoll;
  worker_connections 20480;  # 单个进程允许的客户端最大连接数;
}


进程的最大连接数受linux 系统进程d的最大打开文件数限制。

2.4 nginx worker进程最大打开文件数

worker_rlimit_nofile 65535;
最大打开文件数,可以设置为系统优化后d的ulimit -HSn 的结果。
放置位置:主标签段

2.5 优化服务器域名的散列表大小

放置位置:仅能放置在http 标签端
server_name_hash_max_size 512; # 默认是512kb
server_name_hash_bucket_size 64;

2.6 高效文件传输模式

sendfile on;
tcp_nopush on;
tcp_nodelay on; # 开启这俩on,可以防止网络和磁盘io阻塞,提高nginx工作效率。

2.7 调整连接超时时间

keepalive_timeout 60;  # 长连接超时时间
client_header_timeout 15; # 读取客户端请求头数据的超时时间
client_body_timeout 15; # 读取客户端请求主体的超时时间
send_timeout 25; # 响应客户端的超时时间,如果在这个时间内,客户端没有接受任何数据,连接将被关闭。

2.8 设置最大的客户端请求主体大小

client_max_body_size 8m;
位置:http\server\location

2.9 fastcgi 调优

2.10 gzip压缩性能优化

gzip on;
gzip_min_length 1k; # 允许压缩页面d的最小字节数,建议设置为1k,小于1k可能越压越大。
gzip_buffers 4 32k;# 压缩缓冲区大小
gzip_http_version 1.1; #
gzip_comp_level 9;
gzip_types text/css text/xml applicaton/javascript;
gzip_vary on; 
# 这个选项可以让前段的缓存服务器缓存经过gzip 压缩的页面,比如用squid缓存经过nginx压缩的数据。

2.11 expires 缓存实现性能优化

有可能不希望被缓存的内容:
1、广告图片,用户广告服务,都缓存了就不好控制展示了
2、网站流量统计工具(js代码),都缓存了流量统计就不准了
3、更新很频繁的文件

3、nginx 日志相关优化与安全

3.1 编辑脚本实现nginx access日志轮询

3.2 不记录不需要的访问日志

location ~ .*\.(js|jpg|JPG|css|gif|GIF)$ {
  access_log off;
}

3.3 访问日志的权限设置

# 加入日志目录为/app/logs,则授权方法如下
chown -R root.root /app/logs
chmod -R 700 /app/logs

4、nginx站点目录及文件url访问控制

4.1 根据扩展名限制访问

location ~* ^/data/(attacgment|avatar)/.*\.(php|php5)$ {
  deny all;
}
# 对上述目录d的限制必须在nginx 处理php 服务配置的前边。
location ~ .*\.(php|php5)$ {
  fastcgi_pass 127.0.0.1:9000;
  fastcgi_index index.php;
}

 

4.2 禁止访问指定目录下的所有文件

# 禁止访问多个目录
location ~* ^/data/(js|static) {
  deny all;
}
# 禁止访问并返回指定d的状态码
location ~* ^/data/(js|static) {
  return 403;
}

4.3 限制来源ip访问

使用ngx_http_access_module限制网站来源ip访问。

if ( $remote_addr = 10.0.0.7 ) {
  return 403;
}
location / {
  root html/blog;
  allow 10.0.0.7;
  deny all;
}

对于allow的ip端,从允许访问的端位从小到大排列,例如/24的下边才能是/16,下边是/8.

以deny all;结尾的,表示除了上边允许的,其他都是禁止的。

4.4 禁止ip访问

server {
listen 80 default_server;
server_name _;
return 444;
}
server {
listen 80 default_server;
server_name _;
rewrite ^ http://www.houbinglei.com$request_uri?;
}

# There is nothing special about this name, it is just one of a myriad of invalid domain names which never intersect with any real name. Other invalid names like “--” and “!@#” may equally be used.

if ( $host !~ ^www.houbinglei.com$ ) {
  rewrite ^(.*) http://www.houbinglei.com$request_uri?;
}

#  Nginx 的 $host 与 $http_host 的区别

$host 是nginx的官方变量,可以从官方查询
$http_host 则是读取请求头header里面的key,所有请求头里面的key在nginx里面都可以通过小写和下划线来让nginx读取。例如header里面的Host就能转成$http_host, user_agent可以转成$http_user_agent。
所以,只要是header的请求头都可以这样被nginx读取,

HEAD /rec/app/detail/youxidaren.html HTTP/1.1
Host: mo.ouwan.com
Content-type: html/txt
Test-key: test-value

HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Thu, 22 Mar 2018 12:28:56 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Vary: Cookie
# 这三个头都是我请求的时候加的。
x_host: mo.ouwan.com
x_test_key: test-value
x_content_type: html/txt

当然这个几个头部能在response显示是因为在nginx加了add_header控制的:

location / {
        add_header x_host   $http_host;
        add_header x_test_key $http_test_key;
        add_header x_content_type $http_content_type;
}

$http_header的应用:当我们一个项目部署在两个服务器下面,然后在另外一个服务器搭建nginx反响代理,反响代理把请求转发给两个服务器的时候,他们的日志记录的是反向代理的ip, 而不是真正请求的用户IP, 这时就可以通过配置proxy_set_header 把真实IP设置给一个X-forwarded-For 或者 X-Real-IP 转给后端服务器,然后后端服务器读取通过http_x_real_ip来读取真实IP, 记录到access_log下面

location / {
                proxy_pass http://tg_web_cluster;
                proxy_set_header Host      $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                # proxy_set_header X-Forwarded-Proto $scheme;
        }

日志的格式把第一个IP换成刚才转发过来的头部X-Real-IP就可以记录用户IP了:

 log_format tg_log '$http_x_real_ip - $remote_user [$time_local] '
                '"$request" $status $body_bytes_sent '
                '"$http_referer" "$http_user_agent" "$gzip_ratio" - $request_time';

5、nginx图片及目录防盗链解决方案

防止别人盗用你的链接。

# referer 
# 请求从哪里过来的,通过这个字段,阻止一些不可认的请求。
ngx_http_referer_module 模块用于在referer请求头字段阻止无效的值请求访问。
示例:
location ~* \.(gif|jpg|png|mp4)$ {
    valid_referers none blocked server_names   # none 是没有这个referers这个值, blocked是这个值是空;
                   *.nextdevops.cn nextdevops.* www.example.org/images/
                   ~\.google\. ~\.baidu\.;
    if ($invalid_referer) {
        return 403;}
    expires 3d;  # 设置3天d的浏览器缓存。    
         }

ngx_http_secure_link_modle模块用于检测请求连接的真伪,保护资源未授权访问,并限制连接。

该模块提供了两种操作模式:
a) secure_link和secure_link_md5指令启用,定义URL传参的变量,从中提取md5值及有效期进行比对。

b) secure_link_secret指令启用,检查请求连接的真实性。

示例1:
location /download/ {
secure_link $arg_md5,$arg_expires; 
secure_link_md5 "$secure_link_expires$uri secret"; 
    if ($secure_link = "") {   ## 等于空,是不匹配
        return 403; }
    if ($secure_link = "0") {  ## 等于0,是有效期过了
        return 410;  }
... 
}


# 需要自己写脚本,客户端提前拿到md5值,和过期时间,生成$secure_link。
echo -n '2147483647/s/link127.0.0.1 secret' | \
openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d   

6、错误页面优雅显示

403  === 一般为服务器权限配置不当所致
404  === 资源不存在
502  === 一般为代理服务器下边d的节点出了问题
error_page 404  /404.html;
代码中d的/ 是相对于站点根目录 html/www 的
error_page 400 401 402 403 http://xxxx/error1.html
error_page 500 501 502 503 http://xxxx/error2.html

7、nginx站点目录及目录权限优化

# 单机lnmp环境
所有的目录755,文件644,所有目录和文件用户和组都是root;
然后把用户上传资源的目录权限设置为755,将用户和组设置为nginx 服务用户;
最后对该目录做资源访问限制。
# 集群架构中
动态web集群,nginx+php,755,644,都是root
静态资源集群,nginx,755,644,都是root
上传资源upload集群,用户上传资源的目录权限设置为755,将用户和组设置为nginx 服务用户。

8、防爬虫优化

每个网站都有的爬虫协议说明robots.txt-->希望大家遵守的,也是防止爬虫的一种方法

# 我们可以根据客户端的user-agents信息,轻松地阻止指定的爬虫爬取我们的网站。
if ($http_user_agent ~* "qihoobot|Baiduspider|Googlebot-Modile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Yahoo! SSlurp  China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot")
{
    return 403;
}

9、利用Nginx限制http的请求方法

最常用的HTTP方法为GET,POST,我们可以通过Nginx限制HTTP请求的方法来达到提升服务器安全的目的,例如,让HTTP只能使用GET,HEAD和POST方法的配置如下:

# Only allow these request methods
if ($request_method ! ~ ^(GET|HEAD|POST)$)
{
    return 501;
}

当上传服务器上传数据到存储服务器时,用户上传写入的目录就不得不给Nginx对应的用户相关权限,这样一旦程序有漏洞,木马就有可能被上传到服务器挂载的对应存储服务器的目录里,虽然我们也做了禁止PHP,SH,PL,PY等扩展名的解析限制,但还是会遗漏一些想不到的可执行文件。对于这样情况可以通过限制上传服务器的Web服务(可以具体到文件)使用GET方法,防止用户通过上传服务器访问存储内容,让访问存储渠道只能从静态或图片服务器入口进入。例如,在上传服务器上限制HTTP的GET方法的配置如下:

Only deny GET request methods ##
if ($request_method ~* ^(GET)$)
{
    return 501;
}
#提示:还可以加一层location,更具体地限制文件名

10、CDN网站加速

首先要说的是,不是所有的网站都可以一上来就能用CDN的。要加速的业务数据应该存在独立的域名,例如:img1-4.yunjisuan.com/video1-4.yunjisuan.com,业务内容图片,附件,JS,CSS等静态元素,这样的静态网站域名才可以使用CDN。

;A records
img.yunjisuanl.com IN A 124.106.0.21 (企业服务器的IP)
#删除上面的记录,命令如下:
img.yunjisuanl.com IN A 124.106.0.21 (服务器的IP)
#然后,做下面的别名解析:
;CNAME records
img.yunjisuan.com IN CNAME bbs
img.yunjisuan.com 3M IN CNAME img.yunjisuan.com.cachecn.com.

提示:

这个img.yunjisuan.com.cachecn.com.地址必须是事先由CDN公司配置好的CDN公司的域名。国内较大的CDN提供商为网宿,蓝讯,快网。

11、nginx 程序架构优化

分离的最佳方式是分别使用独立的服务器(需要改动程序),如果程序实在不易更改,次选方案是在前端负载均衡器Haproxy/Nginx上,根据URI(例如目录或扩展名)过滤请求,然后抛给后面对应的服务器。

12、使用普通用户启动nginx ( 监牢模式)

useradd inca
su - inca
mkdir conf logs www     #在普通用户家目录下创建nginx配置文件目录
cp /usr/local/nginx/conf/mime.types ~/conf/
echo "hehe" > www/index.html
# 在普通用户的家目录里的conf目录里创建主配置 文件 主配文件的路径全部找/home/inca
# 特权用户root使用的80端口,改为普通用户使用的端口,在1024以上.8080
[inca@nginx-web01 ~]$ cat conf/nginx.conf 
worker_processes    4;
worker_cpu_affinity 0001 0010 0100 1000;
worker_rlimit_nofile 65535;
error_log    /home/inca/logs/error.log;
user inca inca;
pid    /home/inca/logs/nginx.pid;
events {
    use    epoll;
    worker_connections    10240;
}
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.inca.com;
        root    /home/inca/www;
        location / {
            index   index.php index.html index.htm;
        }
        access_log  /home/inca/logs/web_blog_access.log main;
    }
}


/usr/local/nginx/sbin/nginx -c /home/wk/conf/nginx.conf &>/dev/null 

13、控制nginx 并发连接数量

ngx_http_limit_conn_module这个模块用于限制每个定义的key值的连接数(Nginx默认已经被编译),特别是单IP的连接数。

不是所有的连接数都会被计数。一个符合计数要求的连接是整个请求头已经被读取的连接。

应用场景之一是用于服务器下载,命令如下:

location /download/ {
    limit_conn addr 11;
}
上面的命令限制访问download下载目录的连接数,该连接数1.

不仅可以限制单IP的并发连接数,还可以限制虚拟主机总连接数,甚至可以对两者同时限制。

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    limit_conn_zone $binary_remote_addr zone=addr:10m;  #设置参数下边才会生效
    limit_conn_zone $server_name zone=perserver:10m;   #设置参数下边才会生效
    server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html;
            index  index.html index.htm;
        #limit_conn addr 1;
        limit_conn perserver 2;     #设置虚拟主机连接数为2
        }
    }

14、控制客户端请求nginx的速率

ngx_http_limit_req_module模块用于限制每个IP访问每个定义key的请求速率。

ab 每秒发送300个, 设置limit_req 每秒处理100个:

limit_req_zone $binary_remote_addr zone=qps:10m rate=100r/s;
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;    #以请求的客户端IP作为key值,内存区域命令为one,分配10m内存空间,访问速率限制为1秒1次请求(request)
#    limit_conn_zone $binary_remote_addr zone=addr:10m;
#    limit_conn_zone $server_name zone=perserver:10m;
    server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html;
            index  index.html index.htm;
            limit_req zone=one burst=5;   #使用前面定义的名为one的内存空间,队列值为5,即可以有5个请求排队等待
#           limit_conn addr 1;
#           limit_conn addr 1;
        }
    }
发布了51 篇原创文章 · 获赞 0 · 访问量 477

猜你喜欢

转载自blog.csdn.net/qq_40902339/article/details/103501925