Nginx管理维护运维规范

一、版本约束

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

  • 系统环境,软件版本 【最新文档版本】
    • Centos7.9
    • nginx: 1.22.1

二、软件安装路径

  • 部署路径

    /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.22.1.tar.gz

3.2 安装依赖

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

yum -y install gcc pcre-devel openssl-devel

3.3 创建nginx用户

useradd -s /sbin/nologin nginx -M

3.4 指定安装目录

/home/application/nginx

mkdir /home/application/nginx
tar -xf nginx-1.22.1.tar.gz
cd nginx-1.22.1
./configure --prefix=/home/application/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --with-stream

3.5 编译安装

make && make install

3.6 服务启动

3.6.1 编写 nginx.service 文件

vim /lib/systemd/system/nginx.service

[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

3.6.2 服务启动

systemctl daemon-reload
 
systemctl enable nginx
 
systemctl start nginx 
 
systemctl reload nginx  [重新加载配置文件,相当于 nginx -s reload]

四、平滑升级

4.1 下载

wget https://nginx.org/download/nginx-1.23.1.tar.gz

4.2 解压

tar xf nginx-1.23.1.tar.gz

4.3 编译安装

cd nginx-1.23.1
./configure --prefix=/home/application/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --with-stream
make

4.4 复制启动文件

mv /home/application/nginx/sbin/nginx /home/application/nginx/sbin/nginx-old
cp nginx-1.23.1/objs/nginx /home/application/nginx/sbin/

4.5 平滑升级

make upgrade

4.6 查看版本

/home/application/nginx/sbin/ -v

五、常见配置优化

5.1 版本隐藏(http模块)

server_tokens off

5.2 运行用户(全局模块)

user nginx

5.3 工作进程(全局模块)

worker_processes auto

5.4 进程连接数(events模块)

worker_connections  1024

5.5 开启文件发送(http模块)

sendfile  on

5.6 会话保持超时时间(http模块)

keepalive_timeout 65

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
    

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/fxkj-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 /fxkj-base {
                alias /home/application/nginx/html/fxkj/fxkj-base/;
                index index.html;
                #对于htm,html的页面不缓存
                if ($request_filename ~ .*\.(htm|html)$) {
                      add_header Cache-Control 'no-store, no-cache, must-revalidate';
                }
                try_files $uri /fxkj-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 /fxkj-base {
                alias /usr/local/nginx/html/fxkj/fxkj-base/;
                index index.html;
				#map中加载不缓存配置
				add_header Cache-Control $cache_control;
                try_files $uri /fxkj-base/index.html;
           }

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

}

image-20230905164141788

5.12 文件最大上传限制(http,server模块)

client_max_body_size 100m;

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;
            }

image-20230905164421765

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

[root@nginx conf.d]# cat http-https.conf

server {

        	listen       8208;
			    listen 	     18208 ssl;
        	    root         /home/application/nginx/html/fxkj;
	            ssl_certificate /home/application/nginx/conf/server.crt;
                ssl_certificate_key /home/application/nginx/conf/server.key;
                ssl_session_timeout 5m;
                ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
                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 反向代理

需要注意配置 proxy_pass 时,当在后面的 url 加上了/,相当于是绝对路径,则 Nginx不会把 location中匹配的路径部分加入代理uri

这几个参数是用于反向代理配置的,具体含义如下:

  1. proxy_set_header Host $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地址列表。
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;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    }
}

5.17 websock代理

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

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

image-20221009100726927

nginx主配置文件:
.........
    map $http_upgrade $connection_upgrade {
      default upgrade;
      '' close;
    }
.........


引入	配置文件:
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.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;
        	root         /home/application/nginx/html/fxkj;
	        ssl_certificate /home/application/nginx/conf/server.crt;
                ssl_certificate_key /home/application/nginx/conf/server.key;
                ssl_session_timeout 5m;
                ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
                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;
        	    root         /home/application/nginx/html/fxkj;
	            ssl_certificate /home/application/nginx/conf/server.crt;
                ssl_certificate_key /home/application/nginx/conf/server.key;
                ssl_session_timeout 5m;
                ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
                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中,​http_host、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变量通常在需要获取客户端请求中的完整主机名和端口信息时使用。一些常见的场景包括:

  1. 虚拟主机配置:当配置多个虚拟主机时,可以使用$http_host变量来根据请求的主机名和端口号来路由到不同的虚拟主机配置。
  2. 重定向规则:在配置重定向规则时,可以使用$http_host变量来获取请求的完整主机名和端口信息,并根据需要进行重定向。
  3. 访问日志:在访问日志中记录客户端请求的完整主机名和端口信息。

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

5.20 关于server_name的一些问题

当我们nginx 下监听了一个IP,如果一个域名 配置了解析到这台NGINX 上,且没有在nginx 的server_name 里,那可能会访问到一些nginx 其他server_name 下的页面,不是很安全;当请求的主机名不匹配任何其他server块的server_name时,将会使用该server块的配置来处理请求。处理未知主机名的请求。

另外,在nginx中,listen 80 default_server; 表示将当前server块配置为默认监听端口为80的服务器。这意味着当请求到达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;
}