Skip to main content

域名注册与云服务器项目部署

Auth: LIU Yilin

概述

本篇文档旨在指导读者如何构建一个完整的后端网络架构,实现至少 2 个NestJS服务在同一个云服务器实例中运行,并能通过域名实现 HTTPS 访问。涉及的技术和服务包括域名注册、CDN、云服务器、Docker、反向代理等。具体内容如下:

  • 域名注册:使用 Namecheap 注册域名
  • CDN 和 SSL/TLS 证书:使用 Cloudflare 提供的 CDN 服务和免费 SSL/TLS 证书
  • 云服务器:使用 Amazon Lightsail 作为云服务器提供商
  • Docker:使用 Docker 容器化应用并将镜像存储在 Docker Hub
  • 反向代理:使用 Nginx 作为反向代理服务器以实现负载均衡和 SSL/TLS 证书配置

为顺利完成本篇文档,读者需要掌握以下背景知识:

  • 基本的网络概念,如 DNS、HTTP/HTTPS、域名和 IP 地址等
  • 基本的 Linux 命令行操作
  • 了解 Docker 及其基本操作
  • 了解 Nginx 及其配置方法
  • 了解 NestJS 框架的基本知识

1. 域名注册

在本段中,我们使用 Namecheap 作为域名注册提供商。要注册一个域名,请按照以下步骤操作:

  1. 访问 Namecheap 官网:https://www.namecheap.com/

  2. 在首页的搜索框中输入您想要注册的域名,然后点击搜索图标或按 Enter 键。

    1.2.1

  3. 如果您选择的域名可用,将看到“添加到购物车”的按钮。点击此按钮将域名添加到购物车。

  4. 之后点击购物车图标,然后点击“Checkout”按钮进入结算页面。

  5. 在结算页面,输入您的支付信息,确认订单详情,并同意相关条款。特别注意的是,可以不选择自动续约,同时也不需要勾选相应的 SSL/TLS,CDN 等增值服务,这些我们在后面会采用其他的方案。完成支付后,您将拥有所选域名的使用权。

  6. 在完成购买后,登录 Namecheap 帐户。在“域名列表”或“域名管理”页面中,您将看到您刚注册的域名。后续,我们将需要在这里对域名进行配置。

    1.6.1

2. 将域名绑定至 Cloudflare

在本段中,我们将通过以下步骤将已注册的域名绑定到 Cloudflare,从而利用 Cloudflare 提供的 CDN 和免费 SSL/TLS 证书服务。

  1. 访问 Cloudflare 官网并注册一个帐户(如果尚未注册):https://www.cloudflare.com/

  2. 登录 Cloudflare 帐户后,点击右上角的“+ 添加站点”按钮。

  3. 输入您在 Namecheap 注册的域名,然后点击“添加站点”按钮。

  4. 大部分情况下选择免费套餐即可满足需求,然后点击“确认计划”按钮。

  5. Cloudflare 将扫描您的域名 DNS 记录。扫描完成后,点击“继续”按钮。

  6. 将 Cloudflare 提供的两个 DNS 名称服务器记录复制下来。稍后,我们需要将这些记录添加到 Namecheap 的域名配置中。

  7. 回到 Namecheap 帐户,进入之前注册的域名的管理页面。找到“域名服务器”或“Name Servers”部分,选择“自定义”或“Custom”。将刚刚从 Cloudflare 复制的两个 DNS 名称服务器记录分别填入,然后点击“保存”或“Save”。

    2.7.1

  8. 返回 Cloudflare,点击“完成”按钮。此时,Cloudflare 可能需要几分钟到几小时来检测 DNS 更改。当检测到更改并成功激活后,您将看到 Cloudflare 上的域名状态显示为“活动”。记得关掉这些 AUTO-RENEW,避免多年后忽然信用卡被扣费。

    2.8.1

现在,您已成功将域名绑定至 Cloudflare,并可以使用其 CDN 和 SSL/TLS 证书服务。

3. 创建并配置 Lightsail 实例环境

在本段中,我们将创建 Amazon Lightsail 实例并配置环境,安装 Docker 并准备部署我们的应用。以下是详细步骤:

3.1 创建 Lightsail 实例

  1. 访问 Amazon Lightsail 官网并登录(如果您还没有 AWS 帐户,请先注册一个):https://aws.amazon.com/lightsail/

  2. 在 AWS Management Console 中,找到“Lightsail”服务,进入 Lightsail 主页面。

  3. 点击“创建实例”按钮。

  4. 选择实例位置。建议选择离目标用户最近的区域以获得较低的延迟。

  5. 选择实例平台。在本文中,我们选择“Linux/Unix”。

  6. 选择实例镜像。我们推荐使用“Amazon Linux 2”,因为它是一个经过优化且易于管理的 Linux 发行版。使用 Ubuntu 也是一个不错的选择。

  7. 选择实例计划。根据您的需求和预算选择合适的计划。对于个人应用或者测试少部分项目,例如测试 API,使用 5 美元的套餐即可。

  8. 为实例命名。输入一个便于识别的实例名称,以便后续管理。

  9. 点击“创建实例”按钮。创建过程可能需要几分钟。完成后,您将在 Lightsail 主页面看到新创建的实例。

    3.1.9.1

3.2 配置 Lightsail 实例环境

在本段中,我们将配置 Amazon Lightsail 实例环境,安装 Docker 并准备部署我们的应用。以下是详细步骤:

  1. 在 Lightsail 主页面上,点击刚刚创建的实例。

  2. 点击“连接”按钮,以通过网页终端连接到实例。您也可以使用 SSH 客户端连接到实例,但需要先下载实例的私钥并进行适当的配置。

    • 点击 connect 栏,下拉,点击 Download default key,这时你会得到连接服务器的秘钥

      3.2.2.1

    • 在终端中进入当前文件夹下,我们通过以下命令通过 SSH 连接服务器

      ssh -i LightsailDefaultKey-ap-northeast-2.pem ec2-user@3.39.224.60
    • 过程中输入 yes,连接成功

      3.2.2.2

  3. 首次登录时,您的用户名为ec2-user。Amazon Linux 2 与传统的 Ubuntu 发行版不同,Amazon Linux 2 使用ec2-user作为默认用户名,而 Ubuntu 通常使用ubuntu作为默认用户名。

  4. 更新实例的软件包。在Amazon Linux 2上,可以使用以下命令:

    sudo yum update -y

    在传统的Ubuntu发行版上,相应的命令是:

    sudo apt-get update && sudo apt-get upgrade -y
  5. 安装 Docker。在Amazon Linux 2上,运行以下命令:

    sudo amazon-linux-extras install docker -y

    在传统的Ubuntu发行版上,安装 Docker 的命令可能会有所不同:

    sudo apt-get install -y docker.io
  6. 启动 Docker 服务并设置为开机自启动。在Amazon Linux 2上,使用以下命令:

    sudo systemctl enable docker
    sudo systemctl start docker

    在传统的Ubuntu发行版上,相应的命令是:

    sudo systemctl enable docker
    sudo systemctl start docker
  7. 将当前用户添加到 Docker 组,以允许在未提供sudo前缀的情况下运行 Docker 命令。在Amazon Linux 2上,使用以下命令:

    sudo usermod -aG docker ec2-user

    在传统的Ubuntu发行版上,相应的命令是:

    sudo usermod -aG docker ubuntu

    完成此操作后,您需要断开并重新连接到实例,以便用户组更改生效。

    现在,您已成功配置了 Amazon Lightsail 实例环境,并安装了 Docker。在接下来的部分,我们将使用 Docker 部署应用程序到这个实例。

  8. Nginx 暂时先不需要安装

3.4 将 Cloudflare 域名绑定到 Lightsail IP

  1. 登录到 Cloudflare 帐户,并选择您刚刚添加的域名。

  2. 点击页面顶部的 "DNS" 标签。

  3. 确保您已删除所有现有的 A 记录(如果有的话)。然后,点击 "Add Record"(添加记录)按钮创建一个新的 A 记录。

  4. 选择记录类型为 "A",在 "Name" 字段中输入 @,以表示这是针对主域名的记录(例如:example.com)。在 "IPv4 address" 字段中输入您的 Amazon Lightsail 实例的公共 IP 地址。配置其他选项,然后点击 "Save"(保存)。

    3.4.4.1

  5. 同样,您可以为其他子域(如 www)创建一个新的 A 记录,将其指向相同的 IP 地址。

  6. DNS 更改可能需要一些时间生效,通常在几分钟到几小时之间。在此期间,您可以继续配置 Lightsail 实例和应用程序。

  7. 完成这些步骤后,您的 Cloudflare 域名将成功绑定到 Amazon Lightsail 实例的 IP 地址,显示如下:

    3.4.7.1


4. 镜像打包、上传和部署并简单测试

在本段中,我们将演示如何在本地打包 Docker 镜像,将其上传到 Docker Hub,并在 Lightsail 实例上部署并进行简单测试。以下是详细步骤:

4.1 本地打包 Docker 镜像

  1. 确保您已安装了 Docker。

  2. 创建一个名为Dockerfile的文件(无文件扩展名)并将其放置在项目根目录中。在这个文件中,您将定义构建镜像所需的所有指令。以下是一个简单的示例,这是第一个 NestJS 容器的镜像,先采用 3000 端口,第二个需要用 3001 端口,避免冲突。值得注意的是,如果包管理器是 npm,需要将 pnpm 改成 npm

    FROM node:18

    RUN npm install -g pnpm

    RUN mkdir -p /app
    WORKDIR /app

    COPY package.json .

    RUN pnpm install

    COPY . .
    RUN pnpm build
    EXPOSE 3000

    CMD [ "pnpm", "start" ]
  3. 由于您使用的是 Apple Silicon Mac,您需要为目标平台指定 x86 架构。在终端中,导航到项目根目录,然后运行以下命令:

    docker buildx build --platform linux/amd64 -t your_dockerhub_username/your_image_name:tag_name .

    对于传统的 x86 架构计算机,您只需运行:

    docker build -t your_dockerhub_username/your_image_name:tag_name .

    注意:请替换your_dockerhub_usernameyour_image_nametag_name为您实际的 Docker Hub 用户名、镜像名称和标签。一定要严格按照该命名规范来命名镜像,不然接下来无法上传镜像到 Docker Hub。

    注意:请替换your_dockerhub_usernameyour_image_nametag_name为您实际的 Docker Hub 用户名、镜像名称和标签。

4.2 上传镜像到 Docker Hub

  1. 在 4.2 开始之前,让我们简要了解一下 Docker Hub 及其特性。Docker Hub 是一个用于分享和管理 Docker 镜像的公共仓库。它允许开发者创建和存储自己的镜像,并可以将这些镜像与他人共享。Docker Hub 提供了一个中心化的资源库,使开发者能够轻松地发布和部署容器化的应用程序。Docker Hub 提供免费的公共仓库,以及付费的私有仓库,以满足不同用户的需求。通过将镜像托管在 Docker Hub 上,您可以简化应用程序的部署过程,无论是在本地还是在云服务器上。如果您还没有 Docker Hub 帐户,请注册一个:https://hub.docker.com/

  2. 在终端中,登录到 Docker Hub:

    docker login

    输入您的 Docker Hub 用户名和密码。

  3. 将本地镜像推送到 Docker Hub:

    docker push your_dockerhub_username/your_image_name:tag_name
  4. 如图所示,镜像为 dianapgrande/server-management-system:

    4.2.4.1

4.3 在 Lightsail 实例上部署并简单测试

  1. 连接到 Lightsail 实例。您可以使用之前的网页终端连接,或使用 SSH 客户端连接到实例。

  2. 拉取 Docker 镜像:

    docker pull your_dockerhub_username/your_image_name:tag_name

    注意:请替换your_dockerhub_usernameyour_image_nametag_name为您实际的 Docker Hub 用户名、镜像名称和标签。

  3. 运行容器:

    docker run -d --name your_container_name -p 3000:3000 your_dockerhub_username/your_image_name:tag_name

    注意:请替换your_container_name。在这行代码中,-d表示容器运行后在后台运行,其运行的日志,不会在现有的实例的界面打印出来。-p表示端口映射,左侧是宿主机端口,右侧是容器端口。3000 端口用于访问容器内 NestJS 的服务。

  4. 因为目前没有配置 SSL/TLS 证书,我们是直接通过 IP 地址访问实例中的服务。通过 Postman 进行测试。

    4.3.4.1

    注意:URL 中要加上 3000 端口才能正常访问 NestJS 服务的 API。

5. SSL/TLS 证书创建并配置 Nginx 等

在本段中,我们将使用 Cloudflare 创建 SSL/TLS 证书,并配置 Nginx 以将请求代理到适当的 NestJS 项目。同时,我们将部署第二个 NestJS 项目并确保它在正确的路径下可用。

5.1 创建 SSL/TLS 证书

  1. 登录到 Cloudflare 帐户,选择您的域名。

  2. 点击"SSL/TLS"选项卡。

  3. 在"Overview"下,将 SSL/TLS 加密模式设置为"Full (strict)"。

    5.1.3.1

  4. 转到"Origin Server"部分,点击"Create Certificate"按钮。

  5. 在"Certificate"对话框中,使用默认设置(RSA 私钥类型,有效期为 15 年),然后点击"Next"。

  6. 将显示生成的证书及私钥。复制到文件并保存在 Lightsail 实例中(例如,cert.pemkey.pem)。在本文档,具体放置位置如下:/etc/ssl/certs/dianapgrande.com.pem; /etc/ssl/private/dianapgrande.com.key;

5.2 更新 NestJS 项目路由前缀

为了使两个 NestJS 项目能够正确地通过预定的 URL 访问,需要在每个项目中更新路由前缀。对于每个项目,请按照以下步骤操作:

  1. src/main.ts文件中,在app.listen()之前,添加以下代码,用适当的路径替换your_route_prefix

    app.setGlobalPrefix("your_route_prefix");

    例如对于第一个项目,your_route_prefix应为server-management-system,对于第二个项目,your_route_prefix应为new-york-city-taxi-trip

    5.2.1.1

  2. 确保在每个项目中保存更改并重新构建 Docker 镜像,然后按照第 4 部分的步骤将新的镜像上传到 Docker Hub。

  3. 在 Lightsail 实例上,停止并删除现有的容器,然后使用更新后的镜像重新运行它们。

    docker stop your_container_name
    docker rm your_container_name
    docker run -d --name your_container_name -p 3000:3000 your_dockerhub_username/your_image_name:updated_tag_name

    对于第二个项目,将端口映射和容器名称更改为适当的值,即 3001。

  4. (OPTIONAL)上文中提到了更新 NestJS 项目路由前缀的方法。这是为了确保项目可以通过指定的子路径访问。在大多数情况下,这应该足够使项目正确运行。但是,还有一些可能需要考虑的额外修改:

    1. 静态资源访问:如果您的项目包含静态资源(如图像、CSS 或 JavaScript 文件),请确保它们的路径正确。通常,您需要在静态资源的路径前添加相应的子路径。您可以在 NestJS 的 StaticModule 中配置这些路径。
    2. 跨域资源共享(CORS):如果您的项目涉及跨域请求,例如从不同的域访问 API,您可能需要更新 CORS 设置。确保您允许的域名和路径与新的子路径相匹配。在 NestJS 中,您可以在创建 AppModule 时使用 enableCors 方法配置 CORS 设置。
    3. API 客户端:如果您的项目有前端应用程序或其他客户端使用 API,确保这些客户端也更新为使用新的子路径。这可能包括更新 API 请求的 URL 和处理跨域请求(如上所述)。
    4. 第三方服务和库:如果您使用了第三方服务或库(如身份验证、日志或分析服务),请确保这些服务的配置已更新,以反映新的子路径。

    这些额外修改可能因项目而异,具体取决于项目使用的功能和技术。请仔细审查项目以确保所有相关路径和设置已正确更新。

5.3 部署第二个 NestJS 项目

  1. 按照第 4 部分的步骤将第二个 NestJS 项目的 Docker 镜像打包并上传到 Docker Hub。

  2. 在 Lightsail 实例上,拉取第二个项目的镜像并运行容器,将端口映射到 3001:

    docker run -d --name your_second_container_name -p 3001:3001 your_dockerhub_username/your_second_image_name:tag_name

5.2 配置 Nginx

  1. cert.pemkey.pem文件上传到 Lightsail 实例的/etc/nginx/ssl/目录(如果不存在,请创建此目录)。您可以使用 SCP 或 SFTP 将文件上传到实例。

  2. /etc/nginx/conf.d目录下创建一个新的配置文件,例如your_domain.conf。将以下内容添加到此文件:

    server {
    listen 80;
    server_name dianapgrande.com www.dianapgrande.com;
    return 301 https://$host$request_uri;
    }

    server {
    listen 443 ssl;
    server_name dianapgrande.com www.dianapgrande.com;

    # SSL 证书和密钥文件的路径
    ssl_certificate /etc/ssl/certs/dianapgrande.com.pem;
    ssl_certificate_key /etc/ssl/private/dianapgrande.com.key;

    # 推荐的 SSL 设置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384';
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;

    location /new-york-city-taxi-trip {
    proxy_pass http://localhost:3001;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_cache_bypass $http_upgrade;
    }

    location /server-management-system {
    proxy_pass http://localhost:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_cache_bypass $http_upgrade;
    }
    }

    注意:

    • 这个文件将配置 Nginx 以侦听 HTTP 和 HTTPS 请求。HTTP 请求将被重定向到 HTTPS。同时,基于请求路径,Nginx 将请求代理到不同的 NestJS 项目。

    • 将该配置文件放在/etc/nginx/conf.d目录下是一种更好的设计模式,因为它可以更轻松地扩展以添加更多的项目。每个项目可以有其自己的配置文件,这使得管理和更新配置变得更加简单。对于未来的项目,只需在/etc/nginx/conf.d目录下创建新的配置文件,或者在同一个文件中location块添加内容即可。

  3. 特别补充:

    Ubuntu系统上,/etc/nginx/conf.d目录的使用方式与Amazon Linux 2略有不同。在 Ubuntu 上,主要的差别可能在于 Nginx 的安装和启动方式。在 Ubuntu 中,您可以使用apt软件包管理器安装 Nginx,而在Amazon Linux 2中,您需要使用yumdnf

    • Ubuntu上启动 Nginx,您需要使用systemctl命令:sudo systemctl restart nginx
    • Amazon Linux 2上启动 Nginx,您需要使用service命令:sudo service nginx restart

    Amazon Linux 2中,默认情况下,Nginx 已经包含了一个指向/etc/nginx/conf.d目录的链接,所以无需手动创建链接。

    在其他系统(如Ubuntu)中,如果需要链接conf.d目录到 Nginx 的主配置文件,可以在/etc/nginx/nginx.conf文件的http块中添加以下内容:

    include /etc/nginx/conf.d/*.conf;
  4. 在完成配置文件的编辑后,请检查 Nginx 配置文件的语法正确性。在命令行中执行以下命令:

    sudo nginx -t

    如果配置文件语法正确,您将看到类似以下的输出:

    nginx: configuration file /etc/nginx/nginx.conf test is successful

    如果发现任何语法错误,请根据提示进行修正。

  5. 最后,有两种方法以应用新的配置。

    • 重新启动 Nginx 服务。这将导致 Nginx 进程完全停止并重新启动。这种方法在应用配置更改时非常有效,但可能会导致在重启过程中短暂的服务中断。

      • 在 Amazon Linux 2 上,执行以下命令:

        sudo service nginx restart
      • 在 Ubuntu 上,执行以下命令:

        sudo systemctl restart nginx
    • 重新加载 Nginx 配置而不中断正在运行的进程。在重新加载配置时,Nginx 服务不会停止,客户端不会遇到连接中断。这是一种平滑更新配置的方法,适用于在生产环境中避免服务中断的情况。是一个更优雅的方法来应用 Nginx 配置更改,因为它在重新加载配置时不会导致服务中断。在 Amazon Linux 2 和 Ubuntu 系统中,可以直接使用此命令。

      • 在 Amazon Linux 2 和 Ubuntu 上,命令完全相同:

        sudo nginx -s reload
  6. 现在,您应该能够通过该 URL 访问第一个 NestJS 项目:

    https://dianapgrande.com/server-management-system/

    通过该 URL 访问第二个 NestJS 项目:

    https://dianapgrande.com/new-york-city-taxi-trip

6. 最终测试

成功访问:

6.1

6.2