Nginx运维维护规范及全配置详解【持续更新】

Nginx运维维护规范及全配置详解

一、版本约束

软件的不同版本,在使用起来都有可能带来不可预知的影响,因此需要统一整理,固定下来,不允许轻易变更。

  • Nginx开源版官网,点击右侧download可以看到各个版本的Nginx,其中Mainline是抢先的主干版本(版本号是奇数),Stable是稳定版(版本号是偶数)

  • 系统环境,软件版本

    • OpenEuler22.03 LTS SP4
    • nginx: 1.28.0
    • 运行用户: nginx

二、软件安装路径

  • 部署路径

    /home/application/nginx

  • 前端工程路径

    /home/application/nginx/html

  • 日志路径

    /home/application/nginx/logs

  • 配置文件路径

    /home/application/nginx/conf/nginx.conf 【主配置文件】

    /home/application/nginx/conf.d/*

  • ssl证书路径

    /home/application/nginx/cert

三、安装

3.1 下载

复制代码
$ wget http://nginx.org/download/nginx-1.28.0.tar.gz

3.2 安装依赖

安装依赖包,NGINX是C语言写的,pcre-devel支持正则表达式,openssl 开启加密

复制代码
$ yum -y install gcc pcre-devel openssl-devel tar make zlib zlib-devel

3.3 创建nginx用户

复制代码
$ useradd -s /sbin/nologin nginx -M

3.4 指定安装目录 为/home/application/nginx

  • 启用 HTTP/2 模块;

  • 启用 SSL 模块;

  • 启用 Stub Status 模块;

  • 启用4 层TCP/UDP 代理模块;

  • 启用 Gzip 静态模块

复制代码
$ mkdir /home/application/nginx

$ tar -xf nginx-1.28.0.tar.gz

$ cd nginx-1.28.0
 ./configure --prefix=/home/application/nginx --user=nginx --group=nginx --with-http_v2_module --with-http_ssl_module --with-http_stub_status_module --with-stream --with-http_gzip_static_module  --pid-path=/home/application/nginx/nginx.pid

3.5 编译安装

复制代码
$ make && make install

3.6 使用 systemd 服务管理 nginx

3.6.1 前提
  • 需要定义 nginx.pid 的文件路径 , 修改/home/application/nginx/conf/nginx.conf 配置文件 中 pid /run/nginx.pid; 注意最后有个;标点符号
3.6.2 编写 nginx.service 文件
复制代码
$ cat > /lib/systemd/system/nginx.service << 'EOF'
[Unit]
Description=The NGINX HTTP and reverse proxy server
 
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStart=/home/application/nginx/sbin/nginx
ExecReload=/home/application/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
 
[Install]
WantedBy=multi-user.target
EOF
3.6.3 启动 nginx 并配置开机自启动
复制代码
$ systemctl daemon-reload
 
$ systemctl enable nginx

$ systemctl start nginx

四、平滑升级步骤

4.1 下载

复制代码
$ wget https://nginx.org/download/nginx-1.29.3.tar.gz

4.2 解压

复制代码
$ tar xf nginx-1.29.3.tar.gz

4.3 查看原先使用的模块

复制代码
$ nginx -V
nginx version: nginx/1.28.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled

configure arguments: --prefix=/home/application/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --with-stream --with-http_gzip_static_module --with-http_v2_module

4.4 编译安装带上原来的模块

⚠️ 需要带上原来的安装模块,且只需要make 编译即可,不需要make install !!!切记,切记!!!

复制代码
$ cd nginx-1.29.3
./configure --prefix=/home/application/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --with-stream --with-http_gzip_static_module --with-http_v2_module

$ make

4.4 复制启动文件

复制代码
$ mv /home/application/nginx/sbin/nginx /home/application/nginx/sbin/nginx-old

$ cp nginx-1.29.3/objs/nginx /home/application/nginx/sbin/

4.5 平滑升级

复制代码
$ make upgrade

4.6 查看版本

复制代码
$ /home/application/nginx/sbin/ -v
nginx version: nginx/1.29.3
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled

五、核心配置项详解(逐项)

5.1 版本隐藏

  • (http模块) 让别人扫描不到你的 nginx 版本信息

    server_tokens off

5.2 worker / 事件相关

  • (全局模块) 建议 auto(根据 CPU 自动),或设置具体数值(物理核数或核数*1)
bash 复制代码
worker_processes auto;
  • (全局模块) 进程可打开的最大文件句柄(配合 系统 的 ulimit -n
bash 复制代码
worker_rlimit_nofile 65535;
  • (events模块) 连接数上限
bash 复制代码
  events { 
   worker_connections 65535;
   use epoll; #Linux优选epoll
   multi_accept on;
  }
  • 可并发连接数 = worker_connections * worker_processes (包括 keepalive 连接)

5.3 网络/IO 优化

  • (http模块) 提高静态文件吞吐。
bash 复制代码
    sendfile        on;
    tcp_nopush      on;
    tcp_nodelay     on;
  • (http模块) keepalive 超时时间。
bash 复制代码
    keepalive_timeout  65;

5.4 文件缓存

  • (http模块) 缓存文件句柄,提高静态文件性能。
bash 复制代码
    open_file_cache max=200000 inactive=10m;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;

5.5 请求体与上传

  • (http模块/server模块/location模块) 默认 1M,单位 :支持 kmg(不区分大小写),如 10K2m1G
  • 可上传大文件需灵活调整;上传缓冲与临时路径。
bash 复制代码
    client_body_buffer_size 128k;
    client_max_body_size 100m;
    client_body_temp_path /home/application/nginx/body_temp;

5.6 SSL / TLS

  • http2:与 listen 443 ssl; 配合开启 HTTP/2。
  • ssl_certificatessl_certificate_key:证书与私钥文件路径。
  • ssl_protocols TLSv1.2 TLSv1.3;:禁用 TLS1.0/1.1。⚠️ TLSv1.3 需要openssl 1.1.1版本,并安装 nginx 需要启用 HTTP/2 模块;
  • ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305; 支持的加密套件
  • ssl_prefer_server_ciphers off; 控制 Nginx 在与客户端建立 SSL/TLS 连接时,是否优先使用服务器端配置的加密套件(ciphers)。当该指令设置为 on 时,Nginx 会优先使用服务器端配置的加密套件列表,而不是客户端提供的加密套件列表。这有助于确保服务器使用更安全的加密算法。
  • ssl_session_cache shared:MozSSL:10m; 大约40000个会话
  • ssl_session_timeout 1h; SSL会话超时时间。
bash 复制代码
        listen 443 ssl;
        http2 on;
        server_name  xx.srebro.cn;
        ssl_certificate /home/application/nginx/cert/srebro.cn.crt;
        ssl_certificate_key /home/application/nginx/cert/srebro.cn.key;
        ssl_session_timeout 1h;
        ssl_session_cache shared:MozSSL:10m;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;  # 支持的加密套件
  ssl_prefer_server_ciphers off;

5.7 导入其它配置文件(http模块)

复制代码
include /home/application/nginx/conf.d/*.conf;

5.8 日志

  • 日志格式(http模块)

    复制代码
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';
  • 日志等级

    复制代码
    notice info
  • 日志切割

方法一: 自定义脚本切割

复制代码
1. vi cut_nginx_logs.sh
#!/bin/bash

# 获取日期
d=$(date +%Y-%m-%d)

# 定义存储目录
dir="/home/application/nginx/logs"

# 定义需要分割的源日志
logs_file='/home/application/nginx/logs/access.log'
logs_error='/home/application/nginx/logs/error.log'

# 定义nginx的pid文件
pid_file='/home/application/nginx/logs/nginx.pid'

if [ ! -d "$dir" ]
then
 mkdir $dir
fi

# 移动日志并重命名文件
mv ${logs_file} ${dir}/access_${d}.log
mv ${logs_error} ${dir}/error_${d}.log

# 发送kill -USR1信号给Nginx的主进程号,让Nginx重新生成一个新的日志文件
kill -USR1 $(cat ${pid_file})

PS:这里将脚本放在了home目录下,可根据实际情况存放脚本
这里没设置删除删除原有日志文件,可根据实际情况自行设置

2. 设置定时任务 每两天执行一次切割任务
crontab -e
59 23 */2 * * /home/application/nginx/cut_nginx_logs.sh

方法二: 使用logrotate系统日志的管理工具

https://opforge.srebro.cn/other/notes/22.html

5.9 配置文件对齐

复制代码
约定对齐格式每次缩进4个空格

5.10 开启压缩gzip配置(http模块)

复制代码
gzip on;
gzip_http_version 1.1;
gzip_min_length 1k;
gzip_comp_level 4;
gzip_types text/plain application/json application/javascript application/octet-stream application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/bmp application/x-bmp image/x-ms-bmp application/vnd.ms-fontobject font/ttf font/opentype font/x-woff;
gzip_vary on;
gzip_buffers 4 16k;

5.11 缓存配置

  • 协商缓存

    在nginx中,协商缓存是一种机制,用于在客户端和服务器之间协商确定是否使用缓存的内容。当客户端发送一个请求时,nginx会检查该请求是否已经被缓存,如果有缓存的内容可用,则nginx会发送一个条件请求给服务器,询问服务器是否有新的内容可用。如果服务器返回的响应表明内容没有改变,则nginx会使用缓存的内容,否则会将新的内容缓存起来并返回给客户端。

    协商缓存通常使用HTTP头部字段进行协商,常见的字段包括If-Modified-Since、If-None-Match等。这些字段可以帮助服务器判断内容是否有改变,从而决定是否返回新的内容。

    通过使用协商缓存,可以减少网络传输的数据量,提高网站的性能和效率。同时,协商缓存也可以减轻服务器的负载,节省带宽和资源的消耗。

    复制代码
    location /gis3d {
                   alias /home/application/nginx/html/srebro-screen/;
                   index index.html;
                   try_files $uri $uri/ /gis3d/index.html;
        #协商缓存
                    add_header Cache-Control max-age=no-cache;
    }
  • 强制缓存

    强制缓存是指在客户端和服务器之间不进行任何协商,直接使用缓存的内容。当客户端发送一个请求时,nginx会检查该请求是否已经被缓存,如果有缓存的内容可用且尚未过期,则nginx会直接返回缓存的内容给客户端,而无需向服务器发送请求。

    强制缓存通常使用HTTP头部字段进行控制,常见的字段包括Expires和Cache-Control。这些字段可以指定缓存的有效期,客户端在有效期内再次请求相同的资源时,会直接使用缓存的内容。

    使用强制缓存可以减少对服务器的请求次数,加快网页加载速度,提高用户体验。但是需要注意的是,如果在有效期内服务器的内容发生了变化,客户端将无法得知,仍然使用缓存的内容,可能导致展示的内容不是最新的。为了解决这个问题,可以使用协商缓存的机制进行判断和更新。

    复制代码
     location /3dmap {
           alias /home/application/nginx/html/3d/;
      #强制缓存
            add_header Cache-Control max-age=360000;
    }

5.12 不缓存配置

  • 方法一:server模块中location方法

    location /srebro-base {
    alias /home/application/nginx/html/srebro/srebro-base/;
    index index.html;
    #对于htm,html的页面不缓存
    if (request_filename ~ .*\.(htm|html)) {
    add_header Cache-Control 'no-store, no-cache, must-revalidate';
    }
    try_files $uri /srebro-base/index.html;
    }

  • 方法二:http模块中map方法

    #nginx.conf主配置文件中定义map

    http {
    ..................
    map request_filename cache_control {
    default "";
    "~*.html" 'no-store, no-cache, must-revalidate'; "~*\.htm" 'no-store, no-cache, must-revalidate';
    }
    .............
    }

    #server 中的配置文件直接引入map

    server {

    ................
    location /srebro-base {
    alias /usr/local/nginx/html/srebro/srebro-base/;
    index index.html;
    #map中加载不缓存配置
    add_header Cache-Control cache_control; try_files uri /srebro-base/index.html;
    }

    复制代码
             location /srebro-score {
                  alias /usr/local/nginx/html/srebro/srebro-score/;
                  index index.html;
      #map中加载不缓存配置
      add_header Cache-Control $cache_control;
                  try_files $uri /srebro-score/index.html;
             }

    ................

    }

5.13 根据访问前端IP,限制访问内容

护网期间,不允许外网WEB 访问系统地图

复制代码
location /3dmap {
   proxy_ignore_headers Set-Cookie Cache-Control;
   proxy_hide_header Cache-Control;
   proxy_hide_header Set-Cookie;
   proxy_pass http://112.112.112.112:5004/;
   if ($host = '111.111.111.111') {
   return 400;
   }
}

5.14 跨域配置

  • Access-Control-Allow-Origin:指定允许访问的源(域名)。

  • Access-Control-Allow-Headers:指定允许的头部字段。

  • Access-Control-Expose-Headers: 用于控制浏览器允许客户端访问的额外响应头字段。

  • Access-Control-Allow-Methods:指定允许的HTTP方法。

  • Access-Control-Allow-Credentials:指示是否允许发送身份凭证(如cookies)。

    复制代码
                  add_header Access-Control-Allow-Origin *;
                  add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
                  add_header Access-Control-Expose-Headers mark;
                  add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
      add_header 'Access-Control-Allow-Credentials' 'true';
  • 静态文件-允许跨域访问

    location /baidu {
    alias /home/application/baidu;
    #允许跨域
    add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
    expires 7d;
    #启用了目录索引功能
    autoindex on;
    }

  • 接口-允许跨域访问

    location / {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Expose-Headers mark;
    add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
    add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
    add_header 'Access-Control-Allow-Credentials' 'true';

    复制代码
                  proxy_pass http://172.16.10.140:8002;
                  proxy_http_version 1.1;
                  proxy_set_header Upgrade $http_upgrade;
                  proxy_set_header Connection $connection_upgrade;
              }

5.15 http 和 https 共存一个配置文件

复制代码
$ cat http-https.conf

server {

         listen       8208;
       listen       18208 ssl;
          http2 on;
         root         /home/application/nginx/html/srebro;
         ssl_certificate /home/application/nginx/conf/server.crt;
          ssl_certificate_key /home/application/nginx/conf/server.key;
          ssl_session_timeout 5m;
          ssl_protocols TLSv1.2 TLSv1.3;
          ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
          ssl_prefer_server_ciphers on;

#httpp-https重定向
        location =/ {
                if ($scheme = "http") {
                        proxy_pass http://$http_host/admin/;
                        }

                if ($scheme = "https") {
                        proxy_pass https://$http_host/admin/;
                        }
                }
}

5.16 HTTP反向代理,传递请求头

需要注意配置 proxy_pass 时,当在后面的 url 加上了/,相当于是绝对路径,则 Nginx不会把 location中匹配的路径部分加入代理uri
这几个参数是用于反向代理配置的,具体含义如下:

  1. proxy_set_header Host $host; 将客户端的 Host 头部传递给后端;如果一个 Nginx 实例代理多个域名(如 example.comtest.com),后端需要根据 Host 来区分不同的请求。可以确保后端服务器接收到正确的域名信息。
  2. proxy_set_header X-Real-IP $remote_addr; 将客户端的真实IP地址传递给后端服务器。这样后端服务器可以获取到客户端的真实IP地址。
  3. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 将客户端的原始IP地址传递给后端服务器。如果请求经过多个代理服务器,每个代理服务器会将自己的IP地址追加到该参数中,以便后端服务器可以获取到完整的客户端IP地址列表。
  4. proxy_set_header X-Forwarded-Proto $scheme; 告知后端客户端的实际协议(HTTP 或 HTTPS)。
  5. proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; 支持协议切换(如 WebSocket)。
  6. proxy_set_header X-Custom-Header "my-custom-value"; 传递自定义信息供后端使用,应用需求(如特定用户标识、区域信息等)。
复制代码
http {
    upstream backend {
        server backend_server_ip:backend_server_port;
        # 可以添加多个后端服务器,用来实现负载均衡
        # server backend_server_ip2:backend_server_port2;
    }

    server {
        listen 80;
        server_name your_domain.com;

    location /api {
        proxy_pass http://backend;
    proxy_set_header Host $host;

    # 传递客户端真实 IP
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # 传递客户端协议
    proxy_set_header X-Forwarded-Proto $scheme;

    # WebSocket 支持
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    # 自定义请求头
    proxy_set_header X-Custom-Header "my-custom-value";
    }
    }
}

5.17 websock代理

websock代理,注意 ws 和 wss ; http 和 https 中都需要配置具体的location 配置,指定后端的接口地址

PS : 如果是https 和 http 共存的项目,使用同一套前端代码,需要在js代码中 加入判断 【https连接下浏览器不允许ws协议,只允许wss协议】

复制代码
nginx主配置文件中的 http 区域:
http {
.....
    map $http_upgrade $connection_upgrade {
      default upgrade;
      '' close;
    }
.......
}

server {
    listen 80;
    server_name demo.srebro.cn;  # 自行修改成你的域名
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name          srebro.cn;  # 自行修改成你的域名
    ssl_certificate      sslkey/srebro.cn.crt;  # 自行设置证书
    ssl_certificate_key  sslkey/srebro.cn.key;  # 自行设置证书
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_protocols TLSv1.1 TLSv1.2;
    add_header Strict-Transport-Security "max-age=63072000" always;

    client_max_body_size 4096m;  # 录像及文件上传大小限制
    
	location ^~/socket {
   proxy_buffering off;
   rewrite ^/accidentsocket/(.*)$ /$1 break;
   proxy_pass http://192.168.1.1:9005;
   proxy_read_timeout 300s;
   proxy_send_timeout 300s;
   proxy_set_header Host $host;
   proxy_set_header X-Real-IP $remote_addr;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   #升级http1.1到 websocket协议
   proxy_http_version 1.1;
   proxy_set_header Upgrade $http_upgrade;
   proxy_set_header Connection  $connection_upgrade;
}
}

WebSocket 连接超时问题

WebSocket 连接是长连接,如果长时间没有数据传输,可能会被 Nginx 或后端服务器断开。为了解决这个问题,需要配置 Nginx 的超时参数,并根据实际情况调整。

  • 超时时间的设置需要根据实际应用场景进行调整,过短的超时时间会导致频繁断连,过长的超时时间会占用服务器资源。
  • 同时也要检查后端服务器的超时设置,确保 Nginx 的超时时间小于后端服务器的超时时间,避免 Nginx 提前断开连接。
复制代码
location ^~/socket {
   proxy_buffering off;
   rewrite ^/accidentsocket/(.*)$ /$1 break;
   proxy_pass http://192.168.1.1:9005;
   proxy_read_timeout 300s;
   proxy_send_timeout 300s;
   proxy_set_header Host $host;
   proxy_set_header X-Real-IP $remote_addr;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   #升级http1.1到 websocket协议
   proxy_http_version 1.1;
   proxy_set_header Upgrade $http_upgrade;
   proxy_set_header Connection  $connection_upgrade;
   #增加超时时间
   proxy_connect_timeout 300s;  # 与后端服务器建立连接的超时时间
   proxy_send_timeout 300s;     # 向后端服务器发送数据的超时时间
   proxy_read_timeout 300s;     # 从后端服务器读取数据的超时时间
   send_timeout 300s;           # 客户端发送响应的超时时间
}
  • proxy_connect_timeout: Nginx 与后端服务器建立连接的超时时间,默认为 60 秒。增加此值可以避免因网络延迟导致连接失败。
  • proxy_send_timeout: Nginx 向后端服务器发送数据的超时时间,默认为 60 秒。增加此值可以避免因后端服务器处理缓慢导致发送超时。
  • proxy_read_timeout: Nginx 从后端服务器读取数据的超时时间,默认为 60 秒。增加此值可以避免因后端服务器长时间没有响应导致读取超时。
  • send_timeout: 客户端发送响应的超时时间。增加此值可以避免客户端因网络问题导致发送超时。

WebSocket 性能瓶颈 问题

WebSocket 连接在高并发场景下出现性能瓶颈,响应速度变慢。

解决方案:

  • 增加 Nginx 的 worker 进程数量和 worker 连接数。
  • 启用 gzip 压缩。
  • 使用 SSL/TLS 加速。
  • 优化 TCP 参数。
  • 使用负载均衡。

5.18 自定义 404 界面

在Nginx配置文件中,server 模块,添加一下内容

复制代码
  server {

        error_page  404 /404.html;

        location /404.html {
        alias /usr/local/nginx/old/404.html;
        internal;
        }
}      
  • error_page 404 /404.html;表示当出现404错误时,Nginx会重定向到/404.html页面。固定写法

  • location = /404.html { ... }用于指定404页面的处理方式。

  • alias /path/to/your/website;将/404.html页面映射到你网站的文件目录下。

  • internal;表示该配置只能在Nginx内部使用,外部无法直接访问。

5.19 重定向问题

之前nginx 里配置的return 是直接到 XXXX:80/admin , 但是在容器场景下,外部的端口如果是15099,从重定向访问的时候 ,浏览器请求的是 XXXX:80/admin , 很明显客户端不可能通容器内部的80端口;

原来的配置

复制代码
server {

         listen       8208;
       listen       18208 ssl;
                http2 on;
         root         /home/application/nginx/html/srebro;
         ssl_certificate /home/application/nginx/conf/server.crt;
                ssl_certificate_key /home/application/nginx/conf/server.key;
                ssl_session_timeout 5m;
                ssl_protocols TLSv1.2 TLSv1.3;
                ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
                ssl_prefer_server_ciphers on;

#httpp-https重定向
        location =/ {
                if ($scheme = "http") {
                        proxy_pass http://$host:$server_port/admin/;
                        }

                if ($scheme = "https") {
                        proxy_pass https://$host:$server_port/admin/;
                        }
                }
...............................
}

改变后的配置

复制代码
server {

         listen       8208;
       listen       18208 ssl;
                http2 on;
             root         /home/application/nginx/html/srebro;
             ssl_certificate /home/application/nginx/conf/server.crt;
                ssl_certificate_key /home/application/nginx/conf/server.key;
                ssl_session_timeout 5m;
                ssl_protocols TLSv1.2 TLSv1.3;
                ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
                ssl_prefer_server_ciphers on;

#httpp-https重定向
        location =/ {
                if ($scheme = "http") {
                        proxy_pass http://$http_host/admin/;
                        }

                if ($scheme = "https") {
                        proxy_pass https://$http_host/admin/;
                        }
                }
...............................
}

变量区别

在nginx中, h t t p h o s t 、 http_host、 httphost、host 和 $server_port 是三个不同的变量,它们的作用和含义如下:

  1. $http_host:这个变量包含了客户端请求中的"Host"标头的值。它会包含请求的域名和端口号(如果有的话),例如:www.example.com 或者 www.example.com:8080

  2. host:这个变量包含了客户端请求中的"Host"标头的值,但不包含端口号。如果请求中没有指定端口号,那么host:这个变量包含了客户端请求中的host标头的值,但不包含端口号。如果请求中没有指定端口号,那么host中的值将不包含端口号,例如:www.example.com

  3. server_port:这个变量包含了客户端请求中的端口号。如果请求中指定了端口号,那么server_port:这个变量包含了客户端请求中的端口号。如果请求中指定了端口号,那么server_port中的值将是该端口号;如果请求中没有指定端口号,则$server_port中的值将是80(HTTP默认端口)或443(HTTPS默认端口)。

因此,http_host 包含了完整的主机名和端口信息,$http_host包含了完整的主机名和端口信息,host 只包含主机名而不包含端口信息,而$server_port 则只包含端口信息。

$http_host使用场景

$http_host变量通常在需要获取客户端请求中的完整主机名和端口信息时使用。一些常见的场景包括:

  • 虚拟主机配置:当配置多个虚拟主机时,可以使用$http_host变量来根据请求的主机名和端口号来路由到不同的虚拟主机配置。

  • 重定向规则:在配置重定向规则时,可以使用$http_host变量来获取请求的完整主机名和端口信息,并根据需要进行重定向。

  • 访问日志:在访问日志中记录客户端请求的完整主机名和端口信息。

总之,$http_host 变量在需要获取客户端请求中的完整主机名和端口信息的场景下非常有用。

5.20 关于server name 指令 问题

该指令一般用来区分相同 IP地址和端口组合下的不同服务。NGINX在接收到HTTP 请求后会根据 listen 指令的参数在文件中查找相匹配的 server 块,然后在查找到的所有 server 块中根据 server_name 继续选择。如果找不到对应的 server 块,那么默认使用得到的所有server 块中的第一个。

在使用 server_name 指令时,会匹配请求头中的 Host 字段,通常是一个 FODN 域名或地址。可以使用精确匹配、泛域名匹配和正则表达式匹配这些匹配规则,具体的匹配顺序依次如下:

  • 精确匹配,如 <www.example.co>
  • 以通配符开始的字符串匹配,如*.example.com*
  • *以通配符结束的字符串匹配,如 <www.example>
  • 正则表达式匹配,如^www.example.com$
  • 配置了 default_server 参数的 server 块【如果没有匹配到其他server块的监听端口为80的server_name,那么将会使用当前server块作为默认服务器来处理请求。这通常用于设置默认的虚拟主机或者处理未知主机名的请求。】

案例:

我有一个 nginx 服务器,做为公司的 WEB 服务器,监听在 80 端口上;监听在下面不同的 server_name 下面, 且我的 DNS 解析是 把 *.srebro.cn 都 A 记录到 172.22.33.1 这个ip 上;这样就会有一个问题,当我访问任意 xx.srebro.cn 的时候,他就是随机跳转我下面的 server_name 上; 这意味着当请求到达nginx服务器时,如果没有匹配到其他server块的监听端口为80的server_name,那么将会使用当前server块作为默认服务器来处理请求。

处理方式:设置默认的虚拟主机或者处理未知主机名的请求

复制代码
server {
  listen 80 default_server;
  listen 443 ssl default_server;
  ssl_certificate /home/application/nginx/cert/srebro.cn/srebro.cn.crt;
  ssl_certificate_key /home/application/nginx/cert/srebro.cn/srebro.cn.key;

  server_name _;
        root /home/application/nginx/html;
}

5.21 nginx 中默认使用 http1 还是http2?

在 Nginx 中,默认情况下使用的是 HTTP/1.1 协议。如果希望启用 HTTP/2,需要显式地在配置文件中进行设置。

如果nginx 是编译部署,在编译 Nginx 时没有添加 --with-http_v2_module 参数,Nginx 就不会包含 HTTP/2 模块,因此你无法在配置中启用 HTTP/2 功能,且 openssl 版本要大于 1.1.1版本。

编译 Nginx在安装或重新编译 Nginx 时,加入以下参数:

复制代码
./configure --with-http_v2_module ......

配置文件中启用 http2示例:

复制代码
server {
        listen 443 ssl;
        http2 on; # 启用 HTTP/2
        server_name  xx.srenro.cn;
        ssl_certificate /home/application/nginx/cert/srenro.cn.crt;
        ssl_certificate_key /home/application/nginx/cert/srenro.cn.key;
        ssl_session_timeout 1h;
        ssl_session_cache shared:MozSSL:10m;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;  # 支持的加密套件
        ssl_prefer_server_ciphers on;  #优先使用服务器指定的加密算法
}

在这个配置中,http2 参数使得 Nginx 启用 HTTP/2,并且这个设置仅对 SSL/TLS(即 HTTPS)连接有效。

默认 HTTP 协议:

  • HTTP/1.1 是 Nginx 的默认协议,除非显式启用 HTTP/2。

  • HTTP/2 需要 Nginx 版本 1.9.5 或更高,并且仅能在启用了 SSL/TLS 的情况下使用。

HTTP/1.1 对比 HTTP/2 协议

5.22 nginx 的ssl 配置中ssl_prefer_server_ciphers on 参数用途

在 Nginx 的 SSL 配置中,ssl_prefer_server_ciphers on; 这个指令的作用是控制在客户端和服务器之间协商加密套件时,是否优先使用服务器指定的加密算法(cipher suite)

具体解释:

  • 加密套件(Cipher Suite)是用于 SSL/TLS 连接的加密算法集合,包括加密算法、消息认证码算法(MAC)、密钥交换算法等。
  • 客户端和服务器协商:当客户端和服务器建立 SSL/TLS 连接时,会互相协商一个共同支持的加密套件。这个过程通常是客户端先发送自己支持的加密套件列表,然后服务器从中选择一个双方都支持的加密套件。

作用:

  • 开启 :如果设置为 on,服务器将优先选择自己配置的加密套件,而不是根据客户端的首选顺序来选择。这意味着,服务器可以强制使用更强的加密套件,尽管客户端可能更倾向于使用其他套件。

  • 关闭 (默认值是 off):如果设置为 off,则服务器会遵循客户端提供的加密套件优先顺序,选择客户端列出的最优加密套件。

  • 提高安全性:通过优先选择服务器配置的加密套件,服务器可以确保使用强加密算法,避免客户端可能使用的弱加密算法(即使客户端支持它们)。这种配置有助于提高 SSL/TLS 连接的安全性。

配置文件示例:

复制代码
server {
        listen 443 ssl;
        http2 on; # 启用 HTTP/2
        server_name  xx.srenro.cn;
        ssl_certificate /home/application/nginx/cert/srenro.cn.crt;
        ssl_certificate_key /home/application/nginx/cert/srenro.cn.key;
        ssl_session_timeout 1h;
        ssl_session_cache shared:MozSSL:10m;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;  # 支持的加密套件
        ssl_prefer_server_ciphers on;
}

在这个例子中,ssl_ciphers 指定了服务器允许的加密套件,而 ssl_prefer_server_ciphers on; 确保即使客户端提供了其他加密套件,服务器也会优先选择这些高强度的加密算法。 ssl_ciphers 指定算法为 ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305

5.23 split_clients 模块用途

Nginx 的 split_clients 模块 是一个非常实用的模块,主要用于实现流量分流请求随机分配,常被用在 A/B 测试、灰度发布或负载均衡场景中。

  • split_clients 模块根据预定义的权重,按一定比例将请求划分到不同的组。通过这种方式,可以将用户分配到不同的实验组、版本或后端服务器,便于测试新功能或分配流量。
  • 模块通过对某些用户属性(如 Cookie、IP 地址、客户端类型,请求参数等)的哈希值进行计算,来保证请求的分配是稳定的(即同一个用户总是会被分配到同一组)。

基本语法

复制代码
split_clients "${variable}" $result_variable {
    range1 condition1;
    range2 condition2;
    ...
    * default_condition;
}
  • ${variable} :用于哈希的变量,可以是 $remote_addr$cookie_*$arg_* 等。
  • $result_variable:结果存储变量,用于判断用户属于哪一组。
  • range:划分的范围(权重)。
  • condition:条件的值,表示用户所属的组。
  • default_condition:默认条件,当范围未覆盖到某些请求时的兜底值。

(1)、实现 A/B 测试的示例

假设需要将 50% 的用户分配到版本 A,另 50% 分配到版本 B:

复制代码
nginx


复制代码
split_clients "${remote_addr}" $variant {
    50%     "A";
    50%     "B";
}

location / {
    if ($variant = "A") {
        proxy_pass http://backend_A;
    }

    if ($variant = "B") {
        proxy_pass http://backend_B;
    }
}
  • 根据用户的 IP 地址($remote_addr),以 50% 的比例将请求分流到 backend_Abackend_B
  • 每个用户的分配是固定的,因为基于哈希计算。

(2)、实现灰度发布的示例

在灰度发布中,你可能希望将 20% 的流量发送到新版本,其余 80% 发送到旧版本:

复制代码
nginx


复制代码
split_clients "${remote_addr}" $variant {
    20%     "new";
    *       "old";
}

location / {
    if ($variant = "new") {
        proxy_pass http://new_backend;
    }

    if ($variant = "old") {
        proxy_pass http://old_backend;
    }
}
  • 20% 表示将 20% 的用户分配到 new_backend
  • * 表示剩余的用户,分配到 old_backend

(3)、实现多版本分流

如果有多个版本需要测试,可以设置多个分流比例:

复制代码
nginx


复制代码
split_clients "${remote_addr}" $variant {
    10%     "A";
    20%     "B";
    30%     "C";
    *       "D";
}

location / {
    proxy_pass http://backend_$variant;
}

此配置中:

  • 10% 的用户分配到版本 A;
  • 20% 的用户分配到版本 B;
  • 30% 的用户分配到版本 C;
  • 其余用户分配到版本 D。

实践: 使用 User-Agent 区分移动端和 PC 端

Nginx 的 $http_user_agent 变量可以获取客户端的 User-Agent 字段,通过检测其中的关键标识词来区分设备类型。

复制代码
# 根据 User-Agent 设置变量
map $http_user_agent $device_type {
    ~*Mobile         "mobile";  # 包含 "Mobile" 的 User-Agent,通常为移动设备
    ~*Android|iPhone "mobile";  # 常见移动设备关键字
    default          "pc";      # 其他情况默认为 PC
}

# 使用 split_clients 进行分流
split_clients "${remote_addr}" $variant {
    50% "A";  # 分流到 A 组
    50% "B";  # 分流到 B 组
}

# 不同设备访问不同服务
location / {
    if ($device_type = "mobile") {
        proxy_pass http://mobile_backend_$variant;  # 移动端服务
    }

    if ($device_type = "pc") {
        proxy_pass http://pc_backend_$variant;      # PC 端服务
    }
}

5.24 配置缓冲区

在默认情况下,NGIX 缓冲区中的内容来自后端服务器。当后端服务器返回响应内容时NGINX 先将它存储在内部缓冲区中,直到接收到整个响应内容后才发送给客户端。缓冲区有于优化慢速客户端的性能,如果 NGINX把响应内容同步传递到客户端,那么有可能会浪费代理服务器的时间。而启用缓冲区后,NGINX允许代理服务器快速处理响应,NGINX把响应内容在储下来的时间和客户端下载响应内容所需的时间一样长。

负责启用和禁用缓冲区的指令是 proxy_buffering,其默认值为 on,表示启用缓冲区proxy_buffers 指令用于设置为请求分配的缓冲区大小及数量。缓冲区的大小由 proxybuffer_size 指令设置。来自代理服务器的响应内容的第一部分会被存储在单独的缓冲区中这部分通常包含一个相对较小的响应头。

缓冲区默认大小

复制代码
默认缓冲区大小
以下是一些缓冲区的默认值(不同版本可能略有不同):

proxy_buffers:默认是 8 4k 或 8 8k(8 个缓冲区,每个缓冲区大小为 4k 或 8k)。
proxy_buffer_size:默认值通常为一个内存页大小(4k 或 8k,取决于系统架构)。
client_body_buffer_size:默认通常是 8k 或 16k。

自定义缓冲区大小

复制代码
location / {
proxy_buffers 16 4k;         # 响应体缓冲区
proxy_buffer_size 2k;        # 响应头缓冲区
proxy_pass http://localhost:8080;
}

如果禁用缓冲区,则将从服务器接收到的响应同步发送到客户端。对于需要尽快开始接收响应的快速交互客户端,这样的配置是可行的。

例如在 websock 的场景下,为了时效性,快速交互客户端,就不会开启缓冲区配置

复制代码
location ^~/socket {
   proxy_buffering off;  #禁用缓冲区
   rewrite ^/accidentsocket/(.*)$ /$1 break;
   proxy_pass http://192.168.1.1:9005;
   proxy_read_timeout 300s;
   proxy_send_timeout 300s;
   proxy_set_header Host $host;
   proxy_set_header X-Real-IP $remote_addr;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   #升级http1.1到 websocket协议
   proxy_http_version 1.1;
   proxy_set_header Upgrade $http_upgrade;
   proxy_set_header Connection  $connection_upgrade;
}

5.25 root 和 alias 区别

  • 核心区别

    指令 路径解析逻辑 斜杠规则 适用场景 典型用途
    root location匹配的完整URI拼接到路径后 可省略末尾斜杠 目录结构与URI一致时 托管项目主目录(如Laravel的public目录)
    alias alias路径替换 location匹配的URI部分 必须以/结尾 目录结构与URI不一致时 映射独立资源目录(如CDN资源)
(1)、路径拼接方式

root示例

bash 复制代码
location /static/ {
  root /var/www/html;  # 路径拼接为 /var/www/html/static/
}

请求/static/image.jpg→ 实际路径/var/www/html/static/image.jpg

alias示例

bash 复制代码
location /images/ {
  alias /var/data/media/;  # 路径替换为 /var/data/media/
}

请求/images/photo.jpg→ 实际路径/var/data/media/photo.jpg

(2)、斜杠规则
  • root :路径末尾可加可不加/,Nginx自动处理。
  • alias :必须以/结尾,否则路径拼接错误(如alias /var/data会导致/images/file.jpg解析为/var/dataimages/file.jpg
(3)、正则匹配

root:可与正则结合,直接拼接路径。

bash 复制代码
location ~ ^/user/(.+\.jpg)$ {
  root /var/profiles/;  # 路径为 /var/profiles/user/$1.jpg
}

alias:需配合正则捕获组,替换匹配部分。

复制代码
location ~ ^/user/(.+\.jpg)$ {
  alias /var/profiles/$1.jpg;  # 路径为 /var/profiles/$1.jpg
}

若未使用捕获组,需通过$uri动态处理

相关推荐
洛菡夕4 小时前
nginx安全防护与HTTPS部署实战
nginx·安全·https
刘晨鑫18 小时前
Nginx性能调优
运维·nginx
**蓝桉**8 小时前
prometheus监控nginx
nginx·elasticsearch·prometheus
sszdzq13 小时前
docker 安装 Nginx
nginx·docker·容器
我爱学习好爱好爱13 小时前
ELK 7.17.10 + Redis 5.0.7 构建高可用 Nginx 日志收集系统(Rocky Linux 9.6 实战)
redis·nginx·elk
kc胡聪聪1 天前
nginx的性能优化与监控
运维·nginx·性能优化
zzh0811 天前
nginx安全笔记
笔记·nginx·安全
A10169330711 天前
Nginx 之Rewrite 使用详解
运维·nginx
vanvivo1 天前
Nginx中如何配置WebSocket代理?
运维·websocket·nginx
Java小白笔记1 天前
Nginx中配置IP白名单动态刷新
运维·tcp/ip·nginx