Nginx 基础与实战指南

本文详细介绍了 Nginx 的目录结构、常用命令、日志管理,并结合实战场景讲解了静态资源代理、负载均衡、缓存配置、高可用集群搭建以及 SSL 证书自动化工具 acme.sh 的使用。

1. 简介

nginx 概述

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

HTTP 服务: httpd, IIS, GWS, NGINX

安装

安装最新稳定版 http://nginx.org/en/linux_packages.html

eg: debian
$ apt install curl gnupg2 ca-certificates lsb-release
$ echo deb http://nginx.org/packages/debian/ lsb_release -cs nginx | tee /etc/apt/sources.list.d/nginx.list
$ wget http://nginx.org/keys/nginx_signing.key && apt-key add nginx_signing.key
$ apt update && apt install nginx -y

主要功能

nginx 专为性能优化而开发。主要功能

  1. 正向代理
  2. 反向代理
  3. 负载均衡
  4. 动静分离

配置文件

配置文件分为三块:

  1. 全局块 : 主要是设置一些影响 Nginx 服务器 整体运行的配置指令
  2. events 块 : 影响 Nginx 服务器与用户的网络连接
  3. HTTP 块 : 诸如反向代理和均衡负载都在此配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
## 全局块
##定义Nginx运行的用户和用户组
user www www;

##nginx进程数,通常设置成和cpu的数量相等
## cpu 亲和 把 每个 worker 进程固定在一个 CPU 上执行,减少切换 cpu 的 cache miss 获得更好的性能
worker_processes auto;
##worker_processes 4;

##全局错误日志定义类型,[debug | info | notice | warn | error | crit]
##error_log logs/error.log warn;
##notice_log logs/notice.log notice;
##info_log logs/info.log info;


##进程pid文件
##pid logs/nginx.pid;


##指定进程可以打开的最大描述符:数目
##工作模式与连接数上限
###这个指令是指当一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit -n)与nginx进程数相除,但是nginx分配请求并不是那么均匀,所以最好与ulimit -n 的值保持一致。
##这是因为nginx调度时分配请求到进程并不是那么的均衡,所以假如填写10240,总并发量达到3-4万时就有进程可能超过10240了,这时会返回502错误。
worker_rlimit_nofile 65535;

## events 块

events {
#参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型
#是Linux 2.6以上版本内核中的高性能网络I/O模型,linux建议epoll,如果跑在FreeBSD上面,就用kqueue模型。
#补充说明:
#与apache相类,nginx针对不同的操作系统,有不同的事件模型
#A)标准事件模型
#Select、poll属于标准事件模型,如果当前系统不存在更有效的方法,nginx会选择select或poll
#B)高效事件模型
#Kqueue:使用于FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 和 MacOS X.使用双处理器的MacOS X系统使用kqueue可能会造成内核崩溃。
#Epoll:使用于Linux内核2.6版本及以后的系统。
#/dev/poll:使用于Solaris 7 11/99+,HP/UX 11.22+ (eventport),IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+。
#Eventport:使用于Solaris 10。 为了防止出现内核崩溃的问题, 有必要安装安全补丁。
use epoll


#单个进程最大连接数(最大连接数=连接数+进程数)
#根据硬件调整,和前面工作进程配合起来用,尽量大,但是别把cup跑到100%就行。
worker_connections 1024;

#keepalive 超时时间
keepalive_timeout 60;

#客户端请求头部的缓冲区大小。这个可以根据你的系统分页大小来设置,一般一个请求头的大小不会超过1k,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。
#分页大小可以用命令getconf PAGESIZE 取得。
#[root@web001 ~]# getconf PAGESIZE
#但也有client_header_buffer_size超过4k的情况,但是client_header_buffer_size该值必须设置为“系统分页大小”的整倍数。
client_header_buffer_size 4k;

#这个将为打开文件指定缓存,默认是没有启用的,max指定缓存数量,建议和打开文件数一致,inactive是指经过多长时间文件没被请求后删除缓存。
open_file_cache max=65535 inactive=60s;


#这个是指多长时间检查一次缓存的有效信息。
#语法:open_file_cache_valid time 默认值:open_file_cache_valid 60 使用字段:http, server, location 这个指令指定了何时需要检查open_file_cache中缓存项目的有效信息.
open_file_cache_valid 80s;


#open_file_cache指令中的inactive参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive时间内一次没被使用,它将被移除。
#语法:open_file_cache_min_uses number 默认值:open_file_cache_min_uses 1 使用字段:http, server, location 这个指令指定了在open_file_cache指令无效的参数中一定的时间范围内可以使用的最小文件数,如果使用更大的值,文件描述符在cache中总是打开状态.
open_file_cache_min_uses 1;

#语法:open_file_cache_errors on | off 默认值:open_file_cache_errors off 使用字段:http, server, location 这个指令指定是否在搜索一个文件是记录cache错误.
open_file_cache_errors on;
}


## http 块
##设定http服务器,利用它的反向代理功能提供负载均衡支持
http{
#文件扩展名与文件类型映射表
include mime.types;

#默认文件类型
default_type application/octet-stream;

#默认编码
charset utf-8;

#服务器名字的hash表大小
#保存服务器名字的hash表是由指令server_names_hash_max_size 和server_names_hash_bucket_size所控制的。参数hash bucket size总是等于hash表的大小,并且是一路处理器缓存大小的倍数。在减少了在内存中的存取次数后,使在处理器中加速查找hash表键值成为可能。如果hash bucket size等于一路处理器缓存的大小,那么在查找键的时候,最坏的情况下在内存中查找的次数为2。第一次是确定存储单元的地址,第二次是在存储单元中查找键 值。因此,如果Nginx给出需要增大hash max size 或 hash bucket size的提示,那么首要的是增大前一个参数的大小.
server_names_hash_bucket_size 128;

#客户端请求头部的缓冲区大小。这个可以根据你的系统分页大小来设置,一般一个请求的头部大小不会超过1k,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。分页大小可以用命令getconf PAGESIZE取得。
client_header_buffer_size 32k;

#客户请求头缓冲大小。nginx默认会用client_header_buffer_size这个buffer来读取header值,如果header过大,它会使用large_client_header_buffers来读取。
large_client_header_buffers 4 64k;

#设定通过nginx上传文件的大小
client_max_body_size 8m;

#开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
#sendfile指令指定 nginx 是否调用sendfile 函数(zero copy 方式)来输出文件,对于普通应用,必须设为on。如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络IO处理速度,降低系统uptime。
sendfile on;

#开启目录列表访问,合适下载服务器,默认关闭。
autoindex on;

#此选项允许或禁止使用socke的TCP_CORK的选项,此选项仅在使用sendfile的时候使用
tcp_nopush on;

tcp_nodelay on;

#长连接超时时间,单位是秒
keepalive_timeout 120;

#FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。下面参数看字面意思都能理解。
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;

#gzip模块设置
gzip on; #开启gzip压缩输出
gzip_min_length 1k; #最小压缩文件大小
gzip_buffers 4 16k; #压缩缓冲区
gzip_http_version 1.1; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
gzip_comp_level 2; #压缩等级
gzip_types text/plain application/x-javascript text/css application/xml; #压缩类型,默认就已经包含textml,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn。
gzip_vary on;

#开启限制IP连接数的时候需要使用
#limit_zone crawler $binary_remote_addr 10m;


#负载均衡配置
upstream piao.jd.com {

#upstream的负载均衡,weight是权重,可以根据机器配置定义权重。weigth参数表示权值,权值越高被分配到的几率越大。
server 192.168.80.121:80 weight=3;
server 192.168.80.122:80 weight=2;
server 192.168.80.123:80 weight=3;

#nginx的upstream目前支持4种方式的分配
#1、轮询(默认)
#每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
#2、weight
#指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
#例如:
#upstream bakend {
# server 192.168.0.14 weight=10;
# server 192.168.0.15 weight=10;
#}
#2、ip_hash
#每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
#例如:
#upstream bakend {
# ip_hash;
# server 192.168.0.14:88;
# server 192.168.0.15:80;
#}
#3、fair(第三方)
#按后端服务器的响应时间来分配请求,响应时间短的优先分配。
#upstream backend {
# server server1;
# server server2;
# fair;
#}
#4、url_hash(第三方)
#按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
#例:在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法
#upstream backend {
# server squid1:3128;
# server squid2:3128;
# hash $request_uri;
# hash_method crc32;
#}

#tips:
#upstream bakend{#定义负载均衡设备的Ip及设备状态}{
# ip_hash;
# server 127.0.0.1:9090 down;
# server 127.0.0.1:8080 weight=2;
# server 127.0.0.1:6060;
# server 127.0.0.1:7070 backup;
#}
#在需要使用负载均衡的server中增加 proxy_pass http://bakend/;

#每个设备的状态设置为:
#1.down表示单前的server暂时不参与负载
#2.weight为weight越大,负载的权重就越大。
#3.max_fails:允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream模块定义的错误
#4.fail_timeout:max_fails次失败后,暂停的时间。
#5.backup: 其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。

#nginx支持同时设置多组的负载均衡,用来给不用的server来使用。
#client_body_in_file_only设置为On 可以讲client post过来的数据记录到文件中用来做debug
#client_body_temp_path设置记录文件的目录 可以设置最多3层目录
#location对URL进行匹配.可以进行重定向或者进行新的代理 负载均衡
}


#虚拟主机的配置
server {
#监听端口
listen 80;

#域名可以有多个,用空格隔开
server_name www.jd.com jd.com;
#默认入口文件名称
index index.html index.htm index.php;
root /data/www/jd;

#对******进行负载均衡
location ~ .*.(php|php5)?$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}

#图片缓存时间设置
location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 10d;
}

#JS和CSS缓存时间设置
location ~ .*.(js|css)?$
{
expires 1h;
}

#日志格式设定
#$remote_addr与$http_x_forwarded_for用以记录客户端的ip地址;
#$remote_user:用来记录客户端用户名称;
#$time_local: 用来记录访问时间与时区;
#$request: 用来记录请求的url与http协议;
#$status: 用来记录请求状态;成功是200,
#$body_bytes_sent :记录发送给客户端文件主体内容大小;
#$http_referer:用来记录从那个页面链接访问过来的;
#$http_user_agent:记录客户浏览器的相关信息;
#通常web服务器放在反向代理的后面,这样就不能获取到客户的IP地址了,通过$remote_add拿到的IP地址是反向代理服务器的iP地址。反向代理服务器在转发请求的http头信息中,可以增加x_forwarded_for信息,用以记录原有客户端的IP地址和原来客户端的请求的服务器地址。
log_format access '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $http_x_forwarded_for';

#定义本虚拟主机的访问日志
access_log /usr/local/nginx/logs/host.access.log main;
access_log /usr/local/nginx/logs/host.access.404.log log404;

#对 "/connect-controller" 启用反向代理
location /connect-controller {
proxy_pass http://127.0.0.1:88; #请注意此处端口号不能与虚拟主机监听的端口号一样(也就是server监听的端口)
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;

#后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

#以下是一些反向代理的配置,可选。
proxy_set_header Host $host;

#允许客户端请求的最大单文件字节数
client_max_body_size 10m;

#缓冲区代理缓冲用户端请求的最大字节数,
#如果把它设置为比较大的数值,例如256k,那么,无论使用firefox还是IE浏览器,来提交任意小于256k的图片,都很正常。如果注释该指令,使用默认的client_body_buffer_size设置,也就是操作系统页面大小的两倍,8k或者16k,问题就出现了。
#无论使用firefox4.0还是IE8.0,提交一个比较大,200k左右的图片,都返回500 Internal Server Error错误
client_body_buffer_size 128k;

#表示使nginx阻止HTTP应答代码为400或者更高的应答。
proxy_intercept_errors on;

#后端服务器连接的超时时间_发起握手等候响应超时时间
#nginx跟后端服务器连接超时时间(代理连接超时)
proxy_connect_timeout 90;

#后端服务器数据回传时间(代理发送超时)
#后端服务器数据回传时间_就是在规定时间之内后端服务器必须传完所有的数据
proxy_send_timeout 90;

#连接成功后,后端服务器响应时间(代理接收超时)
#连接成功后_等候后端服务器响应时间_其实已经进入后端的排队之中等候处理(也可以说是后端服务器处理请求的时间)
proxy_read_timeout 90;

#设置代理服务器(nginx)保存用户头信息的缓冲区大小
#设置从被代理服务器读取的第一部分应答的缓冲区大小,通常情况下这部分应答中包含一个小的应答头,默认情况下这个值的大小为指令proxy_buffers中指定的一个缓冲区的大小,不过可以将其设置为更小
proxy_buffer_size 4k;

#proxy_buffers缓冲区,网页平均在32k以下的设置
#设置用于读取应答(来自被代理服务器)的缓冲区数目和大小,默认情况也为分页大小,根据操作系统的不同可能是4k或者8k
proxy_buffers 4 32k;

#高负荷下缓冲大小(proxy_buffers*2)
proxy_busy_buffers_size 64k;

#设置在写入proxy_temp_path时数据的大小,预防一个工作进程在传递文件时阻塞太长
#设定缓存文件夹大小,大于这个值,将从upstream服务器传
proxy_temp_file_write_size 64k;
}

#本地动静分离反向代理配置
#所有jsp的页面均交由tomcat或resin处理
location ~ .(jsp|jspx|do)?$ {
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_pass http://127.0.0.1:8080;
}
}
}

2. nginx文件目录详解

rpm -qi 包名 : 查看一个包的详细信息

rpm -qf 文件名 : 查看一个文件是由哪个包安装的

rpm -ql 包名 : 查看一个包安装了哪些文件

rpm -qa : 查看系统中安装了哪些包

查看 nginx 安装的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[root@instance-2 ~]# rpm -ql nginx
/etc/logrotate.d/nginx # 配置文件 日志轮转
/etc/nginx # 目录 nginx 主要文件
/etc/nginx/nginx.conf # 配置文件 nginx 主要文件
/etc/nginx/conf.d # 目录 nginx 主要文件
/etc/nginx/conf.d/default.conf # 配置文件 nginx 主要文件
/etc/nginx/fastcgi_params # 配置文件 cgi fastcgi 配置等
/etc/nginx/scgi_params # 配置文件 cgi fastcgi 配置等
/etc/nginx/uwsgi_params # 配置文件 cgi fastcgi 配置等
/etc/nginx/koi-utf # 配置文件 编码转换映射转化文件
/etc/nginx/koi-win # 配置文件 编码转换映射转化文件
/etc/nginx/win-utf # 配置文件 编码转换映射转化文件
/etc/nginx/mime.types # 配置文件 设置 http 协议的 Content-Type 与扩展名对应关系
/etc/sysconfig/nginx # 配置文件 用于配置出系统守护进程管理器的管理方式
/etc/sysconfig/nginx-debug # 配置文件 用于配置出系统守护进程管理器的管理方式
/usr/lib/systemd/system/nginx-debug.service # 配置文件 用于配置出系统守护进程管理器的管理方式
/usr/lib/systemd/system/nginx.service # 配置文件 用于配置出系统守护进程管理器的管理方式
/usr/sbin/nginx # 命令 Nginx 服务的管理启动终端命令
/usr/sbin/nginx-debug # 命令 Nginx 服务的管理启动终端命令
/etc/nginx/modules # 目录 Nginx 模块目录
/usr/lib64/nginx/modules # 目录 Nginx 模块目录
/usr/share/doc/nginx-1.18.0 # 目录 Nginx的手册和帮助文件
/usr/share/doc/nginx-1.18.0/COPYRIGHT # 文件 Nginx的手册和帮助文件
/usr/share/man/man8/nginx.8.gz # 文件 Nginx的手册和帮助文件
/var/cache/nginx # 目录 Nginx 的缓存目录
/var/log/nginx # 目录 Nginx 的日志目录

/usr/share/nginx
/usr/share/nginx/html
/usr/share/nginx/html/50x.html
/usr/share/nginx/html/index.html

/usr/libexec/initscripts/legacy-actions/nginx
/usr/libexec/initscripts/legacy-actions/nginx/check-reload
/usr/libexec/initscripts/legacy-actions/nginx/upgrade


3. nginx常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

## 快速关闭Nginx,可能不保存相关信息,并迅速终止web服务
nginx -s stop
## 平稳关闭Nginx,保存相关信息,有安排的结束web服务
nginx -s quit
## 因改变了Nginx相关配置,需要重新加载配置而重载
nginx -s reload
## 重新打开日志文件
nginx -s reopen
## 为 Nginx 指定一个配置文件,来代替缺省的
nginx -c filename
## 不运行,而仅仅测试配置文件。nginx 将检查配置文件的语法的正确性,并尝试打开配置文件中所引用到的文件
nginx -t
## 显示 nginx 的版本
nginx -v
## 显示 nginx 的版本,编译器版本和配置参数
nginx -V
## 格式换显示 nginx 配置参数
2>&1 nginx -V | xargs -n1
2>&1 nginx -V | xargs -n1 | grep lua

4. nginx日志文件


title: nginx日志文件
date: 2021-02-10 12:05:28
tags:

categories: nginx

查看配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[root@instance-2 nginx]# cat /etc/nginx/nginx.conf
user root;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
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 120;
client_max_body_size 20m;
#gzip on;
server {
listen 80;
server_name tj.imwl.cf;
root /usr/share/nginx/html;
index index.php index.html index.htm;
}
}

日志文件,查看格式

1
2
203.189.141.176 - - [20/Feb/2021:19:19:02 +0800] "GET / HTTP/1.1" 200 55123 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7" "-"
172.105.89.161 - - [20/Feb/2021:19:28:26 +0800] "GET /0bef HTTP/1.0" 404 153 "-" "-" "-"

5. nginx模块

模块分类

  1. 官方模块
  2. 第三方模块

所编译的模块

–with 后面主要是 所开启的模块

1
2
3
4
5
6
[root@instance-2 ~]# nginx -V
nginx version: nginx/1.18.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --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'

–with-http_stub_status_module

Nginx 的客户端状态

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
root@R7000:/etc/nginx/conf.d# cat test.conf

server {
listen 81 default_server;
listen [::]:81 default_server;
# listen 80;
#ilisten [::]:83 ipv6only=on;
server_name localhost;
charset utf-8;
client_max_body_size 75M;

location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /mystatus {
stub_status; # 使用 stub_status 模块
}
}

root@R7000:/etc/nginx/conf.d# nginx -s reload # 重载
root@R7000:/etc/nginx/conf.d# curl http://localhost:81/mystatus
Active connections: 2 # 活跃连接数
server accepts handled requests # 接受数 处理数 总的请求数
8 8 12
Reading: 0 Writing: 1 Waiting: 1 # 当前状态 读 写 等待(keep-alive)

–with-http_random_index_module

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
root@R7000:/etc/nginx/conf.d# cat test.conf

server {
listen 81 default_server;
listen [::]:81 default_server;
# listen 80;
#ilisten [::]:83 ipv6only=on;
server_name localhost;
charset utf-8;
client_max_body_size 75M;

location / {
root /usr/share/nginx/html; # 文件目录
random_index on;
# index index.html index.htm;
}
}

root@R7000:/usr/share/nginx/html# ll
total 20
drwxr-xr-x 2 root root 4096 2月 20 21:45 ./
drwxr-xr-x 4 root root 4096 2月 20 21:14 ../
-rw-r--r-- 1 root root 258 2月 20 21:43 index1.html
-rw-r--r-- 1 root root 258 2月 20 21:44 index2.html
-rw-r--r-- 1 root root 258 2月 20 21:45 index3.html

–with-http_sub_module

HTTP 内容替换

1
2
3
4
5
6
location / {
root /opt/app/code;
index index.html index.htm;
sub_filter '<a>imooc' '<a>IMOOC';
sub_filter_once off;
}

连接请求限制

连接限制

limit_conn_zone key zone=name:size

limit_conn_zone number

请求限制

limit_req_zone zone=name:size rate=rate

limit_req_zone=name [burst=number][nodelay]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    limit_conn_zone $binary_remote_addr zone=conn_zone:1m;
limit_req_zone $binary_remote_addr zone=req_zone:1m rate=1r/s;
server {
listen 80;
server_name localhost;

#charset koi8-r;
#access_log /var/log/nginx/log/host.access.log main;


location / {
root /opt/app/code;
limit_conn conn_zone 1;
#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;
}

访问控制

基于 ip

http_access_module

局限性: 可能获取不到用户的真实 ip

x_forwarded_for=IP1,IP2…. 一般 IP1 为用户 IP ,但可能被篡改

使用 geo 模块 ,或者 通过 HTTP 自定义变量传递

1
2
3
4
5
6
location ~ ^/admin.html {
root /opt/app/code;
allow 222.128.189.0/24;
deny all;
index index.html index.htm;
}

基于用户的信任登录

http_auth_basic_module

局限性: 用户信息依赖文件,效率低下

使用 LUA

利用 nginx-auth-ldap 模块


6. nginx静态资源

静态资源

非服务器动态生成的文件

  1. 浏览器渲染 : html, css, js
  2. 图片 : jpg, png, gif
  3. 视频 : flv, mpeg
  4. 文件 : txt, 任意下载文件

配置语法

sendflie on
tcp_nopush on # 开启 sendflie on 可以提高网络包的传输效率
tcp_nodelay on # keep-alive 提高网络包的传输实时性
gzip on
gzip_comp_level 2
gzip_http_version 1.1; #压缩版本

http_gzip_static_module # 预读 gzip 功能
http_gunzip_module # 应用支持 gunzip 的压缩方式

expires time # 缓存过期时间

add_header name value [always] Access-Control-Origin # 跨域访问

1
2
3
4
5
6
location ~ .*\.(htm|html)$ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
#expires 24h;
root /opt/app/code;
}

简单防盗链

区别非正常用户的请求

http_refer

1
2
3
4
5
6
7
8
9
10
11
12
location ~ .*\.(jpg|gif|png)$ {
gzip on;
gzip_http_version 1.1;
gzip_comp_level 2;
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;

valid_referers none blocked 192.168.1.1 jeson.imoocc.com ~wei\.png; # 运行 refer 为空或不标准格式 ,后面 可以接正则匹配
if ($invalid_referer) {
return 403;
}
root /opt/app/code/images;
}

7. 正向代理

节点 192.168.43.101(安装nginx 1.16.1)

节点 192.168.43.102 测试 正向代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[root@k8s01 conf.d]# cat forward-proxy.conf  # 查看 正向代理的配置文件 
server {
resolver 114.114.114.114; #指定DNS服务器IP地址
listen 80;
location / {
proxy_pass http://$http_host$request_uri; #设定代理服务器的协议和地址
proxy_set_header HOST $http_host;
proxy_buffers 256 4k;
proxy_max_temp_file_size 0k;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_next_upstream error timeout invalid_header http_502;
}
}
server {
resolver 114.114.114.114; #指定DNS服务器IP地址
listen 443;
location / {
proxy_pass https://$host$request_uri; #设定代理服务器的协议和地址
proxy_buffers 256 4k;
proxy_max_temp_file_size 0k;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_next_upstream error timeout invalid_header http_502;
}
}
[root@k8s01 conf.d]# nginx -s reload

192.168.43.102 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@k8s02 ~]# curl  -I --proxy 192.168.43.101:80 www.baidu.com  # 测试 http
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Wed, 20 Jan 2021 12:49:37 GMT
Content-Type: text/html
Content-Length: 4833
Last-Modified: Fri, 16 May 2014 15:12:48 GMT
Connection: keep-alive
ETag: "53762af0-12e1"
Accept-Ranges: bytes

[root@k8s02 ~]# curl -I --proxy 192.168.43.101:443 www.baidu.com # 测试 https
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Wed, 20 Jan 2021 12:49:39 GMT
Content-Type: text/html
Content-Length: 277
Connection: keep-alive
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Etag: "575e1f72-115"
Last-Modified: Mon, 13 Jun 2016 02:50:26 GMT
Pragma: no-cache

8. 域名绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

##user nobody;
worker_processes 1;

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

##pid logs/nginx.pid;


events {
worker_connections 1024;
}


http {
include 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 logs/access.log main;

sendfile on;
#tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;

#gzip on;

server {
listen 8088;
server_name www.k8s.com;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
root master;
index index.html index.htm;
}
}


server {
listen 8088;
server_name www.baidu.com;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
root html;
index index.html index.htm;
}
}
}

9. 端口绑定

localhost:8088 : nginx默认页面
localhost:8089 : master文件夹下路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
##user  nobody;
worker_processes 1;

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

##pid logs/nginx.pid;


events {
worker_connections 1024;
}


http {
include 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 logs/access.log main;

sendfile on;
#tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;

#gzip on;

server {
listen 8089;
server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
root master;
index index.html index.htm;
}
}


server {
listen 8088;
server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
root html;
index index.html index.htm;
}
}
}

10. nginx-url匹配规则

1
2
3
location [=|~|~*|^~|@] /uri/ {
...
}

= : 表示精确匹配后面的 url

~ : 表示正则匹配,但是区分大小写

~* : 正则匹配,不区分大小写

^~ : 表示普通字符匹配,如果该选项匹配,只匹配该选项,不匹配别的选项,一般用来匹配目录

@ : @ 定义一个命名的 location,使用在内部定向时,例如 error_page

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
upstream api_server {
server 10.0.101.62:8081;
server 10.0.101.61:8082;
}

location / {
rewrite ^(.*)$ http://10.0.101.62:8000/my-module$1 break;
}

location ^~ /my-module/ {
root /data/my-module/dist;
rewrite ^/my-module/(.*)$ /$1 break;
index index.html index.htm;
}

location /my-module/api {
proxy_pass http://api_server;
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_set_header your-custome-header "myHeader";
proxy_set_header X-NginX-Proxy true;
}

默认访问 / 会重定向到 /my-module , 然后直接返回 /data/my-module/dist 下的 html 等静态文件

补 rewrite

last : 表示 rewrite, 浏览器地址栏不变

break : 本条规则匹配完成后,终止匹配,不再匹配后面的规则,浏览器地址栏不变

redirect : 返回 302 临时重定向,浏览器地址会显示跳转后的 URL 地址

permanent : 返回 301 永久重定向,浏览器地址会显示跳转后的 URL 地址

使用 alias 指令必须用 last 标记;使用proxy_pass指令时,需要使用break标记。last标记在本条rewrite规则执行完毕后,会对其所在server{……}标签重新发起请求,而break` 标记则在本条规则匹配完成后,终止匹配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
if( !-e $request_filename )
{
rewrite ^/(.*)$ index.php last;
}

2.目录对换 /123456/xxxx ====> /xxxx?id=123456
rewrite ^/(\d+)/(.+)/ /$2?id=$1 last;

3.如果客户端使用的是IE浏览器,则重定向到/ie目录下
```if( $http_user_agent ~ MSIE)
{
rewrite ^(.*)$ /ie/$1 break;
}

4.禁止访问多个目录
location ~ ^/(cron|templates)/
{
deny all;
break;
}

5.禁止访问以/data开头的文件
location ~ ^/data
{
deny all;
}

6.禁止访问以.sh,.flv,.mp3为文件后缀名的文件
location ~ .*\.(sh|flv|mp3)$
{
return 403;
}

7.设置某些类型文件的浏览器缓存时间
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
}
location ~ .*\.(js|css)$
{
expires 1h;
}

8.给favicon.ico和robots.txt设置过期时间;
这里为favicon.ico为99天,robots.txt为7天并不记录404错误日志
location ~(favicon.ico) {
log_not_found off;
expires 99d;
break;
}
location ~(robots.txt) {
log_not_found off;
expires 7d;
break;
}

9.设定某个文件的过期时间;这里为600秒,并不记录访问日志
location ^~ /html/scripts/loadhead_1.js {
access_log off;
root /opt/lampp/htdocs/web;
expires 600;
break;
}

10.文件反盗链并设置过期时间
这里的return412 为自定义的http状态码,默认为403,方便找出正确的盗链的请求
“rewrite ^/ http://img.linuxidc.net/leech.gif;”显示一张防盗链图片
“access_log off;”不记录访问日志,减轻压力
“expires 3d”所有文件3天的浏览器缓存

location ~*^.+\.(jpg|jpeg|gif|png|swf|rar|zip|css|js)$ {
valid_referers none blocked *.linuxidc.com*.linuxidc.net localhost 208.97.167.194;
if ($invalid_referer) {
rewrite ^/ http://img.linuxidc.net/leech.gif;
return 412;
break;
}
access_log off;
root /opt/lampp/htdocs/web;
expires 3d;
break;
}

11.只允许固定ip访问网站,并加上密码

root /opt/htdocs/www;
allow 208.97.167.194;
allow 222.33.1.2;
allow 231.152.49.4;
deny all;
auth_basic “C1G_ADMIN”;
auth_basic_user_file htpasswd;

12将多级目录下的文件转成一个文件,增强seo效果
/job-123-456-789.html 指向/job/123/456/789.html

rewrite^/job-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /job/$1/$2/jobshow_$3.html last;

13.文件和目录不存在的时候重定向:

if (!-e $request_filename) {
proxy_pass http://127.0.0.1;
}

14.将根目录下某个文件夹指向2级目录
如/shanghaijob/ 指向 /area/shanghai/
如果你将last改成permanent,那么浏览器地址栏显是/location/shanghai/
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2last;
上面例子有个问题是访问/shanghai时将不会匹配
rewrite ^/([0-9a-z]+)job$ /area/$1/ last;
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2last;
这样/shanghai 也可以访问了,但页面中的相对链接无法使用,
如./list_1.html真实地址是/area/shanghia/list_1.html会变成/list_1.html,导至无法访问。
那我加上自动跳转也是不行咯
(-d $request_filename)它有个条件是必需为真实目录,而我的rewrite不是的,所以没有效果
if (-d $request_filename){
rewrite ^/(.*)([^/])$ http://$host/$1$2/permanent;
}
知道原因后就好办了,让我手动跳转吧
rewrite ^/([0-9a-z]+)job$ /$1job/permanent;
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2last;

15.域名跳转
server
{
listen 80;
server_name jump.linuxidc.com;
index index.html index.htm index.php;
root /opt/lampp/htdocs/www;
rewrite ^/ http://www.linuxidc.com/;
access_log off;
}

16.多域名转向
server_name www.linuxidc.comwww.linuxidc.net;
index index.html index.htm index.php;
root /opt/lampp/htdocs;
if ($host ~ "linuxidc\.net") {
rewrite ^(.*) http://www.linuxidc.com$1permanent;
}

11. nginx作为缓存服务

服务端缓存: 放在 redis

代理缓存: nginx 等中间件

客户端 : 浏览器缓存等

proxy_cache

proxy_cache zone off
proxy_cache_vaild [code …] time
proxy_cache_key string

location ~ .*.(html|htm)$ {
expires 12h; #缓存12小时
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
http {
proxy_cache_path /var/www/cache #缓存地址
levels=1:2 #目录分级
keys_zone=test_cache:10m #开启的keys空间名字:空间大小(1m可以存放8000个key)
max_size=10g #目录最大大小(超过时,不常用的将被删除)
inactive=60m #60分钟内没有被访问的缓存将清理
use_temp_path=pff; #是否开启存放临时文件目录,关闭默认存储在缓存地址

server {
...
location / {
proxy_cache test_cache; #开启缓存对应的名称,在keys_zone命名好
proxy_cache_valid 200 304 12h; #状态码为200 304的缓存12小时
proxy_cache_valid any 10m; #其他状态缓存10小时
proxy_cache_key $host$uri$is_args$args; #设置key值
add_header Nginx-Cache "$upstream_cache_status";
}
}

server {
...
if ($request_uri ~ ^/(login|register) ) { #当请求地址有login或register时,不缓存
set $nocache = 1; #设置一个自定义变量为true
}
location / {
proxy_no_cache $nocache $arg_nocache $arg_comment;
proxy_no_cache $http_pragma $http_authoriztion;
}
}

清理指定缓存

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

大文件分片请求

1
slice size;

每个请求收到的数据会形成一个独立文件,一个请求断了,求它请求不受影响

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


12. nginx负载均衡常见问题

  1. 客户端 IP 地址获取问题
  2. 域名携带问题
  3. 负载均衡导致 session 丢失问题
  4. 动态负载均衡问题
  5. 真实的 Realserver 状态检测

负载均衡的方式

  1. rr 轮询
  2. weight 代表权,权越高优先级越高。
  3. fair 按后端服务器的响应时间来分配请求,相应时间短的优先分配。
  4. ip_hash 每个请求按照访问 ip 的 hash 结果分配

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

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

客户端 IP 地址获取问题

第一种方式的解决办法是在 Nginx 负载均衡的基础上添加了一个转发到后端的标准 head 信息,把用户的 IP 信息通过 X-Forwarded-For 方式传递过去

第二种方式是就是添加一个 X-Real 的自定义头,自定义头我们可以随意的命名,一般情况下命名为 X-Real_IP,把用户的真实四层 IPc地址赋值给它

域名携带问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
http {
        …
        upstream app_servers {
                 server ip1:port1;
                 server ip2:port2;
                 server ip3:port3;
        }
        server {
         …
              location / {
     proxy_set_header Host $host ;
     proxy set_header Host www.test.com; 
     proxy_pass http://app_servers; 
              }
        ….
        }
}

通过 proxy_set_header 配置方式加入 Host 头部字段,如果用户的请求携带了域名,就把这个域名的 head 头以标准的 HTTP 方式将头信息传递到后端,然后让后端获取 Host 头信息

负载均衡导致 session 丢失问题

  1. Session 保持 : ip_hash、URL_hash 来解决
  2. Session 复制 : 让 Session 之间可以以传播的方式进行复制,每个 App 上都会有同样的 Session 信息,不至于因为轮询导致丢失会话失效
  3. Session 共享 : Session 信息不放在本地,通过应用程序把 Session 信息放入共享的 K/V 存储中,这样就不会产生 Session 丢失情况了

使用 ip_hash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
http {
        …
        upstream app_servers {
                 ip_hash;
                 server ip1:port1;
                 server ip2:port2;
                 server ip3:port3;
        }
        server {
         …
              location / {
                  proxy_pass http://app_servers; 
              }
        ….
        }
}

使用 url_hash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
http {
        …
        upstream app_servers {
            hash $request_uri;
                 server ip1:port1;
                 server ip2:port2;
                 server ip3:port3;
        }
        server {
         …
              location / {
                  proxy_pass http://app_servers;   
              }
        ….
        }
}

真实的 Realserver 状态检测

这个第三方模块 nginx_upstream_check_module

1
2
3
4
check interval=3000 rise=2 fall=5 timeout=1000 type=http;  //定义检查间隔、周期、时间
check_keepalive_requests 100;  //一个连接发送的请求数
check_http_send “HEAD / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n”; //定义健康检查方式
check_http_expect_alive http_2xx http_3xx;  //判断后端返回状态码

通过这样的配置,我们定义了检测间隔、周期和超时时间;定义了一个连接发送的请求数;然后是定义健康检查方式,比如检查 head 头的请求信息;最后判断后端返回状态码,如果是非 200 或 300 的话,就认为后台服务不健康,需要把这个问题服务除掉,避免用户请求到问题节点

动态负载均衡问题

可以使用第三方工具


13. nginx高可用

高可用方案

  1. LVS : 4 层负载均衡,性能强的,对内存和 cpu 资源消耗比较低, 不支持正则静态分离,大型网站配置复杂
  2. nginx : 7 层负载均衡, 适用面小,负载均衡可能会遇到 session 等问题,不支持通过 ur l来检测
  3. haproxy : 4+7层,负载均衡策略非常多,能很好地弥补 nginx 的缺点

在 Nginx 1.9.0 版本后,Nginx 便可以通过配置 –with-stream 模块的方式,来实现基于四层的反向代理

基于TCP的四层负载均衡配置文件不能配置 http 层

eg: k8s 主节点 10.0.0.101,10.0.0.102,10.0.0.103.端口均为 6443

访问任一节点 nginx:6443 则负载均衡到任一节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
user root;
worker_processes 1;

error_log /var/log/nginx/error.log warn;

events {
worker_connections 3000;
}

stream {
upstream backend {
server 10.0.0.101:6443 max_fails=2 fail_timeout=3s;
server 10.0.0.102:6443 max_fails=2 fail_timeout=3s;
server 10.0.0.103:6443 max_fails=2 fail_timeout=3s;
}

server {
listen 127.0.0.1:6443 so_keepalive=on; # 开启 TCP 存活探测
# proxy_connect_timeout 10s; # 端口保持时间
proxy_connect_timeout 1s;
proxy_pass backend;
}
}

Keepalived 软件起初是专为 LVS 负载均衡软件设计的,用来管理并监控 LVS 集群系统中各个服务节点的状态,后来又加入了可以实现高可用的 VRRP 功能。因此, Keepalived 除了能够管理 LVS 软件外,还可以作为其他服务(例如:Nginx、Haproxy、MySQL 等)的高可用解决方案软件

准备工作

示例:

  1. 多台 Nginx 服务器 : smtp_server 192.168.43.101(主)smtp_server 192.168.43.102(备)
  2. 安装 Keepalived : yum install -y Keepalived ,配置文件 默认 /etc/keepalived/keepalived.conf
  3. 虚拟 ip : 192.168.43.100

主备模式

192.168.43.101 上修改 keepalived.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
! Configuration File for keepalived

global_defs {
router_id k8s
}

vrrp_instance VI_1 {
state MASTER # 主节点
interface ens33 # 当前用的 ens33 网卡
virtual_router_id 51
priority 100 # 优先级配置
advert_int 2
authentication {
auth_type PASS
auth_pass K8SHA_KA_AUTH
}
virtual_ipaddress { # VIP
192.168.43.100
}

}

192.168.43.102 上修改 keepalived.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
! Configuration File for keepalived

global_defs {
router_id k8s
}

vrrp_instance VI_1 {
state BACKUP # 备节点
interface ens33 # 当前用的 ens33 网卡
virtual_router_id 51
priority 80 # 优先级配置
advert_int 2
authentication {
auth_type PASS
auth_pass K8SHA_KA_AUTH
}
virtual_ipaddress { # VIP
192.168.43.100
}

}

所有主机执行

1
2
systemctl start  keepalived   
systemctl enable keepalived

双主模式

再配置一段新的 vrrp_instance(实例)规则,主 上面加配置一个 从 的实例规则,从 上面加配置一个 主 的实例规则

192.168.43.101 上修改 keepalived.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
! Configuration File for keepalived

global_defs {
router_id k8s
}

vrrp_instance VI_1 {
state MASTER # 主节点
interface ens33 # 当前用的 ens33 网卡
virtual_router_id 51
priority 100 # 优先级配置
advert_int 2
authentication {
auth_type PASS
auth_pass K8SHA_KA_AUTH
}
virtual_ipaddress { # VIP
192.168.43.100
}

}

vrrp_instance VI_2 {
state BACKUP # 备节点
interface ens33 # 当前用的 ens33 网卡
virtual_router_id 51
priority 100 # 优先级配置
advert_int 2
authentication {
auth_type PASS
auth_pass K8SHA_KA_AUTH
}
virtual_ipaddress { # VIP
192.168.43.100
}

}

192.168.43.102 上修改 keepalived.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
! Configuration File for keepalived

global_defs {
router_id k8s
}

vrrp_instance VI_1 {
state BACKUP # 备节点
interface ens33 # 当前用的 ens33 网卡
virtual_router_id 51
priority 80 # 优先级配置
advert_int 2
authentication {
auth_type PASS
auth_pass K8SHA_KA_AUTH
}
virtual_ipaddress { # VIP
192.168.43.100
}

}

vrrp_instance VI_2 {
state MASTER # 主节点
interface ens33 # 当前用的 ens33 网卡
virtual_router_id 51
priority 100 # 优先级配置
advert_int 2
authentication {
auth_type PASS
auth_pass K8SHA_KA_AUTH
}
virtual_ipaddress { # VIP
192.168.43.100
}

}

所有主机执行

1
systemctl restart keepalived

14. nginx优化

nginx 优化

  1. 基础配置优化
  2. 缓存配置优化

基础配置优化

  1. CPU 亲和性优化 : 每一个 Nginxworker 线程都能固定到具体的 CPU 核心上
  2. Nginx 模型优化 : kernel 2.6 后使用 epoll , 单个线程的最大连接数 worker_connections 配置的更合理一点
  3. Nginx 传输方式优化 : 零拷贝,HTTP 配置模块中添加一个 sendfile on,实现静态文件的内核态到用户态的零拷贝
  4. Nginx 文件压缩优化 : gzip on 负责打开后端的压缩功能

nginx master 进程主要用来管理 worker 进程,包含:接收来自外界的信号,向各 worker 进程发送信号,监控 worker 进程的运行状态,当 worker 进程退出后(异常情况下),会自动重新启动新的 worker 进程。

缓存配置优化

  1. 浏览器缓存优化
  2. 代理缓存优化
  3. HTTPS SSL 缓存优化
  4. KV 服务缓存优化等
浏览器缓存

浏览器缓存通常是缓存到客户端(如:浏览器、客户端 app )

可以把静态元素,比如用户请求的图片、CSSJS 等元素缓存到客户端。这种缓存可以通过 Nginx 配置中的 expires 配置项进行设置,expires 后面可以加具体的时间,也可以加对应的特定意义的数值,比如 -1 表示永久缓存,max 设置最大周期缓存(默认缓存周期为 10 年),需要做具体的时间的设置可以写入具体的时间周期,比如一个小时或是一天

HTTPS 配置优化

Nginx 中配置 ssl_session_cache

配置中分配 Nginx 在处理 SSL 会话所需要开辟的共享内存的空间为 10 MB,第二个参数就是设置 SSL SessionKey 的超时时间,这里设置的为 10 分钟,也就是每隔 10 分钟需要重新再进行一次建联,这是一个在服务端的超时时间。

打开文件缓存

open_file_cache 具体的设置策略,max 表示最大能够缓存的文件个数,inactive 表示最少的用户使用次数。我们结合看一下,这个表示在 20 秒内最小需要使用两次。如果没有使用的话,就会把元数据删掉,也这就是一个淘汰元数据的策略。

open_file_cache_valid 是设置主动更新和检查的时间,表示每隔 30 秒检查缓存文件的元信息有没有对应的更新,如果有更新就需要去做对应的更新,它是一个更新的策略

代理缓存优化
1
2
3
4
proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60mlocation / {
        proxy_cache my_cache;
        …
}

通过 Nginx 作代理,可以支持实现动静态的分离,静态元素直接交给 Nginx 来处理,再把后端动态数据适当作缓存。通常做这种代理+缓存的架构,是能有效的提高整体网站的访问并发性能。

缓存使用注意问题

对于缓存的整体使用,之前说的缓存越多越好,越靠前越好,命中率越高越好

  1. 文件更新策略问题
  2. 缓存命中率失败给后端造成的瞬间压力
  3. 多节点缓存一致性

15. acme使用

申请通配符

可以不需要 ip 服务器,只用证明 域名是你的。

https://github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cf 这些提供商可以自动添加记录,不在这些运营商的需要手动添加 txt 记录

当前使用通用的方式,手动添加记录。可以添加多个, -d *.grafana.eu.org -d grafana.eu.org

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
[office-k8s-01][email protected]:~# acme.sh --issue --dns -d *.grafana.eu.org  
[Wed Jul 2 17:03:47 CST 2025] It seems that you are using dns manual mode. Read this link first: https://github.com/acmesh-official/acme.sh/wiki/dns-manual-mode
[office-k8s-01][email protected]:~# acme.sh --issue --dns -d *.grafana.eu.org --yes-I-know-dns-manual-mode-enough-go-ahead-please
[Wed Jul 2 17:04:59 CST 2025] Using CA: https://acme.zerossl.com/v2/DV90
[Wed Jul 2 17:04:59 CST 2025] Creating domain key
[Wed Jul 2 17:04:59 CST 2025] The domain key is here: /root/.acme.sh/*.grafana.eu.org_ecc/*.grafana.eu.org.key
[Wed Jul 2 17:04:59 CST 2025] Single domain='*.grafana.eu.org'
[Wed Jul 2 17:07:15 CST 2025] Getting webroot for domain='*.grafana.eu.org'
[Wed Jul 2 17:07:15 CST 2025] Add the following TXT record:
[Wed Jul 2 17:07:15 CST 2025] Domain: '_acme-challenge.grafana.eu.org'
[Wed Jul 2 17:07:15 CST 2025] TXT value: 'u4aSBaAlbetG1Wkr_PNffvGgxj6vHZujFNyLyFeVMC0'
[Wed Jul 2 17:07:15 CST 2025] Please make sure to prepend '_acme-challenge.' to your domain
[Wed Jul 2 17:07:15 CST 2025] so that the resulting subdomain is: _acme-challenge.grafana.eu.org
[Wed Jul 2 17:07:15 CST 2025] Please add the TXT records to the domains, and re-run with --renew.
[Wed Jul 2 17:07:15 CST 2025] Please add '--debug' or '--log' to see more information.
[Wed Jul 2 17:07:15 CST 2025] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh


### 手动添加 _acme-challenge.grafana.eu.org TXT u4aSBaAlbetG1Wkr_PNffvGgxj6vHZujFNyLyFeVMC0

[office-k8s-01][email protected]:~# acme.sh --issue --dns -d *.grafana.eu.org --yes-I-know-dns-manual-mode-enough-go-ahead-please --renew
[Wed Jul 2 17:09:12 CST 2025] The domain '*.grafana.eu.org' seems to already have an ECC cert, let's use it.
[Wed Jul 2 17:09:12 CST 2025] Renewing: '*.grafana.eu.org'
[Wed Jul 2 17:09:12 CST 2025] Renewing using Le_API=https://acme.zerossl.com/v2/DV90
[Wed Jul 2 17:09:15 CST 2025] Using CA: https://acme.zerossl.com/v2/DV90
[Wed Jul 2 17:09:15 CST 2025] Single domain='*.grafana.eu.org'
[Wed Jul 2 17:09:15 CST 2025] Verifying: *.grafana.eu.org
[Wed Jul 2 17:09:50 CST 2025] Processing. The CA is processing your order, please wait. (1/30)
[Wed Jul 2 17:10:21 CST 2025] Success
[Wed Jul 2 17:10:21 CST 2025] Verification finished, beginning signing.
[Wed Jul 2 17:10:21 CST 2025] Let's finalize the order.
[Wed Jul 2 17:10:21 CST 2025] Le_OrderFinalize='https://acme.zerossl.com/v2/DV90/order/JoDGS0BAiPIBTdNwRu5oNA/finalize'
[Wed Jul 2 17:10:55 CST 2025] Order status is 'processing', let's sleep and retry.
[Wed Jul 2 17:10:55 CST 2025] Sleeping for 15 seconds then retrying
[Wed Jul 2 17:11:11 CST 2025] Polling order status: https://acme.zerossl.com/v2/DV90/order/JoDGS0BAiPIBTdNwRu5oNA
[Wed Jul 2 17:11:14 CST 2025] Downloading cert.
[Wed Jul 2 17:11:14 CST 2025] Le_LinkCert='https://acme.zerossl.com/v2/DV90/cert/XUI_bZ_CfvW42--xLMj_ZA'
[Wed Jul 2 17:11:15 CST 2025] Cert success.
-----BEGIN CERTIFICATE-----
MIIECTCCA4+gAwIBAgIRAIfRQ6hPRFKW6tFOW1q96hwwCgYIKoZIzj0EAwMwSzEL
MAkGA1UEBhMCQVQxEDAOBgNVBAoTB1plcm9TU0wxKjAoBgNVBAMTIVplcm9TU0wg
RUNDIERvbWFpbiBTZWN1cmUgU2l0ZSBDQTAeFw0yNTA3MDIwMDAwMDBaFw0yNTA5
MzAyMzU5NTlaMB4xHDAaBgNVBAMMEyouZG9rcGxveS5ob255LmxvdmUwWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAAT0F8Z5AEOIWX67yb/l3qGj6ngiu+RUg8dzeke/
Zq4+367XS0bvDf4hvFkCDj+hwkxjaf6vmOeeQVU4MbZJmhq2o4ICfzCCAnswHwYD
VR0jBBgwFoAUD2vmS845R672fpAeefAwkZLIX6MwHQYDVR0OBBYEFEcm3Rj4kxRu
Lj5cfEZXtoqSoImCMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1Ud
JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBJBgNVHSAEQjBAMDQGCysGAQQBsjEB
AgJOMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgGBmeB
DAECATCBiAYIKwYBBQUHAQEEfDB6MEsGCCsGAQUFBzAChj9odHRwOi8vemVyb3Nz
bC5jcnQuc2VjdGlnby5jb20vWmVyb1NTTEVDQ0RvbWFpblNlY3VyZVNpdGVDQS5j
cnQwKwYIKwYBBQUHMAGGH2h0dHA6Ly96ZXJvc3NsLm9jc3Auc2VjdGlnby5jb20w
ggEEBgorBgEEAdZ5AgQCBIH1BIHyAPAAdgDd3Mo0ldfhFgXnlTL6x5/4PRxQ39sA
OhQSdgosrLvIKgAAAZfKZ12zAAAEAwBHMEUCIQDdy145LFaIJPu7+GAw5CDH17Qj
0LspxH2Is7nzJ23/EgIga0ICn4NvC+1zn+4CuYUwhgjLoSH4m38VpJeY+So4HJ0A
dgAN4fIwK9MNwUBiEgnqVS78R3R8sdfpMO8OQh60fk6qNAAAAZfKZ12JAAAEAwBH
MEUCIQC6cx5ub4tepIZtpCoZ8srAwdviK9hS5bIRHABf3tx7swIgSZFJx/+SXMuR
24mtUIjGNAw04viIJsjyC4Utr0hIq5UwHgYDVR0RBBcwFYITKi5kb2twbG95Lmhv
bnkubG92ZTAKBggqhkjOPQQDAwNoADBlAjBeqUcSFagFKtxmKnhiw1zJMUIh5RIj
t6CftSj9bvcxv8W8p8posPEsVv++PnZVEhMCMQCfecDMrxKZPgBajDc8TKVgjGNR
1K5f6KEC5udPC264J4cm0JXROAXsxqPIbj9r/Y0=
-----END CERTIFICATE-----
[Wed Jul 2 17:11:15 CST 2025] Your cert is in: /root/.acme.sh/*.grafana.eu.org_ecc/*.grafana.eu.org.cer
[Wed Jul 2 17:11:15 CST 2025] Your cert key is in: /root/.acme.sh/*.grafana.eu.org_ecc/*.grafana.eu.org.key
[Wed Jul 2 17:11:15 CST 2025] The intermediate CA cert is in: /root/.acme.sh/*.grafana.eu.org_ecc/ca.cer
[Wed Jul 2 17:11:15 CST 2025] And the full-chain cert is in: /root/.acme.sh/*.grafana.eu.org_ecc/fullchain.cer

证书详情

1
2
3
4
1. 证书内容(单证书) /root/.acme.sh/*.grafana.eu.org_ecc/*.grafana.eu.org.cer 仅包含你域名的证书(无 CA)
2. 证书私钥 /root/.acme.sh/*.grafana.eu.org_ecc/*.grafana.eu.org.key 证书对应的私钥,部署时用于服务器握手
3. 中间证书(CA) /root/.acme.sh/*.grafana.eu.org_ecc/ca.cer Let’s Encrypt 的中间证书
4. 完整链证书(fullchai) /root/.acme.sh/*.grafana.eu.org_ecc/fullchain.cer

一般使用 2 和 4

更新(测试手动dns解析可能无效。需要删除文件然后重新走上面的 申请通配符 的流程)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[office-k8s-01][email protected]:~# /root/.acme.sh/acme.sh --renew -d "*.grafana.eu.org"  --force --home "/root/.acme.sh"  --yes-I-know-dns-manual-mode-enough-go-ahead-please
[Fri Sep 26 15:13:53 CST 2025] The domain '*.grafana.eu.org' seems to already have an ECC cert, let's use it.
[Fri Sep 26 15:13:53 CST 2025] Renewing: '*.grafana.eu.org'
[Fri Sep 26 15:13:53 CST 2025] Renewing using Le_API=https://acme.zerossl.com/v2/DV90
[Fri Sep 26 15:13:57 CST 2025] Using CA: https://acme.zerossl.com/v2/DV90
[Fri Sep 26 15:13:57 CST 2025] Single domain='*.grafana.eu.org'
[Fri Sep 26 15:14:04 CST 2025] Getting webroot for domain='*.grafana.eu.org'
[Fri Sep 26 15:14:04 CST 2025] Add the following TXT record:
[Fri Sep 26 15:14:04 CST 2025] Domain: '_acme-challenge.grafana.eu.org'
[Fri Sep 26 15:14:04 CST 2025] TXT value: 'WnQ-RrNUIFXXt2beMTgTFxI46nfe0KjcGmXKk8enbXs'
[Fri Sep 26 15:14:04 CST 2025] Please make sure to prepend '_acme-challenge.' to your domain
[Fri Sep 26 15:14:04 CST 2025] so that the resulting subdomain is: _acme-challenge.grafana.eu.org
[Fri Sep 26 15:14:04 CST 2025] Please add the TXT records to the domains, and re-run with --renew.
[Fri Sep 26 15:14:04 CST 2025] Please add '--debug' or '--log' to see more information.
[Fri Sep 26 15:14:04 CST 2025] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
[Fri Sep 26 15:14:04 CST 2025] The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead.

更新 txt 记录

1
2
3
4
5
6
7
8
[office-k8s-01][email protected]:~# nslookup -q=TXT _acme-challenge.grafana.eu.org
Server: 127.0.0.53
Address: 127.0.0.53#53

Non-authoritative answer:
_acme-challenge.grafana.eu.org text = "WnQ-RrNUIFXXt2beMTgTFxI46nfe0KjcGmXKk8enbXs"

Authoritative answers can be found from:

然后重新执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
[office-k8s-01][email protected]:~# /root/.acme.sh/acme.sh --renew -d "*.grafana.eu.org" --force --home "/root/.acme.sh"  --yes-I-know-dns-manual-mode-enough-go-ahead-please
[Fri Sep 26 15:24:57 CST 2025] The domain '*.grafana.eu.org' seems to already have an ECC cert, let's use it.
[Fri Sep 26 15:24:57 CST 2025] Renewing: '*.grafana.eu.org'
[Fri Sep 26 15:24:57 CST 2025] Renewing using Le_API=https://acme.zerossl.com/v2/DV90
[Fri Sep 26 15:24:58 CST 2025] Using CA: https://acme.zerossl.com/v2/DV90
[Fri Sep 26 15:24:58 CST 2025] Single domain='*.grafana.eu.org'
[Fri Sep 26 15:24:58 CST 2025] Verifying: *.grafana.eu.org
[Fri Sep 26 15:25:02 CST 2025] Processing. The CA is processing your order, please wait. (1/30)
[Fri Sep 26 15:25:12 CST 2025] Success
[Fri Sep 26 15:25:12 CST 2025] Verification finished, beginning signing.
[Fri Sep 26 15:25:12 CST 2025] Let's finalize the order.
[Fri Sep 26 15:25:12 CST 2025] Le_OrderFinalize='https://acme.zerossl.com/v2/DV90/order/7N_P3dm1FWxlEZezBm3DOQ/finalize'
[Fri Sep 26 15:25:13 CST 2025] Order status is 'processing', let's sleep and retry.
[Fri Sep 26 15:25:13 CST 2025] Sleeping for 15 seconds then retrying
[Fri Sep 26 15:25:29 CST 2025] Polling order status: https://acme.zerossl.com/v2/DV90/order/JoDGS0BAiPIBTdNwRu5oNA
[Fri Sep 26 15:25:32 CST 2025] Downloading cert.
[Fri Sep 26 15:25:32 CST 2025] Le_LinkCert='https://acme.zerossl.com/v2/DV90/cert/XUI_bZ_CfvW42--xLMj_ZA'
[Fri Sep 26 15:25:36 CST 2025] Cert success.
-----BEGIN CERTIFICATE-----
MIIECTCCA4+gAwIBAgIRAIfRQ6hPRFKW6tFOW1q96hwwCgYIKoZIzj0EAwMwSzEL
MAkGA1UEBhMCQVQxEDAOBgNVBAoTB1plcm9TU0wxKjAoBgNVBAMTIVplcm9TU0wg
RUNDIERvbWFpbiBTZWN1cmUgU2l0ZSBDQTAeFw0yNTA3MDIwMDAwMDBaFw0yNTA5
MzAyMzU5NTlaMB4xHDAaBgNVBAMMEyouZG9rcGxveS5ob255LmxvdmUwWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAAT0F8Z5AEOIWX67yb/l3qGj6ngiu+RUg8dzeke/
Zq4+367XS0bvDf4hvFkCDj+hwkxjaf6vmOeeQVU4MbZJmhq2o4ICfzCCAnswHwYD
VR0jBBgwFoAUD2vmS845R672fpAeefAwkZLIX6MwHQYDVR0OBBYEFEcm3Rj4kxRu
Lj5cfEZXtoqSoImCMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1Ud
JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBJBgNVHSAEQjBAMDQGCysGAQQBsjEB
AgJOMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgGBmeB
DAECATCBiAYIKwYBBQUHAQEEfDB6MEsGCCsGAQUFBzAChj9odHRwOi8vemVyb3Nz
bC5jcnQuc2VjdGlnby5jb20vWmVyb1NTTEVDQ0RvbWFpblNlY3VyZVNpdGVDQS5j
cnQwKwYIKwYBBQUHMAGGH2h0dHA6Ly96ZXJvc3NsLm9jc3Auc2VjdGlnby5jb20w
ggEEBgorBgEEAdZ5AgQCBIH1BIHyAPAAdgDd3Mo0ldfhFgXnlTL6x5/4PRxQ39sA
OhQSdgosrLvIKgAAAZfKZ12zAAAEAwBHMEUCIQDdy145LFaIJPu7+GAw5CDH17Qj
0LspxH2Is7nzJ23/EgIga0ICn4NvC+1zn+4CuYUwhgjLoSH4m38VpJeY+So4HJ0A
dgAN4fIwK9MNwUBiEgnqVS78R3R8sdfpMO8OQh60fk6qNAAAAZfKZ12JAAAEAwBH
MEUCIQC6cx5ub4tepIZtpCoZ8srAwdviK9hS5bIRHABf3tx7swIgSZFJx/+SXMuR
24mtUIjGNAw04viIJsjyC4Utr0hIq5UwHgYDVR0RBBcwFYITKi5kb2twbG95Lmhv
bnkubG92ZTAKBggqhkjOPQQDAwNoADBlAjBeqUcSFagFKtxmKnhiw1zJMUIh5RIj
t6CftSj9bvcxv8W8p8posPEsVv++PnZVEhMCMQCfecDMrxKZPgBajDc8TKVgjGNR
1K5f6KEC5udPC264J4cm0JXROAXsxqPIbj9r/Y0=
-----END CERTIFICATE-----
[Fri Sep 26 15:25:36 CST 2025] Your cert is in: /root/.acme.sh/*.grafana.eu.org_ecc/*.grafana.eu.org.cer
[Fri Sep 26 15:25:36 CST 2025] Your cert key is in: /root/.acme.sh/*.grafana.eu.org_ecc/*.grafana.eu.org.key
[Fri Sep 26 15:25:36 CST 2025] The intermediate CA cert is in: /root/.acme.sh/*.grafana.eu.org_ecc/ca.cer
[Fri Sep 26 15:25:36 CST 2025] And the full-chain cert is in: /root/.acme.sh/*.grafana.eu.org_ecc/fullchain.cer

[office-k8s-01][email protected]:~# openssl x509 -in /root/.acme.sh/*.grafana.eu.org_ecc/fullchain.cer -noout -dates
notBefore=Sep 26 00:00:00 2025 GMT
notAfter=Dec 25 23:59:59 2025 GMT

和 nginx 搭配使用

1
2
3
4
acme.sh --install-cert -d test.com --ecc \
--key-file /root/.acme.sh/grafana.eu.org_ecc/grafana.eu.org.key \
--fullchain-file /root/.acme.sh/grafana.eu.org_ecc/fullchain.cer \
--reloadcmd "docker restart nginx"

nginx 的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
server {
listen 443 ssl;
server_name grafana.eu.org;

ssl_certificate /root/.acme.sh/grafana.eu.org_ecc/fullchain.cer;
ssl_certificate_key /root/.acme.sh/grafana.eu.org_ecc/grafana.eu.org.key;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Range $http_range;
proxy_set_header If-Range $http_if_range;
proxy_redirect off;
proxy_pass http://127.0.0.1:5244;

client_max_body_size 20000m;
}
}

## 强制 HTTP 自动跳转到 HTTPS(可选)
server {
listen 80;
server_name grafana.eu.org;
return 301 https://$host$request_uri;
}