Nginx 是 HTTP 服务器,可以用来做负载代理。
代理配置
1. 最简反向代理配置
在 http
节点下,使用 upstream
配置服务地址,使用 server
的 location
配置代理映射。
upstream my_server {
server 10.0.0.2:8080;
keepalive 2000;
}
server {
listen 80;
server_name 10.0.0.1;
client_max_body_size 1024M;
location /my/ {
proxy_pass http://my_server/;
proxy_set_header Host $host:$server_port;
}
}
通过该配置,访问nginx
地址http://10.0.0.1:80/my
的请求会被转发到my_server
服务地址http://10.0.0.2:8080/
。
需要注意的是,如果按照如下配置:
upstream my_server {
server 10.0.0.2:8080;
keepalive 2000;
}
server {
listen 80;
server_name 10.0.0.1;
client_max_body_size 1024M;
location /my/ {
proxy_pass http://my_server;
proxy_set_header Host $host:$server_port;
}
}
那么,访问nginx
地址http://10.0.0.1:80/my
的请求会被转发到my_server
服务地址http://10.0.0.2:8080/**my**
。
这是因为proxy_pass
参数中如果不包含url
的路径,则会将location
的pattern
识别的路径作为绝对路径。
2. 重定向报文代理
即便配置了nginx
代理,当服务返回重定向报文时(http code为301或302),会将重定向的目标url地址放入 http response
报文的header
的location
字段内。
用户浏览器收到重定向报文时,会解析出该字段并作跳转。此时新的请求报文将直接发送给服务地址,而非nginx
地址。
为了能让nginx
拦截此类请求,必须修改重定向报文的location
信息。
location /my/ {
proxy_pass http://my_server;
proxy_set_header Host $host:$server_port;
proxy_redirect / /my/;
}
使用proxy_redirect
可以修改重定向报文的location
字段,例子中会将所有的根路径下的url
代理到nginx
的/my/
路径下返回给用户。
比如服务返回的重定向报文的location
原始值为/login
,那么经过nginx
代理后,用户收到的报文的location
字段为/my/login
。此时,浏览器将会跳转到nginx
的/my/login
地址进行访问。
需要注意的是,服务返回的重定向报文的location
字段有时会填写绝对路径(包含服务的ip/域名和端口),有时候会填写相对路径,此时需要根据实际情况进行甄别。
location /my/ {
proxy_pass http://my_server;
proxy_set_header Host $host:$server_port;
proxy_redirect http://my_server/ http://$host:$server_port/my/;
}
上述配置便是将my_server
服务的根路径下的所有路径代理到nginx
地址的/my/
路径下。
当nginx
配置只有一个server
时,http://$host:$server_port
前缀可以省略。
3. 报文数据替换
使用nginx
代理最牛(dan)逼(sui)的情况就是http
响应报文内写死了服务地址或web
绝对路径。
写死服务地址的情况比较少见,但也偶尔存在。
最棘手的是写死了web
绝对路径,尤其是绝对路径都没有公共前缀。
举个例子来说:
一般的web页面会包含如下类似路径:
/public
:用于静态页面资源,如js脚本/public/js
,样式表/public/css
,图片/public/img
等。/static
:和/public
类似。/api
:用于后台服务API接口。/login
:用于登录验证。- 其他。
对于这样的服务,可能的代理配置如下:
location /my/ {
proxy_pass http://my_server/;
proxy_set_header Host $host:$server_port;
proxy_redirect / /my/;
}
location /login/ {
proxy_pass http://my_server/public;
proxy_set_header Host $host:$server_port;
}
location /public/ {
proxy_pass http://my_server/public;
proxy_set_header Host $host:$server_port;
}
location /api/ {
proxy_pass http://my_server/api;
proxy_set_header Host $host:$server_port;
}
由于web
页面或静态资源内写死了类似的绝对路径,那么对于用户来说,通过页面内的链接进行跳转时,都会请求到nginx
服务对应的路径上。一旦存在另一个服务也包含类似的路径,也需要nginx
进行代理,那么矛盾就出现了:访问nginx的同一个路径下的请求究竟转发给哪一个服务?
要解决这个问题,必须在用户收到报文前,将报文的数据中包含的绝对路径都添加统一的前缀,如/my/public
,/my/api
,/my/login
,这样nginx代理配置则可以简化为:
location /my/ {
proxy_pass http://my_server/;
proxy_set_header Host $host:$server_port;
proxy_redirect / /my/;
}
location /other/ {
proxy_pass http://other_server/;
proxy_set_header Host $host:$server_port;
proxy_redirect / /other/;
}
nginx
的ngx_http_sub_module
模块提供了类似的报文数据替换功能,该模块默认不会安装,需要在编译nginx时添加--with-http_sub_module
参数,或者直接下载nginx
的 rpm 包。
使用sub_filter
对数据包进行替换的语法如下:
location /my/ {
proxy_pass http://my_server/;
proxy_set_header Host $host:$server_port;
sub_filter 'href="/' 'href="/my/';
sub_filter 'src="/' 'src="/my/';
sub_filter_types text/html;
sub_filter_once off;
}
上述配置会将/my/
下的所有响应报文内容的href="/
替换为href="/my
,以及src="/
替换为src="/my
,即为所有的绝对路径添加公共前缀。
注意,如果需要配置多个sub_filter,必须保证nginx是1.9.4版本之上的。
配置 SSL 证书
- 准备用于 Nginx 的 SSL 证书,可以从各大云服务商免费获取 SSL 证书。
- 证书上传至目标服务器,配置文件(下述举例)
http{ server{ #监听443端口 listen 443; #对应的域名,把baofeidyz.com改成你们自己的域名就可以了 server_name baofeidyz.com; ssl on; #从腾讯云获取到的第一个文件的全路径 ssl_certificate /etc/ssl/1_baofeidyz.com_bundle.crt; #从腾讯云获取到的第二个文件的全路径 ssl_certificate_key /etc/ssl/2_baofeidyz.com.key; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; ssl_prefer_server_ciphers on; #这是我的主页访问地址,因为使用的是静态的html网页,所以直接使用location就可以完成了。 location / { #文件夹 root /usr/local/service/ROOT; #主页文件 index index.html; } } }
502 错误排查
# 查看当前的 PHP FastCGI 进程数是否够用
netstat -anpo | grep "php-cgi" | wc -l
# 查看 Nginx 并发
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a,S[a]}'
# SYN_RECV //一个连接请求已经到达,等待确认
# ESTABLISHED //正常数据传输状态/当前并发连接数
# FIN_WAIT2 //另一边已同意释放
# ITMED_WAIT //等待所有分组死掉
# CLOSING //两边同时尝试关闭
# TIME_WAIT //另一边已初始化一个释放
# LAST_ACK //等待所有分组死掉
访问 PHP 却下载了页面
# 这是因为 nginx没有设置好,碰到php文件时要传递到后方的php解释器。
# 应该开启 PHP 解释器,定义好解释配置。
service php-fpm start
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000; # php-fpm的默认端口是9000
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
Web Socket 反向代理
如果 websocket 中间有反向代理服务器,是不能直接通信的,需要进行配置。
1、在 nginx.conf 文件中进行 http 配置。
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
}
2、在 http 节点中的 server 中增加胚子。
location / {
proxy_pass http://localhost:8010;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
}
设置 nginx 停止自启动
systemctl disable nginx.service
设置 nginx 自启动
systemctl enable nginx.service
检查配置文件是否正确
nginx -t
启动服务
service nginx restart
service php-fpm restart
配置
yum
安装的 Nginx
配置文件在 /etc/nginx
目录下
安装
yum install nginx -y