在 AWS 上部署生产就绪的 React-Express 应用程序

2025-05-26

在 AWS 上部署生产就绪的 React-Express 应用程序

在本教程中,我将讲解如何使用 AWS 和 EC2 从头到尾部署一个 JavaScript 应用。最近,我和我的搭档Tu Vo推出了我们的应用AlgoAcademy(一个用于复习算法和数据结构的资源),我们想与其他开发者分享我们在此过程中学到的一些经验教训。

按照本教程操作,您将获得一个具有以下内容的应用程序:

  • React 前端,Express 后端
  • 配置为托管您的应用程序的 AWS EC2 服务器
  • 使用 Certbot 进行 SSL 认证
  • 自定义域名
  • 使用 Github Actions/SSM Agent 进行持续部署

    我们在这里提供了一个虚拟 repo 供您参考,但您可以根据需要随意将其应用到您自己的应用程序中。

目录

项目布局

项目布局如下:

mern-app
|__ client/ (React App Frontend)
|  |__ public/
|  |__ src/
|__ scripts/
|__ app.js (Express Backend)
|__ package.json
|__ Dockerfile
|__ docker-compose.yml

Enter fullscreen mode Exit fullscreen mode

预览项目

首先使用以下命令克隆项目:

$ git clone https://github.com/rmiyazaki6499/mern-app.git
Enter fullscreen mode Exit fullscreen mode

mern-app使用 Docker预览项目

安装 Docker

为了使这尽可能简单,我们将使用Docker Compose来创建我们的容器。

  • 如果您还没有 Docker,请先下载(如果您使用的是 Mac 或 Windows):
    https://www.docker.com/products/docker-desktop

  • 或者,如果您使用的是 Linux 发行版,请按照此处的说明操作:
    https://docs.docker.com/compose/install/

  • 要确认您有 Docker Compose,请打开终端并运行以下命令:

      $ docker-compose --version
      docker-compose version 1.26.2, build eefe0d31
    
  • 进入项目目录,使用以下命令构建并运行容器:

      $ cd mern-app/
      $ docker-compose up --build
    
  • 导航到http://localhost:5000,您应该看到类似这样的内容:

    mern-app_react_success

清理容器和镜像

  • 要停止容器运行,请使用<Ctrl-C>两次。
  • 要关闭容器,请使用以下命令:

      $ docker-compose down
    
  • 然后使用以下命令清理我们不再使用的容器和图像:

      $ docker system prune -fa
    
  • 使用以下命令确认容器和图像不再存在:

      $ docker system df -v
    

mern-app在本地预览项目

要在本地机器上预览项目,请按照以下说明操作。

  • 安装 Express 和 React 的依赖项:

      $ cd mern-app/
      $ npm install
      $ cd client/
      $ npm install
    
  • 要运行 React 服务器,请在客户端目录中使用此命令:

      $ npm start
    
  • 如果你访问http://localhost:3000,你应该会看到如下内容:

    mern-app_react

    由于我们尚未启动 Express 服务器,因此 API 调用尚未生效。在另一个终端会话中,在项目根目录运行命令“npm start”。

    mern-app_run_server

    Express 现在已在端口 5000 上运行。切换回http://localhost:3000窗口并刷新页面。您应该在底部看到一条更新的消息:

    mern-app_react_success

    我们现在有两台服务器正在运行:一台用于 React 前端,一台用于 Express 后端。但在本教程中,我们只需要运行一台服务器,因此我们将为 React 运行一个反向代理,并让 Express 提供所有内容。使用 Ctrl-C 停止端口 3000 上的 React 服务器。

  • client目录中运行命令:

      $ npm run-script build
    

    React 将创建应用程序的生产版本,作为静态内容(HTML、CSS 和 JavaScript)的入口点。现在,如果您访问http://localhost:5000,您应该会看到与之前相同的 React 页面!

    该项目目前仅在本地显示,因此为了让互联网上的任何人都能看到它,我们需要一台远程计算机来为我们的应用程序提供服务。

    返回目录


创建 AWS 账户

为什么选择 AWS?

  • 它为新账户提供许多免费服务。
  • 在初创企业甚至企业中非常受欢迎。
  • 我们认为,客户服务支持比竞争对手更胜一筹。
  • 如果您没有帐户,请在此处查看亚马逊提供的分步指南。

    在配置新服务器之前,最佳做法是按照安全状态检查清单中的提示,确保您的帐户尽可能安全。您可以在控制台主页的“IAM”选项卡下找到安全状态检查清单。

    安全状态


创建 AWS EC2 实例

亚马逊的 EC2(弹性计算云)是 AWS 提供的核心产品/服务之一,也是 AWS 许多其他服务的主要构建块。它允许用户租用虚拟计算机来运行自己的应用程序。您可以点击此处了解更多关于 EC2 的信息。

首先进入 AWS 控制台,然后转到“EC2”选项卡。一个简单的方法是通过顶部的“服务”链接,然后在提示符中搜索“EC2”。

我们建议您将 AWS 区域设置为距离您或目标受众最近的区域。但请注意,并非所有 AWS 服务都可用,具体取决于区域。在我们的示例中,我们将使用 us-east-1 区域,因为该区域支持所有 AWS 服务。


EC2 控制台

您应该会看到此屏幕(截至 2020 年 7 月):

ec2_控制台

转到EC2 仪表板上的“正在运行的实例”链接,然后单击“启动实例”。

ec2_running_instances


急性心肌梗死

在此步骤中,AWS 将提示您选择一个 AMI。AMI 是用于配置新实例的模板。在本教程中,我们将使用 Ubuntu 18.04 64 位(免费套餐)。

ec2_choose_ami

接下来,选择t2.micro实例类型。

ec2_choose_instance_type

在下一个屏幕上,继续单击“下一步”,直到看到“配置安全组”选项


安全组

安全组是您的实例的虚拟防火墙。

重要提示: 默认情况下,所有端口均被隐式拒绝,这意味着如果您不添加规则,所有传入/传出流量都将被阻止。安全组也是有状态的,这意味着为某个端口设置入站规则也会影响该端口的出站规则。

使用以下内容设置您的安全组设置:

ec2_安全_组_配置

在“自定义 TCP”的“源地址任意位置”设置会显示警告标志,但在本教程中您可以忽略它。理想情况下,您只希望设置已知的 IP 地址。

类型 端口范围 描述。
SSH 22 通过 SSH 连接到服务器的端口
HTTP 80 向 Web 服务器发出 HTTP 请求的端口
HTTPS 443 向您的 Web 服务器发出 HTTPS 请求的端口
自定义TCP 5000 Express 将运行的端口
自定义TCP 27017 连接 MongoDB 的端口

正如您在屏幕底部附近看到的警告,您不应将SSH 源 IP设置为任何位置。这将造成安全漏洞,因为任何人都可以尝试登录您的服务器。

因此,请确保将其设置为您自己的 IP 地址以及可能需要访问该实例的任何其他 IP 地址。


实例详情

点击“前进”查看并启动,查看实例/AMI 的所有配置。
如果配置正确,请点击“启动”


密钥对

启动实例后,AWS 将提示您创建密钥对。密钥对由 AWS 存储的公钥和您存储的私钥文件组成。它们共同作用,允许您通过非对称加密安全地连接到实例。

如果这是您第一次为项目创建密钥对,请从下拉菜单中选择“创建新密钥对”并为密钥对添加名称。

请务必将密钥对存储在安全的位置。密钥对仅生成一次,如果丢失,AWS 将无法访问。这是您通过 SSH 登录 EC2 实例的唯一途径。

密钥对

下载密钥对后,请确保将.pem文件移动到本地计算机上项目的根目录。

mern-app_root_w_pem

接下来,勾选确认您有权访问私钥对的复选框,然后单击“启动实例”。这将带您进入“启动状态”页面。


访问您的 EC2 实例

单击 EC2 控制台上的“实例”选项卡。

ec2_instance_first_initializing

实例可能需要几分钟才能启动。一旦通过状态检查,实例状态应显示绿色圆圈和“正在运行”状态。


弹性 IP

在登录 EC2 实例之前,首先需要生成一个弹性 IP 并将其关联到您的 EC2 实例。

弹性 IP 是您的 EC2 实例的专用 IP 地址。虽然实例在创建时会分配一个公有 IP 地址,但该 IP 地址是动态的,如果您停止并启动实例,该 IP 地址将不再保留。使用弹性 IP 地址,您可以通过将地址重新映射到账户中的另一个实例来掩盖实例故障。

因此,通过使用弹性 IP,您可以拥有一个专用 IP,互联网用户可以通过该 IP 访问您的实例。这在您稍后分配自定义域名并为服务器添加 SSL 认证时会非常有用。

注意:如果您使用免费套餐,并且您的弹性 IP 未与 AWS 身份关联,AWS 将向您收费。

在 EC2 仪表板上,查看“网络和安全”选项卡并转到“弹性 IP”

elastic_ips_link

它会带你到这里:

elastic_ip_addresses

单击分配弹性 IP 地址

它会带你到这里:

分配IP地址

选择分配

elastic_ip_created

这应该会创建一个弹性 IP。下一步是将该弹性 IP 关联到实例。

在左侧检查 Elastic IP:

  • 前往“操作”
  • 点击关联弹性 IP 地址
  • 确保您的资源类型是实例
  • 搜索您的实例(如果这是您的第一次,它应该是唯一的)
  • 点击关联

    要检查一切是否正确完成,请转到“实例”选项卡,在实例详细信息中,您应该看到弹性 IP。


连接到您的 EC2 实例

在 EC2 控制台中选择实例后,点击顶部附近的“连接”。系统将提示您如何连接到 EC2 实例:

连接到您的实例

  • 将 .pem 文件的权限更改为只读可确保没有人可以修改您的私钥。


EC2 环境设置

登录服务器后,使用以下脚本安装所有项目依赖项:

curl https://gist.githubusercontent.com/cornflourblue/f0abd30f47d96d6ff127fe8a9e5bbd9f/raw/e3047c9dc3ce8b796e7354c92d2c47ce61981d2f/setup-nodejs-mongodb-production-server-on-ubuntu-1804.sh | sudo bash
Enter fullscreen mode Exit fullscreen mode

这将安装以下内容:

  • Node.js 10.x 和 NPM
  • MongoDB 4.0
  • PM2
  • NGINX
  • UFW(防火墙)

    *注意:如果您想更好地理解此脚本中发生的情况,请查看此处的他的博客。


在远程服务器上设置项目

回想一下我们之前在本地机器上对虚拟项目执行的步骤。我们将在 EC2 实例上重复该操作。

% git clone https://github.com/rmiyazaki6499/mern-app.git
% cd mern-app/
% npm install
% cd client/
% npm install
% npm run-script build (or npm build if you have that set up)
Enter fullscreen mode Exit fullscreen mode

启动 PM2

PM2 是 Node.js 应用程序的守护进程管理器,用于管理应用程序并使其保持在线。要查看当前的 PM2 进程,请使用以下命令:

% sudo pm2 status
Enter fullscreen mode Exit fullscreen mode

您可以看到我们尚未运行任何进程。
在我们的 Express 应用的项目根目录下运行:

% sudo pm2 start app.js
Enter fullscreen mode Exit fullscreen mode

注意:我们的应用程序使用 app.js,但您的应用程序可能使用 server.js

要停止 Express,请使用:

% sudo pm2 stop app.js
Enter fullscreen mode Exit fullscreen mode

一旦停止它,再次启动 Express,这次使用标志。

% sudo pm2 start app.js -i max --watch
Enter fullscreen mode Exit fullscreen mode
  • -i max- 允许我们使用最大数量的可用线程来运行进程。由于 NodeJS 是单线程的,因此充分利用所有可用核心将最大限度地提高应用程序的性能。
  • --watch- 允许应用在目录发生任何更改时自动重启。你可以将其视为类似于 nodemon 包,但适用于生产环境。


配置 NGINX

接下来,我们需要配置 NGINX 来重定向 Web 流量。目标是让 API 端点通过 Express 传输,并让 React 代码处理其余部分。

使用以下命令创建一个新的 NGINX 配置文件:

% sudo vim /etc/nginx/sites-available/<YOUR-PROJECT-NAME>
Enter fullscreen mode Exit fullscreen mode

粘贴以下配置并将所有大写部分替换为您自己的项目详细信息:

server {
server_name <YOUR EC2 ELASTIC IP ADDRESS>;

# react app & front-end files
location / {
root /home/ubuntu/<YOUR PROJECT DIRECTORY>/client/build/;
try_files $uri /index.html;
}

# node api reverse proxy // the /api/ is assuming your api routes start with that i.e. www.your-site.com/api/endpoint
location /api/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_http_version 1.1;
proxy_pass http://localhost:5000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Enter fullscreen mode Exit fullscreen mode

重要的:

  • 根行location/需要指向静态文件的服务位置。在本例中,它位于客户端的构建目录中。对于后续步骤,它应该是home/ubuntu/mern-app/client/build/
  • location /api 中的 proxy_pass 必须是 Express 的运行位置(在本例中为localhost:5000,但根据你的配置可能会有所不同)。
    设置好 NGINX 配置后,请确保以下语句没有语法错误:

      % sudo nginx -t
    

    接下来,创建一个从 sites-available 到 sites-enabled 目录的配置文件软链接。此步骤非常重要,因为如果 sites-enabled 中没有任何内容,NGINX 将默认使用位于 /etc/nginx/sites-available/default 的配置设置。

      % sudo ln -s /etc/nginx/sites-available/<YOUR-PROJECT-NAME> /etc/nginx/sites-enabled
    

    使用以下命令重新启动 NGINX Web 服务器:

      % sudo systemctl restart nginx
    

    现在,如果您在浏览器上访问您的弹性 IP,它应该会显示该应用程序!

    返回目录


设置持续部署

持续部署很有用,因为它可以节省您每次更新代码库时必须通过 ssh 进入 EC2 实例的时间。

在这个项目中,我们将使用peterkimzz创建的名为AWS SSM Send-Command的 Github Action来实现自动部署。

Github Actions

Github Actions 是 Github 提供的一项服务,允许你在仓库发生任何变化时执行一些操作,例如运行脚本。在本例中,我们将运行一个脚本来安装最新的依赖项,并在每次向 master 推送更新时重启服务器。

为了使 Github Actions 正常工作,它需要一种与 EC2 实例通信的方式,反之亦然。为此,我们需要通过 IAM 角色分配权限。


创建 SSM 角色

要创建具有权限的IAM 角色AmazonSSMFullAccess

  • 通过https://console.aws.amazon.com/iam/打开 IAM 控制台
  • 在导航面板中,选择“角色”,然后单击“创建角色”
  • 在选择受信任实体的类型,选择AWS 服务
  • 选择使用案例部分中,选择EC2,然后选择下一步: 权限
  • 在附加权限策略页面上,搜索该AmazonSSMFullAccess策略,选择它,然后选择下一步: 审核
  • “审核”页面上,在“角色名称”框中键入名称,然后键入描述。
  • 选择创建角色。系统将返回到“角色”页面。


为 EC2 实例分配 SSM 角色

创建角色

  • 前往EC2 实例仪表板
  • 前往实例链接
  • 突出显示实例
  • 点击“操作”
  • 实例设置
  • 附加/替换 IAM 角色
  • 选择您之前创建的 SSM 角色
  • 点击“应用”保存更改


Github 秘密

由于我们的实例能够使用 SSM 代理,我们需要向它提供一些详细信息,以便它可以访问我们的 EC2 实例。

现在,实例已经能够通过 SSM 代理与 Github 通信,您需要向该存储库提供凭据。Github Secrets 就像存储库的环境变量一样,存储敏感数据,例如 AWS 登录信息。为了使 Github Actions 脚本正常工作,它需要以下三个 Secrets:AWS_ACCESS_KEY、AWS_SECRET_ACCESS_KEY 和 INSTANCE_ID。

AWS 有一篇关于如何查找 AWS 访问密钥和秘密访问密钥的文章,请点击此处。您的实例 ID 显示在 EC2 下的“实例”选项卡上。

首先转到你的 Github 项目仓库:

  • 然后转到您的设置
  • 在左侧菜单中,查找“Secrets”的链接
  • 在那里,使用以下密钥添加三个Secret :

    • AWS_ACCESS_KEY_ID
    • AWS_SECRET_ACCESS_KEY
    • INSTANCE_ID


部署脚本

接下来,让我们创建一个 bash 脚本来下载依赖项并重新启动 NGINX 和 PM2。在 EC2 实例内部,在目录根目录下创建一个 deploy.sh 脚本:

% vim deploy.sh
Enter fullscreen mode Exit fullscreen mode

粘贴以下命令:

#!/bin/sh     
sudo git pull origin master
sudo npm install
cd client
npm install
sudo npm run-script build
cd ..
sudo systemctl restart nginx
sudo pm2 restart all
Enter fullscreen mode Exit fullscreen mode

YAML 文件

AWS SSM Send-Command需要 .yml 文件才能执行。在项目根目录下,创建以下两个目录:

% mkdir -p .github/workflows/
Enter fullscreen mode Exit fullscreen mode

使用以下内容创建一个新的 YAML 文件:

% sudo vim .github/workflows/deploy.yml
Enter fullscreen mode Exit fullscreen mode

粘贴以下内容:

name: Deploy using AWS SSM Send-Command 

on:
    push:
        branches: [master]

jobs:
    start:
        runs-on: ubuntu-latest 

        steps:
            - uses: actions/checkout@v2

        - name: AWS SSM Send Command
              uses: peterkimzz/aws-ssm-send-command@1.0.1
          with:
              aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID  }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY  }}
          aws-region: us-east-1
          instance-ids: ${{ secrets.INSTANCE_ID  }}
          comment: Deploy the master branch
          working-directory: /home/ubuntu/<YOUR PROJECT DIRECTORY>
          command: /bin/sh ./deploy.sh
Enter fullscreen mode Exit fullscreen mode

我们之前提供给 repo 的 Secrets 在该脚本中得到了使用。

.yml 文件有 3 个部分需要配置:

  1. aws-region 应与您创建 EC2 实例时所在的区域相同。(如果您不确定,请查看 EC2 控制台左上角以确认您所在的区域)。
  2. working-directory 应该是您创建 deploy.sh 脚本的目录。
  3. 命令应该是您希望 SSM 代理运行的命令。

完成后,提交并将工作流程推送到您的 repo。


设置您的域名

目前为止,用户可以使用弹性 IP 访问网站。但是,由于弹性 IP 不易记忆和共享,因此我们将配置一个自定义域名。

首先,您需要购买一个域名。域名价格从 10 美元到 1000 美元不等。您可以使用亚马逊的 Route53 服务,也可以选择其他提供商,例如Google DomainsGoDaddy等(我们选择了 Google 的 AlgoAcademy,价格为每年 10 美元)。

您需要配置两个步骤来将项目与自定义域连接起来:

  • 使用 DNS 注册商创建域记录
  • 在 EC2 实例上配置 NGINX 以识别域


创建域记录

让我们开始使用记录配置我们的 DNS:

  • 转到注册商的DNS部分。
  • 查找可以创建自定义资源记录的位置。

像这样设置记录:

姓名 类型 TTL 数据
@ 一个 1小时 您的弹性 IP 地址
万维网 别名记录 1小时 your-awesome-site.com

配置我们的Web服务器

编辑 EC2 实例内的 NGINX 配置文件:

% sudo vim /etc/nginx/sites-available/default
Enter fullscreen mode Exit fullscreen mode

更新server:server_name配置文件的部分:

server {
server_name <YOUR-ELASTIC-IP> your-awesome-site.com www.your-awesome-site.com;
...
Enter fullscreen mode Exit fullscreen mode

保存并重启 NGINX:

sudo sudo systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

DNS 更改最多可能需要 48 小时才能更新,因此您的结果可能会有所不同。更新完成后,访问您的自定义域名应该会将您重定向到您的应用。


HTTPS

安全套接字层 (SSL) 是一种用于在服务器和客户端之间建立加密链接的标准安全技术。到目前为止,我们一直通过 HTTP 提供 Web 内容,这可能很危险,因为服务器和客户端之间发送的数据未加密。如果您正在处理用户登录,并且需要保护密码或信用卡信息等数据,那么在您的应用程序上进行 SSL 认证始终是最佳做法。

在本教程中,我们将使用 letsencrypt.org 的 Certbot,这是一个提供免费 SSL 证书的非营利组织。


安装 Certbot

在浏览器上访问https://certbot.eff.org/instructions

选择您正在使用的软件和操作系统 (OS)。在本例中,我们使用的是 NGINX 和 Ubuntu 18.04 LTS (bionic)。

在您的 EC2 实例中,按照命令行说明进行操作,直到看到以下说明:

% sudo certbot --nginx
Enter fullscreen mode Exit fullscreen mode

运行此命令后,Certbot 将向您显示以下提示:您想要为哪些名称激活 HTTPS?

如果 NGINX 配置正确,它应该显示您的根域以及 www 子域:

1: your-awesome-site.com
2: www.your-awesome-site.com
Enter fullscreen mode Exit fullscreen mode

按 Enter 键激活 HTTP 和 HTTPS。接下来的提示如下:

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the web server configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
Enter fullscreen mode Exit fullscreen mode

选择选项 2,因为这会将所有流量重定向到 HTTPS,并且是最安全的选项。之后,Certbot 将更改 NGINX 配置文件。

注意:一旦您的网站使用 HTTPS,请仔细检查您的 API 调用,并确保它们指向 https:// 端点而不是 http://。这可能是一个不必要的预防措施,但却是一个很容易被忽略的错误。

接下来,转到您的自定义域名。检查您的网址旁边是否有锁形图标。

安全站点

恭喜!您已成功部署 HTTPS Web 应用!


结束语

希望本文能为刚开始接触 Web 开发和 AWS 的朋友们提供一些帮助。如果您遇到任何问题,请随时联系我或Tu,我们将竭诚为您服务。感谢您的阅读!

返回目录

文章来源:https://dev.to/rmiyazaki6499/deploying-a-product-ready-react-express-app-on-aws-62m
PREV
延迟加载图像 - 完整指南
NEXT
通缉:忍者摇滚明星 Code Monkey 黑客独角兽