nginx

nginx 是什么?

nginx 是俄罗斯人 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的一个十分轻量级的 HTTP 服务器。它是一个高性能的 HTTP 和反向代理服务器,同时也可以作为 IMAP/POP3/SMTP 的代理服务器。nginx 使用的是 BSD 许可。

Nginx 以事件驱动的方式编写,所以有非常好的性能,同时也是一个非常高效的反向代理、负载平衡。

Nginx 因为它的稳定性、丰富的模块库、灵活的配置和低系统资源的消耗而闻名。

nginx 适合用来做 mongrel clusters 的前端 HTTP 响应。

为什么要用 nginx,nginx 有什么特点?

nginx 的特点

  • 核心特点:高并发请求的同时保持高效的服务
  • 热部署
  • 低内存消耗
  • 处理响应请求很快
  • 具有很高的可靠性

同时,nginx 也可以实现高效的反向代理、负载均衡。

前端可以用 nginx 做些什么?

  • 搭建静态资源服务器
  • 反向代理分发后端服务(可以和 nodejs 搭配实现前后端分离)和跨域问题
  • 根据 User Agent 来重定向站点
  • 开发环境或测试环境切换(切换 host)
  • url 重写,使用 rewrie 规则本地映射
  • 资源内容篡改
  • 获取 cookie 做分流
  • 资源合并
  • gzip 压缩
  • 压缩图片
  • sourceMap 调试

如何安装 nginx?

mac 安装

安装brew之后,执行命令:

1
$ sudo brew install nginx

windows 安装

下载: nginx 官网

  1. 解压运行:解压至c:\nginx,运行nginx.exe(即nginx -c conf\nginx.conf),默认使用 80 端口,日志见文件夹C:\nginx\logs
  2. 关闭:nginx -s stoptaskkill /F /IM nginx.exe > nul

【注意】以下皆以 mac 为例。

nginx 如何启动、重启、关闭?

查看 nginx 版本

nginx -v

启动 nginx 服务

  • 方法一:运行命令:sudo brew services start nginx
  • 方法二:运行命令:nginx

访问http://localhost:8080
出现如下界面则表示安装成功:

关闭 nginx 服务

  • 方法一:运行命令:sudo brew services stop nginx
  • 方法二:运行命令: nginx -s stop
  • 方法三:
    运行命令:ps -ef | grep nginx,找到 master 对应的进程号。
    快速停止:kill -TERM nginx进程号kill -INT nginx进程号
    从容停止: kill -QUIT nginx进程号
    强制停止所有 nginx 进程:pkill -9 nginx

重启 nginx 服务

方法一:nginx -s reload
方法二: 平滑重启命令: kill -HUP nginx进程号

nginx 信号控制

  • TERM,INT 快速关闭
  • QUIT 从容关闭
  • HUP 平滑重启,重新加载配置文件
  • USR1 重新打开日志文件,在切割日志时用途较大
  • USR2 平滑升级可执行程序
  • WINCH 从容关闭工作进程

如何查看 nginx 的配置文件 nginx.conf 的路径和安装路径?

查看配置文件位置和测试配置文件语法,运行命令nginx -t:

查看 nginx 安装路径:
因为是使用 brew 安装的,所以使用 brew 命令:brew info nginx:

nginx.conf 基本配置有哪些?

nginx 配置文件主要分成四个部分:

  • main,全局设置,影响其它部分所有设置
  • server,主机服务相关设置,主要用于指定虚拟主机域名、IP 和端口
  • location,URL 匹配特定位置后的设置,反向代理、内容篡改相关设置
  • upstream,上游服务器设置,负载均衡相关配置

他们之间的关系式:server 继承 main,location 继承 server;upstream 既不会继承指令也不会被继承。

如下是一份通用的配置和详解:

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
#定义 Nginx 运行的用户和用户组,默认由 nobody 账号运行, windows 下面可以注释掉。
user nobody;

#nginx进程数,建议设置为等于CPU总核心数。可以和worker_cpu_affinity配合
worker_processes 1;

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

#进程文件,window下可以注释掉
#pid logs/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模型。
#use epoll;
#connections 20000; # 每个进程允许的最多连接数
# 单个进程最大连接数(最大连接数=连接数*进程数)该值受系统进程最大打开文件数限制,需要使用命令ulimit -n 查看当前设置
worker_connections 65535;
}

#设定http服务器
http {
#文件扩展名与文件类型映射表
#include 是个主模块指令,可以将配置文件拆分并引用,可以减少主配置文件的复杂度
include mime.types;
#默认文件类型
default_type application/octet-stream;
#charset utf-8; #默认编码

#定义虚拟主机日志的格式
# 日志格式设置:
# $remote_addr与$http_x_forwarded_for用以记录客户端的ip地址;
# $remote_user:用来记录客户端用户名称;
# $time_local: 用来记录访问时间与时区;
# $request: 用来记录请求的url与http协议;
# $status: 用来记录请求状态;成功是200,
# $body_bytes_sent :记录发送给客户端文件主体内容大小;
# $http_referer:用来记录从那个页面链接访问过来的;
# $http_user_agent:记录客户浏览器的相关信息;
#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指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
sendfile on;
#autoindex on; #开启目录列表访问,合适下载服务器,默认关闭。

#防止网络阻塞
#tcp_nopush on;

#长连接超时时间,单位是秒,默认为0
keepalive_timeout 65;

# 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 6; #压缩等级
#压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn。
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
gzip_vary on; //和http头有关系,加个vary头,给代理服务器用的,有的浏览器支持压缩,有的不支持,所以避免浪费不支持的也压缩,所以根据客户端的HTTP头来判断,是否需要压缩
#limit_zone crawler $binary_remote_addr 10m; #开启限制IP连接数的时候需要使用

# http_proxy服务全局设置
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 75;
proxy_send_timeout 75;
proxy_read_timeout 75;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_temp_path /usr/local/nginx/proxy_temp 1 2;

# 设定负载均衡后台服务器列表
upstream backend.com {
#ip_hash; # 指定支持的调度算法
# upstream 的负载均衡,weight 是权重,可以根据机器配置定义权重。weigth 参数表示权值,权值越高被分配到的几率越大。
server 192.168.10.100:8080 max_fails=2 fail_timeout=30s ;
server 192.168.10.101:8080 max_fails=2 fail_timeout=30s ;
}

#虚拟主机的配置
server {
#监听端口
listen 80;
#域名可以有多个,用空格隔开
server_name localhost fontend.com;
# Server Side Include,通常称为服务器端嵌入
#ssi on;
#默认编码
#charset utf-8;
#定义本虚拟主机的访问日志
#access_log logs/host.access.log main;

# 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
location / {
root html;
index index.html index.htm;
}

#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}

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

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

#代理配置
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#location /proxy/ {
# proxy_pass http://127.0.0.1;
#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}

# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;

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

# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;

# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;

# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;

# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;

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

# 导入多个外部server
include servers/*;
}

匹配 location

示例:

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
location  = / {
# 精确匹配 / ,主机名后面不能带任何字符串
[ configuration A ]
}

location / {
# 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
# 但是正则和最长字符串会优先匹配
[ configuration B ]
}

location /documents/ {
# 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
# 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
[ configuration C ]
}

location ~ /documents/Abc {
# 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
# 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
[ configuration CC ]
}

location ^~ /images/ {
# 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。
[ configuration D ]
}

location ~* \.(gif|jpg|jpeg)$ {
# 匹配所有以 gif,jpg或jpeg 结尾的请求
# 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则
[ configuration E ]
}

location /images/ {
# 字符匹配到 /images/,继续往下,会发现 ^~ 存在
[ configuration F ]
}

location /images/abc {
# 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在
# F与G的放置顺序是没有关系的
[ configuration G ]
}

location ~ /images/abc/ {
# 只有去掉 config D 才有效:先最长匹配 config G 开头的地址,继续往下搜索,匹配到这一条正则,采用
[ configuration H ]
}

location ~* /js/.*/\.js
  • =开头表示精确匹配
  • ^~ 开头表示 uri 以某个常规字符串开头,不是正则匹配
  • ~开头表示区分大小写的正则匹配;
  • ~* 开头表示不区分大小写的正则匹配
  • / 通用匹配, 如果没有其它匹配,任何请求都会匹配到

优先级:
(location =) > (location 完整路径) > (location ^~ 路径) > (location ~,~* 正则顺序) > (location 部分起始路径) > (/)

配置反向代理

详解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 对 “/” 启用反向代理
location / {
proxy_pass http://127.0.0.1:3000; # 设置要代理的 uri,注意最后的 /。可以是 Unix 域套接字路径,也可以是正则表达式。
proxy_redirect off; # 设置后端服务器“Location”响应头和“Refresh”响应头的替换文本
proxy_set_header X-Real-IP $remote_addr; # 获取用户的真实 IP 地址
#后端的Web服务器可以通过 X-Forwarded-For 获取用户真实IP,多个 nginx 反代的情况下,例如 CDN。参见:http://gong1208.iteye.com/blog/1559835 和 http://bbs.linuxtone.org/thread-9050-1-1.html
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; #缓冲区代理缓冲用户端请求的最大字节数,
proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时)
proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的设置
proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
proxy_temp_file_write_size 64k;
#设定缓存文件夹大小,大于这个值,将从upstream服务器传
}

举例:

1
2
3
4
5
6
7
location ^~ /service/ {
proxy_pass http://192.168.60.245:8080/;
proxy_redirect default;
proxy_set_header Host $host
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

简化:

1
2
3
4
location /proxy/ {
proxy_pass http://backend.com/;
proxy_redirect default;
}

配置 rewrite

rewrite 功能就是集合正则表达式和标志位实现 url 重写和重定向。rewrite 只能放在 server{}、location{}、if(){}块中,并且只能对域名后边的出去传递参数外的字符串起作用。如 URL:
http://microloan-sms-platform.yxapp.xyz/proxy/sms/task/querydeleted?page=1&pagesize=10
只对/proxy/sms/task/querydeleted 进行重写。

如果相对域名或参数字符串起作用,可以使用全局变量匹配,也可以使用 proxy_pass 反向代理。

表明看 rewrite 和 location 功能有点像,都能实现跳转,主要区别在于 rewrite 是在同一域名内更改获取资源的路径,而 location 是对一类路径做控制访问或反向代理,可以 proxy_pass 到其他机器。很多情况下 rewrite 也会写在 location 里,它们的执行顺序是:

  • 执行 server 块的 rewrite 指令
  • 执行 location 匹配
  • 执行选定的 location 中的 rewrite 指令

如果其中某步 URI 被重写,则重新循环执行 1-3,直到找到真实存在的文件;循环超过 10 次,则返回 500 Internal Server Error 错误。

rewrite 规则后边,通常会带有 flag 标志位:

  • last : 相当于 Apache 的[L]标记,表示完成 rewrite
  • break : 停止执行当前虚拟主机的后续 rewrite 指令集
  • redirect : 返回302临时重定向,地址栏会显示跳转后的地址
  • permanent : 返回301永久重定向,地址栏会显示跳转后的地址

lastbreak 区别:

  • last一般写在serverif中,而break一般使用在location
  • last不终止重写后的 url 匹配,即新的 url 会再从server走一遍匹配流程,而break终止重写后的匹配
  • breaklast都能组织继续执行后面的 rewrite 指令

rewrite 常用正则:

  • . : 匹配除换行符以外的任意字符
  • ? : 重复 0 次或 1 次
  • + : 重复 1 次或更多次
  • * : 重复 0 次或更多次
  • \d :匹配数字
  • ^ : 匹配字符串的开始
  • $ : 匹配字符串的介绍
  • {n} : 重复 n 次
  • {n,} : 重复 n 次或更多次
  • [c] : 匹配单个字符 c
  • [a-z] : 匹配 a-z 小写字母的任意一个

可以使用()来进行分组,可以通过$1的形式来引用。

示例:

1
2
3
4
location /proxy/ {
proxy_pass http://microloan-notification-web.yxapp.in;
rewrite /proxy/(.*)$ /$1 break;
}

配置负载均衡

示例:

1
2
3
4
5
6
7
upstream test.net{
ip_hash;
server 192.168.11.1:80;
server 192.168.11.11:80 down;
server 192.168.11.123:8009 max_fails=3 fail_timeout=20s;
server 192.168.11.1234:8080;
}

upstream 是 Nginx 的 HTTP Upstream 模块,这个模块通过一个简单的调度算法来实现客户端 IP 到后端服务器的负载均衡。
Nginx 的负载均衡模块目前支持 4 种调度算法:

  • 轮询(默认)。每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响。Weight 指定轮询权值,Weight 值越大,分配到的访问机率越高,主要用于后端每个服务器性能不均的情况下。
  • ip_hash。每个请求按访问 IP 的 hash 结果分配,这样来自同一个 IP 的访客固定访问一个后端服务器,有效解决了动态网页存在的 session 共享问题。
  • fair。这是比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx 本身是不支持 fair 的,如果需要使用这种调度算法,必须下载 Nginx 的 upstream_fair 模块。
  • url_hash。此方法按访问 url 的 hash 结果来分配请求,使每个 url 定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。Nginx 本身是不支持 url_hash 的,如果需要使用这种调度算法,必须安装 Nginx 的 hash 软件包。

upstream 可以设定每个后端服务器在负载均衡调度中的状态,支持的状态参数:

  • down,表示当前的 server 暂时不参与负载均衡
  • backup,预留的备份机器。当其他所有的非 backup 机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻。
  • max_fails,允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。
  • fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用。

注,当负载调度算法为 ip_hash 时,后端服务器在负载均衡调度中的状态不能是 weight 和 backup。

设置页面缓存

页面缓存设置指令:

  • proxy_cache_path: 指定缓存的路径和一些其他参数,缓存的数据存储在文件中,并且使用代理 url 的哈希值作为关键字与文件名。

    1
    proxy_cache_path /data/nginx/cache/webserver levels=1:2 keys_zone=webserver:20m max_size=1g;

    levels参数指定缓存的子目录数。keys_zone指定活动的 key 和元数据存储在共享池(webserver 为共享池名称,20m 位共享池大小),inactive参数指定的时间内缓存的数据没有被请求则被删除,默认 inactive 为 10 分钟·max_size指定缓存空间的大小。

  • proxy_cache: 设置一个缓存区域的名称,一个相同的区域可以在不同的地方使用。

  • proxy_cache_valid: 为不同的应答设置不同的缓存时间。

设置读写分离

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_pass http://192.128.133.202;
if ($request_method = "PUT"){
proxy_pass http://192.128.18.201;
}
}
}

开机启动

当我们在 Mac 上使用 homebrew 安装 nginx,mysql,php 的时候,遗憾的是 nginx 默认监听的是 8080 端口,而当我们将端口修改为 Web 服务器通用的 80 端口时,却导致 nginx 无法在开机的时候自启。。。

  • 通过 homebrew 安装 nginx 后,我们可以在 nginx 软件的安装目录/usr/local/Cellar/nginx下看到有一个homebrew.mxcl.nginx.plist文件。在 Mac 系统上, .plist文件就是服务开机启动的配置文件。

  • 由于 nginx 监听80端口,必须在开机启动的时候,以管理员权限执行,所以需要将此文件复制一份置于/Library/LaunchDaemons目录之下。注意权限需要和/Library/LaunchDaemons目录下的其他文件权限保持一致,通常是644, 文件所有者为root:wheel,否则真的会报错误的。

  • 然后使用launchctl load -w /Library/LaunchDaemons/homebrew.mxcl.nginx.plist 加载 nginx 服务到系统启动服务中即可。

命令:

1
2
3
4
5
6
7
8
9
10
11
# [可选]先查看此目录是否存在,不存在执行此命令新建
mkdir -p ~/Library/LaunchDaemons

# 拷贝homebrew.mxcl.nginx.plist文件
sudo cp /usr/local/Cellar/nginx/*.plist /Library/LaunchDaemons

# 加载启动服务
sudo launchctl load -w /Library/LaunchDaemons/homebrew.mxcl.nginx.plist

# 配置nginx权限
sudo chown root:wheel /usr/local/Cellar/nginx/{nginx版本}/bin/nginx

完整 nginx 配置举例

nginx 配置主文件: /usr/local/etc/nginx/nginx.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
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
user root owner;
#user nobody;
worker_processes 1;

# pid /logs/nginx/nginx.pid;

# events-模块(工作模式&连接上限): https://www.zybuluo.com/phper/note/89391#events-%E6%A8%A1%E5%9D%97
events {
use kqueue; #mac平台
worker_connections 1024;
}


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


http {
include mime.types;
default_type application/octet-stream;

underscores_in_headers on; # 开启变量下划线支持

client_max_body_size 24M;
client_body_buffer_size 256k;

# 日志格式设置: https://juejin.im/post/59f94f626fb9a045023af34c
# $remote_addr 客户端地址 211.28.65.253
# $remote_user 客户端用户名称 --
# $time_local 访问时间和时区 18/Jul/2012:17:00:01 +0800
# $request 请求的URI和HTTP协议 "GET /article-10000.html HTTP/1.1"
# $http_host 请求地址,即浏览器中你输入的地址(IP或域名) www.wang.com 192.168.100.100
# $status HTTP请求状态 200
# $upstream_status upstream状态 200
# $body_bytes_sent 发送给客户端文件内容大小 1547
# $http_referer url跳转来源 https://www.baidu.com/
# $http_user_agent 用户终端浏览器等信息 "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; SV1; GTB7.0; .NET4.0C;
# $ssl_protocol SSL协议版本 TLSv1
# $ssl_cipher 交换数据中的算法 RC4-SHA
# $upstream_addr 后台upstream的地址,即真正提供服务的主机地址 10.10.10.100:80
# $request_time 整个请求的总时间 0.205
# $upstream_response_time 请求过程中,upstream响应时间 0.002
log_format main 'remote_addr: $remote_addr\n'
'remote_user: $remote_user\n'
'time_local: $time_local\n'
'request: $request\n'
'status: $status\n'
'body_bytes_sent: $body_bytes_sent\n'
'http_referer: $http_referer\n'
'http_user_agent: $http_user_agent\n'
'http_x_forwarded_for: $http_x_forwarded_for\n'
'request_body: $request_body\n'
'------------------------------------------------------------------------';

log_format porxy 'http_x_forwarded_for: $http_x_forwarded_for\n'
'remote_user: $remote_user\n'
'time_local: $time_local\n'
'http_host: $http_host\n'
'request: $request\n'
'status: $status\n'
'body_bytes_sent: $body_bytes_sent\n'
'http_referer: $http_referer\n'
'http_user_agent: $http_user_agent\n'
'proxy_protocol_addr: $proxy_protocol_addr\n'
'request_body: $request_body\n'
'porxy_url: $porxy_url\n'
'------------------------------------------------------------------------';

log_format log404 '$status [$time_local] $remote_addr $host$request_uri $sent_http_location';

access_log /logs/nginx/access.log main;
# error_log /logs/nginx/error.log;
# error_log /logs/nginx/error.log notice;
error_log /logs/nginx/error.log info;

access_log on;
sendfile on;
# tcp_nopush on;
# fastcgi_intercept_errors on;

# keepalive_timeout 0;
keepalive_timeout 65;

# # gzip压缩功能设置
# gzip on;

proxy_redirect off; # 关闭后端返回的header修改
proxy_set_header Host $host; # 修改发送到后端的header的host
proxy_set_header X-Real-IP $remote_addr; # 设置真实ip
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 60; # 代理服务器和后端真实服务器握手连接超时时间
proxy_read_timeout 600; # 后端服务器回传数据给Nginx的时间,需要在设置的时间范围内发送完所有数据,否则Nginx将断开连接
proxy_send_timeout 600; # 代理服务器和后端服务器连接成功后,等待后端服务器响应时间

# # 负载均衡: https://www.zybuluo.com/phper/note/90310#3%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1
# # 设定负载均衡后台服务器列表
# upstream backend {
# #ip_hash; # 记录并访问上一次访问过的服务器
# server 192.168.0.100:8080 weight=10 max_fails=2 fail_timeout=30s;
# server 192.168.0.101:8080 weight=10 max_fails=2 fail_timeout=30s;
# }

server {
listen 1024;
server_name localhost;

#charset koi8-r;
charset utf-8;

access_log /logs/nginx/host.access.log main;

# location匹配: https://segmentfault.com/a/1190000013267839
location / {
root html;
index index.html index.htm;
}

#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 404 403 /50x.html;
location = /50x.html {
root html;
}

# # proxy the PHP scripts to Apache listening on 127.0.0.1:80
# location ~ \.php$ {
# proxy_pass http://127.0.0.1;

# ### 下面都是次要关注项
# proxy_set_header Host $host; # 修改发送到后端的header的host
# proxy_set_header X-Real-IP $remote_addr; # 设置真实ip
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 经过的IP列表
# proxy_method POST;
# # 指定不转发的头部字段
# proxy_hide_header Cache-Control;
# proxy_hide_header Other-Header;
# # 指定转发的头部字段
# proxy_pass_header Server-IP;
# proxy_pass_header Server-Name;
# # 是否转发包体
# proxy_pass_request_body on | off;
# # 是否转发头部
# proxy_pass_request_headers on | off;
# # 显形/隐形 URI,上游发生重定向时,Nginx 是否同步更改 uri
# proxy_redirect on | off;
# }

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}


# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;

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


# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;

# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;

# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;

# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;

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


include servers/*;
}

外部 server 配置: /usr/local/etc/nginx/servers/dev.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
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
# Location 配置demo
# https://segmentfault.com/a/1190000009651161

upstream rd_header {
server rd5-dev.zhaopin.com;
# server rd5-pre.zhaopin.com;
}

upstream bole_api {
server 192.168.214.110:8089 weight=10 max_fails=2 fail_timeout=30s;
# server bole-api-dev.zhaopin.com weight=10 max_fails=2 fail_timeout=30s;
}

server {
listen 80;

server_name *.zhaopin.com;
resolver 127.0.0.1 ipv6=off;

access_log /logs/nginx/$http_host.access.log porxy;
error_log /logs/nginx/zhaopin.error.log;

location ~ /api/rd/rd55/head {
proxy_pass http://rd_header;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location ~ /bolemanage/(.*) {
proxy_pass http://bole_api/bolemanage/$1?$args;

proxy_set_header Host bole-api-dev.zhaopin.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location / {
resolver 127.0.0.1 ipv6=off;

if ($http_host ~* ^(.*-local)(\.zhaopin\.com)$) {
set $porxy_url $1$2:8000;
}
# proxy_pass http://$porxy_url;
proxy_pass http://127.0.0.1:8000;

access_log /logs/nginx/$porxy_url.access.log porxy;
error_log /logs/nginx/zhaopin-porxy_url.error.log;

proxy_set_header Host $http_host:8000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

error_page 404 403 https://github.com/404;
}

# server {
# listen 80;
# server_name rd5-dev.zhaopin.com;

# location /api/rd/rd55/head {
# proxy_pass http://rd5-pre.zhaopin.com;
# }
# }

# server {
# listen 80;

# # 泛域名解析
# server_name *.zhaopin.com;
# resolver 127.0.0.1 ipv6=off;

# # 最末级域名作为localhost端口号
# if ($host ~* ^([^\.]+)\.([^\.]+\.[^\.]+)$) {
# set $subdomain $1;
# set $domain $2;
# set $porxy_url 127.0.0.1:$1;
# }

# access_log /logs/nginx/$subdomain.zhaopin.access.log porxy;
# error_log /logs/nginx/zhaopin.error.log;

# location / {
# proxy_pass http://$porxy_url;
# }

# error_page 404 403 https://github.com/404;
# }

采坑

  • 本机可以访问,但是局域网内其他电脑无法访问

    检查防火墙配置

  • 启动权限错误,不想通过sudo启动

    在使用nginx -t检查nginx配置文件时出现这个错误:

    1
    2
    $ /usr/local/nginx/sbin/nginx -t
    nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /usr/local/nginx/conf/nginx.conf:2

    nginx的所有者是root
    我们都知道nginx的主进程需要使用root来运行,而子进程可以使用普通用户运行,
    普通用户如果不使用sudo命令运行nginx时则需要获取SUID权限才能在nginx运行时将身份切换为root,否则就是用自己的身份来执行nginx,而恰巧在这个nginx.conf文件中设置了ssl的证书的放置位置在一些普通用户不能读取的位置或者一些普通用户不能读取的目录,所以出现了权限的错误.
    解决的方法我总结了两种,一种是使用sudo来运行nginx,另一种是给nginx赋予SUID权限,让普通用户在执行nginx时将身份提升为nginx的所有者也就是root

    给nginx赋予SUID权限

    1
    2
    3
    4
    5
    > $ sudo chmod u+s /usr/local/nginx/sbin/nginx
    > //或者$ sudo chmod 4755 /usr/local/nginx/sbin/nginx
    > $ ll /usr/local/nginx/sbin/nginx
    > -rwsr-xr-x 1 root root 8641260 Sep 7 14:33 /usr/local/nginx/sbin/nginx
    >

    但是由于SUID权限是linux中比较危险的一种程序,假设要执行的程序的所有者是root,那么任何非sudo用户都可以在运行这个程序的时候身份都变为了root,所以这个程序可以让任何人以root身份执行,有点心里慌慌.
    还是用sudo执行好一些吧,至少只有在sudoers列表中的用户才能以root权限执行,还必须在命令前敲sudo来提醒一下自己,感觉安全性是提高了不少.

参考

  • Nginx 中文文档
  • Nginx 能为前端开发带来什么?
  • 前端工程师应该知道的 Nginx
  • 前端 Nginx https SSL proxy + 后端 Nginx http 应用的布署教程
  • nginx 配置 location 总结及 rewrite 规则写法
  • nginx 服务器安装及配置文件详解
  • Nginx 反向代理、负载均衡、页面缓存、URL 重写及读写分离详解
  • Mac 通过 Homebrew 安装 nginx 并设置开机启动配置
  • mac 下 nginx 加入开机启动
坚持原创技术分享,您的支持将鼓励我继续创作!
  • 本文作者: Leo
  • 本文链接: https://xuebin.me/posts/9de3336.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!