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 官网
- 解压运行:解压至
c:\nginx
,运行nginx.exe
(即nginx -c conf\nginx.conf
),默认使用 80 端口,日志见文件夹C:\nginx\logs
- 关闭:
nginx -s stop
或taskkill /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 | #定义 Nginx 运行的用户和用户组,默认由 nobody 账号运行, windows 下面可以注释掉。 |
匹配 location
示例:
1 | location = / { |
- 以
=
开头表示精确匹配 ^~
开头表示 uri 以某个常规字符串开头,不是正则匹配~
开头表示区分大小写的正则匹配;~*
开头表示不区分大小写的正则匹配/
通用匹配, 如果没有其它匹配,任何请求都会匹配到
优先级:
(location =) > (location 完整路径) > (location ^~ 路径) > (location ~,~* 正则顺序) > (location 部分起始路径) > (/)
配置反向代理
详解:
1 | # 对 “/” 启用反向代理 |
举例:
1 | location ^~ /service/ { |
简化:
1 | location /proxy/ { |
配置 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]标记,表示完成 rewritebreak
: 停止执行当前虚拟主机的后续 rewrite 指令集redirect
: 返回302
临时重定向,地址栏会显示跳转后的地址permanent
: 返回301
永久重定向,地址栏会显示跳转后的地址
last
和 break
区别:
last
一般写在server
和if
中,而break
一般使用在location
中last
不终止重写后的 url 匹配,即新的 url 会再从server
走一遍匹配流程,而break
终止重写后的匹配break
和last
都能组织继续执行后面的 rewrite 指令
rewrite 常用正则:
.
: 匹配除换行符以外的任意字符?
: 重复 0 次或 1 次+
: 重复 1 次或更多次*
: 重复 0 次或更多次\d
:匹配数字^
: 匹配字符串的开始$
: 匹配字符串的介绍{n}
: 重复 n 次{n,}
: 重复 n 次或更多次[c]
: 匹配单个字符 c[a-z]
: 匹配 a-z 小写字母的任意一个
可以使用()
来进行分组,可以通过$1
的形式来引用。
示例:
1 | location /proxy/ { |
配置负载均衡
示例:
1 | upstream test.net{ |
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 | server { |
开机启动
当我们在 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 | # [可选]先查看此目录是否存在,不存在执行此命令新建 |
完整 nginx 配置举例
nginx 配置主文件: /usr/local/etc/nginx/nginx.conf
1 | user root owner; |
外部 server 配置: /usr/local/etc/nginx/servers/dev.conf
1 | # Location 配置demo |
采坑
本机可以访问,但是局域网内其他电脑无法访问
检查防火墙配置
启动权限错误,不想通过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:2nginx的所有者是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 加入开机启动