nginx 学习笔记

第一章 Nginx 简介

nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server

nginx 是一个高性能的HTTP反向代理web服务器

1.0 Basic HTTP server features

2.0 Other HTTP server features

3.0 TCP/UDP proxy server features

  1. IO 多路复用epoll

    什么是IO多路复用: 多个描述符的I/O操作都能在一个线程内并发交替地顺序完成,其中复用指复用同一个线程。

  2. 轻量级,功能模块化,代码模块化

  3. CPU亲和(afflinity)

    什么是CPU亲和: 是一种CPU核心和Nginx工作进程绑定的方式,把没一个Worker进程固定在一个cpu上执行,减少切换cpu的cache miss, 获取更好的性能。

  4. sendFile

第二章 基础篇

Nginx快速搭建

官网: http://nginx.org/

Mainline version 开发版本

Stable version 稳定版本

Legacy version 历史版本

Pre-Built Packages

有对应系统的安装方式 linux_package

vim /etc/yum.repos.d/nginx.repos

Nginx 基本命令使用

Ø -h:显示帮助信息

Ø -v:显示Tengine版本

Ø -m:显示所有静态编译的模块

Ø -l:显示所有可配置的指令

Ø -V:显示版本、编译安装时的选项、所有静态编译的模块

Ø -t:检查Tengine配置文件语法

Ø -s [stop | quit | reopen | reload]:关闭 | 退出 | 重新打开 | 重载Tengine

  start nginx
  nginx -s stop(快速停止nginx)  或  nginx -s quit(完整有序的停止nginx)
  nginx.exe -t # 测试conf
  nginx.exe -s reload #重新加载conf
  taskkill /IM  nginx.exe  /F # kill 所有后台nginx实例
  • Nginx 常用命令
  sudo nginx #打开 nginx
  nginx -s reload|reopen|stop|quit  #重新加载配置|重启|停止|退出 nginx
  nginx -t   #测试配置是否有语法错误

  nginx [-?hvVtq] [-s signal] [-c filename] [-p prefix] [-g directives]

  -?,-h           : 打开帮助信息
  -v              : 显示版本信息并退出
  -V              : 显示版本和配置选项信息,然后退出
  -t              : 检测配置文件是否有语法错误,然后退出
  -q              : 在检测配置文件期间屏蔽非错误信息
  -s signal       : stop(停止), quit(退出), reopen(重启), reload
  -p prefix       : 设置前缀路径(默认是:/usr/local/Cellar/nginx/1.2.6/)
  -c filename     : 设置配置文件(默认是:/usr/local/etc/nginx/nginx.conf)
  -g directives   : 设置配置文件外的全局指令

nginx -t 能查看配置文件所在目录

nginx: the configuration file /usr/local/tengine/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/tengine/conf/nginx.conf test is successful

阿里云后台配置文件路径:/usr/local/tengine/conf/nginx.conf

Nginx的目录和配置语法

Building nginx from Sources

https://nginx.org/en/docs/configure.html

Core functionality

https://nginx.org/en/docs/ngx_core_module.html

日志目录

tengine -> /usr/local/tengine/logs

查看nginx的配置

nginx -V

配置模块化

不同功能的配置文件尽量单独编写,使配置文件解耦

http {
    #导入servers/目录下所有conf文件
    include servers/*.conf;
}

错误处理

  1. 自定义错误页
   location /bbs {
       root /vhosts/bbs;
       error_page 404 404/404.html;
   }
   error_page 500 502 503 504 /50x.html;
   location = /50x.html {
           root /usr/share/nginx/html;
   }

Nginx 日志 log_fromat

简单的访问控制

基于来源IP实现访问控制

server{
    location / {
        # 网段的写法:192.168.1.0/24
        deny 192.168.1.222;
        # 从上到下进行匹配,类似iptables
        allow all;
    }

    location /bbs {
        if ( $remote_addr = 192.168.1.146 ) {
        return 404;
    }
}

基于用户名/密码实现访问控制

location /bbs {
    auth_basic "Please Login";
    auth_basic_user_file /usr/local/tengine/conf/.htpasswd;
}

设置账户密码

yum -y install httpd-tools
cd /usr/local/tengine/conf
htpasswd -c -m .htpasswd keyso     //用户名keyso,密码123456
nginx -t
nginx -s reload

htpasswd

-c:自动创建账号文件(仅在添加第一个用户时使用该选项)

-m:使用MD5加密用户密码

-s:使用SHA加密用户密码

-D:删除指定用户

禁止访问某一类资源

location ~ \.(txt|doc)$ {
    if (-f $request_filename){
        root html;
        break;
    }
    deny all;
}

Nginx 变量

HTTP请求变量 - arg_PARAMETER, http_HEADER, sent_http_HEADER

内置变量 - Nginx内置变量 Embedded Variables

自定义变量

server {
    set $foo hello;
    location /test/ {
        default_type application/json;
        return 200 '{"status":"${foo}/$foo"}';
    }
}
  • 定义范围:server{}

    放到外面报错nginx: [emerg] "set" directive is not allowed here

  • 初始化:在加载conf的时候,故没有set变量直接引用无法启动

server {
    listen 8080;

    location /foo {
        set $a hello;
        echo_exec /bar; #内部跳转a值不变
    }

    location /bar {
        #可以看出定义在location范围之外,赋值是在location内
        echo "a = [$a]"; 
    }
}

测试

[root@localhost html]# curl localhost/foo
#内部跳转a值不变
a = [hello]
[root@localhost html]# curl 'http://localhost/bar'
#外部跳转没有赋值
a = []

内建变量

参考 深度学习之 Nginx 变量

全局变量

参考 附录二 Nginx全局变量解析

Nginx 模块讲解

分为 官方模块,第三方模块
官方模块参数: Modules reference

常用的模块用法

ngx_http_stub_status_module 提供访问的基本状态信息

编译选项: –with-http_stub_status_module

用法

location /status {
    stub_status on;
    allow 192.168.101.120;
    deny all;
    access_log off;
}

ngx_http_random_index_module 随机Index.html

用法

location / {
    root /usr/src/nginx/;
     random_index on;
}

/usr/src/nginx/ 下新建1.html,2.html,3.html ,访问/ 会随机访问以上三个文件

ngx_http_sub_module 指定字符串的替换

编译选项: --with-http_sub_module

location / {
    sub_filter '<a href="http://127.0.0.1:8080/'  '<a href="https://$host/';
    sub_filter '<img src="http://127.0.0.1:8080/' '<img src="https://$host/';
    sub_filter_once on; ## 默认为全部替换,开启替换一次
}

Nginx 请求限制

链接频率限制 :

ngx_http_limit_conn_module

this module is used to limit the number of connections per the defined key, in particular, the number of connections from a single IP address.

Not all connections are counted. A connection is counted only if it has a request being processed by the server and the whole request header has already been read.

Directives

Syntax: **limit_conn** *zone* *number*;
Default:
Context: http, server, location

Example Configuration

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;

server {
    ...
    limit_conn perip 10; #每个IP allow 10 connections 
    limit_conn perserver 100;#每个服务 allow 10 connections 
}

注意:HTTP/2 复用的连接是分开计数的,原文:
In HTTP/2 and SPDY, each concurrent request is considered a separate connection.

请求频率限制 :

ngx_http_limit_req_module

this module (0.7.21) is used to limit the request processing rate per a defined key, in particular, the processing rate of requests coming from a single IP address. The limitation is done using the “leaky bucket” method.

Example Configuration

limit_req_zone $binary_remote_addr zone=perip:10m rate=1r/s;
limit_req_zone $server_name zone=perserver:10m rate=10r/s; #(r/m)
server {
    ...
    limit_req zone=perip burst=5 nodelay;
    limit_req zone=perserver burst=10;
}

- burst 下一个周期继续响应5个reqest超过1r/s,当超过5个request的时候看 [nodelay | delay=number] 怎么处理

Directives

| Syntax: | **limit_req** zone=*name* [burst=*number*] [nodelay | delay=*number*]; |
| :——- | ———————————————————— |
| Default: | — |
| Context: | http, server, location |

Nginx 访问控制

auth_mod.conf

基于IP

| Syntax: | **allow** *address* | *CIDR* | unix: | all; |
| :——- | ——————————————— |
| Default: | — |
| Context: | http, server, location, limit_except |

CIDR 网段

Sample Configuration

location / {
    deny  192.168.1.1;
    allow 192.168.1.0/24;
    allow 10.1.1.0/16;
    allow 2001:0db8::/32;
    deny  all;
}

过个IP用ngx_http_geo_module定义

access_module存在的局限性,及当client通过代理访问是remote_addr是不同的

解决方案一

存在问题是,http_x_forwarded_for是协议要求,厂商可以不实现且可以修改

解决方案二 HTP自定义变量

基于用户信任登录

Sample Configuration

location / {
    auth_basic           "Auth access test ! input your password!";
    auth_basic_user_file conf/htpasswd;
}

auth_basic_user_file

# comment 用户名:密码:描述
name1:password1
name2:password2:comment
name3:password3

加密密码:htpasswd

yum install httpd-tools -y 
htpasswd -c ./auth_conf jeson # -c 指定生成文件 jeson 用户名

局限性

  1. 用户信息依赖文件方式
  2. 操作管理机械,效率低下

解决方案:

  1. Nginx结合LUA实现高效验证
  2. Nginx和LDAP打通,利用nginx-auth-ldap模块

第三章 场景实践

Nginx作为静态资源WEB服务

1, 静态资源服务场景-CDN

2 配置语法

tcp_nopush
原理:多个包集中发送,适合大文件开启

Syntax: tcp_nopush on | off;
Default: tcp_nopush off;
Context: http, server, location 

作用: sendfile开启的情况下,提高网络包的传输效率

tcp_nodelay

Syntax: tcp_nodelay on | off;
Default: on
Context: http, server, location 

作用: keepalive连接下,提高网络包的传输实时性;

3. 压缩

Sample_confuration

gzip            on;
gzip_min_length 1000;
gzip_proxied    expired no-cache no-store private auth;
gzip_types      text/plain application/xml;

压缩

Syntax: gzip on | off;
Default: off;
Context: http, server, location, if in location

压缩比

Syntax: gzip_comp_level level;
Default: 1;
Context: http, server, location

压缩版本

Syntax: gzip_http_version 1.0 | 1.1;
Default: gzip_http_version 1.1; # 主流
Context: http, server, location

4 浏览器缓存原理

客户端浏览器缓存原理

etag lastmodified 缓存原理流程图

Expires 配置语法

Syntax: expires  [modified] time;
        expires epoch | max | off;
Default: expires off;
Context: http, server, location, if in location

Sample 以.html/htm结尾的文件过期时间为24小时

location ~ .*\.(htm|html)$ {
    expires 24h;
    root /opt/app/code;
}

5 跨域访问

  1. 浏览器禁止跨域的原因
    不安全容易出现CSRF攻击! CSRF攻击是攻击者利用用户的身份操作用户帐户的一种攻击方式,通常使用Anti CSRF Token来防御CSRF攻击,同时要注意Token的保密性和随机性。
  location / {
        add_header 'Access-Control-Allow-Origin' '*'; # * 允许所有站点跨域访问
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' '*'; # GET,POST,PUT,DELETE,OPTIONS; * 指所有 
        proxy_pass http://localhost:8088;
        # proxy_redirect off ;
        index index.php index.html index.htm;
}

配置Nginx 允许多个域名跨域访问

异常

No'Access-Control-Allow-Origin' header is present on the requested resourse.Origin 'http//localhost:8088' is therefore not allowed access.

解决

map $http_origin $corsHost {
    default 0;
    "~http://www.haibakeji.com" http://www.haibakeji.com;
    "~http://m.haibakeji.com" http://m.haibakeji.com;
    "~http://wap.haibakeji.com" http://wap.haibakeji.com;
}
server
{
    listen 80;
    server_name www.haibakeji.com;
    root /nginx;
    location /
    {
        add_header Access-Control-Allow-Origin $corsHost;
    }
}

6 防盗链接

原因: 1. 防止资源被盗用,2. 防止非法抓取资源导致网站卡顿;

http_refer

Syntax: valid_referers none | blocked | server_names | string ...;
Context: server, location

请求头为指定值时, 内嵌变量$invalid_referer被设置为空字符串, 否则这个变量会被置成“1”。查找匹配时不区分大小写。

  • blocked:“Referer” 请求头存在,但是它的值被防火墙或者代理服务器删除;这些值都不以“http://” 或者 “https://”字符串作为开头;
  • none:缺少“Referer”请求头;
  • server_names:“Referer” 请求头包含某个虚拟主机名;

正则表达式:必须以“~”符号作为开头。 需要注意的是表达式会从“http://”或者“https://”之后的文本开始匹配。

Sample

location ~ .*.(jpg|gif|png)$ {
    # 允许那些referers信息进行访问 
    # ndne 允许没有带referer信息的过来
    # blocked 允许没有带协议信息,如http的
    # ~/google\./ #所有 ~/google\./过来的
    valid_referers none blocked 116.62.103.228 ~/google\./; 
    if ($invalid_referer){
        return 403;
    }
}

利用nginx“ngx_http_referer_module”模块设置防盗链

Nginx作为代理服务

nginx 支持的代理类型

代理分为正向代理和反向代理

fx_proxy.conf

模板设置

server{
    listen 80;
    server_name locahost jeson.t.imooc.io;
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_redirect default;
        #访问日志配置, 传递真的地址给proxy,而不是当前nginx
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;

        proxy_connect_timeout 30; #30s
        proxy_send_timeout 60;
        proxy_read_timeout 60;

        proxy_buffer_size 32k;
        proxy_buffering on; 
        proxy_buffers 4 128k;
        proxy_busy_buffers_size 256k;
        proxy_max_temp_file_size 256k; #config时指定 --http-proxy-temp-path=
        #当出现一下异常是启用下一个 upstream
         proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
    }
}

文件形式导入

location {
    include proxy_params;
}

proxy_params;

proxy_redirect default;

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;

proxy_connect_timeout 30; #30s
proxy_send_timeout 60;
proxy_read_timeout 60;

proxy_buffer_size 32k;
proxy_buffering on; 
proxy_buffers 4 128k;
proxy_busy_buffers_size 256k;
proxy_max_temp_file_size 256k; #config时指定 --http-proxy-temp-path=

转发路径规则

真实请求路径http://localhost/online/wxapi/test/loginSwitch

第一种:proxy_pass 结尾有/

location /online/wxapi/ {
        proxy_pass http://localhost:8080/; #转发不代 location 路径
}

代理结果:http://localhost:8080/test/loginSwitch

第二种:proxy_pass 结尾没有/

location /online/wxapi/ {
        proxy_pass http://localhost:8080;#转发代 location 路径
}

代理结果:http://localhost:8080/online/wxapi/test/loginSwitch

第三种:proxy_pass 结尾有/web

location /online/wxapi/ {
        proxy_pass http://localhost:8080/web;#转发location路径,直接拼接,不带`/`分割符
}

代理结果:http://localhost:8080/webtest/loginSwitch

第二种:proxy_pass 结尾没有/web/

location /online/wxapi/ {
        proxy_pass http://localhost:8080/web/;#转发代 location 路径
}

代理结果:http://localhost:8080/web/test/loginSwitch

实战

location ^~ /static/ 
{     
    #不传 static
    # curl http://localhost:3000/static/index.html
    # proxy_pass 转发为 http://www.test.com/index.html
    proxy_pass http://www.test.com/; 

    #传 static
    # curl http://localhost:3000/static/index.html
    # proxy_pass 转发为 http://www.test.com/static/index.html
    proxy_pass http://www.test.com; 
}

location /forum {
    #http://node1.qiuyue.com/forum ->  http://192.168.1.144/bbs
    proxy_pass http://192.168.1.144/bbs;
    index index.html index.html;
}

#jpg、png或者gif结尾的请求反代
location ~* \.(jpg|png|gif)$ {
    proxy_pass http://192.168.1.144;
}

Nginx作为负载均衡服务

按区域可分为GSLB,SLB

Example Configuration

upstream backend {
    ip_hash; #调度方式 hash 
    server backend1.example.com   weight=5;
    server backend2.example.com:8080 max_fails=3 fail_timeout=30s;;
    server unix:/tmp/backend3 backup; 

    server backup1.example.com:8080   backup;
    server backup2.example.com:8080   backup;
}

server {
    location / {
        proxy_pass http://backend;

    }
}

调度算法

ip_hash 有代理问题

upstream imooc {
    hash $request_url; #可以提取URL指定位置进行hash
}

Nginx作为缓存服务

proxy_cache_path /opt/app/cache levels=1:2 keys_zone=imooc_cache:10m max_size=10g inactive=7d max_size=10g use_temp_path=off;

proxy_cache_path

keys_zone = 1m # 1m可以存储8000个

inactive = 60m# 60分钟内不访问就把他清除掉

use_temp_path = off; #关闭零时文件存储,开启同时和 cache_path 使用可能会产生性能损耗

location / {

    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_cache imooc_cache;
    proxy_cache_valid 200 304 12h; #头部为返回为200 304 12小时过期
    proxy_cache_valid any 10m; #其他的10m过期
    proxy_cache_key $host$uri$is_args$args;
    add_header Nginx-Cache "&upstream_cache_status"; #查看缓存使用状态 Miss 未使用, HIT使用
    #当出现一下异常是启用下一个 upstream
    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
}

清理指定缓存

ngx_cache_purge

安装ngx_cache_purge module块

cd /tmp
wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz
tar -xf ngx_cache_purge-2.3.tar.gz
dso_tool --add-module=/tmp/ngx_cache_purge-2.3

nginx.conf 配置

dso {
    load ngx_cache_purge_module.so;
}

location ~ /purge(/.*) {
       allow 192.168.1.0/24;
       deny all;
       proxy_cache_purge mycache $host$1$is_args$args;
       access_log off;
}

清理缓存

如果要清理http://node1.qiuyue.com/bbs/index.html的缓存,则访问http://node1.qiuyue.com/purge/bbs/index.html即

让部分页面不缓存

Systax: proxy_on_cache string ...
Context: http,server,location

Sample

server {
    #检测url是否已不缓存的页面
    if($request_url ~ ^/(url3|login|register|password\/reset)){ 
        set $cookie_nocache 1; #设置变量的值
    }

    location / {
        proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
        proxy_no_cache $http_pragma $http_authorization;
    }
}

大文件分片请求

http_slice_module

Systax: slice size;
Context: http,server,location

分析

优势:

每个子请求收到的数据都会形成一个独立的文件,一个请求断了,其他请求不收影响

劣势:

当文件很大或者slice很小的时候,可能会导致文件描述符耗尽等情况

–with-http_slice_module

http {
    include      mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    proxy_cache_path /tmp/nginx/cache levels=1:2 keys_zone=cache:100m;
    server {
        listen      8087;
        server_name  localhost;
        location / {
            slice 1m;
            proxy_cache cache;
            proxy_cache_key $uri$is_args$args$slice_range;
            proxy_set_header Range $slice_range;
            proxy_cache_valid 200 206 1h;
            #proxy_set_header Range $http_range;
            proxy_pass http://127.0.0.1:8080;
        }
        error_page  500 502 503 504  /50x.html;
        location = /50x.html {
            root  html;
        }

    }
}
  • 该模块用在 proxy_cache 大文件的场景,将大文件切片缓存
  • 编译时对 configure 加上 –with-http_slice_module 参数
  • $slice_range 一定要加到 proxy_cache_key 中,并使用 proxy_set_header 将其作为 Range 头传递给后端
  • 要根据文件大小合理设置 slice 大小

参考:Nginx 切片模块、断点续传

Nginx动静分离

nginx分离JSP给Tomcat, jpg,png直接用静态资源

Nginx 搭建文件服务器

第四章 深度学习篇

Nginx简单的语法

Nginx 变量

  1. Nginx 变量名的可见范围虽然是整个配置,但每个请求都有所有变量的独立副本,或者说都有各变量用来存放值的容器的独立副本,彼此互不干扰;
  2. 一个请求在其处理过程中,即使经历多个不同的 location 配置块,它使用的还是同一套 Nginx 变量的副本,Nginx 变量值容器的生命期是与当前正在处理的请求绑定的,而与 location无关。
  1. Nginx 内建变变量 Embedded Variables , 有由 Nginx 核心和各个 Nginx 模块提供的“预定义变量”,或者说“内建变量”(builtin variables)。常用的内键变量请查看附录二,Nginx全局变量解析

  2. $arg_XXX 变量群,大部分arg_xxx变量是只读的,尝试修改会报一些奇特的异常
    $arg_name 案例

    location /test {
           echo "name: $arg_name";
           echo "class: $arg_class";
    }

    请求/test接口

    $ curl 'http://localhost:8080/test'
    name: 
    class: 
    
    $ curl 'http://localhost:8080/test?name=Tom&class=3'
    name: Tom
    class: 3
    
    $ curl 'http://localhost:8080/test?name=hello%20world&class=9'
    name: hello%20world
    class: 9

    $arg_name 不仅可以匹配 name 参数,也可以匹配 NAME 参数,抑或是 Name,等等

    $ curl 'http://localhost:8080/test?NAME=Marry'
    name: Marry
    class: 
    
    $ curl 'http://localhost:8080/test?Name=Jimmy'
    name: Jimmy
    class:

    hello%20world进行解码,使用第三方 ngx_set_misc 模块提供

       location /test {
           set_unescape_uri $name $arg_name;
           set_unescape_uri $class $arg_class;
    
           echo "name: $name";
           echo "class: $class";
       }

    测试效果

    $ curl 'http://localhost:8080/test?name=hello%20world&class=9'
    name: hello world
    class: 9
  3. $arg_XXX 的内建变量群,比如用来取 cookie 值的 $cookie_XXX 变量群,用来取请求头的 $http_XXX 变量群,以及用来取响应头的 $sent_http_XXX 变量群,参考 ngx_http_core 模块的官方文档。

Perl兼容正则表达式

  • .:匹配除换行符\n以外的任意单个字符
  • ?:匹配之前的字符0次或1次
  • +:匹配之前的字符至少1次
  • *:匹配之前的字符任意次
  • \d:匹配数字
  • ^:匹配字符串的开始
  • $:匹配字符串的结尾
  • {m}:重复m次
  • {m,}:重复至少m次
  • {m,n}:重复至少m次,最多n次
  • [a]:匹配单个字符a
  • [a-z]:匹配a-z小写字母中的任意一个
  • [^ ]:匹配任何不包括在指定字符集内的任意字符
  • |:匹配 | 之前或之后的部分
  • ():分组,组成一组用于匹配的实体,通常配合 | 使用。小括号()之间匹配的内容,可以在后面通过$1来引用,$2表示的是前面第二个()里的内容

深入学习参考 正则表达式30分钟入门教程

#localhost:8080/abc/qwe/asd
location ~/abc/(.*)/(.*) {
    set $para1 $1; # qwe
    set $para2 $2;# asd
}

$1|$2|$3 ...nginx在匹配正则时生成的变量,用于捕获一个正则表达式括号中匹配的字符串(从左到右依次存储在$1|$2|$3 ...中),新值覆盖旧值。

if(条件) {…}

  1. if(b), b是空或者任务以0开头的字符串,条件为false
  2. 比较内容,用= 或!=
  3. 检测文件或目录
    1. -f和!-f用来判断文件是否存在
    2. -d和!-d用来判断目录是否存在
    3. -e和!-e用来判断文件和目录是否存在
    4. -x和!-x用来判断文件是否可执行
if(!-f $request_filename){ #如果文件不存在重定向到百度
    rewrite ^/(.*)$ http://www.baidu.com/$1 redirect;
}

正则表达式匹配:

==:等值比较;

~:与指定正则表达式模式匹配时返回“真”,判断匹配与否时区分字符大小写;

~*:与指定正则表达式模式匹配时返回“真”,判断匹配与否时不区分字符大小写;

!~:与指定正则表达式模式

不匹配时返回“真”,判断匹配与否时区分字符大小写;

!~*:与指定正则表达式模式不匹配时返回“真”,判断匹配与否时不区分字符大小写;

实战案例

浏览器实现分离

# 禁止使用curl命令下载文件
if ($http_user_agent ~ curl) {
    return 403;
}

# 浏览器实现分离
if ($http_user_agent ~ Firefox){
       rewrite ^/(.*)$ /firefox/$1 break;
}

if ($http_user_agent ~ MSIE){
      rewrite ^/(.*)$ /msie/$1 break;
}

if ($http_user_agent ~ Edge){
      rewrite ^/(.*)$ /edge/$1 break;
}

if ($http_user_agent ~ Chrome){
      rewrite ^/(.*)$ /chrome/$1 break;
}

浏览器分离的效果

例如: 用chrome访问 http://192.168.1.222/index.html 会访问 /usr/local/tengine/html/chrome/index.html

# echo "Firefox html" > /usr/local/tengine/html/firefox/index.html
# echo "MSIE html" > /usr/local/tengine/html/msie/index.html
# echo "Edge html" > /usr/local/tengine/html/edge/index.html
# echo "Chrome html" > /usr/local/tengine/html/chrome/index.html

网站更新,原服务跳转到停服提示,公司内部IP可以访问

set $my_ip ''; 
if ( $remote_addr = 222.222.222.222){set $my_ip 1;} #注意这里的$remote_addr如何用了负载均衡的话,这里应该是$http_x_forwarded_for
if ( $remote_addr = 192.168.1.170 ){ set $my_ip 1;}
if ( $remote_addr = 192.168.1.169 ){ set $my_ip 1;}
if ( $my_ip != 1) {rewrite ^/design/(.*)\.php$ /tingfu.html?$1&;}  #将*.php转到tingfu.html

只允许指定IP访问,其他IP跳转到指定页面

set $test '';
if ( $request_uri ~* /img/test.php ) {
        set $test P;
}

if ( $http_x_forwarded_for !~* ^222\.222\.222\.222.* ) {
        set $test "${test}C";
}

if ( $test = PC ) {  #当条件符合 访问test.php并且 ip不是222.222.222.222的 转发到55555.php
    rewrite ^(.*)$ /img/55555.php permanent;  
}

Location使用详解

参考 nginx location指令详解

基本语法: location [=|~|~\*|^~|@] pattern{……}**

  1. 没有修饰符 表示:必须以指定模式开始
  2. =表示:必须与指定的模式精确匹配
  3. ~ 表示:指定的正则表达式要区分大小写
    • ~ \.(txt|css)$ 匹配所有以txt和css结尾的请求 区分大小写
  4. ~* 表示:指定的正则表达式不区分大小写
  5. ^~ 类似于无修饰符的行为,也是以指定模式开始,不同的是,如果模式匹配,
    那么就停止搜索其他模式了。
  6. @ :定义命名location区段,这些区段客户段不能访问,只可以由内部产生的请
    求来访问,如try_files或error_page等

优先级 “=” > “^~” > *” 或“\” ** > “/ ”

  1. location块中未设置root时,会取外层(server块)的root,但server.root明显不是先生成字符串然后赋值给location.root,而是直接把模板串交给location.root。

Rewrite规则

CentOS 7.4 Tengine安装配置详解(四)

配置语法

Syntax: rewrite regex replacement [falg];
Context: server, location , if

四种flag标志位

  • last:执行该rewrite规则后,停止处理后续的rewrite指令集,对于重写后的URL会重新匹配location
  • break:执行该rewrite规则后,停止处理后续的rewrite指令集,不再进行location匹配
  • redirect:重写完成之后会返回客户端302状态响应码(临时重定向),地址栏会显示跳转后的地址
  • permanent:重写完成之后会返回客户端301(永久重定向),地址栏会显示跳转后的地址

Sample01 default

location /aaa.html {
    rewrite "^/aaa.html$" /bbb.html; # 先走rewrite 才 location
    rewrite "^/bbb.html$" /ddd.html;
}


location /bbb.html {
    rewrite "^/bbb.html$" /ccc.html;
}

创建测试内容:

# echo "aaa html" > /usr/local/tengine/html/aaa.html
# echo "bbb html" > /usr/local/tengine/html/bbb.html
# echo "ccc html" > /usr/local/tengine/html/ccc.html
# echo "ddd html" > /usr/local/tengine/html/ddd.html

测试结果

curl http://localhost/aaa.html –> ddd.html

Sample02 last

location /aaa.html {

    rewrite "^/aaa.html$" /bbb.html last; # 不会往下rewrite ,走下面的location匹配
    rewrite "^/bbb.html$" /ddd.html; 

}

location /bbb.html {
    rewrite "^/bbb.html$" /ccc.html;
}

测试: curl http://localhost/aaa.html ==> ccc.html

解析: aaa.html –> bbb.html –> 由于flag为last,所以不会将bbb.html –> ddd.html –> 重新匹配bbb.html –> ccc.html

Sample03 break

location /aaa.html {
    rewrite "^/aaa.html$" /bbb.html break;  # 不向下rewrite 及location
    rewrite "^/bbb.html$" /ddd.html;
}

location /bbb.html {
    rewrite "^/bbb.html$" /ccc.html;
}

测试: curl http://localhost/aaa.html –> bbb.html

解析:aaa.html –> bbb.html –> 由于flag为break,所以不再进行location匹配

Sample04 首先执行server段内的rewrite指令

rewrite "^/aaa.html$" /bbb.html;

location /ccc.html {
    rewrite "^/ccc.html$" /eee.html;
}

location /bbb.html {
    rewrite "^/bbb.html$" /ccc.html;
    rewrite "^/ccc.html$" /ddd.html;
}

curl http://localhost/aaa.html –> ddd.html

Sample 05 先把server段的rewrite弄完,然后才location

rewrite "^/aaa.html$" /bbb.html;

rewrite "^/ccc.html$" /ddd.html;


location /bbb.html {
    rewrite "^/bbb.html$" /ccc.html;
}

location /ddd.html {
    rewrite "^/ddd.html$" /eee.html;
}

测试: curl http://localhost/aaa.html –> ccc.html

实战案例

浏览器分离

#http://192.168.1.222/index.html  -> /usr/local/tengine/html/msie/index.html
if ($http_user_agent ~ MSIE){

      rewrite ^/(.*)$ /msie/$1 break;

}
#http://192.168.1.222/index.html  -> /usr/local/tengine/html/edge/index.html
if ($http_user_agent ~ Edge){

      rewrite ^/(.*)$ /edge/$1 break;

}

自动跳转到, http://blog.qiuyue.com时自动跳转到http://www.qiuyue.com/blog

server {

    listen 80;
    server_name blog.qiuyue.com;
    rewrite ^/(.*)$ http://www.qiuyue.com/blog/$1 permanent;

    location / {
         root html/blog;
         index index.html index.html;
    }
}

server {
    listen 80;
    server_name www.qiuyue.com;
    location / {
      root html/www;
      index index.html index.html;
    }
}

http://www.qiuyue.com/bbs时自动跳转到http://bbs.qiuyue.com

server {

    listen 80;
    server_name www.qiuyue.com;
    rewrite ^/bbs/(.*)$ http://bbs.qiuyue.com/$1 permanent;

     location / {
        root html/www;
        index index.html index.html;
     }
}

优雅的Rewrite规则书写

自己写的

server {
    listen 80;
    server_name www.nginx.org nginx.org;
    if($htpp_host = nginx.org){
        rewrite (.*) http://www.nginx.org$1;
    }
}

官方推荐写法

server {
    listen 80;
    server_name nginx.org;
    rewrite ^ http://www.nginx.org$request_url?; #只用一行,并且书写美观
}

server {
    listen 80;
    server_name www.nginx.org;
}

Nginx 高级模块

注意作用:

  1. 制定并允许检查请求的连接的真实性以及保护资源免遭未经授权的访问;
  2. 限制连接生效周期;

配置

enabled with the --with-http_secure_link_module

语法

Syntax:    secure_link expression;
Context:    http, server, location
Syntax:    secure_link_md5 expression;
Context:    http, server, location

Sample

location /s/ {
    secure_link $arg_md5,$arg_expires;
    secure_link_md5 "$secure_link_expires$uri$remote_addr secret";

    if ($secure_link = "") {
        return 403;
    }

    if ($secure_link = "0") {
        return 410;
    }
}

md5url.sh 生成安全连接

#!/bin/sh
#
#Auth:zhilinchn@126.com
servername="zhilinchn.com"
download_file="/dowload/file.img"
time_num=$(date -d "2019-10-16 00:00:00" +%s)
secret_num="secret"  #记得和服务端 secret对应
res=$(echo -n "${time_num}${download_file} ${secret_num}" | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =)
echo "http://${servername}${download_file}?md5=${res}&expires=${time_num}"

source md5url.sh 进行访问

http://zhilinchn.com/dowload/file.img?md5=FFhZt0XJo7ed_X973FsRgA&expires=1571155200

geoip_module 模块

  • ngx_http_geoip_module 基于IP地址MaxMind GeoIP 二进制文件,读取IP所在地域信息。
  • yum install nginx-module-geoip

使用场景

  1. 区别国内国外作HTTP访问规则
  2. 区别国内城市地域HTTP访问规则

ngx-fancyindex 实现文件索引目录

实现索引目录(适用于下载站)tengine

  1. 下载ngx-fancyindex

    yum -y install git \
    cd /tmp \
    git clone https://github.com/aperezdc/ngx-fancyindex.git ngx-fancyindex
  2. 使用Tengine的dso_tool工具编译第三方模块:

    dso_tool -h #help
    dso_tool --add-module=/tmp/ngx-fancyindex
    ls /usr/local/tengine/modules | grep fancyindex  -->  ngx_http_fancyindex_module.so
  3. 添加events 配置

   dso {
       load ngx_http_fancyindex_module.so;
   }
  1. server 设置

    location /software {
        root /download;
        fancyindex on;              # 启用fancy目录索引功能
        fancyindex_exact_size off;    # 不显示文件的精确大小,而是四舍五入,单位是KB、MB和GB
        fancyindex_localtime on;     # 默认为off,显示的是GMT时间,改为on,显示的是服务器时间
    
    }
  2. 重载后测试

  • 访问到测试
  • 检测模块是否加载成功 nginx -m –> ngx_http_fancyindex_module (shared, 3.1)

基于Nginx的HTTPS服务

自建CA服务器创建私有CA

  1. 安装相关软件包,生成私钥

    yum -y install openssl openssh-clients
    #创建保存证书信息的数据库文件
    touch /etc/pki/CA/index.txt
    #保存证书序列号的文件
    echo 01 > /etc/pki/CA/serial
    #生成私钥cakey.pem
    (umask 077; openssl genrsa -out /etc/pki/CA/private/cakey.pem 2048)

    备注:

    genrsa:用于生成RSA密钥对的OpenSSL子命令 (man genrsa)

    -out cakey.pem 指定私钥保存位置

    2048 密钥长度

  2. 生成CA证书cacert.pem

    cd /etc/pki/CA 
    openssl req -new -x509 -key private/cakey.pem -days 7300 -out cacert.pem

    输入信息

    Country Name (2 letter code) [XX]:cn
    State or Province Name (full name) []:guangdong       
    Locality Name (eg, city) [Default City]:shenzhen
    Organization Name (eg, company) [Default Company Ltd]:TX
    Organizational Unit Name (eg, section) []:DEV
    Common Name (eg, your name or your server's hostname) []:ca.vhosts.com #证书颁发者
    Email Address []:zhilinchn@126.com

    备注:

    req子命令常用选项(man req)
    -new:生成新证书签署请求
    -x509:专用于CA生成自签证书
    -key cakey.pem:生成CA证书请求时用到的私钥

    -days 7300:证书的有效期限为20年
    -out cacert.pem:证书的保存路径

参考

Nginx 与Lua开发

Nginx与Lua特性与优势

  1. Lua 是一个简洁、轻量、可扩展的脚本语言。Lua脚本可以很容易的被C/C++ 代码调用,也可以反过来调用C/C++的函数。Lua由标准C编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以编译,运行。一个完整的Lua解释器不过200k,在目前所有脚本引擎中,Lua的速度是最快的。这一切都决定了Lua是作为嵌入式脚本的最佳选择

  2. Nginx+ Lua的优势
    充分结合Nginx的并发处理epoll优势和Lua的轻量级实现简单的功能提高高并发场景。

    • 统计用户IP;
    • 统计用户的访问次数;
    • 安全功能

Lua 基础语法

  1. 安装lua解析器 yum install lua

  2. run Hello World

    • terminal input lua print("Hello World!")

    • script:test.lua , chmod a+x text.lua ./test.lua

      #!/usr/bin/lua
      print("Hello World!")
  3. 注释

    -- 单行注释
    --[[
     多行注释
     多行注释
     --]]
  4. lua的数据类型
    布尔类型只有nil和false, 数字,空字符串(’\0‘)都是true

  5. 变量

    a = 5               -- 全局变量
    local b = 5         -- 局部变量
    
    function joke()
        c = 5           -- 全局变量
        local d = 6     -- 局部变量
    end
    
    joke()
    print(c,d)          --> 5 nil
    
    do 
        local a = 6     -- 局部变量
        b = 6           -- 对局部变量重新赋值
        print(a,b);     --> 6 6
    end
    
    print(a,b)      --> 5 6

while循环

sum = 0 
num = 1
while num <=100 do
    sum = sum + num
    -- 不支持 num++
    num = num +1
end
print("sum=",sum)

for循环

sum=0
for i=1,100 do
    sum = sum +i
end

if-else 判断语句

if age == 40 and sex == "Male" then 
    print("大于40男人")
    -- ~= 不等于
elseif age > 60 and sex ~= "Female" then
    print("非女人而且大于60")
else
    -- 从屏幕终端读取
    local age = io.read()
    -- .. 字符拼接
    print("Your age is "..age)
end

Nginx + lua 环境

  1. LuaJIT

  2. ngx_devel_kit 和lua-nginx-module

  3. 重新编译 参考 http://www.imooc.com/article/19597

  4. 容器化,参考附录二

Nginx 调用lua模块指令

Nginx lua API

比较全的API总结 ngx_lua 模块

location /hello {
      default_type 'text/plain';
      content_by_lua 'ngx.say("hello, lua")';
}

location /myip {
      default_type 'text/plain';
      content_by_lua 'ngx.req.get_headers()["x_forward_for"] ngx.say("IP",clientIP)'
}

location / {
      default_type 'text/plain';
      content_by_lua_file0 /opt/app/lua/dep.lua; #调用lua脚本
}

实战-灰度发布

Nginx + Lua + Memcache基于IP实现灰度发布

dep.lua

-- 取到用户IP
clientIP = ngx.req.get_headers()["X-Real-IP"]
if clientIP == nil then
    clientIP = ngx.req.get_headers()["x_forwarded_for"]
end
if clientIP == nill then 
    clientIP == ngx.var.remote_addr
end
    local memcached = require "resty.memcached"
    local memc, err = memcached:new()
    if not memc then 
        ngx.say("failed to instantiate memc:",err)
        return
    end
    local ok,err = memc:connect("127.0.0.1",11211)
    if not ok then 
        ngx.say("failed to connect:",err)
        return
    end
    local res, flags, err = memc:get(clientIP)
    ngx.say("value key:",res,clientIP)
    if err then 
        ngx.say("failed to get clientIP ", err)
        return 
    end 
    if res == "1" then 

第五章 Nginx架构篇

常见问题

  1. 多个server_name 的优先级
  2. 多个Location优先级
  3. try_files使用
  4. alias 和root区别
  5. 获取用户真实IP
  6. Nginx常见的错误

性能优化

Apache ab 压测试工具

安装

sudo yum install httpd-tools

使用

# -n 发送100次 -c 并发10
ab -n 100 -c 10 [http[s]://]hostname[:port]/path
#-p post 方式 -T 数据格式
#post_wecaht.txt  = {"send_type":"email", "to":"yanyongwen@xiaoniu66.com", "content":"parallel test"}
ab -n 100 -c 10 -p post_wechat.txt -T application/json [http[s]://]hostname[:port]/path
#-H headers
ab -n 1000 -c 200 -p post.txt -H 'X-Custom-Header':'xxxx' -H 'OS-TYPE':'linux' -T application/json http://localhost:9090/hardware
# -k 是否开启长连接

结果分析

Server Software:        Microsoft-HTTPAPI/2.0 
Server Hostname:        192.168.0.10 
Server Port:            80

Document Path:          / 
Document Length:        315 bytes       HTTP响应数据的正文长度

Concurrency Level:      800 
Time taken for tests:   0.914 seconds    所有这些请求处理完成所花费的时间 
Complete requests:      800             完成请求数 
Failed requests:        0                失败请求数 
Write errors:           0                
Non-2xx responses:      800              # 有多少个非200的请求
Total transferred:      393600 bytes     网络总传输量 
HTML transferred:       252000 bytes     HTML内容传输量 
Requests per second:    875.22 [#/sec] (mean) 吞吐量-每秒请求数 
Time per request:       914.052 [ms] (mean)  服务器收到请求,响应页面要花费的时间 
Time per request:       1.143 [ms] (mean, across all concurrent requests) 并发的每个请求平均消耗时间 
Transfer rate:          420.52 [Kbytes/sec] received 平均每秒网络上的流量,可以帮助排除是否存在网络流量过大导致响应时间延长的问题


网络上消耗的时间的分解: 
Connection Times (ms) 
              min  mean[+/-sd] median   max 
Connect:        0    1   0.5      1       3 
Processing:   245  534 125.2    570     682 
Waiting:       11  386 189.1    409     669 
Total:        246  535 125.0    571     684

整个场景中所有请求的响应情况。在场景中每个请求都有一个响应时间 
其中 50% 的用户响应时间小于 571 毫秒 
80 % 的用户响应时间小于 652 毫秒 
最大的响应时间小于 684 毫秒 

系统和Nginx性能优化

文件句柄设置

CPU亲和性设置

Nginx通用配置优化

Nginx安全

恶意行为控制手段

攻击手段之暴力破解

文件上传漏洞

SQL注入

Nginx + lua 防火墙功能

复杂访问攻击中CC攻击方式

1. 调试

1.1 查看nginx的状态信息

需要编译时安装http_stub_status_module 及config –with-http_stub_status_module

location /status {
    stub_status on;
    allow 192.168.101.120;
    deny all;
    access_log off;
}

访问http://192.168.1.222/status

状态说明

  • Active connections:当前活动的客户端连接数
  • accepts:已经接收过的客户端连接总数
  • handled:已经处理过的客户端连接总数
  • requests:客户端的请求总数
  • request_time:请求时间
  • Reading:正在读取的客户端请求数
  • Writing:正在处理请求或发送响应报文的连接数
  • Waiting:等待发出请求的空闲连接数

注意:可以配合 基于用户名/密码实现访问控制进行密码校验

1.2 装载echo模块, 用于打印日志

  1. 下载echo-nginx-module:
yum -y install git \
cd /tmp \
git clone https://github.com/openresty/echo-nginx-module.git
  1. 使用Tengine的dso_tool工具编译第三方模块:

    dso_tool --add-module=/tmp/echo-nginx-module
    ls /usr/local/tengine/modules | grep echo  -->  ngx_http_echo_module.so
  2. nginx 配置

    events{
        dso {
            load ngx_http_echo_module.so;
        }
    }
    server{
    location /echo {
        default_type "text/plain";    # 不指定default_type,会提示下载文件,而非直接输出在浏览器中
        echo "host  -->  $host";                        # 请求主机头字段,否则为服务器名称
        echo "server_name  -->  $server_name";          # 服务器名称
        echo "server_addr  -->  $server_addr";            # 服务器IP地址
        echo "remote_addr  -->  $remote_addr";          # 客户端IP地址
        echo "uri  -->  $uri";                          # 不带请求参数的当前URI,$uri不包含主机名
        echo "document_uri  -->  $document_uri";        # 与$uri含义相同
        echo "request_uri  -->  $request_uri";            # 带请求参数的原始URI,不包含主机名
        echo "request_filename  -->  $request_filename";   # 当前请求的文件路径
        echo "document_root  -->  $document_root";      # 当前请求在root指令中指定的值
    }
    }
    
  3. 测试

Curl 使用

查看一个完整的http请求

curl -v https://coding.imooc.com > /dev/null

测试正则表达式

官网: https://www.pcre.org/

安装

wget https://ftp.pcre.org/pub/pcre/pcre-8.13.tar.gz
tar -xzvf  pcre-8.13.tar.gz
cd pcre-8.13
./configure --enable-utf8  
make && make intall

使用

pcre
pcretest # 正则测试

Expresso 巨好用的正则工具

下载地址: http://www.ultrapico.com/ExpressoDownload.htm

使用返回值调试

location /test/ {
    default_type application/json;
    return 200 '{"status":"success"}';
}

查看日志

tail -f /usr/local/tengine/logs/access.log 

第六章 新特性

Nginx 平滑升级实现和原理

HTTP2.0协议特性gRPC

附录一

参考资料

  1. CentOS 7.4 Tengine安装配置详解(一)
  2. nginx正则相关变量$1,$2,$3使用注意
  3. 正则表达式30分钟入门教程
  4. Nginx 变量漫谈(一)
  5. Nginx入门到实践-Nginx中间件

神级进阶博文

Nginx 变量漫谈

Nginx 配置指令的执行顺序

官方文档

https://nginx.org/en/docs/

ngx_http_core_module 参数官网文档

包含在http上下文内的所有参数解析

ngx_http_log_module(日志模块)

http://nginx.org/en/docs/http/ngx_http_log_module.html

Embedded Variables (nginx 内置变量)

Embedded Variables

附录二

Tengine

Tengine github

documentation

Nginx.conf 标准模板(Tengine)


user tengine;                    # 运行worker进程的用户

worker_processes auto;           # worker进程的个数,命令ps aux | grep nginx可查看启动的worker进程数量

worker_cpu_affinity auto;         # 将worker进程绑定在哪些CPU上,减少由于上下文切换导致的CPU消耗

worker_rlimit_nofile 65535;       # worker进程能够打开的最大文件数限制

error_log logs/error.log error;     # 指定Tengine错误日志的存放路径和级别

pid logs/nginx.pid;              # 指定Tengine进程的pid文件路径

google_perftools_profiles /tmp/tcmalloc;   # tcmalloc保存路径,命令lsof -n | grep tcmalloc验证运行状态



events {

accept_mutex on;           # 让多个worker进程轮流地、序列化地响应新请求

multi_accept on;            # 在Tengine接收到一个新连接通知后,调用accept()来接收尽可能多的连接

worker_connections 65535;   # 单个worker进程所能响应的最大并发连接数

# 此处没有指定use epoll;指令,让Tengine自动选择合适的事件处理模型

}



http {

server_tokens off;           # 隐藏Tengine版本号

include mime.types;         # MIME是网络资源的媒体类型,使用include指令导入mime.types文件

default_type application/octet-stream;   # 指定默认类型



# 自定义访问日志格式,名称为main,指定要保存的日志内容

# ====================================================

# $remote_addr与$http_x_forwarded_for含义相同:客户端的IP地址

# $remote_user:记录客户端用户名称

# $time_local:通用日志格式下的本地服务器时间

# $request:记录请求的URL与HTTP协议

# $status:响应状态码,成功是200

# $body_bytes_sent:发送给客户端HTTP响应的主体内容的字节数大小,不包括响应首部的大小

# $http_referer:记录从哪个页面链接访问过来的

# $http_user_agent:记录客户端浏览器相关信息

# ====================================================

log_format main '$remote_addr - $remote_user [$time_local] "$request" '

                  '$status $body_bytes_sent "$http_referer" '

                 '"$http_user_agent" "$http_x_forwarded_for"';



access_log off;       # 关闭访问日志,提高磁盘的I/O性能

sendfile on;          # 开启高效文件传输模式,调用sendfile()进行数据复制,sendfile()复制数据是在内核级别完成的,所以会比一般的read()、write()更高效,sendfile()可以在磁盘和TCP socket之间互相拷贝数据

tcp_nopush on;      # 开启后服务器的响应头部信息产生独立的数据包发送,即一个响应头信息一个包。在一个数据包里发送所有头文件,而不是一个接一个的发送,用于防止网络阻塞,必须先开启sendfile模式

keepalive_timeout 65; # 客户端keep-alive连接超时时长,服务器将在这个超时时长过后关闭连接,单位秒

charset UTF-8;      # 定义头文件默认字符集



gzip on;                      # 采用gzip压缩形式发送数据,将页面压缩后传输更节省带宽

gzip_disable "msie6";           # IE6的浏览器禁用gzip功能

gzip_proxied any;              # 指定对客户端请求的所有资源启用压缩功能

gzip_min_length 1k;            # 指定对数据启用压缩的最少字节数,如果请求小于1K的文件,不要压缩,压缩小数据会降低处理此请求的所有进程速度

gzip_comp_level 6;             # 指定数据的压缩等级,这个等级可以是1~9之间的任意数值,1压缩比最小但处理速度最快,9处理最慢但压缩比最大,CPU消耗也越大

gzip_buffers 16 8k;             # 指定压缩响应的缓冲区的数量和大小

gzip_vary on;                 # 允许把"Vary: Accept-Encoding"插入响应首部

gzip_http_version 1.1;          # 指定识别HTTP协议版本,默认是1.1

gzip_types text/plain text/css text/xml text/javascript application/json application/x-javascript application/xml application/xml+rss;               # 指定需要压缩的资源类型



reset_timedout_connection on;       # 关闭不响应的客户端连接,释放客户端所占的内存空间

client_body_buffer_size 8k;         # 指定用于读取客户端请求主体的缓冲区大小

client_header_buffer_size 1k;       # 指定用于读取客户端请求首部的缓冲区大小

large_client_header_buffers 4 8k;    # 指定用于读取客户端请求中较大首部的缓冲区的最大数量和大小

client_max_body_size 1m;          # 指定用于客户端请求主体的最大大小

client_header_timeout 30s;         # 指定用于读取客户端请求报文首部的超时时长,单位秒

client_body_timeout 30s;           # 指定用于读取客户端请求报文主体的超时时长,单位秒

send_timeout 30s;                 # 指定用于向客户端发送响应报文的超时时长,单位秒

}

Nginx + Lua 环境容器化脚本

Dockerfile

FROM centos:latest
MAINTAINER  becivells  
RUN yum -y update &&  yum  -y upgrade
RUN yum -y install gcc gcc-c+ openssl openssl-devel pcre-devel zlib-devel  make wget 

ENV TENGINE_VERSION tengine-2.2.3
RUN cd /tmp/ && wget  http://tengine.taobao.org/download/${TENGINE_VERSION}.tar.gz &&\
    tar -zxvf ${TENGINE_VERSION}.tar.gz -C /tmp/ && chmod -R 777 /tmp/${TENGINE_VERSION}
#mkdir
RUN mkdir -p /var/tmp/nginx/client/ &&\
    mkdir -p /var/tmp/nginx/proxy/ &&\
    mkdir -p /var/tmp/nginx/fcgi/ &&\
    mkdir -p /var/tmp/nginx/uwsgi/ &&\
    mkdir -p /var/tmp/nginx/scgi/ 
#./configure

#LuaJIT
RUN cd /tmp/ && wget http://luajit.org/download/LuaJIT-2.0.4.tar.gz && \
    tar xzvf LuaJIT-2.0.4.tar.gz && \
    cd LuaJIT-2.0.4 && \
    make install PREFIX=/usr/local/LuaJIT 

ENV LUAJIT_LIB=/usr/local/LuaJIT/lib 
ENV LUAJIT_INC=/usr/local/LuaJIT/include/luajit-2.0

RUN cd /tmp/ && wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz && \
    tar -xzvf v0.3.0.tar.gz && \
    wget https://github.com/openresty/lua-nginx-module/archive/v0.10.8.tar.gz && \
    tar -xzvf v0.10.8.tar.gz


RUN cd /tmp/${TENGINE_VERSION} && ./configure \
    --prefix=/opt/${TENGINE_VERSION}/ \
    #--sbin-path=/usr/sbin/nginx \
    #--modules-path=/usr/lib64/nginx/modules \
    #--conf-path=/etc/nginx/nginx.conf \
    --error-log-path=/var/log/nginx/error.log \
    --http-log-path=/var/log/nginx/access.log \
    --pid-path=/var/run/nginx/nginx.pid  \
    --lock-path=/var/lock/nginx.lock \
    --http-client-body-temp-path=/var/tmp/nginx/client/ \
    --http-proxy-temp-path=/var/tmp/nginx/proxy/ \
    --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ \
    --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \
    --with-file-aio \
    --with-http_addition_module \
    --with-http_auth_request_module \
    --with-http_dav_module \
    --with-http_flv_module \
    --with-http_gunzip_module \
    --with-http_gzip_static_module \
    --with-http_mp4_module \
    --with-http_random_index_module \
    --with-http_realip_module \
    --with-http_secure_link_module \
    --with-http_slice_module \
    --with-http_ssl_module \
    --with-http_stub_status_module \
    --with-http_sub_module \
    --with-mail \
    --with-mail_ssl_module \
    --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions  -fstack-protector-strong \
    --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' \
    --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' \
    --add-module=/tmp/lua-nginx-module-0.10.8 \
    --add-module=/tmp/ngx_devel_kit-0.3.0 \
    --with-pcre  &&\
    cd /tmp/${TENGINE_VERSION} && make -j 4 && make install && \
    rm -rf /tmp/* && yum clean all && \
    ln -s /opt/${TENGINE_VERSION}/ /opt/tengine && \
    echo "/usr/local/LuaJIT/lib" >> /etc/ld.so.conf && \
    ldconfig
EXPOSE 80
CMD ["/opt/tengine/sbin/nginx", "-g", "daemon off;"] 

使用方式

#构建容器
docker build -t centos:tengine .
#指定81端口运行
docker run --rm -p 81:80 centos:tengine
#进入centos:tengine terminal 终端
docker exec -it  /bin/bash 

测试

location /hello {
      default_type 'text/plain';
      content_by_lua 'ngx.say("hello, lua")';
}

Nginx全局变量解析

$content_length:http请求头中的Content-length字段

$content_type:http请求头中的Content-Type字段

$document_root:当前请求在root指令中指定的值

$host:请求主机头字段,如果请求中没有Host行,则为服务器名称

$http_user_agent:客户端agent信息

$http_cookie:客户端cookie信息

$limit_rate:限制连接速率

$request_method:客户端请求方法,通常为GET或POST

$remote_addr:客户端IP地址

$remote_port:客户端端口

$remote_user:已经经过Auth Basic Module验证的用户名

$request_filename:当前请求的文件路径,由root或alias指令与URL请求生成

$scheme:请求使用的协议,比如http或者是https

$server_protocol:请求使用的协议版本,通常是HTTP/1.0或HTTP/1.1

$server_addr:服务器地址,在完成一次系统调用后可以确定这个值

$server_name:服务器名称

$server_port:请求到达服务器的端口号

$request_uri:包含请求参数的原始URL,不包含主机名,如:/foo/bar.php?arg=baz

$uri:不带请求参数的当前URL,$uri不包含主机名,如:/foo/bar.html

$document_uri:与$uri相同

使用过程中的问题列表

window conf 文件加载无效

原因是 nginx 在后台启动多个实例导致无法更新到当前使用的实例(在任务列表中可以找到多个nginx实例)

解决:关闭所有nginx.exe, 重新启动

taskkill /IM  nginx.exe  /F 

增加别名缓存

错误提示:

could not build the server_names_hash, you should increase server_names_hash_bucket_size: 32

解决方案:

http{
    server_names_hash_bucket_size 64; #必须是32的倍数
}

413 request entity too large

Nginx设置上传文件大小限制

location ^~ /api/media/ {
          proxy_pass http://media_server_pool/media/;
          client_max_body_size 2000m;
}