AIHub

从零到上线:Next.js 项目部署到云服务器全流程实战

进阶20 分钟读完2026-08-04#部署#Next.js#nginx#HTTPS#运维
从零到上线:Next.js 项目部署到云服务器全流程实战

很多人能本地跑通 Next.js 项目,却在"部署到自己的服务器"这一步卡住:教程零散,每一步都只说一半。这篇文章把完整链路串起来,每一步都给出可直接复制的命令。示例统一使用 example.com 这个域名和一台 1 核 2G 的阿里云 ECS(其他云厂商同理)。

准备工作清单

  • 一台云服务器(Linux,本文以 Alibaba Cloud Linux 3 为例,Ubuntu 命令几乎相同)
  • 一个域名,且能管理它的 DNS 解析
  • 本地能跑通 npm run build 的项目
  • 云服务控制台里放行 80 和 443 端口(安全组)

一、域名与 DNS 解析

在域名服务商控制台添加一条 A 记录:主机记录填子域名(比如 ai,即 ai.example.com),记录值填服务器公网 IP。主域名想直接用就填 @,带 www 就再加一条 www

解析生效通常几分钟到半小时。本地验证:

ping ai.example.com   # 应解析到你的服务器 IP

二、ICP 备案注意事项

服务器在中国大陆境内,域名必须完成 ICP 备案才能通过 80/443 端口正常访问,否则云厂商会拦截请求。几点经验:

  • 备案在服务器所属云厂商的备案系统提交,主体与域名所有者保持一致
  • 首次备案周期约 1–3 周,期间网站不能提前开通访问
  • 子域名跟随主域名备案,一般无需单独备案
  • 如果只是测试,可以先用境外服务器免备案跑通流程,再迁回国内

三、SSH 登录

推荐使用密钥登录而非密码。本地生成密钥(已有可跳过),把公钥放到服务器:

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_myserver
ssh-copy-id -i ~/.ssh/id_ed25519_myserver.pub root@你的服务器IP
ssh -i ~/.ssh/id_ed25519_myserver root@你的服务器IP

四、安装 Node.js(国内镜像加速)

官方源在国内很慢,用 npmmirror 的二进制镜像:

cd /tmp
curl -fsSL -o node.tar.xz https://registry.npmmirror.com/-/binary/node/latest-v22.x/node-v22.20.0-linux-x64.tar.xz
tar -xJf node.tar.xz -C /opt
ln -sf /opt/node-v22.20.0-linux-x64/bin/node /usr/local/bin/node
ln -sf /opt/node-v22.20.0-linux-x64/bin/npm /usr/local/bin/npm
node --version   # 应输出 v22.x

注意:版本号会随时间更新,先去镜像目录列表确认最新的 v22 文件名。

五、小内存服务器加 Swap

2G 以下内存的机器跑 npm run build 大概率 OOM(内存耗尽被kill)。加 2G Swap 兜底:

fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo "/swapfile none swap sw 0 0" >> /etc/fstab   # 重启后自动挂载
free -h   # Swap 行应显示 2.0Gi

六、rsync 上传代码

不要用 FTP,也不要把 node_modules 传上去。在本地项目目录执行:

rsync -az --delete -e "ssh -i ~/.ssh/id_ed25519_myserver" \
  --exclude node_modules --exclude .next --exclude data --exclude .git \
  ./ root@你的服务器IP:/var/www/myapp/

--delete 让服务器目录与本地保持一致;排除项里 data 是线上数据库目录,绝不能被本地覆盖

七、安装依赖与构建

cd /var/www/myapp
npm ci --registry=https://registry.npmmirror.com
npm run build

如果项目含 better-sqlite3 这类原生模块且预编译包下载失败,先装编译工具链再重试:dnf install -y gcc-c++ make python3(Ubuntu 用 apt install -y build-essential python3)。

生产环境的环境变量写在 .env.production(如密钥、站点 URL),密钥用 openssl rand -hex 32 生成,不要提交进 Git

八、systemd 常驻服务

直接 npm start 关掉 SSH 就停了。用 systemd 托管,崩了自动重启、开机自启。创建 /etc/systemd/system/myapp.service

[Unit]
Description=My Next.js app
After=network.target

[Service]
Type=simple
WorkingDirectory=/var/www/myapp
EnvironmentFile=/var/www/myapp/.env.production
Environment=NODE_ENV=production
Environment=PORT=3000
ExecStart=/usr/local/bin/npm start
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

启用并验证:

systemctl daemon-reload
systemctl enable --now myapp
curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000   # 期望 200

九、nginx 反向代理

创建 /etc/nginx/conf.d/myapp.conf,完整 server 块:

server {
    listen 80;
    server_name ai.example.com;

    client_max_body_size 10m;

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

client_max_body_size 决定了上传文件的大小上限,默认 1m 很容易踩坑。改完 nginx -t 测试语法,再 systemctl reload nginx

十、certbot 申请免费 HTTPS 证书

服务器装好 certbot 后一条命令搞定,它会自动改 nginx 配置并加上 80→443 跳转:

certbot --nginx -d ai.example.com --redirect --non-interactive --agree-tos -m you@example.com

Let's Encrypt 证书有效期 90 天,certbot 安装时会自动注册续期定时任务。用 certbot renew --dry-run 可以预演续期是否正常。

上线验证清单

逐项过一遍再宣布上线:

  • https://你的域名/ 返回 200,浏览器有锁标志
  • http:// 自动跳转 https://
  • 关键页面(列表页、详情页、登录)逐个点开
  • sitemap.xml / robots.txt 里的 URL 是正式域名而不是 localhost
  • 用错误密码登录一次,确认返回 401 而不是 500
  • 服务器上 systemctl status myapp 是 active (running)

日常更新流程

以后每次发版就三步:

# 1. 本地同步代码(排除项与首次上传相同)
rsync -az --delete -e "ssh -i ~/.ssh/id_ed25519_myserver" \
  --exclude node_modules --exclude .next --exclude data --exclude .git \
  ./ root@你的服务器IP:/var/www/myapp/

# 2. 服务器上重新构建
ssh root@你的服务器IP 'cd /var/www/myapp && npm ci && npm run build'

# 3. 重启服务
ssh root@你的服务器IP 'systemctl restart myapp'

依赖没变时可以跳过 npm ci。页面若是动态渲染(force-dynamic),纯内容更新甚至不需要重新构建。

常见问题

Q:构建时卡住然后进程消失? 基本是内存不足,看 dmesg | grep -i oom 确认,加 Swap 后重试。

Q:nginx 报 502 Bad Gateway? 应用没起来或端口不对,先 curl http://127.0.0.1:3000 自测,再看 journalctl -u myapp -n 100 的日志。

Q:certbot 验证失败? 先确认 DNS 已解析到本机、80 端口在安全组已放行,且 nginx 里该域名的 server 块已生效。

小结

部署的本质是一条链:域名解析 → 服务器环境 → 代码上传 → 进程常驻 → 反向代理 → HTTPS。每一步都有明确的验证手段,哪环断了查哪环。把这篇文章的命令存成自己的发版脚本,之后每次上线就是几分钟的事。

相关教程

从零到上线:Next.js 项目部署到云服务器全流程实战 | AIHub