1. Host 头匹配流程

HOST 匹配

2. 环境设置

2.1. Nginx 用户组

groupadd www-data
useradd -g www-data www-data

2.2. 设置介绍

nginx 配置文件主要分成四个部分:

  1. main, 全局设置, 影响其它部分所有设置
  2. server, 主机服务相关设置, 主要用于指定虚拟主机域名、IP和端口
  3. location, URL匹配特定位置后的设置, 反向代理、内容篡改相关设置
  4. upstream, 上游服务器设置, 负载均衡相关配置

他们之间的关系式: server继承main, location继承server; upstream既不会继承指令也不会被继承。

2.3. Nginx Https 设置

http {
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 10m;

    server {
        listen              443 ssl;
        server_name example.com;
        keepalive_timeout   70;

        access_log /var/log/xxx.log;
        root /xxx/xxx/;

        #证书在服务器的绝对位置
        ssl_certificate /xxx/213996598310998.pem;
        ssl_certificate_key /xxx/213996598310998.key;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;
    }
}

2.4. 日志按月滚动

vim /etc/logrotate.d/nginx

/data/logs/nginx/*.log {
    missingok
    dateext
    dateformat -%Y%m%d
    notifempty
    monthly
    rotate 7
    size 200M
    sharedscripts
    postrotate
        if [ -f /usr/local/nginx/logs/nginx.pid ]; then
            kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
        fi
    endscript
}

crontab -e #添加以下代码
0 0 1 * * /usr/sbin/logrotate -vf /etc/logrotate.d/nginx #每天凌晨定时执行脚本

2.5. worker_processes与worker_connections

2.5.1. worker_processes

worker 角色的进程个数(nginx启动后有多少个 worker 处理 http 请求。master 不处理请求, 而是根据相应配置文件信息管理 worker 进程. master 进程主要负责对外揽活(即接收客户端的请求), 并将活儿合理的分配给多个 worker, 每个 worker 进程主要负责干活(处理请求))。

最理想的 worker_processes 值取决于很多因素, 包含但不限于 CPU 的核数, 存储数据的硬盘驱动器个数(跟这个有什么关系?难道和cpu一样, 存在跨区域读取数据问题), 以及负载模式(?这个是什么?)当其中任何一个因素不确定的时候, 将其设置为cpu核数或许是一个比较好的初始值, “自动”也基本是如此确认一个参数值的。

“自动”这个参数值是从nginx 1.3.8和nginx 1.2.5 开始进行支持的, 自动参数可以自动检测 cpu cores 并设置 worker_processes 参数 。

如果nginx处理的是cpu密集型(比较耗费cpu的)的操作, 建议将此值设置为cpu个数或cpu的核数。

2.5.2. worker_connections

官方解释如下, 个人认为是每一个worker进程能并发处理(发起)的最大连接数(包含所有连接数)。

不能超过最大文件打开数: 在linux终端中输入ulimit -a进行查看

2.5.3. 杂项

# 隐藏Nginx版本信息: 
server_tokens off;

3. Nginx模型

3.1. 进程

Nginx採用多进程模型, 单Master—多Worker, 由Master处理外部信号、配置文件的读取及Worker的初始化。Worker进程採用单线程、非堵塞的事件模型(Event Loop, 事件循环)来实现port的监听及client请求的处理和响应, 同一时候Worker还要处理来自Master的信号。

因为Worker使用单线程处理各种事件。所以一定要保证主循环是非堵塞的, 否则会大大减少Worker的响应能力。

3.2. 协程(Coroutine)

协程类似一种多线程, 与多线程的差别有:

  • 协程并不是os线程, 所以创建、切换开销比线程相对要小。
  • 协程与线程一样有自己的栈、局部变量等, 可是协程的栈是在用户进程空间模拟的, 所以创建、切换开销非常小。
  • 多线程程序是多个线程并发运行。也就是说在一瞬间有多个控制流在运行。而协程强调的是一种多个协程间协作的关系, 仅仅有当一个协程主动放弃运行权, 还有一个协程才干获得运行权, 所以在某一瞬间, 多个协程间仅仅有一个在运行。
  • 因为多个协程时仅仅有一个在执行, 所以对于临界区的訪问不须要加锁。而多线程的情况则必须加锁。
  • 多线程程序因为有多个控制流。所以程序的行为不可控, 而多个协程的运行是由开发人员定义的所以是可控的。

Nginx的每一个Worker进程都是在epoll或kqueue这种事件模型之上, 封装成协程, 每一个请求都有一个协程进行处理。这正好与Lua内建协程的模型是一致的, 所以即使ngx_lua须要运行Lua, 相对C有一定的开销, 但依旧能保证高并发能力。

3.3. 负载均衡

  • 轮询, 即Round Robin, 根据Nginx配置文件中的顺序, 依次把客户端的Web请求分发到不同的后端服务器。
  • 最少连接
  • IP地址哈希
  • 基于权重的负载均衡

3.4. 子请求(subrequest)

事实上在Nginx 世界里有两种类型的“请求”。一种叫做“主请求”(main request), 而还有一种则叫做“子请求”(subrequest)。

所谓“主请求”。就是由 HTTP client从 Nginx 外部发起的请求。比方,从浏览器訪问Nginx就是一个“主请求”。 而“子请求”则是由 Nginx 正在处理的请求在 Nginx 内部发起的一种级联请求。

“子请求”在外观上非常像 HTTP 请求, 但实现上却和 HTTP 协议乃至网络通信一点儿关系都没有。它是 Nginx 内部的一种抽象调用, 目的是为了方便用户把“主请求”的任务分解为多个较小粒度的“内部请求”, 并发或串行地訪问多个 location 接口。

然后由这些 location 接口通力协作, 共同完毕整个“主请求”。当然。“子请求”的概念是相对的, 不论什么一个“子请求”也能够再发起很多其它的“子子请求”。甚至能够玩递归调用(即自己调用自己)。

当一个请求发起一个“子请求”的时候, 依照 Nginx 的术语, 习惯把前者称为后者的“父请求”(parent request)。

location /main {
    echo_location /foo; # echo_location发送子请求到指定的location
    echo_location /bar;
}
location /foo {
    echo foo;
}
location /bar {
    echo bar;
}


$ curl location/main
$ foo 03. bar

这里, main location就是发送2个子请求, 分别到foo和bar。这就类似一种函数调用。

“子请求”方式的通信是在同一个虚拟主机内部进行的。所以 Nginx 核心在实现“子请求”的时候, 就仅仅调用了若干个 C 函数, 全然不涉及不论什么网络或者 UNIX 套接字(socket)通信。我们由此能够看出“子请求”的运行效率是极高的。

4. Nginx处理Http请求的过程

表面上看, 当Nginx处理一个来自client的请求时, 先依据请求头的host、ip和port来确定由哪个server处理, 确定了server之后, 再依据请求的uri找到相应的location。这个请求就由这个location处理。
实际Nginx将一个请求的处理划分为若干个不同阶段(phase)。这些阶段依照前后顺序依次运行。也就是说NGX_HTTP_POST_READ_PHASE在第一个, NGX_HTTP_LOG_PHASE在最后一个。

  • NGX_HTTP_POST_READ_PHASE,                 //0读取请求phase
  • NGX_HTTP_SERVER_REWRITE_PHASE,        //1这个阶段主要是处理全局的(server block)的rewrite
  • NGX_HTTP_FIND_CONFIG_PHASE,             //2这个阶段主要是通过uri来查找相应的location, 然后依据loc_conf设置r的相应变量
  • NGX_HTTP_REWRITE_PHASE,                     //3这个主要处理location的rewrite
  • NGX_HTTP_POST_REWRITE_PHASE,             //4postrewrite, 这个主要是进行一些校验以及收尾工作。以便于交给后面的模块。
  • NGX_HTTP_PREACCESS_PHASE,                 //5比方流控这样的类型的access就放在这个phase, 也就是说它主要是进行一些比較粗粒度的access。
  • NGX_HTTP_ACCESS_PHASE,                         //6这个比方存取控制, 权限验证就放在这个phase, 一般来说处理动作是交给以下的模块做的.这个主要是做一些细粒度的access
  • NGX_HTTP_POST_ACCESS_PHASE,                 //7一般来说当上面的access模块得到access_code之后就会由这个模块依据access_code来进行操作
  • NGX_HTTP_TRY_FILES_PHASE,                 //8try_file模块, 就是相应配置文件里的try_files指令。可接收多个路径作为參数。当前一个路径的资源无法找到, 则自己主动查找下一个路径 
  • NGX_HTTP_CONTENT_PHASE,                     //9内容处理模块 
  • NGX_HTTP_LOG_PHASE                                 //10log模块

每一个阶段上能够注冊handler。处理请求就是执行每一个阶段上注冊的handler。Nginx模块提供的配置指令仅仅会一般仅仅会注冊并执行在当中的某一个处理阶段。
比方, set指令属于rewrite模块的, 执行在rewrite阶段, deny和allow执行在access阶段。

5. Nginx 的 TCP 负载均衡

Nginx除了以前常用的HTTP负载均衡外, Nginx增加基于TCP协议实现的负载均衡方法。

HTTP负载均衡, 也就是我们通常所有“七层负载均衡”, 工作在第七层“应用层”。而TCP负载均衡, 就是我们通常所说的“四层负载均衡”, 工作在“网络层”和“传输层”。例如, LVS(Linux Virtual Server, Linux虚拟服务)和F5(一种硬件负载均衡设备), 也是属于“四层负载均衡”。

5.1. TCP负载均衡的配置方式

Nginx使用了一个新的stream模块来实现TCP负载均衡, 这个模块, 类似于http和mail模块, 允许我们配置一组监听TCP连接的服务。允许你配置多个服务的TCP连接, 通过在upstream的server组中配置proxy_pass指令。

修改nginx.conf文件, 在http模块的统计目录, 添加一个stream模块(和http等同级):

stream {
    server {
        listen 1034;
        proxy_pass app;
    }
 
    upstream app {
        server 192.168.0.3:1034;
        server 192.168.0.4:1034;
        server 192.168.0.6:1034;
    }
}

5.2. TCP负载均衡的执行原理

当Nginx从监听端口收到一个新的客户端链接时, 立刻执行路由调度算法, 获得指定需要连接的服务IP, 然后创建一个新的上游连接, 连接到指定服务器。

TCP负载均衡支持Nginx原有的调度算法, 包括Round Robin(默认, 轮询调度), 哈希(选择一致)等。同时, 调度信息数据也会和健壮性检测模块一起协作, 为每个连接选择适当的目标上游服务器。如果使用Hash负载均衡的调度方法, 你可以使用$remote_addr(客户端IP)来达成简单持久化会话(同一个客户端IP的连接, 总是落到同一个服务server上)。

和其他upstream模块一样, TCP的stream模块也支持自定义负载均和的转发权重(配置“weight=2”), 还有backup和down的参数, 用于踢掉失效的上游服务器。max_conns参数可以限制一台服务器的TCP连接数量, 根据服务器的容量来设置恰当的配置数值, 尤其在高并发的场景下, 可以达到过载保护的目的。

Nginx监控客户端连接和上游连接, 一旦接收到数据, 则Nginx会立刻读取并且推送到上游连接, 不会做TCP连接内的数据检测。Nginx维护一份内存缓冲区, 用于客户端和上游数据的写入。如果客户端或者服务端传输了量很大的数据, 缓冲区会适当增加内存的大小。

当Nginx收到任意一方的关闭连接通知, 或者TCP连接被闲置超过了proxy_timeout配置的时间, 连接将会被关闭。对于TCP长连接, 我们更应该选择适当的proxy_timeout的时间, 同时, 关注监听socke的so_keepalive参数, 防止过早地断开连接。

5.3. 服务健壮性监控

TCP负载均衡模块支持内置健壮性检测, 一台上游服务器如果拒绝TCP连接超过proxy_connect_timeout配置的时间, 将会被认为已经失效。在这种情况下, Nginx立刻尝试连接upstream组内的另一台正常的服务器。连接失败信息将会记录到Nginx的错误日志中。

如果一台服务器, 反复失败(超过了max_fails或者fail_timeout配置的参数), Nginx也会踢掉这台服务器。服务器被踢掉60秒后, Nginx会偶尔尝试重连它, 检测它是否恢复正常。如果服务器恢复正常, Nginx将它加回到upstream组内, 缓慢加大连接请求的比例。

之所“缓慢加大”, 因为通常一个服务都有“热点数据”, 也就是说, 80%以上甚至更多的请求, 实际都会被阻挡在“热点数据缓存”中, 真正执行处理的请求只有很少的一部分。在机器刚刚启动的时候, “热点数据缓存”实际上还没有建立, 这个时候爆发性地转发大量请求过来, 很可能导致机器无法“承受”而再次挂掉。以mysql为例子, 我们的mysql查询, 通常95%以上都是落在了内存cache中, 真正执行查询的并不多。

其实, 无论是单台机器或者一个集群, 在高并发请求场景下, 重启或者切换, 都存在这个风险, 解决的途径主要是两种:

  1. 请求逐步增加, 从少到多, 逐步积累热点数据, 最终达到正常服务状态。
  2. 提前准备好“常用”的数据, 主动对服务做“预热”, 预热完成之后, 再开放服务器的访问。

TCP负载均衡原理上和LVS等是一致的, 工作在更为底层, 性能会高于原来HTTP负载均衡不少。但是, 不会比LVS更为出色, LVS被置于内核模块, 而Nginx工作在用户态, 而且, Nginx相对比较重。另外一点, 令人感到非常可惜, 这个模块竟然是个付费功能。(补注: 本文写于 2015 年 1 月, 当初这个模块是收费的)

6. 禁止其它域名访问

nginx安装在192.168.111.124,上面配置2个域名doc.myj.com.cnzabbix.myj.com.cn。默认情况下输入http://192.168.111.124会打开doc.myj.com.cn页面,要求实现只能通过域名访问,使用IP地址提示403或跳转其它页面。

6.1. 增加default.conf配置文件

server {
listen 80 default_server;
server_name _;
return 403; ## index 403.html

}

6.2. 重启生效

详情可参考:https://nginx.org/en/docs/http/server_names.html

7. 跨域问题处理

假如代理服务器地址是 www.c.com/proxy/html/api/msg?method=1=2;   www.c.com是nginx主机地址

远端服务器地址:http://www.b.com/api/msg?method=1=2

在nginx服务器上做如下配置。在location下面再添加一个location。

location ^~/proxy/html/{
      rewrite ^/proxy/html/(.*)$ /$1 break;
      proxy_pass http://www.b.com/;
}

7.1. 说明

'^~ /proxy/html/ ‘

  就像上面说的一样是一个匹配规则,用于拦截请求,匹配任何以 /proxy/html/开头的地址,匹配符合以后,停止往下搜索正则。

rewrite ^/proxy/html/(.*)$ /$1 break;

  代表重写拦截进来的请求,并且只能对域名后边的除去传递的参数外的字符串起作用,例如www.c.com/proxy/html/api/msg?method=1=2重写。只对/proxy/html/api/msg重写。

  rewrite后面的参数是一个简单的正则 ^/proxy/html/(.*)$ ,$1代表正则中的第一个(),$2代表第二个()的值,以此类推。

  break代表匹配一个之后停止匹配。

8. Node.js 反向代理

服务端如果使用nodejs运行服务,由于端口不能同时多个服务占用,而服务器中可能又是多个网站,那么可以使用 Nginx 做反向代理,比如有这些网站域名和端口:

域名 端口
www.xxoo.com 8001
www.xo.com 8002
www.xo.cn 8003

8.1. 配置文件

server {
    server_name www.xxoo.com;
    listen 80;

    # 设置这个网站的根目录
    root /wwwroot/www.xxoo.com/;

    # 由于下面配置了文件不存在则代码到 Node.js 中,那么直接访问目录(不带默认主页)的话会有问题,这里做下判断
    # 如果访问目录下有 index.html 文件,则直接重写到该文件
    # break 表示重写且停止,但 url 不变,而 permanent 表示301重定向,url 会更新
    if ( -f $request_filename/index.html ){
        rewrite (.*) $1/index.html break;
    }

    # 如果请求的文件不存在,则代理到 Node.js
    if ( !-f $request_filename ){
        rewrite (.*) /index.js;
    }

    # 代理node服务 8001
    location = /index.js {
        # 设置一些代理的header信息,这些信息将被透传到 Node.js 服务的header信息里
        proxy_set_header Connection "";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;

        # 代理服务
        proxy_pass http://127.0.0.1:8001$request_uri;

        # 忽略其他重写
        proxy_redirect off;
    }
}

内容说明

访问链接 解析过程 备注
www.xxoo.com/index.html Nginx 由于文件存在,直接使用 Nginx 输出
www.xxoo.com Nginx 由于判断该目录下有 index.html 文件,则自动重写到该文件,但 url 不变
www.xxoo.com/xx.html Nginx -> Node.js:8001 由于文件不存在,使用 Nginx 代理到 Node.js 的 8001 端口
www.xxoo.com/xxoo/ Nginx -> Node.js:8001 首先判断该目录是否存在
如果存在再判断是否有 index.html 文件
一旦不成立,直接代理到 Node.js

9. 重写网页图片 CDN

在不调整网页代码的情况下重新调整页面展示图片的后端网络

    location ^~ /test/ {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host       "appfleet.com";
        proxy_set_header        X-Forwarded-Proto https;
        proxy_pass http://127.0.0.1:2368;
        proxy_redirect off;
        
        #disable compression 
        proxy_set_header Accept-Encoding "";
        #rewrite the html
        sub_filter_once off;
        sub_filter_types text/html;
         sub_filter '<img src="https://appfleet.com' '<img loading="lazy" src="https://appfleet-com.cdn.ampproject.org/i/s/appfleet.com';
    }

10. rewrite 重定向

10.1. rewrite 语法格式及参数语法

rewrite是实现URL重写的关键指令,根据regex (正则表达式)部分内容,重定向到replacement,结尾是flag标记。

rewrite    <regex>    <replacement>    [flag];

  • 关键字      正则        替代内容         flag标记
  • 关键字:其中关键字error_log不能改变
  • 正则:perl兼容正则表达式语句进行规则匹配
  • 替代内容:将正则匹配的内容替换成replacement
  • flag标记:rewrite支持的flag标记

rewrite参数的标签段位置:server,location,if

flag标记说明:

  • last  #本条规则匹配完成后,继续向下匹配新的location URI规则
  • break  #本条规则匹配完成即终止,不再匹配后面的任何规则
  • redirect  #返回302临时重定向,浏览器地址会显示跳转后的URL地址
  • permanent  #返回301永久重定向,浏览器地址栏会显示跳转后的URL地址

10.2. Nginx rewrite变量

常用于匹配HTTP请求头信息、浏览器主机名、URL

HTTP headers:HTTP_USER_AGENT, HTTP_REFERER, HTTP_COOKIE, HTTP_HOST, HTTP_ACCEPT;

connection & request: REMOTE_ADDR, QUERY_STRING;

server internals: DOCUMENT_ROOT, SERVER_PORT, SERVER_PROTOCOL;

system stuff: TIME_YEAR, TIME_MON, TIME_DAY。

详解如下:

  • HTTP_USER_AGENT      用户使用的代理,例如浏览器;
  • HTTP_REFERER         告知服务器,从哪个页面来访问的;
  • HTTP_COOKIE          客户端缓存,主要用于存储用户名和密码等信息;
  • HTTP_HOST            匹配服务器ServerName域名;
  • HTTP_ACCEPT          客户端的浏览器支持的MIME类型;      
  • REMOTE_ADDR          客户端的IP地址
  • QUERY_STRING         URL中访问的字符串;
  • DOCUMENT_ROOT        服务器发布目录;
  • SERVER_PORT          服务器端口;
  • SERVER_PROTOCOL      服务器端协议;
  • TIME_YEAR            年;
  • TIME_MON             月;
  • TIME_DAY              日;

10.3. 场景举例

1、将uri中的所有空格替换为"_",连续的空格替换为一个"_"放到proxy_pass之前

rewrite '^(\S+) +(\S+)(.*)' $1_$2$3 last;

2、将zy.com跳转至www.zy.com

if ($host = zy.com' ) {
     #其中$1是取自regex部分()里的内容,匹配成功后跳转到的URL。
     rewrite ^/(.*)$  http://www.zy.com/$1  permanent;
}

3、访问www.zy.com跳转www.test.com/index01.html

rewrite   ^/$  http://www.test.com/index01.html  permanent;

4、访问/zy/test01/跳转至/newindex.html,浏览器地址不变

rewrite   ^/zy/test01/$     /newindex.html     last;

5、多域名跳转到www.zy.com

if ($host != ‘www.jfedu.net’ ) {
    rewrite ^/(.*)$  http://www.zy.com/$1  permanent;
}

6、访问文件和目录不存在跳转至index.php

if ( ! -e $request_filename ) {
    rewrite  ^/(.*)$  /index.php  last;
}

7、目录对换 /xxxx/123456 ====> /xxxx?id=123456

rewrite    ^/(.+)/(\d+)      /$1?id=$2       last;

8、判断浏览器User Agent跳转

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

9、禁止访问以.sh,.flv,.mp3为文件后缀名的文件

location ~ .*\.(sh|flv|mp3)${
       return 403;
}

 10、将移动用户访问跳转至移动端

if ( $http_user_agent ~* "(Android)|(iPhone)|(Mobile)|(WAP)|(UCWEB)" ){
      rewrite ^/$    http://m.jfedu.net/    permanent;
}

11、访问/10690/zy/123跳转至/index.php?tid/10690/items=123,[0-9]表示任意一个数字,+表示多个,(.+)表示任何多个字符

rewrite   ^/([0-9]+)/zy/(.+)$     /index.php?tid/$1/items=$2     last;

12、匹配URL访问字符串跳转

if ($args ~* tid=13){
    return 404;
}

11. Nginx 取代理后的 IP

1、系统安装:CentOS7/8 系统安装标准

2、Nginx安装:Nginx 编译安装及配置指南

3、Nginx需要包含--with-http_realip_module模块

11.1. 针对普通的代理方式

在Server段增加

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

提示

$proxy_add_x_forwarded_for 这个变量会将所有代理的IP都包含其中,而第一个IP就是用户的真实IP,值的格式如下:TTP_X_FORWARDED_FOR => remote_ip,proxy1_ip, proxy2_ip,... ...

11.2. 针对CDN后的反向代理模式

proxy_set_header X-Real-IP                  $remote_addr; 
proxy_set_header X-Forwarded-For     $proxy_add_x_forwarded_for; 
set_real_ip_from 118.89.52.242; 
real_ip_header X-Forwarded-For;

上游服务器IP是:118.89.52.242,同时需要从X-Forwarded-For字段中获取访客IP

提示

set_real_ip_from:指定上游服务器

real_ip_header:指定获取访客IP的位置

两个语句可以放置在http、server和location区块中,放置在http区块中将对所有的虚拟空间生效。

12. Conflunece 的 Nginx 配置

server {
	client_max_body_size 100m;
	
	listen        80;
	listen        443;
 
	ssl        on;
	ssl_certificate         /usr/local/etc/ssl/wiki.ourclass.com.pem;
	ssl_certificate_key     /usr/local/etc/ssl/wiki.ourclass.com.key;
 
	server_name   wiki.ourclass.com;
	access_log    /var/log/nginx/wiki.log  main;
 
	location / {
		proxy_pass http://127.0.0.1:8090/;
		proxy_set_header   Host    $host;
		proxy_set_header   X-Real-IP   $remote_addr;
		proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
	}

	location /synchrony {
		proxy_pass http://127.0.0.1:8091;
		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_http_version 1.1;
		proxy_set_header Upgrade $http_upgrade;
		proxy_set_header Connection "upgrade";
	}

  location ~ ^/ttyd(.*)$ {
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_pass http://127.0.0.1:8094/$1;
  }
 
 # 重定向non-https流量到https
	if ($scheme != "https") {
		return 301 https://$host$request_uri;
	}
}

注意,上面的路径配置有两个,分别是/和/synchrony,前者就是wiki的主体,后者是用来检测wiki的URL地址的一个心跳服务。其中,第二个映射/synchrony中的如下配置必须要有,否则前端多人协作的时候就会有一些问题。

http 1.1 添加的配置是为了保证wiki中的Websocket服务正常运行。

12.1. 配置Confluence

配置完了上述的系统以后就觉得可以访问了,但是一直会报一个警告就是

无法检测Base URL,是不是存在代理的配置问题

英文版的是

can't check base url warning

这个问题的解决方案除了上述的/stnchrony配置外,还需要加入一个Tomcat的配置,就是要在<install-directory>/conf/server.xml这个文件里面添加proxyPort和proxyName的配置,如下:

<Connector port="8090" connectionTimeout="20000" redirectPort="8443"
     maxThreads="48" minSpareThreads="10"
     enableLookups="false" acceptCount="10" debug="0" URIEncoding="UTF-8"
     protocol="org.apache.coyote.http11.Http11NioProtocol" 
     proxyName="ourclass.com" proxyPort="443" scheme="https"/>

12.2. 总结

这个问题的解决方案还是需要理解confluence的几个核心的组件,然后在根据这些核心的组件进行相应的配置。尤其是这个/synchrony组件非常关键,如果不加上这个完整的服务根本就起不来。


13. stream 端口转发配置

13.1. 安装

./configure  --with-stream  #添加stream模块

13.2. 配置

主配置文件nginx.conf增加stream模块配置

之前在http增加的include会提示虚拟目录里的配置项不允许在某个位置

stream {
    include rds/*.conf;
}

13.3. 虚拟目录配置

#nTMXX-01-ZFPT-订单
upstream nTMXX-01-ZFPT-DD {
       server rm-wz994z33d9e8i9b38yo.sqlserver.rds.aliyuncs.com:3433 weight=5 max_fails=3 fail_timeout=30s;
}

server {
       listen 39600;
       proxy_connect_timeout 60s;
       proxy_timeout 4h;
       proxy_pass nTMXX-01-ZFPT-DD;
}

13.4. 测试

nginx -t

nginx -s reload 或 systemctl reload nginx

13.5. Nginx 邮件代理

# nginx 分流 993 端口的配置参考如下,465 和 995 照样画葫芦。25 、587 端口用 postfix 或 exim4 ,具体配置可以问 gpt 。

stream {
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    map $ssl_preread_server_name $stream_map993 {
      mail.domain1.com upstream_993_svr1;
      mail.domain2.com upstream_993_svr2;
      mail.domain3.com upstream_993_svr3;
    }

    upstream upstream_993_svr1 {
      server 192.168.1.100:993;
    }

    upstream upstream_993_svr2 {
      server 192.168.1.101:993;
    }

    upstream upstream_993_svr3 {
      server 192.168.1.102:993;
    }

# stream 模块监听 993 端口,并进行端口复用
  server {
    listen 993 reuseport;
    listen [::]:993 reuseport ipv6only=on;
    proxy_pass $stream_map993;
    ssl_preread on;
  }
}

14. 参考

14.1. Nginx Config 在线生成配置文件

Nginx Config 是一款可以一键生成 Nginx 配置的神器,相当给力。支持反向代理、HTTPS、HTTP/2、IPv6, 缓存、WordPress、CDN、Node.js 、 Python (Django) 服务器等等。打开网站:https://nginxconfig.io,按照自己的需求进行操作就行了。选择你的场景,填写好参数,系统就会自动生成配置文件

常用的全局变量

nginx变量 作用
$arg_PARAMETER 这个变量包含GET请求中, 如果有变量PARAMETER时的值
$args 这个变量等于请求行中(GET请求)的参数, 例如foo=123&bar=blahblah
$binary_remote_addr 二进制的客户地址
$body_bytes_sent 响应时送出的body字节数数量。即使连接中断, 这个数据也是精确的。
$content_length 请求头中的Content-length字段。
$content_type 请求头中的Content-Type字段。
$cookie_COOKIE cookie COOKIE变量的值
$document_root 当前请求在root指令中指定的值
$document_uri 与$uri相同
$host 请求主机头字段, 否则为服务器名称
$hostname Set to the machine’s hostname as returned by gethostname
$is_args 如果有$args参数, 这个变量等于”?”, 否则等于”", 空值
$http_user_agent 客户端agent信息
$http_cookie 客户端cookie信息
$limit_rate 这个变量可以限制连接速率
$query_string 与$args相同
$request_body_file 客户端请求主体信息的临时文件名
$request_method 客户端请求的动作, 通常为GET或POST
$remote_addr 客户端的IP地址
$remote_port 客户端的端口
$remote_user 已经经过Auth Basic Module验证的用户名
$request_completion 如果请求结束, 设置为OK. 当请求未结束或如果该请求不是请求链串的最后一个时, 为空(Empty)
$request_method GET或POST
$request_filename 当前请求的文件路径, 由root或alias指令与URI请求生成
$request_uri 包含请求参数的原始URI, 不包含主机名, 如: ”/foo/bar.php?arg=baz”。不能修改
$scheme HTTP方法(如http, https)
$server_protocol 请求使用的协议, 通常是HTTP/1.0或HTTP/1.1
$server_addr 服务器地址, 在完成一次系统调用后可以确定这个值
$server_name 服务器名称
$server_port 请求到达服务器的端口号
$uri 不带请求参数的当前URI, uri不包含主机名,如”/foo/bar.html”。该值有可能和request_uri 不一致。$request_uri是浏览器发过来的值。该值是rewrite后的值。例如做了internal redirects后。

15. 常见问题

15.1. 502 错误

错误提示:upstream sent too big header while reading response header from upstream

日志中存在以下的错误提示

2015/03/19 10:46:40 [error] 6412#0: *16436265 upstream sent too big header while reading response header from upstream, client: 192.168.101.100, server: localhost, request: "GET /search_rst.html?word=%E7%88%B1%E6%82%A0 HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: ......

在Nginx配置文件的的http段, 加入下面的配置

proxy_buffer_size 128k;
proxy_buffers 32 32k;
proxy_busy_buffers_size 128k;

重启Nginx错误依旧。再在host配置的php段加入下面配置

fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;

  • 无标签
写评论...