Skip to content

nginx 配置地址转发到 tomcat

	try_files $uri $uri/ /index.html; //https://www.cnblogs.com/boundless-sky/p/9459775.html介绍这个属性的


	location /prod-api/{
  		proxy_set_header Host $http_host;
  		proxy_set_header X-Real-IP $remote_addr;
  		proxy_set_header REMOTE-HOST $remote_addr;
  		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  		proxy_pass http://localhost:8080/atwr-park-manage-prod-api/;
  	}

$host 详解

nginx 为了实现反向代理的需求而增加了一个 ngx_http_proxy_module 模块。其中 proxy_set_header 指令就是该模块需要读取的配置文件。在这里,所有设置的值的含义和 http 请求同中的含义完全相同,除了 Host 外还有 X-Forward-For。

Host 的含义是表明请求的主机名,因为 nginx 作为反向代理使用,而如果后端真是的服务器设置有类似防盗链或者根据 http 请求头中的 host 字段来进行路由或判断功能的话,如果反向代理层的 nginx 不重写请求头中的 host 字段,将会导致请求失败【默认反向代理服务器会向后端真实服务器发送请求,并且请求头中的 host 字段应为 proxy_pass 指令设置的服务器】。

同理,X_Forward_For 字段表示该条 http 请求是有谁发起的?如果反向代理服务器不重写该请求头的话,那么后端真实服务器在处理时会认为所有的请求都来在反向代理服务器,如果后端有防攻击策略的话,那么机器就被封掉了。因此,在配置用作反向代理的 nginx 中一般会增加两条配置,修改 http 的请求头:

proxy_set_header Host $http_host;
proxy_set_header X-Forward-For $remote_addr;

这里的$http_host 和$remote_addr 都是 nginx 的导出变量,可以再配置文件中直接使用。如果 Host 请求头部没有出现在请求头中,则$http_host 值为空,但是$host 值为主域名。因此,一般而言,会用$host 代替$http_host 变量,从而避免 http 请求中丢失 Host 头部的情况下 Host 不被重写的失误。

X-Forwarded-For

X-Forwarded-For:简称 XFF 头,它代表客户端,也就是 HTTP 的请求端真实的 IP,只有在通过了 HTTP 代理或者负载均衡服务器时才会添加该项。 它不是 RFC 中定义的标准请求头信息,在 squid 缓存代理服务器开发文档中可以找到该项的详细介绍。标准格式如下:X-Forwarded-For: client1, proxy1, proxy2。

这一 HTTP 头一般格式如下:

X-Forwarded-For: client1, proxy1, proxy2

其中的值通过一个 逗号+空格 把多个 IP 地址区分开, 最左边(client1)是最原始客户端的 IP 地址, 代理服务器每成功收到一个请求,就把 请求来源 IP 地址添加到右边。 在上面这个例子中,这个请求成功通过了三台代理服务器:proxy1, proxy2 及 proxy3。请求由 client1 发出,到达了 proxy3(proxy3 可能是请求的终点)。请求刚从 client1 中发出时,XFF 是空的,请求被发往 proxy1;通过 proxy1 的时候,client1 被添加到 XFF 中,之后请求被发往 proxy2;通过 proxy2 的时候,proxy1 被添加到 XFF 中,之后请求被发往 proxy3;通过 proxy3 时,proxy2 被添加到 XFF 中,之后请求的的去向不明,如果 proxy3 不是请求终点,请求会被继续转发。

鉴于伪造这一字段非常容易,应该谨慎使用 X-Forwarded-For 字段。正常情况下 XFF 中最后一个 IP 地址是最后一个代理服务器的 IP 地址, 这通常是一个比较可靠的信息来源。

host 变量的值按照如下优先级获得:

  1. 请求行中的 host.
  2. 请求头中的 Host 头部.
  3. 与一条请求匹配的 server name.

什么是请求行中的 host

我们知道,HTTP 是一个文本协议,建立在一个可靠的传输层协议之上。这个传输层协议要是可靠的,面向连接的。由于 TCP 的普及程度,让它成了 HTTP 下层协议事现上的标准。但我们要知道,HTTP 并不仅限于建立在 TCP 之上。只要是可靠的,面向连接的传输层协议,都可以用来传输 HTTP。下面所说的 HTTP,都是指搭载在 TCP 之上的 HTTP。

一个 HTTP 请求过程是这样的,客户端先与服务器建立起 TCP 连接,然后再与服务器端进行请求和回复的收发。请求包含请求行、请求头和请求体,其中,根据请求方法的不同,请求体是可选的。

在发送请求行之前,客户端与服务器已经建立了连接。所以此时请求行中并不需要有服务器的信息。我们用 telnet 测试, 例如:

GET /index.php HTTP/1.1

这就是一个完整的 HTTP 请求行。虽然请求行中不需要有服务器的信息,但仍然可以在请求行中包含服务器的信息。例如:

GET www.test.info/index.php HTTP/1.1

两者一比较,就很容易理解什么叫请求行中的 host 了。第一个请求行中,就没有 host,第二种请求行中,就带了 host,为www.test.info。

Host 请求头与 HTTP/1.0、HTTP/1.1

一个请求,请求行下面就是一些列的请求头。这些请求头,在 HTTP/1.0 中,都是可选的,且 HTTP/1.0 不支持 Host 请求头;而在 HTTP/1.1 中,Host 请求头部必须存在,否则会返回 400 Bad Request 我们看个例子, 使用 telnet 连接:

GET /index.php HTTP/1.1 HTTP/1.1 400 Bad Request Server: nginx/1.4.6 (Ubuntu)

但是 HTTP/1.0 是不支持 Host 头部的,所以请求,不需要带这个 Host,我们也测试一下:

HEAD /rec/app/detail/youxidaren.html HTTP/1.0 HTTP/1.1 404 NOT FOUND Server: nginx/1.4.6 (Ubuntu)

可以看到没有返回 400, 而是返回了 404,说明这个请求还是来到 nginx 处理,命中了其中一个配置的"虚拟主机", 我到 nginx 下面看 access_log,看到日志写在了第一个的 nginx 虚拟主机配置的日志文件下面,说明 http1.0 情况下,没有带 host 头部,请求默认来到了 nginx 第一个虚拟主机下处理。

什么是与请求匹配的 server name

server name 是指在 Nginx 配置文件中,在 server 块中,用 server_name 指令设置的值。一个 server 可以多次使用 server_name 指令,来实现俗称的“虚拟主机”。例如:

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

server { listen 80; server_name example.net www.example.net; ... }

server { listen 80; server_name example.com www.example.com; ... }

关于虚拟主机的确定方法,还是引用 Nginx 的官方文档:

在这个配置中,nginx 仅仅检查请求的“Host”头以决定该请求应由哪个虚拟主机来处理。如果 Host 头没有匹配任意一个虚拟主机,或者请求中根本没有包含 Host 头,那 nginx 会将请求分发到定义在此端口上的默认虚拟主机。在以上配置中,第一个被列出的虚拟主机即 nginx 的默认虚拟主机——这是 nginx 的默认行为。而且,可以显式地设置某个主机为默认虚拟主机,即在”listen”指令中设置”default_server”参数:

server {
listen 80 default_server;
server_name example.net www.example.net;

}

这就解释了上面的 HTTP1.0 请求,不带 Host 头,默认来到了第一个配置的 server 处理了。 然后我测试一下把www.test.info这个域名设成默认的主机default_server,看请求能不能正常来到www.test.info这个server来处理。

nginx 配置修改:

server { listen 80 default_server; server_name www.test.info }

再次请求:

HEAD /index.php HTTP/1.0 HTTP/1.1 200 OK Server: nginx/1.4.6 (Ubuntu) 实际测试,正常,default_server 确实起作用了。

nginx 配置项详解

#安全问题,建议用nobody,不要用root.
#user  nobody;

#worker数和服务器的cpu数相等是最为适宜
worker_processes  2;

#work绑定cpu(4 work绑定4cpu)
worker_cpu_affinity 0001 0010 0100 1000

#work绑定cpu (4 work绑定8cpu中的4个) 。
worker_cpu_affinity 0000001 00000010 00000100 00001000



#error_log path(存放路径) level(日志等级)path表示日志路径,level表示日志等级,
#具体如下:[ debug | info | notice | warn | error | crit ]
#从左至右,日志详细程度逐级递减,即debug最详细,crit最少,默认为crit。

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    #这个值是表示每个worker进程所能建立连接的最大值,所以,一个nginx能建立的最大连接数,应该是worker_connections * worker_processes。
    #当然,这里说的是最大连接数,对于HTTP请求本地资源来说,能够支持的最大并发数量是worker_connections * worker_processes,
    #如果是支持http1.1的浏览器每次访问要占两个连接,
    #所以普通的静态访问最大并发数是: worker_connections * worker_processes /2,
    #而如果是HTTP作为反向代理来说,最大并发数量应该是worker_connections * worker_processes/4。
    #因为作为反向代理服务器,每个并发会建立与客户端的连接和与后端服务的连接,会占用两个连接。

    worker_connections  1024;

    #这个值是表示nginx要支持哪种多路io复用。
    #一般的Linux选择epoll, 如果是(*BSD)系列的Linux使用kquene。
    #windows版本的nginx不支持多路IO复用,这个值不用配。
    use epoll;

    # 当一个worker抢占到一个链接时,是否尽可能的让其获得更多的连接,默认是off 。
    multi_accept on;

    # 默认是on ,开启nginx的抢占锁机制。
    accept_mutex  on;
}


http {
    #当web服务器收到静态的资源文件请求时,依据请求文件的后缀名在服务器的MIME配置文件中找到对应的MIME Type,再根据MIME Type设置HTTP Response的Content-Type,然后浏览器根据Content-Type的值处理文件。

    include       mime.types;

    #如果 不能从mime.types找到映射的话,用以下作为默认值
    default_type  application/octet-stream;



     #日志位置
     access_log  logs/host.access.log  main;

     #一条典型的accesslog:
     #101.226.166.254 - - [21/Oct/2013:20:34:28 +0800] "GET /movie_cat.php?year=2013 HTTP/1.1" 200 5209 "http://www.baidu.com" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MDDR; .NET4.0C; .NET4.0E; .NET CLR 1.1.4322; Tablet PC 2.0); 360Spider"

     #1)101.226.166.254:(用户IP)
     #2)[21/Oct/2013:20:34:28 +0800]:(访问时间)
     #3)GET:http请求方式,有GET和POST两种
     #4)/movie_cat.php?year=2013:当前访问的网页是动态网页,movie_cat.php即请求的后台接口,year=2013为具体接口的参数
     #5)200:服务状态,200表示正常,常见的还有,301永久重定向、4XX表示请求出错、5XX服务器内部错误
     #6)5209:传送字节数为5209,单位为byte
     #7)"http://www.baidu.com":refer:即当前页面的上一个网页
     #8)"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; #.NET CLR 3.0.30729; Media Center PC 6.0; MDDR; .NET4.0C; .NET4.0E; .NET CLR 1.1.4322; Tablet PC 2.0); 360Spider": agent字段:通常用来记录操作系统、浏览器版本、浏览器内核等信息

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                       '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';



    #开启从磁盘直接到网络的文件传输,适用于有大文件上传下载的情况,提高IO效率。
    sendfile        on;


    #一个请求完成之后还要保持连接多久, 默认为0,表示完成请求后直接关闭连接。
    #keepalive_timeout  0;
    keepalive_timeout  65;



    #开启或者关闭gzip模块
    #gzip  on ;

    #设置允许压缩的页面最小字节数,页面字节数从header头中的Content-Length中进行获取。
    #gzip_min_lenth 1k;

    # gzip压缩比,1 压缩比最小处理速度最快,9 压缩比最大但处理最慢(传输快但比较消耗cpu)
    #gzip_comp_level 4;

    #匹配MIME类型进行压缩,(无论是否指定)"text/html"类型总是会被压缩的。
    #gzip_types types text/plain text/css application/json  application/x-javascript text/xml



    #动静分离
    #服务器端静态资源缓存,最大缓存到内存中的文件,不活跃期限
    open_file_cache max=655350 inactive=20s;

    #活跃期限内最少使用的次数,否则视为不活跃。
    open_file_cache_min_uses 2;

    #验证缓存是否活跃的时间间隔
    open_file_cache_valid 30s;



    upstream myserver{

    # 1、轮询(默认)
    # 每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
    # 2、指定权重
    # 指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
    #3、IP绑定 ip_hash
    # 每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
    #4、备机方式 backup
    # 正常情况不访问设定为backup的备机,只有当所有非备机全都宕机的情况下,服务才会进备机。
    #5、fair(第三方)
    #按后端服务器的响应时间来分配请求,响应时间短的优先分配。
    #6、url_hash(第三方)
    #按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。


      # ip_hash;
             server 192.168.161.132:8080 weight=1;
             server 192.168.161.132:8081 weight=1;

      #fair

      #hash $request_uri
      #hash_method crc32

      }

    server {
        #监听端口号
        listen       80;

        #服务名
        server_name  192.168.161.130;

        #字符集
        #charset utf-8;




	#location [=|~|~*|^~] /uri/ { … }
	# = 精确匹配
	# ~ 正则匹配,区分大小写
	# ~* 正则匹配,不区分大小写
	# ^~  关闭正则匹配

	#匹配原则:

	# 1、所有匹配分两个阶段,第一个叫普通匹配,第二个叫正则匹配。
	# 2、普通匹配,首先通过“=”来匹配完全精确的location
        #   2.1、 如果没有精确匹配到, 那么按照最大前缀匹配的原则,来匹配location
        #   2.2、 如果匹配到的location有^~,则以此location为匹配最终结果,如果没有那么会把匹配的结果暂存,继续进行正则匹配。
        # 3、正则匹配,依次从上到下匹配前缀是~或~*的location, 一旦匹配成功一次,则立刻以此location为准,不再向下继续进行正则匹配。
        # 4、如果正则匹配都不成功,则继续使用之前暂存的普通匹配成功的location.


        location / {   # 匹配任何查询,因为所有请求都已 / 开头。但是正则表达式规则和长的块规则将被优先和查询匹配。

	    #定义服务器的默认网站根目录位置
            root   html;

	    #默认访问首页索引文件的名称
	    index  index.html index.htm;

	    #反向代理路径
            proxy_pass http://myserver;
            #host upstream时候这个需要配置,不然会包400。作用是把原http请求的Header中的Host字段也放到转发的请求里。若不设置,得到的是代理服务(ngnix)的ip,这样对于动态拼接的url,后端服务器能在页面里返回正确的url
            proxy_set_header Host $host;
            proxy_redirect off;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            #反向代理的超时时间
            proxy_connect_timeout 60;
            proxy_read_timeout 600;
            proxy_send_timeout 600;

         }

         location  /images/ {
	    root images ;
	 }

	 location ^~ /images/jpg/ {  # 匹配任何已 /images/jpg/ 开头的任何查询并且停止搜索。任何正则表达式将不会被测试。
	    root images/jpg/ ;


	 }
         location ~*.(gif|jpg|jpeg)$ {

	      #所有静态文件直接读取硬盘
              root pic ;

	      #expires定义用户浏览器缓存的时间为3天,如果静态页面不常更新,可以设置更长,这样可以节省带宽和缓解服务器的压力
              expires 3d; #缓存3天
         }


        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    }



}

History mode config

conf
  location / {
    root   /web/dist;
    index  index.html index.htm;
    try_files $uri $uri/ /index.html;

    # 为 index.html 设置单独的缓存策略
    location = /index.html {
      expires -1;
      add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
    }

  }

解释 Cache-Control 头部字段:

add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0' 这句配置中的各个参数是用来控制浏览器和代理服务器如何缓存内容的。以下是每个参数的详细解释:

no-store:
指示浏览器和任何中间缓存(如代理服务器)不要存储响应内容。
每次请求都会重新从服务器获取内容。

no-cache:
强制浏览器在使用本地缓存副本之前,每次都向服务器验证缓存的内容是否过期。
浏览器可以保存响应内容,但在使用之前必须验证其有效性。

must-revalidate:
指示缓存必须重新验证过期内容,而不能使用过期的缓存内容。
即使缓存内容的有效期已过,缓存服务器在返回缓存内容前必须与源服务器进行验证。

proxy-revalidate:
类似于 must-revalidate,但专门针对共享缓存(例如代理服务器)。
要求代理服务器在内容过期后,必须重新验证缓存内容,而不是直接使用过期内容。

max-age=0:
设置内容的最大缓存时间为0秒。
表示内容在获取后立即过期,浏览器或缓存服务器必须每次都从源服务器获取内容。

Nginx 同一端口下部署多个 Vue3 项目

nginx perl 模块代理以及环境变量

conf
# nginx.conf
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;
# load_module /usr/lib/nginx/modules/ngx_http_perl_module.so;
# 确保环境变量传递到 Nginx
env BYWL_BACKEND_PORT;
events {
   worker_connections  1024;
}

http {

   perl_set $backend_port 'sub { return $ENV{"BYWL_BACKEND_PORT"}; }';
   include       /etc/nginx/mime.types;
   default_type  application/octet-stream;

   log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for"';

   access_log  /var/log/nginx/access.log  main;

   sendfile        on;
   #tcp_nopush     on;

   keepalive_timeout  65;

   #gzip  on;

   include /etc/nginx/conf.d/*.conf;
}
conf
# web.conf
server {
    listen       80;
    server_name  localhost;
    client_max_body_size 5G;  # 设置最大上传文件大小为5G

    location / {
         root   /etc/nginx/www/dist;
         index  index.html index.htm;
         try_files $uri $uri/ /index.html;

        # 为 index.html 设置单独的缓存策略
        location = /index.html {
                expires -1;
                add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
        }
   }

   location /api {
        resolver 127.0.0.11 valid=30s;# Docker 的默认 DNS 服务器  porxy包含变量的时候,需要指定DNS服务器,否则会导致解析失败
        proxy_pass http://backend:$backend_port;
   }

   location /env {
     default_type text/plain;
     return 200 "BACKEND_PORT=$backend_port";
   }

   error_page   500 502 503 504  /50x.html;
}

nginx perl 镜像打包

shell
# 进入正常nginx:latest镜像容器以后
apt-get install -y \
    perl \
    perl-dev \
    build-essential \
    libperl-dev \
    zlib1g-dev \
    libpcre3-dev \
    libssl-dev \
    wget

cd /tmp && \
    # 获取最新稳定版本的 Nginx
    LATEST_NGINX_VERSION=$(wget -qO- https://nginx.org/en/download.html | grep -oP 'nginx-\K[0-9.]+(?=\.tar\.gz)' | head -n 1) && \
    echo "Latest Nginx version: $LATEST_NGINX_VERSION" && \
    wget https://nginx.org/download/nginx-$LATEST_NGINX_VERSION.tar.gz && \
    tar -zxvf nginx-$LATEST_NGINX_VERSION.tar.gz && \
    cd nginx-$LATEST_NGINX_VERSION

# 查看当前nginx有那些模块
nginx -V

# 编译安装,以下的模块只是perl需要的,nginx -V输出的在编译的时候也要添加上
./configure --with-http_perl_module \
                --with-http_ssl_module \
                --with-pcre \
                --with-zlib \
                --with-openssl && \
    make && \
    make install

# 完成后 nginx -V查看有没有perl模块