jtwang7 / React-Note

React 学习笔记
8 stars 2 forks source link

React 前后端项目部署上线记录 #16

Open jtwang7 opened 3 years ago

jtwang7 commented 3 years ago

全栈 - 项目部署上线流程

项目部署前,你需要满足以下几点要求:

  1. 一个前端项目 (后端项目)
  2. 一个域名
  3. 一台云服务器

域名 AND 服务器

如果你没有属于自己的域名或云服务器,请购买服务器的购买和配置✅ 本人域名和服务器均在腾讯云上购买,购买流程按照提示来就行。 有几点需要注意的是:

  1. 重置服务器密码(重置后ssh远程连接默认通过密码登陆)

    tips. Mac 系统可以下载 FileZilla 来可视化文件传输

  2. 配置服务器防火墙:服务器会默认开放 443(https) / 80(http) / 22(linux) / 3389(windows) 端口。前两个是协议默认端口,后两个是远程连接的默认端口。除默认端口外,后续我们会用 nginx 来代理服务器,因此也要对服务器端口开放做相应配置。

    假设 nginx 监听的是 800 端口,请务必在服务器防火墙中开放该端口,否则无法访问。也可以在 nginx 中配置相应监听端口为 80(http) 或 443(https),这样就不必在访问网址时添加端口了。

  3. 网站搭建指引:注册域名 - 网站备案 - 域名解析 - 安装SSL证书

    注册域名:购买域名并实名认证 网站备案:国内服务器建站需要备案(购买服务器后隔几天才可以备案)。国外服务器不需要,例如 github 的服务器,博客若由 github 代理则不需要备案 域名解析:将你购买的域名解析绑定到你的服务器上 安装SSL证书:获取证书文件,开启 HTTPS 加密传输。

服务器配置

Node.js 安装请参考 linux安装nodejs

安装 nginx

在 CentOS 服务器上的 Nginx 的安装请参考 Nginx 安装流程

⚠️:Nginx 是安装在服务端而不是客户端,因为 Nginx 代理的是服务端,客户端只需要发送请求,剩下的工作都交由服务端的 Nginx 代理,再由 Nginx 将请求分发到它所管理的各个服务器中。

Nginx 安装完毕后,开启自启动,打开防火墙,设置 HTTPS,并配置相应的 nginx.conf 文件,重新加载配置文件后,可以在客户端输入对应服务器的域名或 ip 地址进行访问,若成功显示访问页面,则表明安装和配置都没有问题。若显示 403 Forbidden,请移步 Nginx 访问 403 Forbidden 查看解决方法。

请确保 Nginx 的启动用户和工作用户相同,否则返回 403

nginx.conf 配置

nginx.conf 的配置请参考:

关键在于 server 模块和 location 模块的配置: server 模块中配置本模块所管理请求的端口和域名(或 IP)信息,location 模块则具体管理目标文件在服务器中的存储路径,以便请求匹配成功后 Nginx 可以在服务器中找到并返回。 以下是本人 server 模块以及 location 模块的一些配置示例:

server {
    listen        80; // 监听端口(HTTP 默认 80 端口)
    server_name   1.117.223.88; // 监听 ip (也可以是域名)
    error_page    404 /404.html;
    location / { // location 匹配部分
            root    /usr/share/nginx/html; // 目标文件所在路径
            index   index.html index.htm; // 目标文件名
    }
}

前端项目上传

以 react 项目为例,通过 npm run build 将项目文件打包,默认生成一个 build 文件夹,这就是我们所需要的打包文件。 将该文件上传至服务器的任意路径(可借助一些可视化上传工具,例如 Xftp,FileZilla 等),一般放在 /root 文件夹及其子目录下。然后将该项目配置到 nginx.conf 中:

此处配置的是 HTTPS,一些额外的添加均为参考模版自带。

# picture-wall
server {
    listen       443 ssl http2;  // 监听端口 (HTTPS 默认 443 端口,ssl http2 是 nginx.conf 模版自带的)
    listen       [::]:443 ssl http2;
    server_name  xxx.com; // 监听域名

    location / { // 匹配规则
            root    /root/picture-wall/build/; // 项目文件路径
            index   index.html index.htm; // 目标返回文件名
    }

    // nginx.conf 关于 HTTPS 的一些默认配置
    ssl_certificate "/etc/nginx/nginx.crt"; // 用 openssl 生成,并填写相应路径,参考 nginx 安装流程
    ssl_certificate_key "/etc/nginx/nginx.key"; // 用 openssl 生成,并填写相应路径,参考 nginx 安装流程
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout  10m;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;

    error_page 404 /404.html;
        location = /40x.html {
    }

    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }
}

项目文件路径通过 cd 到具体项目文件 (此处为 index.html) 处,输入命令 pwd,返回的就是该文件所在的路径。 配置完成后保存退出,并重新加载 nginx 以更新 nginx.conf 配置即可。 访问 https://你的域名:443 即可看到你的项目被显示在网页上了!

jtwang7 commented 3 years ago

Mac 系统下 nginx 安装流程

参考文章:Mac下安装nginx

一步到位的安装教程,简单易懂

前提

确保你电脑上有 homebrew (mac 的包管理工具)

国内通过 homebrew 官网安装大概率不成功,若失败请移步 homebrew 安装流程

常用 brew 命令

Step1. 安装依赖

nginx 参考文档中提到需要 1.1.3 以上版本的 zlib,4.4 以上版本的 pcre,x.x 以上版本的 openssl 因此,请在终端执行下述命令:

可通过 brew info xxx 来检查各个依赖是否安装成功

Step2. 安装 nginx

nginx 有多个类型版本,建议安装最全版 nginx-full。

  1. 首先安装 brew 的第三方仓库:brew tap denji/nginx
  2. 安装 nginx 同时添加 echo 模块(该模块不是必须的):brew install nginx-full --with-echo-module

    如果之前使用 brew 安装过 nginx,那么安装 nginx-full 时可能会报错,这时需要执行 brew unlink nginx 解除关联,然后再安装 nginx-full

Step3. 检查 nginx 是否安装成功

终端输入 brew info nginx,打印结果如下:

几点比较重要的信息:

  1. nginx: stable x.xx.x:版本号
  2. HTTP(S) ... Not installed:还未部署 HTTP(S)
  3. Dependencies:依赖是否安装 (此处 openssl,pcre 均☑️,说明安装成功)
  4. Docroot:文档根目录,不同计算机根目录可能不同。(本人 mac 中根目录在 /opt/homebrew/var/www 下)
  5. The default port has been set in /opt/homebrew/etc/nginx/nginx.conf to 8080 so that nginx can run without sudo.:重要信息点是 a. nginx.conf 配置文件路径在 /opt/homebrew/etc/nginx/nginx.conf 下;b. 默认端口设置为 8080,不需要 mac 的 sudo 权限就可启动
  6. nginx will load all files in /opt/homebrew/etc/nginx/servers/.:nginx 会加载 /opt/homebrew/etc/nginx/servers/ 下的所有资源。
  7. brew services start nginx:nginx 的启动方式,也可以直接输入 nginx 启动

Step4. 配置 https

为了代理https请求,我们需要生成一套证书,这里使用openssl来生成: openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout nginx配置文件存储路径/nginx.key -out nginx配置文件存储路径/nginx.crt 示例: openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout /opt/homebrew/etc/nginx/nginx.key -out /opt/homebrew/etc/nginx/nginx.crt

注意:ssl 证书的存放路径为 nginx 配置文件路径,本机 nginx 配置文件的存储路径为 /opt/homebrew/etc/nginx/,可通过 brew info nginx 查看

生成 SSL 证书后,将 nginx 配置(路径为/opt/homebrew/etc/nginx/nginx.conf)中的 ssl 证书路径(位于 server https 模块下)替换为命令中生成的证书路径即可。

Step5. 启动 nginx

执行 brew services start nginx 或者 nginx 启动 nginx 服务 进入浏览器,输入 http://127.0.0.1:8080,若成功访问,说明 nginx 的 http 服务成功启动。 输入 http://127.0.0.1:443,若成功访问,说明 nginx 的 https 服务启动成功。

nginx 相关命令

jtwang7 commented 3 years ago

Mac 命令式修改文件

  1. 打开终端,切换至目标文件(夹)目录下:cd 文件(夹)路径。举例:cd /opt/abc/
  2. 进入编辑模式:vim xxx.xxx。举例:vim nginx.conf
  3. 开启 INSERT 模式:i
  4. 修改完成后,ESC 退出 INSERT 模式
  5. 退出编辑模式并保存:shift + : 然后输入 wq
jtwang7 commented 3 years ago

nginx 及其配置项

参考文章:

什么是 nginx

Nginx (engine x) 是一个轻量级高性能的 HTTP 和反向代理服务器,同时也是一个通用代理服务器 (TCP/UDP/IMAP/POP3/SMTP),最初由俄罗斯人Igor Sysoev编写。它采用了事件驱动的异步非阻塞处理方式框架,这让其具有极好的IO性能,时常用于服务端的反向代理和负载均衡。

在工作上,由于工作平台和语言的原因,对于大部分前端,更倾向于用Nodejs来搭建服务器,进而实现一些需求,对Nginx有天然的抗拒感。的确,Nginx中的绝大部分功能,如果单纯的使用Node.js也可以满足和实现。但实际上,Nginx和Node.js并不冲突,都有自己擅长的领域:Nginx更擅长于底层服务器端资源的处理(静态资源处理转发、反向代理,负载均衡等),Node.js更擅长于上层具体业务逻辑的处理 (例如接口的编写)。两者可以实现完美组合,助力前端开发。

反向代理

什么是反向代理? 互联网应用基本都基于CS基本结构,即client端和server端。代理其实就是在client端和真正的server端之前增加一层提供特定服务的服务器,即代理服务器。 在理解反向代理前,我们先了解下正向代理。翻墙软件实际上就是一个正向代理工具,它会把访问墙外服务器 server 的网页请求,代理到一个可以访问该网站的代理服务器 proxy,这个代理服务器 proxy 把墙外服务器server上的网页内容获取,再转发给客户。流程图如下:

在正向代理中,客户端和代理服务器处于一个局域网中,可以直接互相访问,因此正向代理服务器可以接受多个客户端的请求;接受请求后,代理服务器通过代理用户端的请求来向域外服务器请求响应内容。 代理服务器既可以联系客户端,又可以联系服务端,因此它扮演的实际上就是一个“代购”的角色,将客户端的请求转达给服务端,然后从服务端获取结果后传递给客户端。

在反向代理中,客户端向服务端发送的请求,会先被代理服务器proxy接收,这个代理服务器将把请求代理到和自己属于同一个LAN(局域网)下的内部服务器上。与正向代理不同的是,反向代理的对象不是客户端而是服务端。反向代理服务器向客户端提供了一个统一的代理入口,客户端的请求,都先经过这个proxy服务器,至于在内网真正访问哪台服务器内容,由这个proxy去控制,因此,客户端经过反向代理,是无法选择具体请求哪台服务器的。流程图如下:

代理服务器和真正server服务器可以直接互相访问,属于一个LAN(服务器内网);代理对用户是透明的,即无感知。不论加不加这个反向代理,用户都是通过相同的请求进行的,且不需要任何额外的操作;代理服务器通过代理内部服务器接受域外客户端的请求,并将请求发送到对应的内部服务器上。

反向代理的优势:

  1. 安全及权限。使用反向代理后,客户端将无法直接通过请求访问真正的内容服务器,而必须首先通过Nginx。可以通过在Nginx层上将危险或者没有权限的请求内容过滤掉,从而保证了服务器的安全。
  2. 负载均衡。例如一个网站的内容被部署在若干台服务器上,可以把这些机子看成一个集群,那么Nginx可以将接收到的客户端请求“均匀地”分配到这个集群中所有的服务器上(内部模块提供了多种负载均衡算法),从而实现服务器压力的负载均衡。此外,nginx还带有健康检查功能(服务器心跳检查),会定期轮询向集群里的所有服务器发送健康检查请求,来检查集群中是否有服务器处于异常状态,一旦发现某台服务器异常,那么在以后代理进来的客户端请求都不会被发送到该服务器上(直到后面的健康检查发现该服务器恢复正常),从而保证客户端访问的稳定性。

nginx.conf 配置文件

参考:从一份配置清单详解Nginx服务器配置

nginx.conf 配置文件结构

主要分为:

  1. 全局块 该部分配置主要影响Nginx全局,通常包括下面几个部分:

    • 配置运行Nginx服务器用户(组)
    • worker process数
    • Nginx进程PID存放路径
    • 错误日志的存放路径
    • 配置文件的引入
  2. events块 该部分配置主要影响Nginx服务器与用户的网络连接,主要包括:

    • 设置网络连接的序列化
    • 是否允许同时接收多个网络连接
    • 事件驱动模型的选择
    • 最大连接数的配置
  3. http块

    • 定义MIMI-Type
    • 自定义服务日志
    • 允许sendfile方式传输文件
    • 连接超时时间
    • 单连接请求数上限
  4. server块

    • 配置网络监听
    • 基于名称的虚拟主机配置
    • 基于IP的虚拟主机配置
  5. location块

    • location配置
    • 请求根目录配置
    • 更改location的URI
    • 网站默认首页配置

拿到 nginx.conf 文件后,我们主要对 server 和 location 块进行配置

server / location 模块

此处只列举常用配置参数,其余配置项可参考 从一份配置清单详解Nginx服务器配置

# HTTP server
server {
    listen    8080; // 配置网络监听
    server_name    localhost; // 配置虚拟主机(服务端)
    error_page    404    /404.html;
    location  /  {
        root   html; // 配置请求根目录路径
        index  index.html index.htm; // 配置网站默认入口文件
    }
}
# HTTPS server
server {
    listen       443 ssl;
    server_name  localhost;

    ssl_certificate      /opt/homebrew/etc/nginx/nginx.crt; // ssl 证书 - 通过 openssl 生成
    ssl_certificate_key  /opt/homebrew/etc/nginx/nginx.key; // ssl 证书 - 通过 openssl 生成

    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;
    }
}

配置网络监听

指令格式:

实际举例:

listen 192.168.31.177:8080; # 监听具体IP和具体端口上的连接
listen 192.168.31.177;      # 监听IP上所有端口上的连接
listen 8080;                # 监听具体端口上的所有IP的连接

配置虚拟主机

虚拟主机可以通过“域名”或“IP地址”指定。

name可以有多个并列名称,而且此处的name支持正则表达式书写

基于域名配置: 指令格式:server_name name1 name2 ... 实际举例: server_name ~^www\d+\.myserver\.com$ 表示该虚拟主机可以接收类似域名 www1.myserver.com 等的请求而拒绝 www.myserver.com 的域名请求,用正则表达式可以实现更精准的控制

基于IP配置: 指令格式:server_name IP地址

location 配置

指令格式为:location [ = | ~ | ~* | ^~ ] uri {...}

uri分为标准uri和正则uri,两者的唯一区别是uri中是否包含正则表达式

uri前面的方括号中的内容是可选项,解释如下:

配置请求根目录

指令格式为:root path; path:Nginx接收到请求以后查找资源的根目录路径

客户端通过 url 地址访问项目页面,该访问请求会被 nginx 代理,nginx 接收到请求后,会从服务端的根目录路径下开始查找所上传的项目文件。因此,该处所指的资源根目录为云服务器端的目录。

当然,还可以通过alias指令来更改location接收到的URI请求路径,指令为:alias path; # path为修改后的根路径

jtwang7 commented 3 years ago

nginx 中 server_name / loaction / root 的关系

参考文章:nginx 中location和root,你确定真的明白他们关系?

nginx 是如何通过 location 和 root 查找文件的

nginx 配置文件中,在 server 模块内,我们设置了 server_name 和 listen 两个参数,来限制“域名”和“端口”。location 模块位于 server 模块内,通过相应路径参数,来定位服务端的入口文件(一般为 index.html)。

现假设一个网站访问了域名 https://www.baidu.com,此时便会触发客户端请求,nginx 代理了该请求。该请求为 HTTPS 协议,www.baidu.com 域名,默认 443 端口。根据上述信息,它会定位到相应的 server 模块。但是,想要让客户端显示网页,nginx 需要从服务端中找到相应的 index.html 页面并返回,而这一步的路径定位就依靠了 location 和 root 中所包含的两个路径参数。

项目打包后会上传到服务端的某个位置进行存储,不一定存放在服务端的根目录上。因此,配置 location 和 root 来指明 index.html 的位置是非常有必要的。

root / alias

nginx 指定文件路径有两种方式:

  1. root
  2. alias

root 与 alias 主要区别在于 nginx 如何解释 location 后面的 uri,这会使两者分别以不同的方式将请求映射到服务器文件上。

举例:

root

location ^~ /t/ {
     root /www/root/html/;  // 当使用 root 时,路径最后的 '/' 可加可不加,因为 root 后面会拼接上 location 路径
}

假设 nginx 接收到了一个 URI 请求 /t/index.html,发现 URI 请求匹配了 location 的 ^~ /t/ 规则时,web服务器将会返回服务器上的 /www/root/html/t/index.html 的文件。

alias

location ^~ /t/ {
 alias /www/root/html/new_t/;
}

如果一个请求的URI是 /t/index.html 时,web服务器将会返回服务器上的 /www/root/html/new_t/index.html 的文件。注意这里是new_t,因为 alias 会把 location 后面配置的路径丢弃掉,把当前匹配到的目录指向到指定的目录。 注意:

  1. 使用alias时,目录名后面一定要加"/"。
  2. alias在使用正则匹配时,必须捕捉要匹配的内容并在指定的内容处使用。
  3. alias只能位于location块中。(root可以不放在location中)

总结

location 模块后面跟着的路径信息,可以理解为 nginx 接受 URI 请求后定位相应模块的匹配规则。当 nginx 匹配到相应 location 块后,它就会根据 root / alias 所包含的路径信息,来拼接生成最终的文件路径。 简单理解,nginx 通过 location 和 root 确定 index.html 入口文件路径的方式,就是 root/loction 拼接出 index.html 所在的文件夹路径,然后 nginx 返回 index.html 到客户端。

jtwang7 commented 3 years ago

nginx 中的 proxy_pass 配置项

参考文章:

前言

之前提到了 nginx 中关于 location,root 以及 alias 的配置及 nginx 使用这些配置项时的匹配流程。在 nginx location 模块中,其实还有一个配置项同 root / alias 类似,它就是 proxy_pass (代理转发)。proxy_pass 指令提供给了 nginx 一个很重要的能力- 跨域,nginx 凭借它,可以从客户端的域名访问到服务端的域名,然后将跨域结果返回给前端。

proxy_pass

proxy_pass 配置项是用来设置代理服务器地址的 (效果有点类似于路由的重定向功能)。配置项的值可以是主机名称,IP地址加端口号等形式。基本语法如下所示: proxy_pass: URL;

server {
  listen 80;
  server_name xy.xxx.com; // 接口的域名
  access_log  /data/www/logs/nginx/access.log main;
  add_header Access-Control-Allow-Origin http://xy.xxx.com; // 允许的域名跨域
  add_header Access-Control-Allow-Credentials true;
  include nginx_xxx.conf;
  location / {
    proxy_pass http://192.168.1.212:8136;
    include nginx_proxy.conf;
  }
  error_page   500 502 503 504  /502.html;
  location = /50x.html {
    root   html;
  }
}

以上述 server 模块配置为例,结合前面所学的知识,我们可以知道该模块所代理的(端口|域名|),除此之外,在 location 模块中还设置了 proxy_pass 代理转发,当 nginx 接受的 uri 地址匹配上 / 时,nginx 会将该请求“重定向”到设置的转发地址上去。也就是说,本次请求访问最终得到的结果是从 http://192.168.1.212:8136/index.html 返回的。

关于 proxy_pass 绝对路径和相对路径

在 nginx 中配置 proxy_pass 代理转发时,如果在 proxy_pass 后面的 url 末尾加 /,表示绝对根路径;如果没有 /,表示相对路径,把匹配的路径部分也给代理走。

示例: 假设下面四种情况分别用 http://192.168.1.1/proxy/test.html 进行访问。

1.

location /proxy/ {
    proxy_pass http://127.0.0.1/;
}

结果:设置的是绝对路径,因此不会拼接上 location 所匹配的那部分路径 /proxy/,代理到 http://127.0.0.1/test.html

  1. (相对于第一种,最后少一个 / )

    location /proxy/ {
    proxy_pass http://127.0.0.1;
    }

    结果:设置的是相对路径,最终代理路径会拼接上 location 所匹配的路径,代理到URL:http://127.0.0.1/proxy/test.html

  2. location /proxy/ {
    proxy_pass http://127.0.0.1/aaa/;
    }

    结果:nginx 匹配到了 /proxy/,然后跨域访问绝对路径 http://127.0.0.1/aaa/,最终代理到URL:http://127.0.0.1/aaa/test.html

4.(相对于第三种,最后少一个 / )

location /proxy/ {
    proxy_pass http://127.0.0.1/aaa;
}

结果:nginx 匹配到了 /proxy/,然后跨域访问 http://127.0.0.1/aaa,返回:http://127.0.0.1/aaatest.html

此处由于域名后面有更深层次的路径,所以 /proxy/不会被拼接到 /aaa 后面,而是直接替换。