NestJS生产部署实战:Docker Compose+MySQL+Redis高可用架构

发布时间:2026/7/4 1:47:50

NestJS生产部署实战:Docker Compose+MySQL+Redis高可用架构 1. 这不是又一篇“Hello World”教程而是一份能直接上线的 NestJS 生产部署手册你搜“NestJS 部署教程”刷出来的十篇里八篇停在npm run start:prod剩下两篇教你手动拷贝 dist 文件夹到服务器——这根本不是部署这是给生产环境埋雷。我带团队用 NestJS 做过 7 个中大型 SaaS 后台从日活 2000 的内部工具到支撑 5 万商户的供应链系统所有项目上线前都必须过三关进程不挂、数据不丢、缓存不崩。今天这篇就是把这三关拆开揉碎告诉你怎么用 Docker Compose 把 NestJS、MySQL 和 Redis 真正拧成一股绳。核心关键词一个不落NestJS 是骨架Docker 是容器Docker Compose 是指挥官MySQL 是主心骨Redis 是加速器。它适合两类人一类是刚写完第一个 CRUD 接口、对着npm run build发呆的前端转全栈开发者另一类是运维同事被开发喊“本地跑得好好的上服务器就 500”结果发现连 MySQL 的wait-for-it.sh脚本都没加。这不是教你怎么敲命令而是教你怎么设计一个有呼吸感、能自愈、出问题能秒定位的部署结构。下面所有步骤我都拿一个真实电商后台的订单服务模块做过三轮压测和故障注入——比如故意 kill 掉 MySQL 容器看 Redis 缓存降级是否生效比如把 Redis 内存设成 64MB观察连接池耗尽时 NestJS 的熔断日志是否清晰。现在我们从最底层的逻辑开始为什么非得用 Docker Compose因为单靠docker run启动五个容器你得记十五个参数而线上出问题时没人会给你三分钟翻文档。2. 为什么必须放弃“裸机部署”Docker Compose 是唯一解2.1 裸机部署的三大死穴每个都够你加班到凌晨两点很多人觉得“Docker 太重”不如直接在 Ubuntu 上装 Node、MySQL、Redis。我试过也踩过。去年一个客户项目开发在 Mac 上用 MySQL 8.0.33运维在 CentOS 7 上装了 5.7结果JSON_CONTAINS函数直接报错查日志查了六小时最后发现是版本差异。这就是裸机部署的第一个死穴环境漂移Environment Drift。你的本地、测试、预发、生产四个环境 MySQL 版本、字符集、SQL 模式全不一样sql_modeSTRICT_TRANS_TABLES开或不开直接影响INSERT IGNORE的行为。第二个死穴是依赖耦合。NestJS 项目里nestjs/typeorm依赖 MySQL 驱动但驱动版本又和 Node 版本强绑定。Node 18 升级到 20TypeORM 从 0.3.17 升到 0.3.20MySQL 驱动就得跟着换而运维同事可能还在用apt-get install mysql-client装旧版客户端。第三个死穴最致命启动顺序失控。NestJS 应用启动时要连 MySQL连不上就直接process.exit(1)Redis 同理。但裸机上你systemctl start mysql再systemctl start redis最后pm2 start main.js这中间有毫秒级的时间差。我见过最惨的一次是 Redis 启动慢了 800msNestJS 已经重试三次失败自动退出而 systemd 认为服务启动失败不再重试——整个服务就卡在“启动中”状态监控告警却没响因为进程根本没起来。Docker Compose 解决的不是“能不能跑”的问题而是“能不能稳、能不能查、能不能扩”的问题。它用depends_onhealthcheck构建了一个有心跳、有依赖、有超时的启动链。depends_on只控制启动顺序不等健康healthcheck才是真正的守门员。下面这张表是我对比三种部署方式在真实故障下的表现故障场景裸机部署Docker 单容器Docker Compose含 healthcheckMySQL 容器启动慢5sNestJS 启动失败需人工重启NestJS 启动失败需人工重启自动等待 MySQL 健康后才启动 NestJS零干预Redis 内存满OOMNestJS 连接超时日志只写“ECONNREFUSED”同左且容器无自愈能力Redis 容器自动重启NestJS 连接池自动重建业务中断 3sMySQL 配置错误如 max_connections10服务启动成功但高并发时大量请求阻塞同左且无法快速回滚配置修改docker-compose.yml中command参数docker-compose up -d一键生效5 秒内完成看到没Docker Compose 的价值不在“多了一个 yml 文件”而在于它把“服务间依赖”这个软性概念变成了可配置、可检测、可超时的硬性规则。healthcheck不是锦上添花是生产环境的底线。没有它你的depends_on就是纸糊的墙。2.2 为什么选 Docker Compose 而不是 Kubernetes一个务实的选择看到这里肯定有人问“K8s 不是更牛吗”当然牛但牛得过头了。Kubernetes 是给管理 200 微服务、每天发布 50 次的公司准备的。而你手上的 NestJS 项目大概率是一个单体应用或者最多拆成 Auth、Order、Product 三个服务。K8s 的学习成本是 Docker Compose 的 5 倍你要学 Pod、Service、Ingress、ConfigMap、Secret、Helm Chart……而 Docker Compose你只需要懂 4 个核心字段image、volumes、environment、healthcheck。我拿一个真实数据说话我们团队接手一个遗留 NestJS 项目原部署用的是 PM2 Nginx 手动脚本。迁移到 Docker Compose总共花了 3 天第一天写Dockerfile第二天写docker-compose.yml并加healthcheck第三天压测和调优。而如果上 K8s光是搭建一套最小可用集群k3s加上 CI/CD 流水线对接保守估计要 2 周。更关键的是Docker Compose 的调试体验远胜 K8s。docker-compose logs -f nestjs一条命令就能实时看所有服务日志docker-compose exec mysql mysql -uroot -p直接进数据库docker-compose down docker-compose up -d一键重置全部环境。K8s 呢kubectl logs -f deploy/nestjs、kubectl exec -it pod/mysql-xxx -- mysql、kubectl delete all --all……命令长到要贴便签在显示器上。所以别被“技术先进性”绑架。Docker Compose 是那个“刚刚好”的工具它足够轻量让小团队快速落地它足够强大能覆盖 90% 的生产需求它足够标准未来真要上 K8s你的Dockerfile和docker-compose.yml里的services定义80% 都能直接复用。记住一句话能用docker-compose up -d解决的问题就别去碰kubectl apply -f。2.3 NestJS、MySQL、Redis 三者的协作逻辑不是并列而是主从很多教程把 NestJS、MySQL、Redis 当成三个平级服务来写docker-compose.yml这是大忌。它们的关系是典型的“一主二辅”NestJS 是大脑MySQL 是心脏Redis 是肾上腺。大脑要工作必须等心脏跳动MySQL 就绪肾上腺可以稍晚Redis 可降级。所以docker-compose.yml里nestjs服务的depends_on必须明确指向mysql而redis可以只做软依赖。具体怎么体现看healthcheck的设计。MySQL 的健康检查必须是 SQL 级别的mysql -h localhost -u root -proot -e SELECT 1而不是简单的端口探测curl -f http://localhost:3306——因为 MySQL 端口通了不代表你能连上可能只是 mysqld 进程在但数据库初始化还没完。Redis 的健康检查同理要用redis-cli -h localhost -p 6379 ping返回PONG才算真健康。而 NestJS 的健康检查必须是业务级的curl -f http://localhost:3000/health这个/health接口里你要主动去await this.mysqlService.ping()和await this.redisService.ping()任何一个失败就返回 503。这才是真正的端到端健康。我见过太多项目NestJS 的healthcheck只写了个return { status: UP }结果 MySQL 挂了K8s 或负载均衡器还认为服务是健康的流量照常打进来全部 500。所以healthcheck不是装饰是契约。它定义了“什么才算一个服务真正可用”。下面这段代码是我们所有 NestJS 项目的HealthController标准模板import { Controller, Get, HttpStatus } from nestjs/common; import { HealthCheck, HealthCheckService, TypeOrmHealthIndicator, HealthCheckResult, MicroserviceHealthIndicator } from nestjs/terminus; Controller(health) export class HealthController { constructor( private health: HealthCheckService, private db: TypeOrmHealthIndicator, private redis: MicroserviceHealthIndicator, ) {} Get() HealthCheck() check(): PromiseHealthCheckResult { return this.health.check([ // 检查 MySQL 连接 () this.db.pingCheck(database, { timeout: 5000 }), // 检查 Redis 连接 () this.redis.pingCheck(redis, { url: redis://redis:6379, timeout: 3000 }), // 检查 NestJS 自身状态如内存、CPU () this.db.pingCheck(nestjs, { timeout: 1000, message: NestJS is running }), ]); } }注意两个细节一是pingCheck的timeout参数MySQL 设为 5000ms因为初始化可能慢Redis 设为 3000ms因为响应快NestJS 自身设为 1000ms纯内存操作。二是url字段Redis 的地址写的是redis://redis:6379不是localhost——这是 Docker 网络的关键。在 Compose 网络里服务名redis就是 DNS 名容器内直接解析比localhost更可靠。这些细节决定了你的部署是“能跑”还是“敢上生产”。3. 从零开始构建Dockerfile、docker-compose.yml 与 NestJS 配置的黄金三角3.1 NestJS 的 Dockerfile为什么不用node:alpine而选node:18-slimDockerfile 是部署的起点也是最容易被忽视的坑点。网上 90% 的 NestJS 教程第一行就写FROM node:alpine理由是“体积小”。我劝你立刻删掉。Alpine 是基于 musl libc 的轻量发行版而 Node.js 官方二进制包是为 glibc 编译的。这就导致一个问题某些 C 扩展比如bcrypt、sharp在 Alpine 上编译失败或运行异常。我们有个项目用户注册用bcrypt.hash本地 Mac 和 Ubuntu 都正常上了 Alpine 镜像后hash出来的字符串长度不对登录全失败。查了三天才发现是 musl 和 glibc 对getrandom系统调用的实现差异。所以我的铁律是生产环境永远用node:version-slim不用alpine。slim版本基于 Debian兼容性完美体积只比alpine大 30MB但省下的是你三天的排查时间。下面是我们的标准Dockerfile# 构建阶段 FROM node:18-slim AS builder # 设置工作目录 WORKDIR /app # 复制 package.json 和 lock 文件先安装依赖利用 Docker 层缓存 COPY package*.json ./ RUN npm ci --onlyproduction # 复制源码 COPY . . # 构建 NestJS 项目生成 dist RUN npm install npm run build # 运行阶段 FROM node:18-slim # 创建非 root 用户提升安全性 RUN groupadd -g 1001 -f nodejs useradd -S -u 1001 -U nodejs USER nodejs # 复制构建阶段的依赖和 dist COPY --frombuilder --chownnodejs:nodejs /app/node_modules ./node_modules COPY --frombuilder --chownnodejs:nodejs /app/dist ./dist COPY --frombuilder --chownnodejs:nodejs /app/package*.json ./ # 暴露端口 EXPOSE 3000 # 启动命令 CMD [node, dist/main.js]重点解释三个关键点。第一分阶段构建Multi-stage Build。AS builder定义构建阶段里面装了npm install和npm run build所需的全部工具包括 TypeScript 编译器。运行阶段则只复制node_modules和dist不带任何开发依赖镜像体积从 1.2GB 直降到 280MB。第二npm ci --onlyproduction。ci比install更严格它会清空node_modules并严格按照package-lock.json安装确保环境一致性。--onlyproduction表示只装dependencies不装devDependencies如nestjs/cli、typescript避免把编译器打进生产镜像。第三创建非 root 用户。USER nodejs这一行至关重要。默认 Docker 容器以 root 运行一旦 NestJS 有漏洞被利用攻击者就拿到宿主机 root 权限。用普通用户运行是安全基线。chownnodejs:nodejs确保复制的文件权限正确。这条规则我强制要求所有团队成员遵守生产镜像里没有任何进程能以 root 身份运行。3.2 docker-compose.yml不只是服务列表而是部署策略的蓝图docker-compose.yml是整个部署的灵魂。它不是简单罗列服务而是定义了服务如何交互、如何容错、如何扩展。下面是我们经过 7 个项目验证的生产级docker-compose.ymlversion: 3.8 # 定义网络所有服务都在同一个自定义网络里DNS 解析基于服务名 networks: app-network: driver: bridge ipam: config: - subnet: 172.20.0.0/16 # 定义卷用于持久化数据和日志 volumes: mysql-data: driver: local redis-data: driver: local nestjs-logs: driver: local services: # MySQL 服务 mysql: image: mysql:8.0.34 restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: nestjs_db MYSQL_USER: nestjs_user MYSQL_PASSWORD: nestjs_pass # 关键配置禁用 strict mode避免 ORM 兼容问题 MYSQL_INITDB_SKIP_TZINFO: 1 # 设置时区避免时间戳错乱 TZ: Asia/Shanghai volumes: - mysql-data:/var/lib/mysql - ./mysql/init:/docker-entrypoint-initdb.d ports: - 3306:3306 networks: - app-network # 健康检查必须执行 SQL 查询不能只探端口 healthcheck: test: [CMD, mysql, -h, localhost, -u, root, -proot, -e, SELECT 1] interval: 30s timeout: 10s retries: 5 start_period: 40s # Redis 服务 redis: image: redis:7.2-alpine restart: unless-stopped command: redis-server /usr/local/etc/redis/redis.conf environment: TZ: Asia/Shanghai volumes: - redis-data:/data - ./redis/redis.conf:/usr/local/etc/redis/redis.conf ports: - 6379:6379 networks: - app-network healthcheck: test: [CMD, redis-cli, -h, localhost, ping] interval: 30s timeout: 5s retries: 5 start_period: 30s # NestJS 应用服务 nestjs: build: context: . dockerfile: Dockerfile restart: unless-stopped environment: # 数据库连接信息使用服务名作为 host DB_HOST: mysql DB_PORT: 3306 DB_USERNAME: nestjs_user DB_PASSWORD: nestjs_pass DB_NAME: nestjs_db # Redis 连接信息 REDIS_HOST: redis REDIS_PORT: 6379 # JWT 密钥等敏感信息生产环境应从 Secret 注入 JWT_SECRET: your-jwt-secret-change-in-prod NODE_ENV: production PORT: 3000 ports: - 3000:3000 networks: - app-network # 依赖关系必须等 MySQL 健康后才启动 depends_on: mysql: condition: service_healthy redis: condition: service_started # Redis 可稍后NestJS 有降级逻辑 volumes: - nestjs-logs:/app/logs # 健康检查调用业务级健康接口 healthcheck: test: [CMD, curl, -f, http://localhost:3000/health] interval: 30s timeout: 10s retries: 3 start_period: 60s这份配置里藏着三个必须掌握的硬核技巧。第一start_period的设定逻辑。MySQL 的start_period: 40s是因为 MySQL 8.0 初始化数据库要 20~35 秒Redis 的30s是因为加载 RDB 文件可能需要 10 秒NestJS 的60s是因为它要等 MySQL 健康40s 自身启动10s 第一次健康检查10s。这个值不是拍脑袋是实测出来的。第二condition的精准选择。mysql用service_healthy因为 NestJS 绝对不能在 MySQL 不可用时启动redis用service_started因为我们的业务逻辑里Redis 不可用时NestJS 会自动降级到直连 MySQL保证核心功能如登录、下单不中断。第三volumes的路径映射哲学。./mysql/init:/docker-entrypoint-initdb.d这一行是让 MySQL 在首次启动时自动执行init目录下的.sql文件。我们放一个01-create-tables.sql里面建好所有表结构和初始数据避免 NestJS 启动时还要自己synchronize: true——那在生产环境是自杀行为。同样./redis/redis.conf是我们定制的配置里面设置了maxmemory 256mb、maxmemory-policy allkeys-lru防止 Redis OOM 拖垮整个服务。这些细节才是区分“玩具部署”和“生产部署”的分水岭。3.3 NestJS 应用层配置环境变量、TypeORM 与 Redis 客户端的实战适配Docker Compose 定义了基础设施而 NestJS 应用层的配置决定了这些设施能否被高效、安全地使用。核心是三件事环境变量注入、TypeORM 连接池调优、Redis 客户端熔断。先说环境变量。很多人把数据库密码写死在app.module.ts里这是严重安全隐患。正确的做法是用ConfigModule从环境变量读取// app.module.ts import { Module } from nestjs/common; import { ConfigModule, ConfigService } from nestjs/config; import { TypeOrmModule } from nestjs/typeorm; import { RedisModule } from liaoliaots/nestjs-redis; Module({ imports: [ // 加载环境变量支持 .env 文件和 process.env 双来源 ConfigModule.forRoot({ isGlobal: true, load: [databaseConfig, redisConfig], }), // TypeORM 模块连接池配置是关键 TypeOrmModule.forRootAsync({ inject: [ConfigService], useFactory: (configService: ConfigService) ({ type: mysql, host: configService.get(DB_HOST), port: configService.get(DB_PORT), username: configService.get(DB_USERNAME), password: configService.get(DB_PASSWORD), database: configService.get(DB_NAME), // 关键连接池大小根据 CPU 核数设置 entities: [__dirname /**/*.entity{.ts,.js}], synchronize: false, // 生产环境绝对禁止 logging: false, // 连接池配置min5, max20避免连接数爆炸 pool: { min: 5, max: 20, acquireTimeoutMillis: 60000, idleTimeoutMillis: 60000, }, }), }), // Redis 模块启用哨兵模式虽单节点但为扩展预留 RedisModule.forRootAsync({ inject: [ConfigService], useFactory: (configService: ConfigService) ({ config: { host: configService.get(REDIS_HOST), port: configService.get(REDIS_PORT), password: configService.get(REDIS_PASSWORD) || undefined, db: 0, // 关键启用重连和熔断 retry_strategy: (options) { if (options.error options.error.code ECONNREFUSED) { return new Error(The server refused the connection); } if (options.total_retry_time 1000 * 60 * 60) { return new Error(Retry time exhausted); } if (options.times_connected 10) { return undefined; // 重连 10 次后放弃 } return Math.min(options.attempt * 100, 3000); // 指数退避 }, }, }), }), ], }) export class AppModule {}这里有两个魔鬼细节。一是TypeORM 连接池的min和max。min: 5表示池里永远保持 5 个空闲连接避免高并发时频繁创建连接的开销max: 20是上限防止打爆 MySQL 的max_connections。MySQL 默认max_connections151如果你有 5 个 NestJS 实例每个max20总连接数就到 100还剩 51 给管理员和其他服务很安全。二是Redis 的retry_strategy。它不是简单重试而是有策略的第一次失败等 100ms第二次等 200ms第三次等 400ms……最大等 3s重试 10 次后彻底放弃并抛出错误。这样当 Redis 临时不可用时NestJS 不会疯狂重连拖垮自己而是优雅降级。最后别忘了synchronize: false。这是血的教训。synchronize: true会在每次启动时对比实体和数据库结构自动ALTER TABLE。生产环境谁敢让它改表轻则锁表几秒重则误删字段。所有表结构变更必须走 Flyway 或 TypeORM Migration由 DBA 审核后执行。这个配置是我们所有 NestJS 项目的“宪法”违反者代码提交直接被 CI 拦截。4. 实操全流程从本地构建到服务器上线每一步都附带避坑指南4.1 本地构建与验证docker-compose up -d之后你该看什么docker-compose up -d按下回车的那一刻不是结束而是开始。真正的功夫在up之后的三分钟验证。我把它拆成四个必查环节缺一不可。第一步查容器状态与日志。不要只信docker-compose ps显示的Up要立刻docker-compose logs -f nestjs。重点看三行[NestApplication] Nest application successfully started表示 NestJS 启动成功[TypeOrmModule] Connected to database表示 MySQL 连通[RedisModule] Redis client connected表示 Redis 连通。如果卡在某一行超过 30 秒立刻CtrlC停掉查docker-compose logs mysql或docker-compose logs redis。常见坑MySQL 的healthcheck命令里-proot没加空格写成-proot实际变成-p root密码传错健康检查永远失败。第二步查健康状态。运行docker-compose ps看STATUS列。健康的容器状态应该是Up x minutes (healthy)。如果显示Up x minutes (unhealthy)说明healthcheck失败。这时不要急着改代码先手动进容器验证docker-compose exec mysql mysql -uroot -proot -e SELECT 1。如果报错Access denied检查MYSQL_ROOT_PASSWORD环境变量是否和healthcheck命令里的密码一致如果报错Cant connect to local MySQL server检查mysql容器的healthcheck是否用了localhost而应该用127.0.0.1Docker 内部网络有时localhost解析不准。第三步查业务接口。打开浏览器或 Postman访问http://localhost:3000/health。你应该看到 JSON 响应status是UP且checks数组里database和redis的status都是UP。如果redis是DOWN但业务还能用比如登录接口返回 200恭喜你降级逻辑生效了。这是设计目标不是 bug。再访问一个真实接口比如http://localhost:3000/users看是否返回数据。如果返回500立刻docker-compose logs nestjs | tail -20找error关键字。90% 的500是环境变量没配对比如DB_HOST写成了DB_HOSTNAME。第四步查资源占用。运行docker stats看三个容器的 CPU 和内存。NestJS 应该稳定在 1%~5% CPU内存 150~250MBMySQL 在空闲时 CPU 1%内存 300~500MBRedis 空闲时 CPU ~0%内存 5~10MB。如果 NestJS 内存飙升到 800MB 并持续增长可能是内存泄漏检查nestjs/cache-manager的配置是否ttl设得太长缓存没清理。这四步做完本地环境才算真正“活”了。记住docker-compose up -d只是点燃引信这四步验证才是确认炸弹有没有哑火。4.2 服务器部署Ubuntu 22.04 上的零失误操作清单把本地跑通的环境搬到阿里云或腾讯云的 Ubuntu 22.04 服务器上看似简单实则暗礁密布。我整理了一份“零失误操作清单”按顺序执行每一步都有原理和避坑点。第 1 步安装 Docker 和 Docker Compose不要用apt-get install docker.io那是 Ubuntu 自带的旧版版本太低。必须用官方源# 卸载旧版 sudo apt-get remove docker docker-engine docker.io containerd runc # 安装依赖 sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg lsb-release # 添加 Docker 官方 GPG 密钥 sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 添加仓库 echo \ deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null # 安装 Docker Engine sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # 验证 sudo docker run hello-world关键点docker-compose-plugin是新版 Compose取代了独立的docker-compose二进制。sudo docker run hello-world成功证明 Docker 引擎装对了。第 2 步上传项目代码用scp或rsync把整个项目文件夹含Dockerfile、docker-compose.yml、src/传到服务器/home/ubuntu/nestjs-app。切记不要用git clone因为git可能没装且.git文件夹会增大镜像体积。上传后cd /home/ubuntu/nestjs-app检查文件权限ls -la确保Dockerfile和docker-compose.yml可读。第 3 步配置防火墙Ubuntu 默认开启ufw必须放行端口sudo ufw allow OpenSSH sudo ufw allow 3000 # NestJS 端口 sudo ufw allow 3306 # MySQL 端口仅内网不对外 sudo ufw allow 6379 # Redis 端口仅内网不对外 sudo ufw enable重要提醒MySQL 和 Redis 的 3306、6379 端口绝不能对公网开放。ufw allow 3306只是允许本机即 Docker 容器访问因为 Docker 默认桥接网络在172.17.0.0/16而ufw规则默认针对eth0公网网卡。真正的安全是靠 Docker 网络隔离docker-compose.yml里ports只写了3000:3000没写3306:3306所以 MySQL 只在app-network内部可达外部扫不到。第 4 步启动服务# 启动-d 后台运行 sudo docker-compose up -d # 查看状态等 2 分钟 sudo docker-compose ps # 查看日志重点关注 nestjs sudo docker-compose logs -f nestjs如果ps显示Unhealthy别慌。先sudo docker-compose logs mysql看是不是mysqld: Cant open and lock privilege tables: Table mysql.user doesnt exist。这是 MySQL 数据卷残留旧数据导致的。解决方案sudo docker volume rm nestjs-app_mysql-data注意这会清空数据库然后sudo docker-compose down sudo docker-compose up -d。这是生产环境第一次部署的常见问题提前知道就不慌。第 5 步配置反向代理Nginx直接暴露3000端口不专业。加一层 Nginx做 HTTPS 和负载均衡# 安装 Nginx sudo apt-get install -y nginx # 创建配置文件 sudo nano /etc/nginx/sites-available/nestjs内容如下server { listen 80; server_name your-domain.com; # HTTP 重定向到 HTTPS return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name your-domain.com; # SSL 证书用 Certbot 获取 ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; # NestJS 代理 location / { proxy_pass http://127.0.0.1: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; } # 健

相关新闻