微信入群一块学习技术:Day9884125
一、介绍
nginx作为最流行的代理服务器之一,承担反向代理、负载均衡的职责,梳理实际应用细节,对于技术复制,构建安全可靠的项目有重要意义。
目标
使用nginx是期望它完成相应的职责,具体来讲,我们期望能够完成以下内容:
- 根据域名不同代理不同的后台服务器
- 根据uri不同代理不同的后台服务器
- 代理前端静态资源(html+css+js+图片等)
- 支持https安全加密
二、安装与运行
2.1 安装
nginx是通过源码编译安装,可按需编译各个功能模块,其中使用较多的是SSL模块。为了便于管理,源代码存储在/usr/local/src路径下,NGX_HOME的路径为/usr/local/nginx,其配置编译命令如下:
./configure
--with-http_ssl_module
一台服务器,我们通常只安装一个nginx应用。假设日常运行nginx的用户为lj:dev,使用root用户安装完毕后,将文件的所有者移交给该用户。
cd /usr/local/nginx
# 不修改临时文件夹(包含文件)
find $PWD | grep -v '_temp' | xargs chown -R lj:dev *
将NGX_HOME目录下的所有文件变更所有者。
nginx在运行过程中需要临时保存文件,因此需要配置读写权限,变更NGX_HOME目录下临时文件夹的读写权限命令如下,文件所有者、文件同组用户、其他用户组用户都具有读写权限,保证了任何能够启动nginx的用户在运行期间都拥有临时文件夹访问权限。
cd /usr/local/nginx/logs
chmod -R 666 * #将子文件夹赋予全用户读写权限
chmod 644 nginx.pid
2.2 运行
由于nginx需要启动80(443)端口,需要使用root用户或者使用具有root用户权限的普通用户(lj:dev)来启动,在使用过程中,二者可能交替使用,对于日志文件和临时文件夹的读写权限尤为要注意。
| 名称 | 文件夹(及子文件) | 所有者 | 权限 |
|---|---|---|---|
| 启动文件 | sbin | lj:dev | 555 |
| 配置文件 | conf | lj:dev | 644 |
| html文件 | html | lj:dev | 644 |
| 日志文件 | logs | lj:dev | 666 |
| 运行时临时文件 | *_temp | nobody:dev | 666 |
用户lj:dev使用sudo命令启动nginx是正常的,使用root来启动同样是正常启动与运行,两个用户运行时依赖的读写权限分别赋予成功。
2.2.1 前台运行
Nginx默认是以后台进程方式运行,对于Docker等场景,需要应用保持前台运行。
# 在配置文件最外层此语句
daemon off;
或者在启动时,添加如下参数:
nginx -g "daemon off;"
2.3 开机自启
服务器在使用过程中不可避免出现关机重启的情况,设置开机自启,能够最大限度的减少nginx服务中断的时间。
2.3.1 在CentOS上设置开机自启
CentOS指的是7及以上版本,设置开机自启非常简单,具体操作如下:
编写nginx.service配置文件
# /usr/lib/systemd/system # 需要设置开机自启的统一目录
vim /usr/lib/systemd/system/nginx.service
向配置文件中添加如下内容:
[Unit]
Description=nginx
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s restart
ExecStop=/usr/local/nginx/sbin/nginx -s stop
PrivateTmp=true
[Install]
WantedBy=multi-user.target
通过标准的系统调用管理服务。
systemctl enable nginx #在任意目录下运行(设置开机自启)
/usr/local/nginx/sbin/nginx -s stop #如果已经运行,则先停止
systemctl start nginx #启动nginx服务
systemctl status nginx #查看服务状态
2.3.2 在Mac上设置开机自启
Mac版的开机自启配置文件都在目录/Library/LaunchDaemons下,其它配置可参考处理。
配置文件存储位置
分别在以下6个目录中检查是否有与进程相关的plist文件
~/Library/Preferences/ – (当前用户设置的进程)
~/Library/LaunchAgents/ – (当前用户的守护进程)
/Library/LaunchAgents/ – (管理员设置的用户进程)
/Library/LaunchDaemons/ – (管理员提供的系统守护进程)
/System/Library/LaunchAgents/ – (Mac操作系统提供的用户进程)
/System/Library/LaunchDaemons/ – (Mac操作系统提供的系统守护进程)
- 新建
com.nginx.plist文件并添加以下内容
sudo vim /Library/LaunchDaemons/com.nginx.plist
文件的内容如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.nginx.plist</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/nginx/sbin/nginx</string>
</array>
<key>KeepAlive</key>
<false/>
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/usr/local/nginx/logs/error.log</string>
<key>StandardOutPath</key>
<string>/usr/local/nginx/logs/access.log</string>
</dict>
</plist>
- 修改权限
sudo chmod 644 /Library/LaunchDaemons/com.nginx.plist
- 注册为系统服务,实现开机自启
sudo launchctl load -w /Library/LaunchDaemons/com.nginx.plist
- 如果想取消系统服务,则使用如下命令
sudo launchctl unload -w /Library/LaunchDaemons/com.nginx.plist
2.4 日志轮转
nginx在运行时会产生大量的日志文件,防止服务器因日志文件暴增而导致服务器宕机,是维护服务器安全的重要环节。
Nginx默认生成一个访问日志文件,需要使用日志轮转技术来管理日志。
三、基础使用
3.1 代理静态资源
在实际使用过程中,除了转发请求外,还需要代理静态文件。
3.1.1 不缓存静态资源
# 如果是静态资源,nginx不缓存
if ($request_filename ~* ^.*?.(js|html|css)$) {
add_header Cache-Control no-cache, no-store;
add_header Pragma no-cache;
add_header Expires 0;
}
3.1.2 平级代理
平级代理是指URL请求相对路径与静态资源存放目录内容层级结构保持一致。平级代理使用root关键字指定静态资源存放路径(对于目录需要执行权限)
/aa/bb -> /aa/bb
3.1.3 多层代理
多层代理应用于请求路径与资源路径不一致的情况。root请求路径与资源路径一致;alias请求路径与资源路径不一致;
location ^~ /img {
alias /tmp/html;
index index.html;
}
上述语法表示,拦截请求资源以img为前缀的URI,并且实际映射资源路径时,忽略img前缀。
/img/aa/1.txt -> /aa/bb
多次代理应用较为灵活,可以理解为逻辑路由
3.1.4 拓展
随着技术的飞速发展,静态资源更多的部署在CDN上面,以减少服务器带宽压力。因此对于前端项目部署来说,仅仅需要部署一个index.html文件,余者静态资源全部转存至CDN。
3.2 代理动态请求
proxy_pass反向代理转发请求时,请求前缀与实际代理前缀并不完全一致,由此区分平级路由与多级路由。
3.2.1 平级路由
平级路由适用于一层代理的情况,路由时会将location拦截的后缀全部附加在代理路径上。
3.2.2 多级路由
多级路由适用于两层及以上代理的情况,路由时会将location拦截的后缀忽略,可自定义后缀。
location ^~ /app/typora {
proxy_pass http://images.altitude.xin/typora;
}
多级路由类似于网关的分发功能,将不同的流量导向不同的服务模块。
^~/aa/bb -> /cc
3.3 反向代理
反向代理时,向应用服务器传递客户端真实IP地址。
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
四、高级使用
4.1 请求访问限制
在实际使用过程中,常常需要对特定的IP地址进行访问限制,根据场景不同,大致分为三类:
- 限制搜索引擎爬虫
- 访问白名单制度
- 访问黑名单制度
4.1.1 限制搜索引擎爬虫
根据网站的性质,自由选择是否过滤爬虫流量,新建agent_deny.conf文件,并配置如下:
#禁止Scrapy等工具的抓取
if ($http_user_agent ~* (Scrapy|Curl|HttpClient|Baiduspider)) {
return 403;
}
#禁止指定UA及UA为空的访问
if ($http_user_agent ~ "Baiduspider|WinHttp|WebZIP|FetchURL|node-superagent|java/|FeedDemon|Jullo|JikeSpider|Indy Library|Alexa Toolbar|AskTbFXTV|AhrefsBot|CrawlDaddy|Java|Feedly|Apache-HttpAsyncClient|UniversalFeedParser|ApacheBench|Microsoft URL Control|Swiftbot|ZmEu|oBot|jaunty|Python-urllib|lightDeckReports Bot|YYSpider|DigExt|HttpClient|MJ12bot|heritrix|EasouSpider|Ezooms|BOT/0.1|YandexBot|FlightDeckReports|Linguee Bot|^$" ) {
return 403;
}
#禁止非GET|HEAD|POST方式的抓取
if ($request_method !~ ^(GET|HEAD|POST)$) {
return 403;
}
4.1.2 白名单制度
白名单限制大多数流量访问,只允许特定的白名单IP访问。开发环境需要与之配套的白名单,保证测试环境处于隔离的环境中,白名单文件(whiteListIp.conf)配置如下
allow 101.242.124.201;
deny all;
4.1.3 黑名单制度
黑名单指少数的IP地址被限制,其余所有IP都能正常访问。生产环境需要与之配套的黑名单,允许大多数流量访问,对于特定的不友好流量,添加至黑名单予以限制,黑名单文件(blackListIp.conf)配置如下
deny 219.136.75.103;
allow all;
4.2 自定义403页面
在项目开发过程中,希望达到允许一小部分客户端访问,其余所有客户端禁止访问的效果。随着时间的推移,不断有新增申请获取访问权限的需求。快速定位申请访问客户端的IP,及时加入访问白名单,能增加授权管理便利性。自定义403页面,在客户端显示被拦截的IP地址,然后经使用者申请,管理员同意并添加白名单,顺利放行使用者被限制的流量。
4.2.1 自定义页面
编辑文件名为403.html文件,并放在html文件夹下,页面内容如下:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html">
<title>403 Forbidden</title>
</head>
<body>
<center>
<h1>403 Forbidden</h1>
</center>
</body>
</html>
此文件仅仅是实现了自定义的演示目的,仍需要继续定制。
4.2.2 修改配置文件
在nginx.conf配置文件的http模块加入:fastcgi_intercept_errors on;在server模块下location模块结尾处添加如下内容:
error_page 403 /403.html;
location /403.html {
allow all;
}
重启nginx服务即可实现nginx自定义403页面
4.2.3 深度定制自定义页面
本节着重解决将nginx内置remote_addr变量传递给403页面的问题。
4.2.3.1 优化页面部分
重新编辑文件名为【403.html】文件,并放在html文件夹下,页面内容如下:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;">
<title>403 Forbidden</title>
</head>
<style>
@media(max-width : 600px) {
#h1_div {
font-size: 28px !important;
}
#p_div {
font-size: 22px !important;
}
}
</style>
<body>
<center>
<h1 id="h1_div">403 Forbidden</h1>
<p style="display: none;font-size: 18px;" id="p_div">
<!--# echo var="remote_addr" default="" -->
</p>
</center>
<script>
var h1_div = document.getElementById("h1_div");
var p_div = document.getElementById("p_div");
h1_div.onclick = function(event) {
p_div.style.display = 'block';
}
</script>
</body>
</html>
4.2.3.2 nginx配置
error_page 403 /403.html;
location /403.html {
#新增配置
ssi on;
internal;
allow all;
}
重启nginx即可实现能够显示远程IP的403访问禁止页面,通过将此信息提交给网站管理员,能够快速申请访问权限。
4.3 全局解决40X错误码
403和404错误码,是web项目中常见的错误码,各个项目都有相似的40X错误码需求。本节针对前后端分离项目之前端项目部分寻求统一的错误码解决方式。
# 前台系统前端(非首页)页面
location /p {
root /var/website/point/point_view_1.0;
error_page 404 /404.html;
error_page 403 /403.html;
}
# 前台系统前端(首页)页面
location =/ {
root /var/website/point/point_view_1.0;
index /index.html;
error_page 404 /404.html;
error_page 403 /403.html;
}
location =/404.html {
ssi on;
internal;
}
location =/403.html {
ssi on;
internal;
allow all;
}
通过上述配置,另外在html文件夹分别添加自定义403和404通用页面,即可实现web项目40X错误码通用管理。
4.3.1 403错误码
nginx返回403错误码主要有两种情况,一种是无资源访问权限,另一种是客户端IP被禁止访问。为了简化问题,给所有nginx代理的静态资源(包含路径)授予755权限,排除第一种情况造成的403错误码。通过自定义403页面(包含客户端IP),能够快速定位申请授权的源IP。
4.3.2 404错误码
因文件资源不存在而报404错误,特别注意,文件存在但文件访问权限不足时会报403错误。通过自定义404页面(包含web项目应用域名),能够根据项目的不同自动跳转到对应项目的首页。