Nginx入门到实践

Nginx入门到实践

学习Nginx入门到实践-Nginx中间件笔记

nginx官网

Nginx是一个开源且高性能、可靠的HTTP中间件、代理服务。

Nginx优势

  1. IO多路复用epoll

  2. 轻量级

  3. CPU亲和

  4. sendfile

安装Nginx

  1. 进入官网
    Nginx入门到实践_第1张图片
  2. 选择对应的操作系统
    Nginx入门到实践_第2张图片
  3. 根据文档配置,将$releasever修改为对应的Centos版本。例如我是Centos7,就修改为7
    Nginx入门到实践_第3张图片

示例

Nginx入门到实践_第4张图片

Nginx默认配置语法

参数 注释
user 设置nginx服务的系统使用用户
worker_processes 工作进程数
error_log nginx的错误日志
pid nginx服务启动时候的pid
参数 注释
events worker_connections 每个进程允许最大连接数
use 使用内核模型

虚拟机主机配置方式

  1. 基于主机多IP方式
  2. 基于多port方式
  3. 基于多host名称方式 (多域名方式)

Nginx日志

error.log 错误日志

access.log 每次请求

log_format日志详解

Syntax: log_format name [escape=default|json|none] string …;
Default: log_format combined “…”;
Context: http

log_format 关键字
name 自定义变量
[escape=default|json|none] string … 日志具体内容,即HTTP请求变量、nginx内置变量、自定义变量组成
log_format combined “…” 日志默认值

日志内容:
HTTP请求变量 - arg_PARAMETER http_HEADER sent_http_HEADER
内置变量 - Nginx内置的http-只能配置在http作用域下配置
自定义变量 - 自定义的

Nginx模块

  • nginx官方模块

  • 第三方模块

–with-http_stub_status_module

作用:Nginx的客户端状态,连接信息

Syntax: stub_status;
Default:
Context: server,location
  • 示例

    在配置文件中添加

    server {
    	...
    	location /mystatus{
            stub_status;
       }
      ...
    }
    

​ 访问结果
Nginx入门到实践_第5张图片

  • 状态参数详解
  1. Active connections 活跃连接数
  2. accepts 已接受的客户端连接总数
  3. handled 已处理的连接总数
  4. requests 客户端连接总数
  5. Reading 读取请求头的当前连接数
  6. Writing 将响应写回客户端的当前连接数
  7. Waiting 等待请求的当前空闲客户端连接数

–with-http_random_index_module

作用:目录中选择一个随机主页

Syntax: random_index on|off;
Default: random_index off;
Context: location
  • 示例

    在配置文件中添加

    server {
    	...
    	 location / {
            root   /opt/app/code;
            random_index on;
            #index  index.html index.htm;
        }
      ...
    }
    

.开始的隐藏文件不会选择

–with-http_sub_module

作用:HTTP内容替换

Syntax: sub_filter string replacement;
Default:
Context: http,server,location
  • 允许在替换期间保留原始响应中的“Last-Modified”头字段,以便于响应缓存。
Syntax: sub_filter_last_modified on|off;
Default: sub_filter_last_modified off;
Context: http,server,location
  • 匹配第一个(on)还是所有(off)
Syntax: sub_filter_once on|off;
Default: sub_filter_once on;
Context: http,server,location

Nginx请求限制

连接频率限制

limit_conn_module

Syntax: limit_conn_zone key zone=name:size;
Default:
Context: http

key 表示存储在共享内存中的key

zone=name:size 表示共享内存名称和大小

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

zone 表示存储在共享内存中的key
number 表示限制的连接数

  • 示例

    在配置文件中添加

      limit_conn_zone $binary_remote_addr zone=conn_zone:1m;
      server {
      	...
      	 location / {
              root   /opt/app/code;
              # 服务端同一时刻只允许一个IP连接过来
              limit_conn conn_zone 1;
              index  index.html index.htm;
          }
        ...
      }
    

请求频率限制

limit_req_module

Syntax: limit_req_zone key zone=name:size rate=rate;
Default:
Context: http

key 表示存储在共享内存中的key

zone=name:size 表示共享内存名称和大小

rate=rate 表示请求数率,例如:10r/s每秒请求10次

Syntax: limit_req zone=name [burst=number] [nodelay];
Default:
Context: http,server,location

zone 表示存储在共享内存中的key

[burst=number] 表示突发请求数(最大请求数),遗留的请求放到下一秒执行(延迟响应)

[nodelay | delay=number] 其中nodelay表示请求没有延迟,超出的请求丢失;delay=number表示可以延迟处理请求的数量

  • 示例

    在配置文件中添加

      # 通过$binary_remote_addr(ip)限制,每秒1个
      limit_req_zone $binary_remote_addr zone=req_zone:1m rate=1r/s;
      server {
      	...
      	 location / {
              root   /opt/app/code;
              #limit_req zone=req_zone burst=3 nodelay;
              #limit_req zone=req_zone burst=3;
              #limit_req zone=req_zone;
              index  index.html index.htm;
          }
        ...
      }
    

Nginx的访问控制

基于IP的访问控制

http_access_module

  • 允许访问
Syntax: allow address|CIDR|unix:|all;
Default:
Context: http,server,location,limit_except

address:IP地址

CIDR:网段

unix:unix或linux上socket方式的访问

all:允许所有

  • 拒绝访问
Syntax: deny address|CIDR|unix:|all;
Default:
Context: http,server,location,limit_except
  • 局限性解决
  1. 采用别的HTTP头信息控制访问,如:HTTP_X_FORWARD_FOR
  2. 结合geo模块
  3. 通过HTTP自定义变量传递

基于用户的信任认证

http_auth_basic_module

Syntax: auth_basic string|off;
Default: auth_basic off;
Context: http,server,location,limit_except
  • 存储用户名和密码信息
Syntax: auth_basic_user_file file;
Default:
Context: http,server,location,limit_except

参考官方文档

  • 局限性
  1. 用户信息依赖文件方式
  2. 操作管理机械,效率低下
  • 局限性解决
  1. Nginx结合LUA实现高效验证
  2. Nginx和LDAP打通,利用nginx-auth-ldap模块

静态资源web服务

  1. 静态资源类型:非服务器动态运行生成的文件
  2. 静态资源服务场景—CDN

Nginx入门到实践_第6张图片

  • 配置语法-文件读取
Syntax: sendfile on |off;
Default: sendfile off;
Context: http,server,location,if in location

引读:–with-file-aio 异步文件读取 (很少用)

  • 配置语法-tcp_nopush (多个文件打包一起发送)

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

    sendfile开启才能使用

Syntax: tcp_nopush on | off;
Default: tcp_nopush off;
Context: http,server,location
  • 配置语法-tcp_nodelay 文件不等待,实时发送(实时性高)

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

Syntax: tcp_nodelay on | off
Default: tcp_nodelay on;
Context: http,server,location
  • 配置语法-压缩

    作用:压缩传输

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

Nginx入门到实践_第7张图片

  • 配置语法-压缩比
Syntax: gzip_comp_level level;
Default: gzip_comp_level 1;
Context: http,server,location
  • gzip_http版本
Syntax: gzip_http_version 1.0|1.1;
Default: gzip_http_version 1.1;
Context: http,server,location

扩展nginx压缩模块

http_gzip_static_module 预读gzip功能,需要事先压缩好

http_gunzip_module 应用支持gunzip的压缩方式(不支持gzip压缩时使用,较少)

  • 示例

    在配置文件中添加

      server {
      	...
      	# 开启文件读取
      	sendfile on;
      	
          location ~ .*\.(jpg|gif|png)$ {
              gzip on;
              gzip_http_version 1.1;
              gzip_comp_level 2;
              # gzip压缩类型
              gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
              root  /opt/app/code/images;
          }
      
          location ~ .*\.(txt|xml)$ {
              gzip on;
              gzip_http_version 1.1;
              gzip_comp_level 1;
              gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
              root  /opt/app/code/doc;
          }
      
          location ~ ^/download {
          	# 预读功能
              gzip_static on;
              tcp_nopush on;
              root /opt/app/code;
          }
        ...
      }
    

浏览器缓存

HTTP协议定义的缓存机制(如:Expires;Cache-control等)

  1. 浏览器无缓存

Nginx入门到实践_第8张图片

  1. 客户端有缓存

Nginx入门到实践_第9张图片

  1. 校验过期机制
校验是否过期 Expires、Cache-Control(max-age) 协议版本不同
协议中Etag头信息校验 Etag 一串字符串
Last-Modified头信息校验 Last-Modified 具体的时间到秒

Nginx入门到实践_第10张图片

  1. 配置语法 - expires

    作用:添加Cache-Control、Expires头

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

    在配置文件中添加

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

跨域访问

为什么浏览器禁止跨域访问?(不安全,容易出现CSRF攻击)

  • 配置语法-打开跨域访问
Syntax: add_header name value [always];
Default:
Context: http,server,location,if in location

读取这个Access-Control-Allow-Origin头信息,查看是否允许跨站;默认阻止

  • 示例

    在配置文件中添加

    server {
    	...
    	location ~ .*\.(htm|html)$ {
    				# 允许的域名 *代表所有 可以只打开指定的域名
            add_header Access-Control-Allow-Origin *; 
            # 允许的方法
            add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
            root  /opt/app/code;
        }
    	....
    }
    

防盗链

目的:防止资源被盗用

  • 设置思路

    首要方式:区别哪些请求是非正常的用户请求

基于http_refer防盗链配置模块

Syntax: valid_referers none|blocked|server_names|string…;
Default:
Context: server,location
  • 示例

    在配置文件中添加

    server {
    	...
    	location /app{
    		...
    		# none代表没有refer信息的 blocked代表refer信息不是http://这种标准形式的
    		# 支持域名正则匹配的方式
    		valid_referers none blocked 192.168.247.130 ~/google\./;
    		if($invalid_referer){
    				return 403;
    		}
    		....
    	}
    	....
    }
    

http_refer的方式有一定的局限性

代理服务

  • 正向代理:代理的对象是客户端

  • 反向代理:代理的对象是服务端

http的方式:http://localhost:8000/uri/

https的方式:https://192.168.1.1:8000/uri/

socket的方式:http://unix:/tmp/backend.socket:/uri/;

  • 配置语法
Syntax: proxy_pass URL;
Default:
Context: location,if in location,limit_except
  • 示例

    在配置文件中添加

    server {
    	...
    	# 代理到8080端口
    	location ~ /test_proxy.html$ {
    			proxy_pass http://127.0.0.1:8080;
    	}
    	....
    }
    

其他配置语法

  • 缓冲区
Syntax: proxy_buffering on|off;
Default: proxy_buffering on;
Context: http,server,location

扩展 proxy_buffer_size 、proxy_buffers 、proxy_busy_buffers_size

  • 跳转重定向
Syntax: proxy_redirect default;
proxy_redirect off;
proxy_redirect redirect replacement;
Default: proxy_redirect default;
Context: http,server,location
  • 头信息
Syntax: proxy_set_header field value;
Default: proxy_set_header Host $proxy_host; proxy_set_header Connection close;
Context: http,server,location

扩展:proxy_hide_header 、proxy_set_body

  • 超时
Syntax: proxy_connect_timeout time;
Default: proxy_connect_timeout 60s;
Context: http,server,location

扩展:proxy_read_timeout 、proxy_send_timeout

  • 示例

    在配置文件中添加

    server {
    	...
    	# 代理到8080端口
    	location ~ /test_proxy.html$ {
            proxy_pass http://127.0.0.1:8080;
    		    proxy_redirect default;
    
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
    
            proxy_connect_timeout 30;
            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;
    
    	}
    	....
    }
    

负载均衡服务

nginx属于七层负载均衡

  • Nginx负载均衡
    Nginx入门到实践_第11张图片

nginx通过代理,将请求代理到upstream server,upstream server里面存放了一些相似的服务

  • 配置语法
Syntax: upstream name {…}
Default:
Context: http
  • 示例

    在配置文件中添加

    http {
    	...
    	# 负载均衡 默认轮询 ip/域名/socket方式
    	 upstream test {
            server 192.168.247.130:8001;
            server 192.168.247.130:8002;
            server 192.168.247.130:8003;
        }
        ...
        server {
        	...
        	location / {
              proxy_pass http://test;
              #500/502/503/504/invalid_header/timeout/error 这些情况时用下一个代理
              proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
              ...
        	}
        	...
        }
    	...
    }
    

后端服务器在负载均衡调度中的状态

down 当前的server暂时不参与负载均衡
backup 预留的备份服务器
max_fails 允许请求失败的次数
fail_timeout 经过max_fails失败后,服务暂停的时间
max_conns 限制最大的接收的连接数
  • 示例

    在配置文件中添加

    http {
    	...
    	 upstream test {
            server 192.168.247.130:8001 down;
            server 192.168.247.130:8002 backup;
            server 192.168.247.130:8003 max_fails=1 fail_timeout=10s;
        }
        ...
        server {
        	...
        	location / {
              proxy_pass http://test;
              ...
        	}
        	...
        }
    	...
    }
    

调度算法

轮询 按时间顺序逐一分配到不同的后端服务器
加权轮询 weight值越大,分配到的访问几率越高
ip_hash 每个请求按访问IP的hash结果分配,这样来自同一个IP的固定访问一个后端服务器
url_hash 按照访问的URL的hash结果来分配请求,是每个URL定向到同一个后端服务器
least_conn 最少连接数,哪个机器连接数少就分发
hash关键数值 hash自定义的key
加权轮询示例

在配置文件中添加

http {
	...
	 upstream test {
        server 192.168.247.130:8001;
        server 192.168.247.130:8002 weight=5;
        server 192.168.247.130:8003;
    }
    ...
    server {
    	...
    	location / {
          proxy_pass http://test;
          ...
    	}
    	...
    }
	...
}
ip_hash示例

在配置文件中添加

http {
	...
	 upstream test {
        ip_hash;
        server 192.168.247.130:8001;
        server 192.168.247.130:8002;
        server 192.168.247.130:8003;
    }
    ...
    server {
    	...
    	location / {
          proxy_pass http://test;
          ...
    	}
    	...
    }
	...
}
自定义hash关键数值
  • 配置语法
Syntax: hash key [consistent]
Default:
Context: upstream
  • 示例

    在配置文件中添加

    http {
    	...
    	 upstream test {
            hash $request_uri;
            server 192.168.247.130:8001;
            server 192.168.247.130:8002;
            server 192.168.247.130:8003;
        }
        ...
        server {
        	...
        	location / {
              proxy_pass http://test;
              ...
        	}
        	...
        }
    	...
    }
    

缓存服务

  • 配置语法
Syntax: proxy_cache_path path [levels=levels] [user_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
Default:
Context: http
Syntax: proxy_cache zone|off
Default: proxy_cache off;
Context: http,server,location
  • 配置语法-缓存过期周期
Syntax: proxy_cache_valid [code …] time;
Default:
Context: http,server,location
  • 配置语法-缓存的维度
Syntax: proxy_cache_key string;
Default: proxy_cache_key $scheme$proxy_host$request_uri;
Context: http,server,location
  • 示例

    在配置文件中添加

    http{
        #配置3台服务
        upstream test {
            server 192.168.247.130:8001;
            server 192.168.247.130:8002;
            server 192.168.247.130:8003;
        }
    	#配置proxy_cache_path 存放缓存临时文件的目录 缓存的目录分级(2层) keys_zone开辟的空间 max_size最大大小(超过启动淘汰规则) 不活跃时间60分钟 
        proxy_cache_path /opt/app/cache levels=1:2 keys_zone=test_cache:10m max_size=10g inactive=60m use_temp_path=off;
    
        server {
            ...
            location / {
                proxy_cache test_cache;
                proxy_pass http://test;
                # 200或304的code 在12小时过期
                proxy_cache_valid 200 304 12h;
                # 其他code 在10分钟过期
                proxy_cache_valid any 10m;
                # 缓存的key定义
                proxy_cache_key $host$uri$is_args$args;
                #add_header  Nginx-Cache "$upstream_cache_status";  
            	#500/502/503/504/invalid_header/timeout/error 这些情况时用下一个服务
                proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
                ...
            }
          ...
        }
    }
    

如何清理指定缓存

  1. rm -rf 缓存目录内容
  2. 第三方扩展模块ngx_cache_purge

如何让部分页面不缓存

Syntax: proxy_no_cache string …;
Default:
Context: http,server,location
  • 示例

    在配置文件中添加

    http{
        ...
        server {
            ...
            if($request_uri ~ ^/(url3|login|register|password\/reset)){
                set $cookie_nocache 1;
            }
            
            location / {
                proxy_cache test_cache;
                proxy_pass http://test;
                # 200或304的code 在12小时过期
                proxy_cache_valid 200 304 12h;
                # 其他code 在10分钟过期
                proxy_cache_valid any 10m;
                # 缓存的key定义
                proxy_cache_key $host$uri$is_args$args;
                proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
                proxy_no_cache $http_pragma $http_authorization;
                #add_header  Nginx-Cache "$upstream_cache_status";  
            	#500/502/503/504/invalid_header/timeout/error 这些情况时用下一个服务
                proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
                ...
            }
          ...
        }
    }
    

分片请求

大文件分片请求

Syntax: slice size;
Default: slice 0;
Context: http,server,location

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

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

动静分离

通过中间件将动态请求和静态请求分离。

upstream java_api {
    server 127.0.0.1:8080;
}
server {
    listen       80;
    server_name  localhost;

    root /opt/app/code;
		# 动态请求 请求tomcat页面 代理方式
    location ~ \.jsp$ {
        proxy_pass http://java_api;
	      proxy_set_header Host $host;
    }
    # 静态请求
    location ~ \.(jpg|png|gif)$ {
	      expires 1h;
	      gzip on;
    }
    ...
}

Rewrite规则

  1. 作用:实现url重写以及重定向

  2. 场景

    1. URL访问跳转,支持开发设计(页面跳转、兼容性支持、展示效果等)
    2. SEO优化
    3. 维护(后台维护、流量转发等)
    4. 安全
  3. 配置语法

Syntax: rewrite regex replacement[flag];
Default:
Context: server,location,if
  1. flag
last 停止rewrite检测
break 停止rewrite检测
redirect 返回302临时重定向,地址栏会显示跳转后的地址
permanent 返回301永久重定向,地址栏会显示跳转后的地址
  • 示例

    在配置文件中添加

    server{
        ...
        root /opt/app/code;
        # break会去/opt/app/code/test/下面寻找
        location ~ ^/break {
            rewrite ^/break /test/ break;
        }
        # last重新建了一个请求到test
        location ~ ^/last {
            rewrite ^/last /test/ last;
        }
        location /test/ {
            default_type application/json;
            return 200 '{"status":"success"}';
        }
        ...
    }
    

规则场景

server {
    listen       80;
    server_name  localhost;
    root   /opt/app/code;

    location / {
    		# 场景一 重写请求路径
        rewrite ^/course-(\d+)-(\d+)-(\d+)\.html$ /course/$1/$2/course_$3.html break;
        # 场景二 Chrome浏览器访问的指定地址重定向百度
        if ($http_user_agent ~* Chrome) {
            rewrite ^/nginx http://www.baidu.com redirect;
        } 
				# 场景三 请求的资源不存在就重定向百度
        if (!-f $request_filename) {
            rewrite ^/(.*)$ http://www.baidu.com/$1 redirect;
        }
        index  index.html index.htm;
    }
    ...
}
  • Rewrite规则优先级

    ​ 执行server块的rewrite指令

    ​ 执行location匹配

    ​ 执行选定的location中的rewrite

Nginx高级模块

secure_link_module模块

  1. 制定并允许检查请求的链接的真实性以及保护资源免遭未经授权的访问
  2. 限制链接生效周期
  • 配置语法
Syntax: secure_link expression;
Default:
Context: http,server,location
Syntax: secure_link_md5 expression;
Default:
Context: http,server,location
  • 示例

    在配置文件中添加

    server {
        listen       80;
        server_name  localhost;
        root /opt/app/code;
    
        location / {
        	# 两个参数md5和expires
            secure_link $arg_md5,$arg_expires;
            # secure_link_md5加密方式 test自定义加密串
            secure_link_md5 "$secure_link_expires$uri test";
    
            if ($secure_link = "") {
                return 403;
            }
    
            if ($secure_link = "0") {
                return 410;
            }
        }
    	...
    }
    

geoip_module模块

基于IP地址匹配MaxMind GeoIP二进制文件,读取IP所在地域信息。

安装模块 yum install nginx-module-geoip

  • 使用场景

    1. 区别国内外作HTTP访问规则
    2. 区别国内城市地域作HTTP访问规则
  • 查看module安装

    $ cd /etc/nginx/modules/
    $ ls
    
  • 示例

    1. 在nginx.conf中引入模块

      load_module "modules/ngx_http_geoip_module.so";
      load_module "modules/ngx_stream_geoip_module.so";
      
    2. 下载文件

      # 现在要登陆后下载
      $ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
      $ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
      
    3. 修改配置文件

      # 引入文件
      geoip_country /etc/nginx/geoip/GeoIP.dat;
      geoip_city /etc/nginx/geoip/GeoLiteCity.dat;
      server {
          listen       80;
          server_name  localhost;
          
          location / {
              if ($geoip_country_code != CN) {
                  return 403;
              }
              root   /usr/share/nginx/html;
              index  index.html index.htm;
          }
      
         location /myip {
              default_type text/plain;
              return 200 "$remote_addr $geoip_country_name $geoip_country_code $geoip_city";
         }
         ...
      }
      

基于Nginx的HTTPS服务

  • 生成密钥和CA证书
    1. 确认openssl(openssl version)
    2. 查看ssl模块(nginx -V 查看–with-http_ssl_module)
  • 步骤
    1. 生成key密钥
    2. 生成证书签名请求文件(csr文件)
    3. 生成证书签名文件(CA文件)
# 1. 生成key密钥 设置一个密码
$ openssl genrsa -idea -out test.key 1024
# 2. 生成证书签名请求文件(csr文件)使用设置的密码
$ openssl req -new -key test.key -out test.csr
# 3. 生成证书签名文件(CA文件) 使用设置的密码
# 注意一定要加-days,否则默认一个月左右过期
$ openssl x509 -req -days 3650 -in test.csr -signkey test.key -out test.crt

# 查看当前加密证书算法类型
$ openssl x509 -noout -text -in ./test.crt
# 去除key密钥文件的保护密码
$ openssl rsa -in ./test.key -out ./test_nopass.key
  • HTTPS语法配置

ssl的开启与关闭

Syntax: ssl on|off;
Default: ssl off;
Context: http,server;

ssl证书文件

Syntax: ssl_certificate file;
Default:
Context: http,server

ssl密码文件

Syntax: ssl_certificate_key file;
Default:
Context: http,server
  • 示例

    在配置文件中添加

    server
     {
       listen       443;
       server_name  192.168.247.130;
       ssl on;
       ssl_certificate /etc/nginx/ssl_key/test.crt;
       ssl_certificate_key /etc/nginx/ssl_key/test.key;
    
       index index.html index.htm;
       location / {
           root  /opt/app/code;
       }
    }
    

场景 - 配置苹果要求的证书

  1. 服务器所有的连接使用TSL1.2以上版本(openssl 1.0.2)
  2. HTTPS证书必须使用SHA256以上哈希算法签名
  3. HTTPS证书必须使用RSA 2048位或ECC 256位以上公钥算法
  4. 使用前向加密技术
# 直接通过key密钥文件生成CA证书文件,不生成中间csr文件
$ openssl req -days 3650 -x509 -sha256 -nodes -newkey rsa:2048 -keyout test.key -out test_apple.crt
server
 {
   listen       443;
   server_name  192.168.247.130;
   ssl on;
   ssl_certificate /etc/nginx/ssl_key/test_apple.crt;
   ssl_certificate_key /etc/nginx/ssl_key/test.key;

   index index.html index.htm;
   location / {
       root  /opt/app/code;
   }
}

HTTPS服务优化

  1. 激活keepalive长连接
  2. 设置ssl session缓存
server
 {
   listen       443;
   server_name  192.168.247.130;
 
   # 激活长连接
   keepalive_timeout 100;

   ssl on;
   # 设置ssl session缓存
   ssl_session_cache   shared:SSL:10m;
   ssl_session_timeout 10m;

   ssl_certificate /etc/nginx/ssl_key/test.crt;
   ssl_certificate_key /etc/nginx/ssl_key/test.key;

   index index.html index.htm;
   location / {
       root  /opt/app/code;
   }
}

Nginx与Lua开发

Lua是一个简洁、轻量、可扩展的脚本语言。

优势:充分得结合Nginx的并发处理epoll优势和Lua的轻量,实现简单的功能和高并发的场景。

Lua基础语法

安装Lua yum install lua

-- 行注释

--[[
	块注释
--]]

-- while循环
sum=0
num=1
while num <= 100 do
    sum = sum + 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

--[[
布尔类型只有nil和false是false,其他都是true
lua没有++或是+=这样的操作
变量默认都是全局变量,local修饰表示局部变量
"~=" 是不等于
字符串的拼接操作符 ".."
io库的分别从stdin和stdout读写的read和write函数
--]]

Nginx+Lua环境安装

  1. 下载相关文件

    # 下载nginx 1.18.0
    $ wget http://nginx.org/download/nginx-1.18.0.tar.gz
    # 下载LuaJIT 2.1
    $ wget https://luajit.org/download/LuaJIT-2.1.0-beta3.tar.gz
    # 下载ngx_devel_kit模块
    $ wget https://github.com/vision5/ngx_devel_kit/archive/refs/tags/v0.3.1.tar.gz
    # 下载lua-nginx-module模块
    $ wget https://github.com/openresty/lua-nginx-module/archive/refs/tags/v0.10.13.tar.gz
    
  2. 安装LuaJIT

    # 解压缩
    $ tar -zxvf LuaJIT-2.1.0-beta3.tar.gz
    # 进入相关目录
    $ cd LuaJIT-2.1.0-beta3/
    # 编译安装
    $ make install  PREFIX=/usr/local/LuaJIT
    # 添加环境变量
    $ echo 'export LUAJIT_LIB=/usr/local/LuaJIT/lib' >> /etc/profile
    $ echo 'export LUAJIT_INC=/usr/local/LuaJIT/include/luajit-2.1' >> /etc/profile
    # 加载lua库,加入到ld.so.conf文件
    $ echo '/usr/local/lib' >> /etc/ld.so.conf
    $ echo '/usr/local/LuaJIT/lib' >> /etc/ld.so.conf
    # 重新加载环境变量
    $ source /etc/profile
    $ ldconfig
    
  3. 解压ngx_devel_kitj和lua-nginx-module

    $ tar -zxvf v0.3.1.tar.gz
    $ tar -zxvf v0.10.13.tar.gz
    
  4. 安装配置nginx1.18

    # 安装必要依赖
    $ yum install -y gcc pcre-devel openssl-devel zlib-devel
    # 解压缩
    $ tar -zxvf nginx-1.18.0.tar.gz
    # 进入相关目录
    $ cd nginx-1.18.0 
    # 编译安装nginx
    $./configure --prefix=/etc/nginx \
                 --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.pid \
                 --lock-path=/var/run/nginx.lock \
                 --http-client-body-temp-path=/var/cache/nginx/client_temp \
                 --http-proxy-temp-path=/var/cache/nginx/proxy_temp \
                 --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
                 --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
                 --http-scgi-temp-path=/var/cache/nginx/scgi_temp \
                 --user=nginx \
                 --group=nginx \
                 --with-compat \
                 --with-file-aio \
                 --with-threads \
                 --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-http_v2_module \
                 --with-mail \
                 --with-mail_ssl_module \
                 --with-stream \
                 --with-stream_realip_module \
                 --with-stream_ssl_module \
                 --with-stream_ssl_preread_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=/home/anglesang/work/app/ngx_devel_kit-0.3.1 \
                 --add-module=/home/anglesang/work/app/lua-nginx-module-0.10.13
    # 同目录下,编译安装
    $ make -j 4 && make install
    # 验证 查看最后几行
    $ nginx -V
    
避坑
  1. lua-nginx-module-0.10.19 模板使用了新版导致,使用 lua-nginx-module-0.10.13 解决

    adding module in /home/anglesang/work/app/lua-nginx-module-0.10.19
    checking for LuaJIT 2.x ... not found
        ./configure: error: unsupported LuaJIT version; ngx_http_lua_module requires LuaJIT 2.x.
    
  2. 安装lua开发包解决 yum install -y lua-devel

    checking for Lua library ... not found
    checking for Lua library in /usr/local/ ... not found
    checking for Lua library in /usr/local/ ... not found
    checking for Lua library in /usr/pkg/ ... not found
    checking for Lua library in /opt/local/ ... not found
    checking for Lua library in /usr/local/*/lua51/ ... not found
    checking for Lua library in /usr/ ... not found
    checking for LuaJIT library in /usr/local/ ... not found
    checking for LuaJIT library in /usr/ ... not found
    checking for LuaJIT library in /usr/ ... not found
     ./configure: error: ngx_http_lua_module requires the Lua library.
    

Nginx调用Lua模块指令

Nginx的可插拔模块化加载执行,共11个处理阶段

set_by_lua
set_by_lua_file
设置nginx变量,可以实现复杂的赋值逻辑
access_by_lua
access_by_lua_file
请求访问阶段处理,用于访问控制
content_by_lua
content_by_lua_file
内容处理器,接受请求处理并输出响应

Nginx Lua API

ngx.var nginx变量
ngx.req.get_headers 获取请求头
ngx.req.get_uri_args 获取url请求参数
ngx.redirect 重定向
ngx.print 输出响应内容体
ngx.say 同ngx.print,但是会最后输出一个换行符
ngx.header 输出响应头

实战场景 - 灰度发布

按照一定的关系区别,分部分的代码进行上线,使代码的发布能平滑过渡上线。

  1. memcached 配置

    # 安装memcached 
    $ sudo yum install -y memcached
    # 启动memcached
    $ memcached -p 11211 -u nobody -d -m 128
    # 连接memcached
    $ telnet 127.0.0.1 11211
    # 设置值
    $ set 192.168.247.133 0 0 1
    > 1
    # 获取值 验证
    $ get 192.168.247.133
    
  2. 启动并配置两个tomcat 8080和9090

    复制tomcat8080为tomcat9090,将tomcat9090中的server.xml文件中的所有8改为9

  3. 修改nginx配置

    server {
        listen       80;
        server_name  localhost;
    
        access_log  /var/log/nginx/log/host.access.log  main;
        
        location /hello {
            default_type 'text/plain';
            content_by_lua 'ngx.say("hello, lua")';
        }
     
        location /myip {
            default_type 'text/plain';
            content_by_lua '
                clientIP = ngx.req.get_headers()["Host"]
                ngx.say("IP:",clientIP)
                ';
        }
    
        location / {
            default_type "text/html"; 
            content_by_lua_file /opt/app/lua/dep.lua;
        }
    
        location @server{
            proxy_pass http://127.0.0.1:9090;
        }
    
        location @server_test{
            proxy_pass http://127.0.0.1:8080;
        }
    
        error_page   500 502 503 504 404  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }
    
  4. 测试lua

    访问http://192.168.247.130/hello 地址

  5. 添加lua文件

    clientIP = ngx.req.get_headers()["X-Real-IP"]
    if clientIP == nil then
        clientIP = ngx.req.get_headers()["x_forwarded_for"]
    end
    if clientIP == nil 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)
    if err then
        ngx.say("failed to get clientIP ", err)
        return
    end
    if  res == "1" then
        ngx.exec("@server_test")
        return
    end
    ngx.exec("@server")
    
  6. 添加lua调用memcached的模块

    # 下载lua中memcached的模块
    $ wget https://github.com/openresty/lua-resty-memcached/archive/refs/tags/v0.15.tar.gz
    # 解压
    $ tar -zxvf v0.15.tar.gz
    # 移动
    $ cp -r lua-resty-memcached-0.15/lib/resty /usr/lib64/lua/5.1
    # 重新加载环境变量
    $ ldconfig
    

Nginx常见问题

  • 相同server_name多个虚拟主机优先级访问

    server{
    	listen 80;
    	server_name testserver1 aaa.aaa.com;
    	location / {
    		...
    	}
    }
    server{
    	listen 80;
    	server_name testserver2 aaa.aaa.com;
    	location / {
    		...
    	}
    }
    

    优先级根据配置加载顺序

  • location匹配优先级

    匹配方式 含义
    = 全等匹配
    普通匹配
    ^~ 普通匹配,使用前缀匹配
    ~ 正则匹配,区分大小写
    ~* 正则匹配,不区分大小写
  1. 匹配到全等匹配时,终止后续所有匹配,直接返回
  2. 步骤一未匹配上时,遍历所有的普通匹配,按照最长匹配原则找到最满足的匹配项,如果匹配项前面有^~符号,则终止后续正则匹配,采用该匹配项;反之则继续后续的正则匹配
  3. 步骤一二都未匹配上时,此时进行正则匹配,找到第一个满足的正则匹配项,直接返回,若都不满足,则返回步骤二中的最长匹配项(正则匹配和loaction的顺序有关系
  • try_files使用

    按顺序检查文件是否存在,返回第一个找到的文件或文件夹(结尾加斜线表示为文件夹),如果所有的文件或文件夹都找不到,会进行一个内部重定向到最后一个参数。

    location / {
    	try_files $uri $uri/ /index.php;
    }
    
  • Nginx的alias和root区别

    • root

      location /test/img/ {
      	root /home/anglesang/img/;
      }
      

      请求 http://www.test.com/test/img/cat.png

      实际访问资源 /home/anglesang/img/test/img/cat.png

      root地址+uri

    • alias

      location /test/img/ {
        	alias /home/anglesang/img/;
      }
      

      请求 http://www.test.com/test/img/cat.png

      实际访问资源 /home/anglesang/img/cat.png

  • 用什么方法传递用户的真实IP

    set x_real_ip = $remote_addr

  • nginx中常见错误码

    • 413 Request Entity Too Large

      用户上传文件限制 client_max_body_size

    • 503 bad gateway

      后端服务无响应

    • 504 Gateway Time-out

      后端服务执行超时

Nginx性能优化

ab压测工具

  • 几个关于压力测试的概念

    1. 吞吐率(Requests per second)
      概念:服务器并发处理能力的量化描述,单位是reqs/s,指的是某个并发用户数下单位时间内处理的请求数。某个并发用户数下单位时间内能处理的最大请求数,称之为最大吞吐率。
      计算公式:总请求数 / 处理完成这些请求数所花费的时间,即
      Request per second = Complete requests / Time taken for tests

    2. 并发连接数(The number of concurrent connections)
      概念:某个时刻服务器所接受的请求数目,简单的讲,就是一个会话。

    3. 并发用户数(The number of concurrent users,Concurrency Level)
      概念:要注意区分这个概念和并发连接数之间的区别,一个用户可能同时会产生多个会话,也即连接数。

    4. 用户平均请求等待时间(Time per request)
      计算公式:处理完成所有请求数所花费的时间/ (总请求数 / 并发用户数),即
      Time per request = Time taken for tests /( Complete requests / Concurrency Level)

    5. 服务器平均请求等待时间(Time per request: across all concurrent requests)
      计算公式:处理完成所有请求数所花费的时间 / 总请求数,即
      Time taken for / testsComplete requests
      可以看到,它是吞吐率的倒数。
      同时,它也=用户平均请求等待时间/并发用户数,即
      Time per request / Concurrency Level

  1. 安装

    yum install -y httpd-tools

  2. ab -n 2000 -c 2 http://127.0.0.1/

    -n 总的请求数

    -c 并发数

    -k 是否开启长连接

系统与Nginx性能优化

  • 文件句柄设置

    linux\Unix 一切皆文件,文件句柄就是一个索引

    • 设置方式

      1. 系统全局性修改

      2. 用户局部性修改

      3. 进程局部性修改

  • CPU亲和配置

    # 物理CPU个数
    $ cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l 
    # 每个物理CPU中core的个数
    $ cat /proc/cpuinfo | grep "cpu cores" | uniq
    # 逻辑CPU的个数
    $ cat /proc/cpuinfo | grep "processor" | wc -l
    
  • nginx通用配置优化

    # 每个work连接数
    work_connections 1024;
    # 字符集统一
    charset utf-8;
    # 日志格式
    log_format ....
    # 日志情况设置
    access_log off;
    # sendfile设置
    sendfile on;
    # 静态资源推荐
    tcp_nopush on;
    # 动态资源推荐
    tcp_nodeny on;
    keepalive_timeout 65;
    # gzip压缩可配置
    

Nginx安全

  1. 常见恶意行为

    爬虫行为和恶意抓取、资源盗用
    基础防盗链功能 - 目的不让恶意用户能轻易的爬取网站对外数据
    secure_link_module - 对数据安全性提高加密验证和失效性,适合如核心重要重要数据
    access_module - 对后台、部分用户服务的数据提供IP防控

  2. 常见的攻击手段

    • 后台密码撞库 - 通过猜测密码字典不断对后台系统登录性尝试,获取后台登录密码
      方法一、后台登录密码复杂度
      方法二、access_module - 对后台提供IP防控
      方法三、预警机制

    • 文件上传漏洞 - 利用这些可以上传的接口将恶意代码植入到服务器中,再通过url去访问以执行代码

      对上传文件判断

      location ^~ /upload {
      	root /opt/app/images;
      	if($request_filename ~* (.*)\.php){
      		return 403;
      	}
      }
      
    • SQL注入 - 利用未过滤/未审核用户输入的攻击方法,让应用运行本不应该运行的SQL代码

其他

# 检查配置文件语法
$ nginx -t -c /etc/nginx/nginx.conf 
# centos系,查看nginx文件
$ rpm -ql nginx
$ systemctl start nginx
$ systemctl restart nginx
$ systemctl stop nginx
$ systemctl reload nginx
$ systemctl status nginx

你可能感兴趣的:(nginx)