网站部署到香港CN2服务器要配哪些基础项:Nginx反向代理、进程守护与备份怎么安排

Planning Hong Kong CN2 server article structureDefining deployment boundaries and systemd setupRefining nginx proxy configurationPlanning nginx backup and certbot setupSpecifying apt-only CA client usagePlanning certbot setup and rollback proceduresAdvising systemd process supervisionDiagnosing failure modes and resource limitsPlanning backup strategy with tar and rsyncDesigning remote backup strategyDetailing database dump and backup schedulingPlanning rollback procedures for failuresOutlining domain-to-app request flowPlanning detailed step-by-step guide structureAdding appuser creation commandAdvising user existence verification and service unit creationOutlining safe Nginx config writing and reload stepsReviewing Nginx and resource configuration considerationsDesigning secure config backup and restore proceduresDesigning backup and restore strategyDocumenting deployment troubleshooting and rollbackPlanning article structure with key terms常见的生产现场是:网站代码已经放到香港CN2服务器,应用也能在服务器本机访问,但一旦服务器重启,进程没有自动拉起;或者公网访问出现502,排查后发现Nginx转发到了错误端口。还有一些站点只备份了网站目录,忘记保存Nginx配置、环境变量、证书私钥和数据库,真正需要恢复时仍然无法完成上线。
比较稳妥的基础链路应当是:域名请求进入Nginx,Nginx负责80/443端口、TLS证书和反向代理;应用只监听127.0.0.1上的内部端口,由systemd负责启动、重启和日志收集;网站文件、数据库、配置和证书按照数据重要程度备份到独立存储,并通过恢复测试确认备份可用。下面以使用systemd的Debian/Ubuntu类系统为例,应用端口使用示例值3000,实际部署时需要替换为应用真实端口。
先确认部署边界和前置条件
在修改配置前,现场需要先确认以下条件:
- 已有可用域名,例如
example.com,并准备将其解析到香港CN2服务器的公网IP。 - 已能通过SSH登录服务器,并拥有
sudo权限。 - 应用可以在服务器本机启动,明确启动命令、工作目录、运行用户和监听端口。
- 系统使用
systemd管理服务,Nginx已经安装或允许通过系统包管理器安装。 - 应用所需的数据库、上传目录、环境变量和密钥位置已经梳理清楚。
- 已准备独立的备份位置。仅把备份留在同一块系统盘上,不能应对磁盘损坏或误删。
- 证书申请前,域名的A记录已经生效,且公网能够访问服务器的80端口。
先查看系统和现有监听情况,避免在不知道当前服务状态的情况下重复部署:
cat /etc/os-release
command -v systemctl
nginx -v
sudo ss -lntp
如果系统中没有Nginx,可在Debian/Ubuntu环境执行:
sudo apt update
sudo apt install -y nginx
已经存在生产配置时,不要直接覆盖。先把配置目录和应用配置保存一份:
sudo cp -a /etc/nginx "/etc/nginx.before-change.$(date +%F-%H%M%S)"
if [ -d /etc/myapp ]; then
sudo cp -a /etc/myapp "/etc/myapp.before-change.$(date +%F-%H%M%S)"
fi
上面的/etc/myapp只是示例路径,实际环境可能使用/etc/default/myapp、/srv/myapp/.env或其他位置。备份环境变量时要注意文件权限,不能因为临时排障而把数据库密码或API密钥放到公开目录。
先让应用由进程守护接管
现场排查时,使用nohup、screen或SSH窗口直接运行应用,是重启后服务消失的常见原因。生产环境需要明确一个进程管理者。使用systemd时,不要再叠加PM2、Supervisor等多个管理器,否则可能出现重复拉起、端口冲突和停止命令失效。
假设应用目录为/srv/myapp/current,实际启动文件为/srv/myapp/current/bin/start,运行用户为已经存在的appuser。先确认目录、用户和启动文件:
getent passwd appuser
sudo test -x /srv/myapp/current/bin/start
sudo ls -la /srv/myapp/current
如果运行用户或启动文件不存在,不要直接照抄示例。应先根据应用实际运行方式创建专用用户、部署依赖,并确认启动命令可以在前台正常运行。启动命令必须能在非交互环境下工作,不能依赖登录Shell、终端输入或当前目录。
创建服务文件:
# /etc/systemd/system/myapp.service
[Unit]
Description=My application service
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=appuser
Group=appuser
WorkingDirectory=/srv/myapp/current
EnvironmentFile=-/etc/myapp/myapp.env
ExecStart=/srv/myapp/current/bin/start
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
PrivateTmp=true
NoNewPrivileges=true
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
其中几个配置项需要结合应用判断:
ExecStart必须替换成真实的可执行文件和参数,不能把示例路径原样使用。EnvironmentFile前面的-表示文件不存在时不阻止服务启动。如果应用必须依赖环境变量,建议去掉-,让配置缺失时直接失败,避免应用以错误默认值运行。Restart=on-failure适合处理异常退出,不会因为正常停止而无限重启。LimitNOFILE只是资源边界示例。连接数较高的应用可能需要提高,但应结合应用连接池、Nginx连接数和系统内存一起评估。PrivateTmp和NoNewPrivileges通常有助于减少权限风险,但如果应用依赖特殊系统能力或共享临时目录,应先在测试环境验证。
加载并启动服务:
sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp
sudo systemctl status myapp --no-pager
先不要急着配置Nginx,直接从服务器本机访问应用:
curl --fail --max-time 5 http://127.0.0.1:3000/health
如果应用没有/health接口,可以换成确定会返回成功状态的路径。随后检查进程和日志:
sudo ss -lntp | grep ':3000'
sudo journalctl -u myapp -n 100 --no-pager
本机访问失败时,问题还不在Nginx,优先检查启动命令、依赖、环境变量、端口冲突和目录权限。只有本机应用访问正常,才进入反向代理配置。
用Nginx接管公网请求
Nginx配置的基本原则是:
- Nginx监听公网的80和443端口。
- 应用只监听
127.0.0.1:3000,不直接暴露到公网。 - Nginx把原始域名、客户端地址和访问协议通过请求头传递给应用。
- 请求体大小和超时时间按照业务需求设置,不用一个过大的值掩盖应用处理能力不足。
- 修改后先执行
nginx -t,确认语法正确后再平滑加载。
创建站点配置,例如/etc/nginx/sites-available/example.com:
upstream myapp_backend {
server 127.0.0.1:3000;
keepalive 32;
}
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
access_log /var/log/nginx/myapp.access.log;
error_log /var/log/nginx/myapp.error.log warn;
client_max_body_size 20m;
location / {
proxy_pass http://myapp_backend;
proxy_http_version 1.1;
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_set_header Connection "";
proxy_connect_timeout 5s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}
}
20m和60s是示例边界,不代表所有网站都应使用这些值。上传图片、视频或安装包的网站,需要根据单文件限制设置client_max_body_size;普通内容站点不应为了处理一次异常请求而无限提高它。proxy_read_timeout过小可能导致长请求被提前断开,过大则可能让异常请求长期占用连接,应该结合接口响应时间和异步任务设计调整。
启用站点配置:
sudo ln -s /etc/nginx/sites-available/example.com \
/etc/nginx/sites-enabled/example.com
sudo nginx -t
sudo systemctl reload nginx
如果sites-enabled中已经存在同名链接,不要重复创建;先使用以下命令确认当前生效配置:
sudo nginx -T
nginx -T可能输出包含内部路径或敏感配置,不要直接粘贴到公开场所。配置加载后,先在服务器本机用域名请求验证Nginx:
curl --resolve example.com:80:SERVER_IP \
-I http://example.com/
将SERVER_IP替换为服务器公网IP。--resolve可以在DNS尚未完全生效时,仍然携带正确的Host请求头。若应用会根据协议生成绝对地址,还要确认X-Forwarded-Proto已经被应用正确识别。应用只有在明确知道请求来自本机Nginx时,才应信任这些转发头,不能无条件信任公网客户端自行提交的同名请求头。
如果业务使用WebSocket或其他需要连接升级的协议,应在确认应用协议需求后补充Upgrade和Connection处理,不能因为普通HTTP配置能够访问,就默认长连接也一定正常。
配置证书,并验证自动续期
证书申请建立在HTTP站点可访问、域名解析正确和80端口可达的基础上。以Debian/Ubuntu使用系统包为例,可以安装Certbot及其Nginx插件:
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
申请证书前,先确认两个域名是否都确实指向当前服务器。只为实际使用的域名申请证书:
sudo certbot --nginx -d example.com -d www.example.com
Certbot可能会修改Nginx站点配置。执行前已经保存配置的情况下,仍然要检查变更结果:
sudo nginx -t
sudo systemctl reload nginx
验证证书和站点:
curl --resolve example.com:443:SERVER_IP \
-I https://example.com/
openssl s_client \
-connect SERVER_IP:443 \
-servername example.com /dev/null |
openssl x509 -noout -subject -issuer -dates
证书部署完成不等于续期已经验证。检查系统定时任务和模拟续期:
systemctl list-timers --all | grep -i certbot
sudo certbot renew --dry-run
如果申请工具、系统发行版或证书管理方式不同,应使用当前环境对应的官方客户端,不要混用多个客户端写入同一套Nginx配置。
证书变更失败时,回滚的重点是恢复Nginx配置,而不是盲目删除证书文件。恢复前先保存当前状态:
sudo cp -a /etc/nginx "/etc/nginx.before-tls-rollback.$(date +%F-%H%M%S)"
再恢复之前的站点配置文件,最后执行:
sudo nginx -t
sudo systemctl reload nginx
如果旧证书已经过期,不能简单回滚到旧证书继续对外提供HTTPS,应优先修复域名校验、续期任务或证书路径问题。
日志要分清Nginx、应用和系统三层
出现访问异常时,排查顺序应当由外到内:
sudo tail -n 100 /var/log/nginx/myapp.error.log
sudo tail -n 100 /var/log/nginx/myapp.access.log
sudo journalctl -u myapp -n 100 --no-pager
sudo systemctl --failed
三类信息的含义不同:
- Nginx访问日志显示请求是否到达、状态码、请求路径和响应时间。
- Nginx错误日志用于判断上游连接失败、超时、权限和配置问题。
journalctl -u myapp显示应用启动失败、异常退出、环境变量缺失和运行时错误。
Nginx的访问日志通常由系统提供的Logrotate规则管理,应该先确认规则存在并进行只读测试:
sudo test -f /etc/logrotate.d/nginx
sudo logrotate -d /etc/logrotate.d/nginx
应用如果将日志输出到标准输出和标准错误,通常由Journald接收。需要同时查看磁盘占用:
sudo journalctl --disk-usage
df -h
df -ih
不要只限制Nginx日志而忽略应用日志、系统日志、上传文件和备份文件。磁盘接近耗尽时,数据库写入、证书续期、日志切割和应用临时文件都可能同时失败。对日志保留周期的选择,应根据故障追溯要求和可用磁盘空间确定;备份目录也不能无限增长。
给CPU、内存、连接和磁盘划出边界
香港CN2服务器上的应用能否长期稳定运行,不只取决于带宽或网络可达性,进程数量、内存、文件描述符和磁盘使用同样需要设边界。可以先采集实际资源,而不是直接复制其他站点的参数:
nproc
free -h
df -hT
sudo systemctl show myapp \
-p MemoryCurrent \
-p CPUUsageNSec \
-p TasksCurrent
常见判断方式如下:
| 资源项 | 需要确认的边界 | 调整依据 |
|---|---|---|
| 应用进程数 | 是否会因多进程重复占用内存或端口 | 应用运行模式、CPU核心数、常驻内存 |
| Nginx连接 | 是否有大量空闲连接长期占用资源 | 并发量、请求类型、超时时间 |
| 请求体大小 | 是否允许超大上传 | 业务文件类型和应用处理能力 |
| 请求超时 | 慢请求是否会长期占用工作进程 | 接口实际响应时间和异步化程度 |
| 文件描述符 | 连接数增加后是否出现“Too many open files” | 并发连接、日志文件、数据库连接 |
| 磁盘空间 | 日志、上传和备份是否挤占系统盘 | 数据增长速度和备份保留策略 |
应用进程数量不要只按CPU核心数机械设置。每个进程的内存、数据库连接数和缓存都会叠加;在内存有限的环境中,盲目增加Worker可能比减少Worker更早触发OOM。应用自己的并发参数、Nginx连接数和数据库连接池也要一起计算。
如果需要提高文件描述符上限,可以在systemd服务中调整LimitNOFILE,但修改后应重启服务并重新验证:
sudo systemctl daemon-reload
sudo systemctl restart myapp
sudo systemctl show myapp -p LimitNOFILE
这会造成应用短暂中断,执行前应确认Nginx错误页、应用重启时间和回滚方式。若资源异常来自请求堆积,优先定位慢接口、外部依赖或数据库,而不是单纯调大超时和连接数。
备份要覆盖配置、代码、数据和恢复方法
网站备份不应只打包/var/www或应用目录。至少需要区分以下对象:
| 对象 | 建议保存内容 | 恢复时的用途 |
|---|---|---|
| 服务配置 | Nginx站点、systemd服务、环境变量模板 | 重建反向代理和进程守护 |
| 证书材料 | 证书配置及私钥,严格限制权限 | 在恢复服务器上恢复HTTPS |
| 应用代码 | 发布版本或可重新部署的制品 | 回滚代码版本 |
| 用户数据 | 上传目录、媒体文件、附件 | 恢复网站内容 |
| 数据库 | 使用数据库自身工具导出的备份 | 恢复结构和业务数据 |
| 部署记录 | 版本号、迁移记录、依赖版本 | 判断代码与数据是否匹配 |
配置备份可以先保存在本机临时目录,但本机副本不能作为唯一备份。示例:
sudo install -d -m 0700 /var/backups/myapp
sudo sh -c '
umask 077
tar -czf "/var/backups/myapp/config-$(date +%F-%H%M%S).tgz" \
/etc/nginx \
/etc/systemd/system/myapp.service \
/etc/myapp
'
如果某个路径不存在,应按实际路径调整命令。备份中包含环境变量和证书私钥时,必须限制读取权限,并将副本传到独立存储。可以使用不带--delete的rsync先完成安全复制:
sudo rsync -aH --numeric-ids \
/srv/myapp/shared/uploads/ \
backupuser@BACKUP_HOST:/srv/backup/myapp/uploads/
BACKUP_HOST需要替换为独立备份主机。示例没有使用--delete,避免源目录误删后同步删除备份;如果确实需要镜像同步,必须先确认源目录、目标目录和删除范围,并保留带版本的历史副本。
数据库必须使用对应数据库的备份工具,并且要避免把密码直接写在命令行中。以常见数据库为例:
# PostgreSQL示例,认证方式由环境中的.pgpass或其他安全机制提供
umask 077
pg_dump -Fc --dbname=appdb > /var/backups/myapp/appdb.dump
# MySQL或兼容数据库示例,密码不要直接拼接在命令行
umask 077
mysqldump --single-transaction \
--routines \
--events \
--databases appdb \
> /var/backups/myapp/appdb.sql
--single-transaction是否适用,要看数据库引擎和表类型。涉及大表、非事务表或特殊存储引擎时,需要根据数据库文档选择一致性备份方式。备份计划也要根据业务可接受的数据丢失窗口安排:配置可以在每次发布前保存,数据库和用户上传数据则应按实际变化频率执行,并将副本复制到与生产服务器不同的存储位置。
备份完成后至少做两类验证:
tar -tzf /var/backups/myapp/config-YYYY-MM-DD-HHMMSS.tgz | head
pg_restore --list /var/backups/myapp/appdb.dump
更可靠的验证是定期在隔离环境恢复数据库和文件,再启动一套不接收公网流量的应用进行访问测试。只有“文件存在”和“备份命令返回成功”并不能证明恢复可用。
按由外到内的顺序验收和排障
完成部署后,可以按照下面的顺序检查:
- 确认应用服务已设置开机启动。
sudo systemctl is-enabled myapp nginx
sudo systemctl is-active myapp nginx
- 确认应用只监听内部地址,Nginx监听公网端口。
sudo ss -lntp | grep -E ':(3000|80|443)\b'
如果应用监听的是0.0.0.0:3000,应检查是否确有必要对外暴露;在仅由Nginx转发的架构中,通常应改为127.0.0.1:3000。
- 先验证应用本机接口,再验证HTTP域名。
curl --fail --max-time 5 http://127.0.0.1:3000/health
curl --resolve example.com:80:SERVER_IP \
-I http://example.com/
- 验证HTTPS、证书名称和应用返回状态。
curl --resolve example.com:443:SERVER_IP \
-I https://example.com/
- 检查配置和日志是否出现错误。
sudo nginx -t
sudo journalctl -u myapp --since "10 minutes ago" --no-pager
sudo tail -n 100 /var/log/nginx/myapp.error.log
不同结果对应的判断也应区分:
- 本机访问应用失败:优先检查应用服务、依赖、环境变量和端口,不要反复修改Nginx。
- 本机访问正常,公网返回502:通常检查Nginx上游地址、应用监听地址、服务权限和应用是否刚好重启。
- 返回504:重点查看应用处理时间、数据库和外部依赖,不能只把Nginx超时调得更大。
- HTTP正常、HTTPS失败:检查443监听、证书域名、证书路径和证书续期任务。
- 页面正常但上传失败:对照
client_max_body_size、应用上传限制、临时目录空间和目录权限。 - 服务器重启后服务消失:检查
systemctl is-enabled、服务文件路径和启动命令是否依赖交互式Shell。
变更失败时保留可回滚路径
Nginx变更应坚持“先测试、后加载”。如果nginx -t失败,不要执行reload;如果reload后访问异常,恢复变更前的站点配置,再次测试并平滑加载。恢复前应先保存当前故障状态,便于后续定位,而不是直接覆盖所有配置。
应用发布可以采用版本目录和current软链接:
/srv/myapp/releases/release-a/
/srv/myapp/releases/release-b/
/srv/myapp/current -> /srv/myapp/releases/release-b
切换前记录当前版本:
readlink -f /srv/myapp/current
新版本验证失败时,将current切回上一个已知可用版本,再重启应用:
sudo ln -sfn /srv/myapp/releases/release-a /srv/myapp/current
sudo systemctl restart myapp
sudo systemctl status myapp --no-pager
如果新版本已经执行了不可逆数据库迁移,不能只回滚代码。此时要根据迁移设计选择向前修复,或从经过验证的数据库备份恢复到隔离环境后再制定切换方案。应用、数据库结构和配置必须作为一个发布单元管理。
上线后容易漏掉的核对项
生产环境部署完成后,现场通常还会遗漏以下检查:
- Nginx和应用是否都设置了开机启动。
- 应用是否错误监听了公网地址。
www与主域名是否都配置了正确的证书和站点规则。- 应用是否正确识别HTTPS转发头,避免登录回调或绝对链接生成错误。
- Nginx、应用日志是否会自动切割,Journald和备份是否持续占满磁盘。
- 上传目录、环境变量、证书私钥和数据库是否都进入了相应备份范围。
- 备份是否复制到独立存储,最近一次恢复测试是否成功。
- 调整资源上限后,是否观察到内存、CPU、文件描述符和磁盘使用变化。
- 最近一次配置、证书、应用版本变更是否保留了明确的回滚副本。
这些检查完成后,香港CN2服务器上的网站才不只是“能够打开”,而是具备反向代理、进程自恢复、日志追踪、证书续期、资源约束和可恢复备份这几项生产运行所需的基础能力。