最近有一个项目要部署到线上服务器,花了几天时间终于把所有的问题都完美解决了。在部署期间遇到一些与nginx相关问题及解决方法一并记录了下来。
目录
3.1 nginx配置后,只有一个页面(首页)能正常访问,其他页面全加载不出来
3.2 Nginx报错"no live upstreams while connecting to upstream",错误码502
3.3 用nginx进行负载均衡时,web项目的session共享问题
3.4 服务器上配置好nginx后,用两台电脑访问,总是命中后台某一个服务器
1 nginx概述
1.1 nginx简介
Nginx是俄罗斯人Igor Sysoev编写的轻量级Web服务器,它的发音为 [ˈendʒɪnks] ,它不仅是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/SMTP代理服务器。
通常是用来做代理/反向代理,负载均衡的。至于它的特点优点这里不再赘述,我们重点看它的用法和可能遇到问题的解决方案。
1.2 nginx下载
1.2.1 windows下载
windows下载地址:http://nginx.org/en/download.html,点击进去如下图:

1.2.2 Linux下载
方式一
和Windows同样的地址http://nginx.org/en/download.html,点击进去如下图:

方式二
从网站去去下载,http://nginx.org/download/,如下图:

方式三
在linux环境下安装,在下面网页中有详细介绍
https://jingyan.baidu.com/article/e3c78d648516243c4c85f5c2.html
1.3 启动测试
1.3.1 windows环境
下载后,如下图:

进入nginx-1.16.1目录后,双击nginx.exe,有个窗口会一闪而过,在浏览器中输入localhost,如下图:

说明nginx正常启动了。
1.3.2 linux环境
也很简单,这里不再赘述,详情可以参照:https://jingyan.baidu.com/article/e3c78d648516243c4c85f5c2.html
启动成功后,也会有欢迎页面,若不成功注意防火墙对默认监听端口80的拦截,要开放这个端口。
1.4 常用命令
nginx -s stop # 快速关闭Nginx,可能不保存相关信息,并迅速终止web服务。
nginx -s quit #平稳关闭Nginx,保存相关信息,有安排的结束web服务。
nginx -s reload #因改变了Nginx相关配置,需要重新加载配置而重载。
nginx -s reopen #重新打开日志文件。
nginx -c filename #为 Nginx 指定一个配置文件,来代替缺省的。
nginx -t #不运行,而仅仅测试配置文件。nginx 将检查配置文件的语法的正确性,并尝试打开配置文件中所引用到的文件。
nginx -v #显示 nginx 的版本。
nginx -V #显示 nginx 的版本,编译器版本和配置参数。
注意运行这些命令要在nginx.exe所在的路径下。
2 nginx配置
2.1 一个简单例子
场景:我们现在在本地启动了两个web项目,访问地址分别为“127.0.0.8080”和“127.0.0.8081”,要实现代理/反向代理,负载均衡可以像下面这样配置。
下面是一个默认初始的nginx.conf文件,其他都没变,添加的是蓝色框中的代码,该文件的关键部分,如下图:

注意:
两个蓝色框中都有myWebs,mywebs是后台服务器组的名称,这两个地方一定要一样。
在上面例子中,如果你的web项目登录路径为:127.0.0.1:8080/webAppName 那么nginx配置启动后,应该访问 localhost:80/webAppName
2.2 语句含义
#user nobody; #定义 Nginx 运行的用户和用户组,默认由 nobody 账号运行, windows 下面可以注释掉。
worker_processes 1; #nginx进程数,建议设置为等于CPU总核心数。可以和worker_cpu_affinity配合
#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
error_log logs/error.log;
error_log logs/error.log notice;
error_log logs/error.log info;
#pid logs/nginx.pid; #进程文件,window下可以注释掉
events {
accept_mutex on; #设置网路连接序列化,防止惊群现象发生,默认为on
multi_accept on; #设置一个进程是否同时接受多个网络连接,默认为off
#use epoll; #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
worker_connections 1024; # 单个进程最大连接数(最大连接数=连接数*进程数)该值受系统进程最大打开文件数限制,需要使用命令ulimit -n 查看当前设置
}
http {
include mime.types; #文件扩展名与文件类型映射表
default_type application/octet-stream; #默认文件类型,默认为text/plain
#定义虚拟主机日志的格式
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 0;
keepalive_timeout 65;
#开启gzip压缩输出
#gzip on;
#被代理的后台服务器列表
upstream myWeb {
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:9081 weight=1;
ip_hash; #ip_hash 模式,解决session不能共享问题
}
server {
listen 2041; # 监听端口
server_name localhost; #域名可以有多个,用空格隔开
#charset koi8-r;
charset utf-8; #字符编码设置
#access_log logs/host.access.log main; #定义本虚拟主机的访问日志
location / {
# root html; #一个基本路径
# index index.html index.htm; # 在上面的基本路径下找该文件,若是静态文件(html)则展示;若是动态文件(jsp)在下载
proxy_pass http://myWeb; # 代理的后台服务器列表
proxy_set_header Host $host:$server_port;
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_connect_timeout 10000;
proxy_read_timeout 10000;
proxy_send_timeout 10000;
}
#设定查看Nginx状态的地址
location /NginxStatus {
stub_status on;
access_log on;
auth_basic "NginxStatus";
auth_basic_user_file conf/htpasswd;
}
#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;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# 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;
# }
#}
}
2.3 重要模块
2.3.1 负载均衡
Nginx负载均衡是通过upstream模块来实现的,内置实现了三种负载策略,配置还是比较简单的。官网负载均衡配置说明如下图:
官网地址:http://nginx.org/en/docs/http/load_balancing.html

我们接下来一个个看。
2.3.1.1轮循(默认)
顾名思义,后台服务器组的各个服务器会一个接着一个,轮流去处理请求。从整体上来看,每台服务器处理的请求数是差不多的。

upstream 块是配置负载均衡的,webs1是后台服务器组名称;
location 块是配置代理/反向代理的(具体见下一个模块)
2.3.1.2.最少连接
那个服务器处理的请求(被连接的)的次数最少,就那个服务器去处理当前这个请求

2.3.1.3.会话持久性
解决session共享问题。适用场景,当你的后台服务器有多个,涉及登录,session验证问题。一个客户端会持续访问一个固定的服务器。

2.3.1.4.一些其他设置
(1) weight
默认为1,将请求平均分配给每台server,例如:
upstream webs1 {
server 192.168.0.101:8081 weight=2;
server 192.168.0.102:8082 weight=2;
server 192.168.0.103:8083 weight=1;
}如果有5各请求,那么这3台服务器从上到下,分别处理请求个数为2、2、1。
(2) max_fails 和 fail_timeout
max_fails默认为1。某台Server允许请求失败的次数,超过最大次数后,在fail_timeout时间内,新的请求将不会分配给这台机器。如果设置为0,Nginx会将这台Server置为永久无效状态,然后将请求发给定义了proxy_next_upstream, fastcgi_next_upstream, uwsgi_next_upstream, scgi_next_upstream, and memcached_next_upstream指令来处理这次错误的请求。
fail_timeout默认为10秒。某台Server达到max_fails次失败请求后,在fail_timeout期间内,nginx会认为这台Server暂时不可用,不会将请求分配给它
max_fails和fail_timeout的使用,如下:
upstream webs1 {
server 192.168.0.101:8081 max_fails=3 fail_timeout=15;
server 192.168.0.102:8082 max_fails=3 fail_timeout=15;
server 192.168.0.103:8083 max_fails=3 fail_timeout=15;
}即,在15秒内,如果某台服务器连续处理请求失败了3次,则这台服务器判定为宕机,请求将不会让这台服务器处理。
(3)backup
备份技机,其他服务器宕机后,才会这台备份机(服务器)。
upstream webs1 {
server 192.168.0.101:8081 max_fails=3 fail_timeout=15;
server 192.168.0.102:8082 max_fails=3 fail_timeout=15;
server 192.168.0.103:8083 backup;
}
当前两台服务器宕机后,请求才会发到第三台服务器上。
(4)down
标识某台服务器不可用,请求不会发到这台服务器。
upstream webs1 {
server 192.168.0.101:8081 max_fails=3 fail_timeout=15;
server 192.168.0.102:8082 down;
server 192.168.0.103:8083 backup;
}
(5)max_conns
限制分配给某台Server处理的最大连接数量,超过这个数量,将不会分配新的连接给它。默认为0,表示不限制。注意:1.5.9之后的版本才有这个配置。
upstream webs1 {
server 192.168.0.101:8081;
server 192.168.0.102:8082;
server 192.168.0.103:8083 max_oount=10;
}
(6)resolve
将server指令配置的域名,指定域名解析服务器。需要在http模块下配置resolver指令,指定域名解析服务。
具体见官方文档:http://nginx.org/en/docs/http/ngx_http_upstream_module.html#resolver
2.3.2 代理/反向代理
一般是在location块中配置的。
2.3.2.1 默认配置
我们先来看看,默认nginx的默认配置,为什么启动nginx后,在浏览器中输入域名(一般是localhost),会出现nginx的欢迎页面呢?
下面是nginx默认的初始nginx.conf文件的部分配置,其中红框中是location块的配置。

root html;
html是一个基本路径(相对路径或者绝对路径)。
index index.html index.htm;
当在浏览器中访问localhost:80或者localhost(端口默认为80)时,是在root配置的基本路径下找index.html 或者 index.htm文件并且响应到页面展示,如果不能展示则去下载该文件。
我们去nginx文件下找html文件下,看能不能找到index.html或者index.htm文件,找到了,如下图:

我们双击index.html,响应页面正好就是我们在刚开始启动nginx时,浏览器中访问localhost时响应的页面,如下图:

2.3.2.2 与upstream配合使用
我们再次回过头来看2.1中的那一个简单的例子。

proxy_pass http://myWebs;
这个location块接收(拦截)的请求(不是localhost:80请求)会去转发给myWebs这个服务器组里面的一台服务器去处理。
两个蓝色框中用到的服务器组名称一定要保持一致(比如,都是myWebs)。
2.3.2.3 其他
loction块的配置还有很多,可以去https://segmentfault.com/a/1190000013781162 查看该文章的“location如何匹配“模块。
3 可能遇到的问题
3.1 nginx配置后,只有一个页面(首页)能正常访问,其他页面全加载不出来
3.1.1描述
当配置完ginx启动后,只有一个页面可以正常访问(一般情况下是登录页,只能登录进系统),接着点击其他页面无反应,打开F2开发者模式,查看请求头,请求路径是:”
http://localhost:80/setPassword.html”,里面的localhost是你nginx配置的域名,80端口是nginx配置的监听端口。
3.1.2 解决
当请求到代理服务器(一般是你的后台服务器,会有多个),不能获取到真实的后台服务器ip,所以就用你配置的域名去请求了。
给location 块里面添加下面代码:
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr; # 获取用户的真实 IP 地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 如下图:

3.2 Nginx报错"no live upstreams while connecting to upstream",错误码502
3.2.1 描述
前提是你的后台服务器有两台(可能你的情况是多台),nginx和web项目部署在同一台服务器上。当你关闭和nginx部署在同一台服务器上的web项目时(人为造成一台服务器故障),再次请求时发现响应页面如下:

打开nginx的logserror.log日志,查看报错信息为“no live upstreams while connecting to upstream”;
页面上F12查看报错“502,bad gateway!“
3.2.2 解决
当你尝试了网上的多种解决方案无果后,试试在 nginx和web项目都部署了那台服务器A访问其他服务器B上的web项目,若还是访问失败。那么恭喜你,问题就要解决了。
你的请求被服务器B的防火墙拦截了,要么关掉B服务器的防火墙,要么设置服务器B防火墙的出入站规则(开放请求所用的端口)
3.3 用nginx进行负载均衡时,web项目的session共享问题
3.3.1 描述
当你的web项目技术很简单,登录的session没有存数据库,也没有存redis。在部署上线时,web项目有多个节点(web项目在多台服务器上启动了)这时用nginx做代理/反向代理,负载均衡时怎么解决登录一台服务器时session共享给所以服务器呢?
最直观的响应就是,当你配置好nginx启动后,发出请求可能会报空指针异常。
3.3.2 解决
- 方案一,修改web项目代码,把session入库(reids或关系型数据库),这样成本大不采取;
- 方案二,注释验证session的拦截器,任何人不登录都可以访问该网站了,出于安全性的考虑,不可取;
- 方案三,负载均衡时,采用ip_hash策略,固定的客户端访问固定的服务端,完美解决session共享问题;
3.4 服务器上配置好nginx后,用两台电脑访问,总是命中后台某一个服务器
3.4.1 描述
当你用配置好nginx,负载均衡部分采用的ip_hash策略。用局域网内的两台服务器访问服务器(服务器和你不是同一个局域网),发现这两台电脑发出请求命中的后台服务器竟然是一台(往往是upstream节点里面配置的第一台)。这负载均衡也没生效啊,是什么原因呢?
当服务器部署的网和你的客户端访问的网是同一个网时,一般出现上述问题。
3.4.2 解决
事实上这是正常现象,不需要解决。
因为,在nginx使用ip_hash这种策略时,内部是使用ip的前三段去做关键字进行hash处理的。当你用同一局域网当的两台电脑(这两台电脑ip的前三段是一样的)去访问时就会始终命中后台的某一台服务器。
当你一台电脑连你的局域网,一台连手机热点,再次访问服务器时,就会发行请求命中到了不同的服务器上。
3.5 要对某些代理做验证
3.5.1 描述
现在有个location节点需要做验证,输入账户密码才能访问,该节点如下:

根据上面配置可以看到nginx监听端口:80,域名:localhost。访问/NginxStatus时需要验证,验证文件是nginx-1.16.1/conf/htpasswd。
3.5.2 解决
现在我们在conf文件夹下新建一个htpasswd文件,不要后缀名(可以先新建文本文件,再删掉后缀名)。文件内容如下:

可以发现用户名是cdd,密码是123456。配置好后,我们重启nginx,在浏览器中输入localhost:80/NginxStatus,回车,响应页面如下要输入账户和密码。

我们用户名输入cdd,密码输入:123456,点击登录,响应页面如下:

4 参考资料
nginx中文文档:
https://www.nginx.cn/doc/index.html
nginx局域网中使用ip_hash策略,总是命中后台某一台服务器:
https://blog.csdn.net/sd4493091/article/details/54894479?utm_source=itdadao&utm_medium=referral
https://www.linuxidc.com/Linux/2014-02/96868.htm
linux环境下安装nginx:https://jingyan.baidu.com/article/e3c78d648516243c4c85f5c2.html
nginx的使用及配置:https://blog.csdn.net/finnson/article/details/82461600
前端nginx使用札记:https://segmentfault.com/a/1190000013781162
nginx负载均衡配置:https://blog.csdn.net/xyang81/article/details/51702900
nginx语句含义:https://www.cnblogs.com/knowledgesea/p/5175711.html