今天松哥和大伙分享几个常见的 Nginx 优化配置。
整体上来说,Nginx 的优化可以从多个层面进行:
- 系统层面
- 配置层面
- 缓存利用
- 压缩策略
- 负载均衡策略
接下来我们就来看看具体该如何做。
一 Nginx 配置优化
- 调整 worker_processes 参数,通常设置为等于服务器的 CPU 核心数。
- 调整 worker_connections 参数,以增加每个 Worker 进程可以打开的连接数。
events {
worker_connections 1024;
}
worker_processes auto;
- 使用 HTTP/2 协议,利用多路复用和头部压缩等特性,提高页面加载速度。
server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
}
- 优化 SSL/TLS 配置,如关闭不安全的加密算法、使用 TLS 1.3 等,提高安全性和性能。
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
二 缓存利用
- 启用文件缓存,减少磁盘 I/O 操作。
- 使用代理缓存,缓存后端服务器的响应内容。
- 设置合理的缓存过期策略,通过 Cache-Control 和 Expires 头控制浏览器缓存的有效期,减少请求次数。
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;
server {
location / {
proxy_cache my_cache;
proxy_pass http://backend;
}
}
在上面这段配置中,proxy_cache_path 指令用于配置一个缓存区域,该区域用于存储代理请求的响应内容。这个指令通常在 http 块中使用,并且是 ngx_cache_purge 模块和 ngx_http_proxy_module 模块的一部分。
这项配置中的各参数含义如下:
- /data/nginx/cache:这是缓存文件存储的物理路径。Nginx 将在该目录下存储缓存数据。
- levels=1:2:这定义了缓存文件的目录结构。在这个例子中,1:2 意味着 Nginx 将缓存文件存储在 /data/nginx/cache 下的一级目录和二级目录中。1 代表第一级目录的数量(通常是 3 个,如 data、tmp、html),2 代表第二级目录的数量(通常是 64 个,基于 0 到 63 的数字或字母)。
- keys_zone=my_cache:10m:这定义了一个共享内存区域,用于存储缓存键和元数据。my_cache 是该区域的名称,10m 表示分配的共享内存大小为 10MB。这个区域用于存储缓存的键和相关信息,以便快速检索和验证缓存的有效性。
- max_size=10g:这指定了缓存区域的最大大小,单位是字节。在这个例子中,缓存区域的最大大小为 10GB。当缓存数据达到这个大小时,Nginx 将使用一种策略(通常是最近最少使用 LRU 算法)来移除旧的缓存数据,为新的缓存数据腾出空间。
- inactive=60m:这定义了缓存对象在多久没有被访问后会被认为“非活跃”并可能被移除。在这个例子中,如果一个缓存对象在 60 分钟内没有被访问,它将被认为是非活跃的。这个参数有助于控制缓存中旧数据的生命周期。
- use_temp_path=off:这指定了是否使用临时路径来存储缓存文件。off 表示不使用临时路径,所有的缓存文件都直接存储在指定的 /data/nginx/cache 路径下。如果设置为 on,则 Nginx 会使用一个临时目录来存储缓存文件,在文件被访问后,它们会被移动到永久的缓存目录中。
三 压缩策略
- 启用 Gzip 压缩,减少数据传输量,提高响应速度。
- 根据服务器的 CPU 能力和网络条件平衡压缩级别和最小压缩大小,以达到最佳的性能。
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types text/plain application/xml application/json application/javascript text/css;
各项配置的含义分别如下:
- gzip on;:启用 Gzip 压缩。当这个指令被设置为 on 时,Nginx 会尝试压缩响应体并发送给客户端。
- gzip_vary on;:这个指令告诉 Nginx 在响应头中添加Vary: Accept-Encoding。这允许缓存系统(如代理或 CDN)根据客户端是否支持压缩来存储不同的响应版本。
- gzip_proxied any;:这个指令允许 Nginx 对从任何代理服务器接收的响应进行压缩,无论响应是否已经被压缩。any 表示无论原始响应是否被压缩,Nginx 都会尝试再次压缩它。其他选项包括 off(不压缩任何代理的响应)和 expired(只压缩那些已经过期的代理响应)。
- gzip_comp_level 5;:这个指令设置 Gzip 压缩级别。压缩级别范围从 1(最快,压缩比最低)到 9(最慢,压缩比最高)。5 是一个在速度和压缩比之间取得平衡的常用值。
- gzip_min_length 256;:这个指令设置响应体的最小长度,只有当响应体大于或等于这个值时,Nginx 才会对其进行压缩。这里设置为 256 字节,意味着只有当响应体大于或等于 256 字节时,才会进行压缩。
- gzip_types text/plain application/xml application/json application/javascript text/css;:这个指令指定了哪些 MIME 类型的响应应该被压缩。在这个例子中,文本、XML、JSON、JavaScript 和 CSS 类型的响应将被压缩。
四 安全性优化
- 隐藏 Nginx 版本号信息,更改源码隐藏 Nginx 软件名及版本号。
- 修改 Nginx 服务的默认用户,提高安全性。
- 配置 OCSP stapling、ssl_stapling、ssl_stapling_verify 等以增强 SSL/TLS 的安全性。
隐藏版本信息可以提高服务器的安全性,使攻击者难以通过版本信息推断出服务器可能存在的安全漏洞。
要隐藏 Nginx 版本号,有三个办法,一般来说我们使用第一种方式就可以了。
修改配置文件
在 Nginx 的配置文件中,在 http 块中添加以下配置:
server_tokens off;
这样设置后,Nginx 将不会在错误页面上显示版本号。
配置完成之后,保存配置文件并重新加载 Nginx 以应用更改:
nginx -t # 测试配置文件是否正确
nginx -s reload # 重新加载Nginx配置
这种方法可以隐藏错误页面上的版本信息,但可能无法完全隐藏所有响应头中的版本信息 。
修改 Nginx 源码
如果想要从根源上修改 Nginx 版本信息,需要重新编译 Nginx,步骤如下:
- 修改 src/core/nginx.h 文件中的版本定义。
- 修改 src/http/ngx_http_header_filter_module.c 文件中的服务器字符串。
- 修改 src/http/ngx_http_special_response.c 文件中的错误页面底部信息。
修改完这些文件后,需要重新编译 Nginx。这样编译安装后,Nginx 的版本信息将被彻底修改 。
使用第三方模块
如果需要动态修改响应头中的版本信息,可以使用如 headers-more-nginx-module 模块。这个模块允许你动态地添加、修改或删除 Nginx 的响应头。通过这个模块,可以完全控制 Server 响应头的内容 。
选择哪种方法取决于你的具体需求和环境。
如果你只是想简单地隐藏版本信息,修改配置文件可能是最简单的方法。如果你需要更彻底地控制版本信息,可能需要考虑修改源码并重新编译 Nginx。
五 监控和日志优化
- 使用日志分析工具(如 ELK Stack、Graylog 等)来分析和可视化 Nginx 的日志数据。
- 定期维护策略,如更新 Nginx、审查配置文件、备份配置文件等。
- 使用定时任务工具(如 cron)定期清理缓存,使用 Nginx 的 proxy_cache_path 指令中的 inactive 参数设置缓存的过期时间。
日志配置如下:
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
六 系统层面优化
- 调整文件描述符限制(在 /etc/sysctl.conf 中设置):
fs.file-max = 65535
- 调整 TCP 连接队列大小(在 /etc/sysctl.conf 中设置):
net.core.somaxconn = 1024
七 故障转移优化
- 优化健康检查,调整健康检查的频率、超时时间、检查的内容等参数,以更准确地检测服务器的故障。
- 结合监控系统,实时监控服务器的健康状况、请求流量、响应时间等指标,及时发现潜在的问题,并进行预警和处理。
配置健康检查(使用第三方模块 nginx_upstream_check_module):
upstream backend {
server backend1.example.com check;
server backend2.example.com check;
}