【Nginx】Nginx部署实战——静态文件+反向代理+均衡负载+Https+Websocket

DDGarfield 2022-06-23 17:58:48 阅读数:51

nginx实战部署静态

Nginx是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的 Web和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。前一段时间听说Igor Sysoev被俄罗斯警方带走了,不知道放出来了没有。言归正常,来看一下nginx的相关配置如何满足我们的日常需求吧。

0.巧克力安装nginx

由于博主手上是windows,所以直接介绍windows下如何安装nginx,如果想知道linux下如何安装,请阅读另一篇文章http://www.randyfield.cn/post/2019-06-01-netcore-centos/#3-nginx

记得CentOs下是不是有yum软件包管理器,那windows下呢?有没有这么方便的东西?答案是肯定的,chocolatey,

chocolatey

  • chocolatey安装
Get-ExecutionPolicy
#如果返回的是Restricted
#就运行如下命令
Set-ExecutionPolicy AllSigned
#或者
Set-ExecutionPolicy Bypass -Scope Process
#接着执行-Paste the follow text into your shell and press Enter
#Wait a few seconds for the command to complete
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
#If you don't see any errors, you are ready to use Chocolatey
  • 安装nginx
choco install nginx

这里有两点需要注意

  1. 通过choco安装nginx,会配套安装NSSM,这是个好东西,可以把nginx注册成windows服务,相当于linux下的SupervisorPM2
  2. 通过choco安装nginx,在最后一次需要您同意选择y[Yes]之前,注意回写的内容是,他将会执行C:\ProgramData\chocolatey\lib\nginx\tools\chocolateyInstall.ps1脚本
 $toolsDir = Split-Path -parent $MyInvocation.MyCommand.Definition
. "$toolsDir\helpers.ps1"
$pp = Get-PackageParameters
$arguments = @{
packageName = $env:chocolateyPackageName
file = "$toolsDir\nginx-1.17.8.zip"
destination = if ($pp.installLocation) { $pp.installLocation } else { Get-ToolsLocation }
port = if ($pp.Port) { $pp.Port } else { 80 }
serviceName = if ($pp.NoService) { $null } elseif ($pp.serviceName) { $pp.serviceName } else { 'nginx' }
}
if (-not (Assert-TcpPortIsOpen $arguments.port)) {
throw 'Please specify a different port number...'
}
Install-Nginx $arguments

注意看port那行,没错,80端口,nginx默认,所以在继续之前,请检查下80端口是否被占用,被占用就会安装失败。怎么办?这是您只需要编辑如上脚本,把80修改为一个未被占用的端口。然后回到命令窗口继续执行,选择Y,就能成功。

比如我修改为

 $toolsDir = Split-Path -parent $MyInvocation.MyCommand.Definition
. "$toolsDir\helpers.ps1"
$pp = Get-PackageParameters
$arguments = @{
packageName = $env:chocolateyPackageName
file = "$toolsDir\nginx-1.17.8.zip"
destination = if ($pp.installLocation) { $pp.installLocation } else { Get-ToolsLocation }
port = if ($pp.Port) { $pp.Port } else { 81 }
serviceName = if ($pp.NoService) { $null } elseif ($pp.serviceName) { $pp.serviceName } else { 'nginx' }
}
if (-not (Assert-TcpPortIsOpen $arguments.port)) {
throw 'Please specify a different port number...'
}
Install-Nginx $arguments

安装好的nginxC:\tools下,配置文件也会默认如下一节的初始化配置

1.初始化配置

#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#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 on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 81;
server_name localhost;
#charset koi8-r;
#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;
}
# 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 81;
# listen 81;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 81 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.部署静态文件

其实初始化就是一个静态文件部署

/ 请求到html文件夹下的 index.html文件

worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 81;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

3.部署Vue构建的静态文件

引用Vue官方文档--”vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。但是这里url会有一个#,那就只能改为history 模式,不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问就会返回 404,这就不好看了。就需要加上try_files uri uri/ /index.html;"

try_files的含义是:首先会匹配uri文件,如果没有去匹配url/文件,如果再没有才会去找/index.html

worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 81;
server_name localhost;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
#proxy_redirect off;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

4.反向代理

同域下部署前后端分离的前端与后端

后端这块可能部署在IIS,Node,Apache等等web服务器,但是我们又不想在前端api请求中硬编码后端url,且如果后端没有添加允许跨越的请求头,浏览器还会阻止。

worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 81;
server_name localhost;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
#proxy_redirect off;
}
location /api/ {
proxy_pass http://ip:port/outside/api/; #反向代理
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_cookie_path /api /;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

即当前端调用接口http://ip:81/api/的请求,都会被反向代理至http://ip:port/outside/api/,如果后台没有做允许跨域的配置,那么这种方式就是欺骗浏览器的解决方案。

5.均衡负载

前后端分离模式的流行,除了解决前后端开发的并行效率问题,解放生产力,解耦,快速定位问题等一系列的优点之外,还有一个就是横向扩展。大并发情况下,可以同时水平扩展前后端服务器,这个扩展就运用了均衡负载。

worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
#api接口部署至3个不同的地方
upstream centerapi{
server 192.168.110.10:82 weight=5;
server 192.168.110.11:82 weight=3;
server 192.168.110.10:83 weight=2;
}
server {
listen 81;
server_name localhost;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
#proxy_redirect off;
}
location /api/ {
proxy_pass http://centerapi/; #反向代理
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $http_host;
proxy_cookie_path /api /;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
#暴露反向代理的地址
#add_header backendIP $upstream_addr;
#add_header backendCode $upstream_status;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

这里的请求api接口nginx就会按照权重把请求分配下面3个url

 upstream centerapi{
server 192.168.110.10:82 weight=5;
server 192.168.110.11:82 weight=3;
server 192.168.110.10:83 weight=2;
}

如果您想测试每次是不是不同的地址,可以让nginx把每次请求转发到的地址返回给浏览器就再加上如下配置

 #暴露反向代理的地址
add_header backendIP $upstream_addr;
add_header backendCode $upstream_status;

6.子系统的融合部署

我司有一个ASP.NET MVC老项目 与前后端分离的新项目的融合

老项目一个平台,包含几个中心,其中一个中心就是新项目

  • /---反向代理至IIS 上部署的ASP.NET MVC主站
  • ^~/center1---前端构建的静态页面,已通过nginx发布
  • ^~/center1/api/---前端使用的api接口,反向代理+均衡负载
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream centerapi{
server 192.168.110.10:82 weight=5;
server 192.168.110.11:82 weight=3;
server 192.168.110.10:83 weight=2;
}
server {
listen 80;
server_name 192.168.110.10;
#主站
location / {
proxy_pass http://192.168.110.10/;#ASP.NET MVC主站 IIS已部署
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
}
#新中心前端
location ^~/center1 {
proxy_pass http://192.168.110.10:81/;#前端构建的静态页面 即下面的配置
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
}
#新中心api
location ^~/center1/api/ {
proxy_pass http://centerapi/;#前端调用的接口
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
server {
listen 81;
server_name localhost;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
#proxy_redirect off;
}
#location /api/ {
#proxy_pass http://centerapi/; #反向代理
#proxy_http_version 1.1;
#proxy_set_header Host $http_host;
#proxy_cookie_path /api /;
#proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection keep-alive;
#proxy_cache_bypass $http_upgrade;
#暴露反向代理的地址
#add_header backendIP $upstream_addr;
#add_header backendCode $upstream_status;
#}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

7.Https

领导说,以前iis就可以让网站通过https访问,新项目也需要,https需要ssl证书,都知道SSL证书只有大公司的证书,人家浏览器才会认,比如Symantec、Entrust、Geotrust,不然就会报不被信任的证书。但是为了迎合领导的需求,还是通过openssl生成了相关的证书。

worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream centerapi{
server 192.168.110.10:82 weight=5;
server 192.168.110.11:82 weight=3;
server 192.168.110.10:83 weight=2;
}
server {
listen 80;
server_name 192.168.110.10;
#ssl开启
ssl on;
ssl_certificate ssl/server.crt;
ssl_certificate_key ssl/server.key;
location / {
proxy_pass http://192.168.110.10/;#ASP.NET MVC主站
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
}
location ^~/center1 {
proxy_pass http://centerapi/;#前端构建的静态页面 即下面的配置
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
}
location ^~/center1/api/ {
proxy_pass http://192.168.110.10:81/;#前端调用的接口
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
server {
listen 81;
server_name localhost;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
#proxy_redirect off;
}
#location /api/ {
#proxy_pass http://centerapi/; #反向代理
#proxy_http_version 1.1;
#proxy_set_header Host $http_host;
#proxy_cookie_path /api /;
#proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection keep-alive;
#proxy_cache_bypass $http_upgrade;
#暴露反向代理的地址
#add_header backendIP $upstream_addr;
#add_header backendCode $upstream_status;
#}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

8.Websocket

系统突然增加了websocket的服务,直接访问ws://ip:port的前端硬编码应该杜绝,所以nginx再次发挥作用。

websocket协议不同于http协议,但是websocket握手是通过http,通过协议提升实现通信方式从http转向websocket。

8.1 ws

worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream centerapi{
server 192.168.110.10:82 weight=5;
server 192.168.110.11:82 weight=3;
server 192.168.110.10:83 weight=2;
}
upstream websocket{
server 192.168.110.10:1443 weight=1;
}
server {
listen 80;
server_name 192.168.110.10;
#ssl on;
#ssl_certificate ssl/server.crt;
#ssl_certificate_key ssl/server.key;
location / {
proxy_pass http://192.168.110.10/;#ASP.NET MVC主站
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
}
location ^~/center1 {
proxy_pass http://centerapi/;#前端构建的静态页面 即下面的配置
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
}
location ^~/center1/api/ {
proxy_pass http://192.168.110.10:81/;#前端调用的接口
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
}
#websocket
location ^~/websocket/ {
proxy_pass http://websocket;#前端调用的接口
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_connect_timeout 4s;
proxy_read_timeout 600;
proxy_send_timeout 12s;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
server {
listen 81;
server_name localhost;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
#proxy_redirect off;
}
#location /api/ {
#proxy_pass http://centerapi/; #反向代理
#proxy_http_version 1.1;
#proxy_set_header Host $http_host;
#proxy_cookie_path /api /;
#proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection keep-alive;
#proxy_cache_bypass $http_upgrade;
#暴露反向代理的地址
#add_header backendIP $upstream_addr;
#add_header backendCode $upstream_status;
#}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

8.2 wss

正常的情况下(http访问网站,接口),上面就完成了配置,但是一旦ssl on,原有的ws,就会导致控制台输出

Mixed Content: The page at ‘https://{域名}.com/‘ was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint ‘ws://{ip}:{port}/‘. This request has been blocked; this endpoint must be available over WSS.
Uncaught DOMException: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.

那么就需要如下配置

worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream centerapi{
server 192.168.110.10:82 weight=5;
server 192.168.110.11:82 weight=3;
server 192.168.110.10:83 weight=2;
}
upstream websocket{
server 192.168.110.10:1443 weight=1;
}
server {
listen 80;
server_name 192.168.110.10;
ssl on;
ssl_certificate ssl/server.crt;
ssl_certificate_key ssl/server.key;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 SSLv2 SSLv3;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://192.168.110.10/;#ASP.NET MVC主站
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
}
location ^~/center1 {
proxy_pass http://centerapi/;#前端构建的静态页面 即下面的配置
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
}
location ^~/center1/api/ {
proxy_pass http://192.168.110.10:81/;#前端调用的接口
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_cache_bypass $http_upgrade;
}
location ^~/websocket/ {
proxy_pass http://websocket;#前端调用的接口
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_connect_timeout 4s;
proxy_read_timeout 600;
proxy_send_timeout 12s;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
server {
listen 81;
server_name localhost;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
#proxy_redirect off;
}
#location /api/ {
#proxy_pass http://centerapi/; #反向代理
#proxy_http_version 1.1;
#proxy_set_header Host $http_host;
#proxy_cookie_path /api /;
#proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection keep-alive;
#proxy_cache_bypass $http_upgrade;
#暴露反向代理的地址
#add_header backendIP $upstream_addr;
#add_header backendCode $upstream_status;
#}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

9.常见问题

Nginx 转发时Header中信息丢失

通过Nginx转发后, Header中access_token信息丢失,经查,发现Nginx在转发时,header中带下划线_的属性默认不转发,需要增加配置:

server {
listen 80;
server_name 127.0.0.1;
#charset koi8-r;
#access_log logs/host.access.log main;
underscores_in_headers on;
}

反向代理,操作超时

反向代理某接口,接口处理业务时间超过60秒,就会报time out的错误.

 proxy_read_timeout 600;

10.参考链接

https://blog.csdn.net/qq_29663071/article/details/80759098

https://www.nginx.com/blog/websocket-nginx/

https://blog.csdn.net/duyiwuerluozhixiang/article/details/100358930

版权声明:本文为[DDGarfield]所创,转载请带上原文链接,感谢。 https://cloud.tencent.com/developer/article/2028960