RedCloud Help

nginx

nginx配置

Nginx的默认配置文为nginx.conf nginx -c xxx.config - 以指定的文件作为配置文件,启动Nginx

配置文件实例

#定义 nginx 运行的用户和用户组 user www www; #nginx 进程数,建议设置为等于 CPU 总核心数。 worker_processes 8; #nginx 默认没有开启利用多核 CPU, 通过增加 worker_cpu_affinity 配置参数来充分利用多核 CPU 以下是 8 核的配置参数 worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000; #全局错误日志定义类型,[ debug | info | notice | warn | error | crit ] error_log /var/log/nginx/error.log info; #进程文件 pid /var/run/nginx.pid; #一个 nginx 进程打开的最多文件描述符数目,理论值应该是最多打开文件数(系统的值 ulimit -n)与 nginx 进程数相除,但是 nginx 分配请求并不均匀,所以建议与 ulimit -n 的值保持一致。 worker_rlimit_nofile 65535; #工作模式与连接数上限 events { #参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll 模型是 Linux 2.6 以上版本内核中的高性能网络 I/O 模型,如果跑在 FreeBSD 上面,就用 kqueue 模型。 #epoll 是多路复用 IO(I/O Multiplexing) 中的一种方式,但是仅用于 linux2.6 以上内核,可以大大提高 nginx 的性能 use epoll; ############################################################################ #单个后台 worker process 进程的最大并发链接数 #事件模块指令,定义 nginx 每个进程最大连接数,默认 1024。最大客户连接数由 worker_processes 和 worker_connections 决定 #即 max_client=worker_processes*worker_connections, 在作为反向代理时:max_client=worker_processes*worker_connections / 4 worker_connections 65535; ############################################################################ } #设定 http 服务器 http { include mime.types; #文件扩展名与文件类型映射表 default_type application/octet-stream; #默认文件类型 #charset utf-8; #默认编码 server_names_hash_bucket_size 128; #服务器名字的 hash 表大小 client_header_buffer_size 32k; #上传文件大小限制 large_client_header_buffers 4 64k; #设定请求缓 client_max_body_size 8m; #设定请求缓 sendfile on; #开启高效文件传输模式,sendfile 指令指定 nginx 是否调用 sendfile 函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘 IO 重负载应用,可设置为 off,以平衡磁盘与网络 I/O 处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成 off。 autoindex on; #开启目录列表访问,合适下载服务器,默认关闭。 tcp_nopush on; #防止网络阻塞 tcp_nodelay on; #防止网络阻塞 ##连接客户端超时时间各种参数设置## keepalive_timeout 120; #单位是秒,客户端连接时时间,超时之后服务器端自动关闭该连接 如果 nginx 守护进程在这个等待的时间里,一直没有收到浏览发过来 http 请求,则关闭这个 http 连接 client_header_timeout 10; #客户端请求头的超时时间 client_body_timeout 10; #客户端请求主体超时时间 reset_timedout_connection on; #告诉 nginx 关闭不响应的客户端连接。这将会释放那个客户端所占有的内存空间 send_timeout 10; #客户端响应超时时间,在两次客户端读取操作之间。如果在这段时间内,客户端没有读取任何数据,nginx 就会关闭连接 ################################ #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; ###作为代理缓存服务器设置####### ###先写到 temp 再移动到 cache #proxy_cache_path /var/tmp/nginx/proxy_cache levels=1:2 keys_zone=cache_one:512m inactive=10m max_size=64m; ###以上 proxy_temp 和 proxy_cache 需要在同一个分区中 ###levels=1:2 表示缓存级别,表示缓存目录的第一级目录是 1 个字符,第二级目录是 2 个字符 keys_zone=cache_one:128m 缓存空间起名为 cache_one 大小为 512m ###max_size=64m 表示单个文件超过 128m 就不缓存了 inactive=10m 表示缓存的数据,10 分钟内没有被访问过就删除 #########end#################### #####对传输文件压缩########### #gzip 模块设置 gzip on; #开启 gzip 压缩输出 gzip_min_length 1k; #最小压缩文件大小 gzip_buffers 4 16k; #压缩缓冲区 gzip_http_version 1.0; #压缩版本(默认 1.1,前端如果是 squid2.5 请使用 1.0) gzip_comp_level 2; #压缩等级,gzip 压缩比,1 为最小,处理最快;9 为压缩比最大,处理最慢,传输速度最快,也最消耗 CPU; gzip_types text/plain application/x-javascript text/css application/xml; #压缩类型,默认就已经包含 text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个 warn。 gzip_vary on; ############################## #limit_zone crawler $binary_remote_addr 10m; #开启限制 IP 连接数的时候需要使用 upstream blog.ha97.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; } #虚拟主机的配置 server { #监听端口 listen 80; #############https################## #listen 443 ssl; #ssl_certificate /opt/https/xxxxxx.crt; #ssl_certificate_key /opt/https/xxxxxx.key; #ssl_protocols SSLv3 TLSv1; #ssl_ciphers HIGH:!ADH:!EXPORT57:RC4+RSA:+MEDIUM; #ssl_prefer_server_ciphers on; #ssl_session_cache shared:SSL:2m; #ssl_session_timeout 5m; ####################################end #域名可以有多个,用空格隔开 server_name www.ha97.com ha97.com; index index.html index.htm index.php; root /data/www/ha97; 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; } #日志格式设定 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 /var/log/nginx/ha97access.log access; #对 "/" 启用反向代理 location / { proxy_pass http://127.0.0.1:88; 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; #允许客户端请求的最大单文件字节数 client_body_buffer_size 128k; #缓冲区代理缓冲用户端请求的最大字节数, ##代理设置 以下设置是 nginx 和后端服务器之间通讯的设置## proxy_connect_timeout 90; #nginx 跟后端服务器连接超时时间(代理连接超时) proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时) proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时) proxy_buffering on; #该指令开启从后端被代理服务器的响应内容缓冲 此参数开启后 proxy_buffers 和 proxy_busy_buffers_size 参数才会起作用 proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小 proxy_buffers 4 32k; #proxy_buffers 缓冲区,网页平均在 32k 以下的设置 proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2) proxy_max_temp_file_size 2048m; #默认 1024m, 该指令用于设置当网页内容大于 proxy_buffers 时,临时文件大小的最大值。如果文件大于这个值,它将从 upstream 服务器同步地传递请求,而不是缓冲到磁盘 proxy_temp_file_write_size 512k; 这是当被代理服务器的响应过大时 nginx 一次性写入临时文件的数据量。 proxy_temp_path /var/tmp/nginx/proxy_temp; ##定义缓冲存储目录,之前必须要先手动创建此目录 proxy_headers_hash_max_size 51200; proxy_headers_hash_bucket_size 6400; ####################################################### } #设定查看 nginx 状态的地址 location /nginxStatus { stub_status on; access_log on; auth_basic "nginxStatus"; auth_basic_user_file conf/htpasswd; #htpasswd 文件的内容可以用 apache 提供的 htpasswd 工具来产生。 } #本地动静分离反向代理配置 #所有 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; } #所有静态文件由 nginx 直接读取不经过 tomcat 或 resin location ~ .*.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$ { expires 15d; } location ~ .*.(js|css)?$ { expires 1h; } } }

基本规则

管理nginx配置

随着Nginx配置增长,你又必要组织、管理配置内容 当你的Nginx配置增加时,组织配置的需求也要增加。井井有条的代码是:

  • 易于理解

  • 易于维护

  • 易于使用

使用include指令可将常用服务器配置移动到单独的文件中,并将特定代码附加到全局陪吹,上下文中。 我总是尝试在配置树的根目录中保留多个目录。这些目录存储所有附加到主文件的配置文件。我更喜欢一下结构

  • html - 用于默认静态文件,例如全局5xx错误页面

  • master -用于主要配置,例如acl,监听指令和域

    • _acls -用于访问控制列表,例如地理或地图模块

    • _basic -用于速率限制规则,重定向映射或代理参数

    • _listen -用于所有监听指令;还存储ssl配置。

    • _server - 用于域(localhost)配置;还存储所有后端定义

  • modules - 用于动态加载Nginx中的模块

  • snippets -用于nginx别名,配置模块。

如果有必要,我会将其中一些附加到具体server指令的文件中。

## Store this configuration in https.conf for example: listen 10.240.20.2:443 ssl; ssl_certificate /etc/nginx/master/_server/example.com/certs/nginx_example.com_bundle.crt; ssl_certificate_key /etc/nginx/master/_server/example.com/certs/example.com.key; ## Include this file to the server section: server { include /etc/nginx/master/_listen/10.240.20.2/https.conf; ## And other: include /etc/nginx/master/_static/errors.conf; include /etc/nginx/master/_server/_helpers/global.conf; ... server_name domain.com www.domain.com; ...

重加载nginx配置

## 1) systemctl reload nginx ## 2) service nginx reload ## 3) /etc/init.d/nginx reload ## 4) /usr/sbin/nginx -s reload ## 5) kill -HUP $(cat /var/run/nginx.pid) ## or kill -HUP $(pgrep -f "nginx: master") ## 6) /usr/sbin/nginx -g 'daemon on; master_process on;' -s reload

监听80和443端口

如果你使用完全相同的配置http和https提供服务(单个服务器同同时处理http和https请求),nginx足够智能,可能忽略通过端口80加载的SSL指令。 Nginx 的最佳时间是使用单独的服务器进行这样的重定向(不与你的主要配置的服务器共享),对所有内容进行硬编码,并且完全不适用正则表达式。 我不喜欢复制规则,但是单独的监听指令无疑可以帮助你维护和修改配置。 如果将多个域固定到一个ip地址,则很有用。这使你可以将一个监听指令(例如,如果将其保留在配置文件中)附加到多个域配置。 如果你使用的是https,则可能还需要对域进行硬编码,因为你必须预先知道要提供的证书。

## For HTTP: server { listen 10.240.20.2:80; ... } ## For HTTPS: server { listen 10.240.20.2:443 ssl; ... }

显示指定监听的地址和端口

Nginx的listen指令用于监听指定的ip地址和端口号,配置形式为:listen : 。若ip地址或端口缺失,Nginx会以默认值来替换。 而且,仅当需要区分域listen指令中的同一级别匹配的服务器块时,才会评估server_name指令。 实例:

server { ## This block will be processed: listen 192.168.252.10; ## --> 192.168.252.10:80 ... } server { listen 80; ## --> *:80 --> 0.0.0.0:80 server_name api.random.com; ... }

防止使用未定义的服务器名称处理请求

Nginx应该组织使用未定义的服务器名称(也使用ip地址)处理请求。它可以防止配置错误,例如流量转发不到不正确的后端。通过创建默认虚拟虚拟主机可以轻松解决该问题,该虚拟主机可以捕获带有无法识别的主机标头的所有请求。 如果没有一个listen指令具有default_server参数,则具有address:port对的第一台服务器将是该对的默认服务器(这意味着Nginx始终具有默认服务器)。 如果有人使用IP地址而不是服务器名称发出请求,则主机请求标头字段将包含IP地址,并且可以使用IP地址作为服务器名称来处理请求。 在现代版本的Nginx中,不需要服务器名称。如果找不到具有匹配的listen和server_name的服务器,Nginx将使用默认服务器。如果你的配置分散在多个文件中,则评估顺序将不明确,因此你需要显式标记默认服务器。 Nginx使用Host标头进行server_name匹配。它不适用TLSSNI。这意味着对于SSL服务器,Nginx必须能够接受SSL链接,这归结为具有证书/秘钥。证书/密钥而昆虫是任意值,例如自签名。 示例:

## Place it at the beginning of the configuration file to prevent mistakes: server { ## For ssl option remember about SSL parameters (private key, certs, cipher suites, etc.); ## add default_server to your listen directive in the server that you want to act as the default: listen 10.240.20.2:443 default_server ssl; ## We catch: ## - invalid domain names ## - requests without the "Host" header ## - and all others (also due to the above setting) ## - default_server in server_name directive is not required - I add this for a better understanding and I think it's an unwritten standard ## ...but you should know that it's irrelevant, really, you can put in everything there. server_name _ "" default_server; ... return 444; ## We can also serve: ## location / { ## static file (error page): ## root /etc/nginx/error-pages/404; ## or redirect: ## return 301 https://badssl.com; ## return 444; ## } } server { listen 10.240.20.2:443 ssl; server_name domain.com; ... } server { listen 10.240.20.2:443 ssl; server_name domain.org; ... }

不要在 listen 或 upstream 中使用 hostname

通常,在 listen 或上游指令中使用主机名是一种不好的做法。

在最坏的情况下,Nginx 将无法绑定到所需的 TCP 套接字,这将完全阻止 Nginx 启动。

最好和更安全的方法是知道需要绑定的 IP 地址,并使用该地址代替主机名。 这也可以防止 Nginx 查找地址并消除对外部和内部解析器的依赖。

在 server_name 指令中使用$ hostname(计算机的主机名)变量也是不当行为的示例(类似于使用主机名标签)。

我认为也有必要设置 IP 地址和端口号对,以防止可能难以调试的软错误。 示例: 错误配置:

upstream { server http://x-9s-web01-prod:8080; } server { listen rev-proxy-prod:80; ... }

正确配置:

upstream { server http://192.168.252.200:8080; } server { listen 10.10.100.20:80; ... }

指令中只配置一个 SSL

此规则使调试和维护更加容易。

请记住,无论 SSL 参数如何,您都可以在同一监听指令(IP 地址)上使用多个 SSL 证书。

我认为要在多个 HTTPS 服务器之间共享一个 IP 地址,您应该使用一个 SSL 配置(例如协议,密码,曲线)。这是为了防止错误和配置不匹配。

还请记住有关默认服务器的配置。这很重要,因为如果所有 listen 指令都没有 default_server 参数,则配置中的第一台服务器将是默认服务器。因此,您应该只使用一个 SSL 设置,并且在同一 IP 地址上使用多个名称。

从 Nginx 文档中:

这是由 SSL 协议行为引起的。在浏览器发送 HTTP 请求之前,已建立 SSL 连接,nginx 不知道所请求服务器的名称。因此,它可能仅提供默认服务器的证书。

还要看看这个:

TLS 服务器名称指示扩展名(SNI,RFC 6066)是在单个 IP 地址上运行多个 HTTPS 服务器的更通用的解决方案,它允许浏览器在 SSL 握手期间传递请求的服务器名称,因此,服务器将知道哪个用于连接的证书。

另一个好主意是将常用服务器设置移到单独的文件(即 common / example.com.conf)中,然后将其包含在单独的服务器块中。

示例:

## Store this configuration in e.g. https.conf: listen 192.168.252.10:443 default_server ssl http2; ssl_protocols TLSv1.2; ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384"; ssl_prefer_server_ciphers on; ssl_ecdh_curve secp521r1:secp384r1; ... ## Include this file to the server context (attach domain-a.com for specific listen directive): server { include /etc/nginx/https.conf; server_name domain-a.com; ssl_certificate domain-a.com.crt; ssl_certificate_key domain-a.com.key; ... } ## Include this file to the server context (attach domain-b.com for specific listen directive): server { include /etc/nginx/https.conf; server_name domain-b.com; ssl_certificate domain-b.com.crt; ssl_certificate_key domain-b.com.key; ... }

使用 geo/map 模块替代 allow/deny

使用地图或地理模块(其中之一)可以防止用户滥用您的服务器。这样就可以创建变量,其值取决于客户端 IP 地址。

由于仅在使用变量时才对其进行求值,因此甚至仅存在大量已声明的变量。地理位置变量不会为请求处理带来任何额外费用。

这些指令提供了阻止无效访问者的完美方法,例如使用 ngx_http_geoip_module。例如,geo 模块非常适合有条件地允许或拒绝 IP。

geo 模块(注意:不要将此模块误认为是 GeoIP)在加载配置时会构建内存基数树。这与路由中使用的数据结构相同,并且查找速度非常快。如果每个网络有许多唯一值,那么较长的加载时间是由在数组中搜索数据重复项引起的。否则,可能是由于插入基数树引起的。

我将两个模块都用于大型列表。您应该考虑一下,因为此规则要求使用多个 if 条件。我认为,对于简单的列表,毕竟允许/拒绝指令是更好的解决方案。看下面的例子:

## Allow/deny: location /internal { include acls/internal.conf; allow 192.168.240.0/24; deny all; ... ## vs geo/map: location /internal { if ($globals_internal_map_acl) { set $pass 1; } if ($pass = 1) { proxy_pass http://localhost:80; } if ($pass != 1) { return 403; } ... }

示例:

## Map module: map $remote_addr $globals_internal_map_acl { ## Status code: ## - 0 = false ## - 1 = true default 0; ### INTERNAL ### 10.255.10.0/24 1; 10.255.20.0/24 1; 10.255.30.0/24 1; 192.168.0.0/16 1; } ## Geo module: geo $globals_internal_geo_acl { ## Status code: ## - 0 = false ## - 1 = true default 0; ### INTERNAL ### 10.255.10.0/24 1; 10.255.20.0/24 1; 10.255.30.0/24 1; 192.168.0.0/16 1; }

Map所有事物

使用地图管理大量重定向,并使用他们来自定义建/值对。 map指令可映射字符串,因此可以表示例如192.168.144.0/24作为正则表达式,并继续使用map指令。 Map模块提供了一种更优雅的解决方案,使用清晰解析大量正则表达式,例如 用户代理,引荐来源。 你还可以对地图使用includ指令,这样配置文件看起来很漂亮。 实例:

map $http_user_agent $device_redirect{ default "desktop"; ~(?i)ip(hone|od) "mobile"; ~(?i)android.*(mobile|mini) "mobile"; ~Mobile.+Firefox "mobile"; ~^HTC "mobile"; ~Fennec "mobile"; ~IEMobile "mobile"; ~BB10 "mobile"; ~SymbianOS.*AppleWebKit "mobile"; ~Opera\sMobi "mobile"; } ## Turn on in a specific context (e.g. location): if ($device_redirect = "mobile") { return 301 https://m.domain.com$request_uri; }

为所有未配置的路径设置根路径

为请求设计服务器指令内部的全局根路径。它为未定义的位置指定根路径。 根据官方文档: 如果你在每个位置块中添加一个根路径,则不匹配的位置块将没有根路径。因此,重要的是,根指令必须在你的位置块之前发生,然后根目录指令可以在需要时覆盖该指令。 示例:

server { server_name domain.com; root /var/www/domain.com/public; location / { ... } location /api { ... } location /static { root /var/www/domain.com/static; ... } }

使用return指令进行URL重定向(301/302)

这是一个简单的规则。你应该使用服务器块和return语句,因为它们比评估RegEx更快。因为Nginx停止处理请求(而不必处理正则表达式),所以它更加简单快捷。 示例:

server { server_name www.example.com; ## return 301 https://$host$request_uri; return 301 $scheme://www.example.com$request_uri; }

配置日志轮换策略

日志文件为你提供有关服务器活动和性能一级可能出现得任何问题的反馈。他们记录了有关请求和Nginx内部的详细信息。不幸的是,日志使用了更多的磁盘空间。 你应该定义一个过程,该过程将定期存档当前日志文件并启动一个新日志文件,重命名并有选择地压缩当前日志文件,删除旧日志文件,并强制日志记录系统开始使用新日志文件。 我认为最好的工具是logrotate。如果我想自动管理日志,也想睡个好觉,那么我会在任何地方使用它。那么我会在任何地方使用它。这是一个旋转日志的简单程序,使用corontab可以工作。它是计划的工作,而不是守护程序,因为无需重新加载其配置。 示例:

  • 手动旋转

## Check manually (all log files): logrotate -dv /etc/logrotate.conf ## Check manually with force rotation (specific log file): logrotate -dv --force /etc/logrotate.d/nginx
  • 自动旋转

cat > /etc/logrotate.d/nginx << __EOF__ /var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 nginx nginx sharedscripts prerotate if [ -d /etc/logrotate.d/httpd-prerotate ]; then \ run-parts /etc/logrotate.d/httpd-prerotate; \ fi \ endscript postrotate ## test ! -f /var/run/nginx.pid || kill -USR1 `cat /var/run/nginx.pid` invoke-rc.d nginx reload >/dev/null 2>&1 endscript } /var/log/nginx/localhost/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 nginx nginx sharedscripts prerotate if [ -d /etc/logrotate.d/httpd-prerotate ]; then \ run-parts /etc/logrotate.d/httpd-prerotate; \ fi \ endscript postrotate ## test ! -f /var/run/nginx.pid || kill -USR1 `cat /var/run/nginx.pid` invoke-rc.d nginx reload >/dev/null 2>&1 endscript } /var/log/nginx/domains/example.com/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 nginx nginx sharedscripts prerotate if [ -d /etc/logrotate.d/httpd-prerotate ]; then \ run-parts /etc/logrotate.d/httpd-prerotate; \ fi \ endscript postrotate ## test ! -f /var/run/nginx.pid || kill -USR1 `cat /var/run/nginx.pid` invoke-rc.d nginx reload >/dev/null 2>&1 endscript } __EOF__

不要重复所有指令,只能在http块中使用

一次使用index指令。它只需要在你的http上下文中发生,并将在下面继承。 我认为我们在赋值相同规则时应格外小心。但是,当前,规则的重复有时是可以的,或者不一定是大麻烦。 示例: 错误配置

http { ... index index.php index.htm index.html; server { server_name www.example.com; location / { index index.php index.html index.$geo.html; ... } } server { server_name www.example.com; location / { index index.php index.htm index.html; ... } location /data { index index.php; ... } ... }

正确的配置:

http { ... index index.php index.htm index.html index.$geo.html; server { server_name www.example.com; location / { ... } } server { server_name www.example.com; location / { ... } location /data { ... } ... }

Debugging

使用自定义日志格式

你可以在Nginx配置中作为变量访问的任何内容都可以记录,包括非标准的HTTP标头等。因此,这是一种针对特定情况创建自己的日志格式的简单办法。 这对于调试特定的location指令非常有帮助。 示例:

## Default main log format from the Nginx repository: log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; ## Extended main log format: log_format main-level-0 '$remote_addr - $remote_user [$time_local] ' '"$request_method $scheme://$host$request_uri ' '$server_protocol" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time'; ## Debug log formats: log_format debug-level-0 '$remote_addr - $remote_user [$time_local] ' '"$request_method $scheme://$host$request_uri ' '$server_protocol" $status $body_bytes_sent ' '$request_id $pid $msec $request_time ' '$upstream_connect_time $upstream_header_time ' '$upstream_response_time "$request_filename" ' '$request_completion';

使用调试模式来追踪以外行为

通常,error_log指令是在main中指定的,但是也可以在server或location块中指定,全局设置将被覆盖,并且这个error_log指令将设置其自己的日志文件和日志记录级别。 如果要记录ngx_http_rewite_module(at the notice level),应该在http、server或location块中开启rewrite_log on; 注意:

  • 永远不要将调试日志记录留在生产环境的文件中

  • 不要忘记在流量非常高的站点上回复error_log的调试级别

  • 必须使用日志回滚则略。

示例

  • 将debug信息写入文件

## Turn on in a specific context, e.g.: ## - global - for global logging ## - http - for http and all locations logging ## - location - for specific location error_log /var/log/nginx/error-debug.log debug;
  • 将debug信息写入内存

error_log memory:32m debug;
  • IP地址/范围的调试日志:

events{ debug_connection 192.168.252.15/32; debug_connection 10.10.10.0/24; }
  • 为不同服务器设置不同Debug配置

error_log /var/log/nginx/debug.log debug; ... http { server { ## To enable debugging: error_log /var/log/nginx/domain.com/domain.com-debug.log debug; ## To disable debugging: error_log /var/log/nginx/domain.com/domain.com-debug.log; ... } }

核心转储

核心转储基本上是程序崩溃时内存的快照。 Nginx是一个非常文档的守护程序,但是有时可能会发生正在运行的Nginx进程独特终止的情况 如果要保存内存存储,它可以确保应启用两个重要的指令,但是,为了正确处理内存转储,需要做一些事情。有关它的完整信息,请参阅转储进程的内存(来自本手册)。 当你的Nginx实例收到以外错误或崩溃,应始终启用核心转储。 实例:

worker_rlimit_core 500m; worker_rlimit_nofile 65535; working_directory /var/dump/nginx;

性能

工作进程数

work_processes -用于设置Nginx的工作进程。

  • work_processes的默认值为1.

  • 设置worker_processes的安全做法是将其设为auto,则启动Nginx时会自动分配工作进程数。当然,也可以显示的设置一个工作进程数值。

一般一个进程足够了,你可以把连接数设的很大。(worker_processes:1,work_connections:10000)如果有SSL、gzip这些比较消耗CPU的工作,而且是多核CPU的话,可以设为和CPU的数量一样。或者要处理很多很多的小文件,而且文件总大小比内存大很多的时候,也可以吧进程数增加,以充分利用Io带宽(主要似乎是IO操作有block)。

实例:

## the safest way: worker_processes auto; ## VCPU = 4,expr $(nproc --all) -1 worker_processes 3;

最大连接数

worker_connections - 单个Nginx工作进程允许同时建立的外部链接的数量。数字越大,能同时处理的连接越多。 worker_connections不是随便设置的,而是与两个指标有重要关联:

  • 内存

    每个连接数分别对应一个read_event、一个write_event事件,一个连接数大概占用232字节,2个事件总占用96字节,那么一个链接总共占用328字节,通过数学公式可以算出100000个连接数大概占用31M=100000* 328/1024/1024,当然这只是nginx启动时,worker_connections连接数所占用的nginx。

  • 操作系统级别“进程最大可打开文件数”

    • 进程最大可打开文件受限于操作系统,可通过ulimit -n命令查询,以前是1024,现在是65535.

    nginx提供了worker_rlimit_nofile指令,这是出了ulimit的一种设置可用的描述符的方式。该指令与使用ulimit对用户的设置是同样的效果。此指令的值将覆盖ulimit的值,如worker_rlimit_nofile 20960;设置ulimits:ulimit -SHn 65535

使用HTTP/2

HTTP/2将使我们的应用程序更快,更简单且可靠。HTTP/2的主要目标是通过启用完整的请求和响应多路复用来减少延迟,通过有效压缩HTTP标头字段来最小化协议开销,并增加对请求优先级和服务器推送的支持。 HTTP/2与HTTP/1.1向后兼容,因此有可能完全忽略它,并且一些都会像以前一样继续工作,因为如果不支持HTTP/2的客户端永远不会像服务器请求HTTP/2通讯升级:他们之间的通讯将完全是HTTP/1. 请注意,http/2在单个TCP连接中多路复用许多请求。通常,当使用HTTP/2时,将与服务器建立单个TCP链接。 你还应该包括ssl参数,这是必须得,因为浏览器不支持未经加密的HTTP/2. HTTP/2对旧和不安全的密码有一个非常大的黑名单,因此你应该避免使用他们。 实例:

server{ listen 10.240.20.2:443 ssl http2; ... }

维护SSL会话

客户端每次发出请求是都进行新的SSL握手的需求。默认情况下,内置会话缓存并不是最佳选择,因为它只能由一个工作进程使用,并且可能导致内存碎片,最好是共享缓存。 使用ssl_session_cache时,通过ssl保持链接的性能可能会大大提高。10M的值是一个很好的起点(1MB共享缓存可以容纳大约4000个会话)。通过共享,所有工作进程之间共享一个缓存(可能在多个虚拟服务器中使用相同名称的缓存)。 但是,大多数服务器不清除会员或票证秘钥,因此增加了服务器受到损害将泄露先前(和将来)连接中的数据的风险。 示例:

ssl_session_cache shared:NGX_SSL_CACHE:10m; ssl_session_timeout 12h; ssl_session_tickets off; ssl_buffer_size 1400;

尽可能在server_name指令中使用明确名称

确切名称,以星号开头的通配符名称和以星号结尾的通配符名称存储在绑定到监听端口的三个哈希表中,首先搜索确切名称哈希表。如果未找到名称,则搜索具有以星号开头的通配符的哈希表。如果未在此处找到名称,则搜索带有通配符名称以星号结尾的哈希表。搜索通配符名称哈希表比搜索精确名称哈希表要慢,因为名称是按域部分搜索的。 正则表达式是按顺序测试的,因此是最慢的方法,并且不可缩放。由于这些原因,最好在可能的地方使用确切的名称。 示例:

## It is more efficient to define them explicitly; server{ listen 192.168.252.10:80; server_name example.org www.example.org *.example.org; ... } ## than to use the simplified form: server { listen 192.168.252.10:80; server_name .example.org; ... }

避免使用if检查serve_name

当Nginx受到请求时,无论请求的是那个子域,无论是www.example.com还是普通的example.com,如果始终对if指令进行评估。由于你是在nginx检查每个请求的Host标头。效率极低。 而是使用两个服务器指令,如下面的示例。这种方法降低了Nginx的处理要求。 示例: 错误配置

server{ server_name domain.com www.domain.com; if($host = www.domain.com){ return 301 https://domain.com$request_uri; } server_name domain.com ... }

正确的配置:

server{ server_name www.domain.com; return 301 $scheme://domain.com$request_uri; ## if you force your web traffic to use https: ## 301 https://domain.com$request_uri; } server{ listen 192.168.252.10:80; server_name domain.com; ... }

使用$request_uri来避免使用正则表达式

使用内置变量$request_uri,我们可以完全避免进行任何捕获或匹配。默认情况下,正则表达式的代价较高,并且会降低性能。 此规则用于解决将URL不变地传递到新主机,确保仅通过现有URI进行返回的效率更高。 示例: 错误示例:

## 1) rewrite ^/(.*)$ https://example.com/$1 permanent; ## 2) rewrite ^ https://example.com$request_uri?permanent;

正确配置:

return 301 https://example.com$request_uri;

使用try_files指令确认文件是否存在

try_files绝对是一个非常有用的东西。你可以使用try_files指令检查一个文件是否按指定顺序存在。 你应该使用try_files而不是if指令。对于这个操作,它肯定是比使用if更好的方法,因为if指令非常低效,因为它在每次请求时都会执行。 使用try_files的好处是,一个命令可以立即切换行为。我认为代码也更具有可读性。 try_files允许你;

  • 从预定义的列表中检查文件是否存在

  • 检查指定目录下的文件是否存在

  • 如果找不到任何文件,则使用内部重定向。

示例 错误配置:

... root /var/www/example.com; location /images { if (-f $request_filename) { expires 30d; break; } ... }

正确配置:

... root /var/www/example.com; location /images { try_files $uri =404; ... }

使用return代替rewrite来做重定向

你应该使用服务器块和return语句,因为他们比通过位置块评估RegEx更简单,更快捷。该指令停止处理,并将指定的代码返回给客户端。 示例: 错误配置:

server { ... if ($host = api.domain.com) { rewrite ^/(.*)$ http://example.com/$1 permanent; } ...

正确配置:

server { ... if ($host = api.domain.com) { return 403; ## or other examples: ## return 301 https://domain.com$request_uri; ## return 301 $scheme://$host$request_uri; } ...

开启PCRE JIT来加速正则表达式处理

允许使用JIT的正则表达式来加速他们的处理 通过PCRE库编译Nginx的,你可以用你的location块进行复杂的操作和使用功能强大的return和rewrite。 PCRE JIT可以显著加快正则表达式的处理。Nginx的与pcre_jit比没有更快的幅度。 如果你试图在使用pcre_jit;没有可用的JIT,或者Nginx的与现有JIT,单当前加载PCRE库编译不支持JIT,将配置解析式发出警告。 当你编译使用nginx配置pcre库时,才需要--with-PCRE-JIT时(./configure --with-PCRE=)。当使用系统PCRE库JIT是否被支持依赖于库是如何被编译。 从nginx的文档: JIT正在从与--enable-JIT配置参数内置8.20版本开始PCRE库提供。当PCRE库与nginx的内置(with-PCRE=)时,JIT支持经由--with-PCRE-JIT配置参数使能。 示例:

## in global context: pcre_jit on;

进行精确的位置匹配以加快选择过程

精确的位置匹配通常用于通过立即结束算法的执行来加快选择过程。 示例:

## Matches the query / only and stops searching: location = / { ... } ## Matches the query /v9 only and stops searching: location = /v9 { ... } ... ## Matches any query due to the fact that all queries begin at /, ## but regular expressions and any longer conventional blocks will be matched at first place: location / { ... }

使用limit_conn改善对下载速度的限制

Nginx提供了两个指令来限制下载速度

  • limit_rate_after 设置limit_rate指令生效之前传输的数据量

  • limit_rate 允许你限制单个客户端链接的传输速率。

此解决方案限制了每个链接的nginx下载速度,因此,如果一个用户打开多个(例如)视频文件,则可以下载X*链接到视频文件的次数。 示例:

## Create limit connection zone: limit_conn_zone $binary_remote_addr zone=conn_for_remote_addr:1m; ## Add rules to limiting the download speed: limit_rate_after 1m; ## run at maximum speed for the first 1 megabyte limit_rate 250k; ## and set rate limit after 1 megabyte ## Enable queue: location /videos { ## Max amount of data by one client: 10 megabytes (limit_rate_after * 10) limit_conn conn_for_remote_addr 10; ...
13 February 2026