LHIDC

把外贸网站服务器投入生产环境前,反向代理、证书与备份应如何配置

面向维护外贸网站服务器的站长与技术负责人,本文按上线流程讲解Nginx反向代理、systemd进程守护、HTTPS证书自动续期、日志关联、异地备份与资源限制,并提供配置验证、恢复测试及故障回滚要点。

把外贸网站服务器投入生产环境前,反向代理、证书与备份应如何配置

投入生产环境后的目标状态应当是:应用进程只监听本机或内网地址,由 Nginx 统一接收公网请求;HTTPS 证书可以自动续期;应用由 systemd 等服务管理器守护;代理日志与应用日志能够关联;数据库、上传文件和配置有独立于服务器的备份,并且已经验证可以恢复。任何一项缺失,都可能让外贸网站服务器在流量进入后出现无法续证、进程退出、磁盘写满或备份不可用等问题。

以下操作以 Ubuntu 22.04/24.04、Debian 12、Nginx 和 systemd 为例,假设应用监听 127.0.0.1:3000。执行前需要准备已解析的域名、服务器管理权限、可用的 80/443 端口和一个短时维护窗口。其他发行版的包管理器、Nginx配置目录和服务名称可能不同,应先核对,不能直接照搬。

先确认现状和变更影响范围

不要从安装证书或修改 Nginx 开始。先确认请求现在经过哪些组件,以及应用是否能绕过反向代理直接被公网访问。

cat /etc/os-release
nginx -v
systemctl --version | head -n 1
sudo nginx -T
sudo ss -lntp
systemctl list-units --type=service --state=running
df -h
free -h

重点核对以下事项:

  • 域名的 A、AAAA 记录是否都指向当前入口。若存在错误的 AAAA 记录,ACME 验证可能访问到另一台服务器。
  • 80 和 443 端口前是否还有 CDN、负载均衡器或云防火墙。
  • 应用是否只监听 127.0.0.1。如果监听 0.0.0.0:3000 且端口对公网开放,用户可能绕过 Nginx、证书和访问控制。
  • Nginx 是否已有同名 server_name,避免新旧虚拟主机相互冲突。
  • 数据库和上传目录在哪里,是否存在依赖本机磁盘的持久化数据。
  • 当前应用如何启动。由终端、nohup 或临时脚本启动的进程,不适合作为生产环境的长期运行方式。

如果入口前还有 CDN 或负载均衡器,Nginx 看到的 $remote_addr 通常是上游节点地址。此时需要按照上游公开的地址范围配置 Real IP 模块,不能为了获取客户端 IP 而信任任意来源提交的 X-Forwarded-For

在改动前留下可回退副本

配置备份和业务备份不是一回事。前者用于快速撤销本次变更,后者用于服务器损坏或数据误操作后的恢复,两者都需要。

下面的命令会把 Nginx、systemd 自定义服务和证书目录保存到仅 root 可读的位置。证书目录包含私钥,不能放到公开目录或未经加密的共享存储中。

CHANGE_ID=$(date +%Y%m%d-%H%M%S)
sudo install -d -m 0700 /root/change-backups

sudo tar --acls --xattrs -czf \
  "/root/change-backups/nginx-systemd-${CHANGE_ID}.tar.gz" \
  /etc/nginx /etc/systemd/system

if [ -d /etc/letsencrypt ]; then
  sudo tar --acls --xattrs -czf \
    "/root/change-backups/letsencrypt-${CHANGE_ID}.tar.gz" \
    /etc/letsencrypt
fi

再导出当前生效配置,便于比较变更前后的差异:

sudo nginx -T > "/tmp/nginx-before-${CHANGE_ID}.txt" 2>&1
sudo systemctl cat site-app.service > "/tmp/site-app-before-${CHANGE_ID}.txt" 2>&1 || true

如果部署同时包含数据库迁移,必须先确认迁移是否可逆。仅回滚应用代码而数据库结构无法回退,通常不能恢复到原来的运行状态。

先让应用具备独立运行能力

反向代理只能转发请求,不能代替应用进程守护。Node.js、Python 或自定义二进制程序可以使用 systemd;PHP 应用通常应管理对应的 PHP-FPM 服务,而不是额外启动一个长期 PHP 进程。

下面是 Node.js 应用的 systemd 示例。User、运行路径和 ExecStart 必须根据实际环境修改,可以先用 command -v node 核对可执行文件位置。

[Unit]
Description=Website Application
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=siteapp
Group=siteapp
WorkingDirectory=/srv/site/current
EnvironmentFile=-/etc/site-app.env
ExecStart=/usr/bin/node /srv/site/current/server.js
Restart=on-failure
RestartSec=5s
TimeoutStopSec=30s
KillSignal=SIGTERM
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ReadWritePaths=/srv/site/shared

[Install]
WantedBy=multi-user.target

将其保存为 /etc/systemd/system/site-app.service 后,先检查环境变量文件和目录权限。应用不应以 root 身份运行,敏感环境变量文件建议设置为仅管理员和服务账号可读。

sudo systemctl daemon-reload
sudo systemctl enable --now site-app.service
sudo systemctl status site-app.service
sudo journalctl -u site-app.service -n 100 --no-pager

不要看到 active (running) 就认为应用正常,还应直接访问本机监听端口:

curl -sS -o /dev/null \
  -w 'HTTP %{http_code} time=%{time_total}s\n' \
  http://127.0.0.1:3000/

如果应用提供专用健康检查接口,应优先检查该接口。连接被拒绝通常意味着进程未监听、端口不一致或服务启动失败;返回 500 则应继续查看应用日志和数据库连接状态。

分两阶段启用 Nginx 反向代理

证书签发依赖域名验证,因此更稳妥的顺序是先启用 HTTP 和 ACME 验证目录,确认域名请求能够到达当前服务器,再申请证书并启用 HTTPS。

先建立验证目录:

sudo install -d -m 0755 /var/www/acme/.well-known/acme-challenge

在 Ubuntu、Debian 的标准 Nginx 目录中,可以创建 /etc/nginx/sites-available/site.conf。先使用以下 HTTP 配置,并把示例域名替换为真实域名:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    access_log /var/log/nginx/site.access.log;
    error_log /var/log/nginx/site.error.log warn;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/acme;
        default_type text/plain;
        try_files $uri =404;
    }

    location / {
        proxy_pass http://127.0.0.1:3000;
        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 X-Request-ID $request_id;

        add_header X-Request-ID $request_id always;
    }
}

启用站点前,先检查是否已经存在同名配置:

sudo grep -R "server_name.*example.com" /etc/nginx
sudo ln -s /etc/nginx/sites-available/site.conf /etc/nginx/sites-enabled/site.conf
sudo nginx -t

如果符号链接已经存在,不要强制覆盖,应先确认它指向哪个文件。只有 nginx -t 成功后才能平滑加载:

sudo systemctl reload nginx

创建临时验证文件并从域名访问:

echo "acme-check" | sudo tee \
  /var/www/acme/.well-known/acme-challenge/check.txt >/dev/null

curl -i http://example.com/.well-known/acme-challenge/check.txt

应返回 200acme-check。如果返回 404,需要检查请求是否进入了另一个虚拟主机;超时则应检查 DNS、入口防火墙和上游负载均衡器。

申请证书并切换到 HTTPS

在上述系统中,可以使用 Certbot 的 Webroot 模式申请证书。它不会为了签发证书而接管应用端口,也便于保留明确的 Nginx 配置。

sudo apt update
sudo apt install certbot
sudo certbot certonly \
  --webroot \
  -w /var/www/acme \
  -d example.com \
  -d www.example.com

签发成功后,将站点配置调整为 HTTP 跳转和 HTTPS 代理。不要在证书文件尚未生成时提前引用相应路径,否则 Nginx 配置检查会失败。

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/acme;
        default_type text/plain;
        try_files $uri =404;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    access_log /var/log/nginx/site.access.log;
    error_log /var/log/nginx/site.error.log warn;

    location / {
        proxy_pass http://127.0.0.1:3000;
        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 https;
        proxy_set_header X-Request-ID $request_id;

        add_header X-Request-ID $request_id always;
    }
}

再次执行检查和加载:

sudo nginx -t
sudo systemctl reload nginx

如果应用包含 WebSocket,需要额外配置 UpgradeConnection 请求头;如果有大文件上传或长时间任务,还要根据业务实际调整 client_max_body_sizeproxy_read_timeout 等参数。不能为了避免 413 或超时而无限放大这些值,否则会增加内存、连接和慢请求占用。

证书自动续期必须单独验证:

systemctl list-timers --all | grep -i certbot
sudo certbot renew --dry-run

可以在 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx 中设置续期后的安全加载脚本:

#!/bin/sh
/usr/sbin/nginx -t && /bin/systemctl reload nginx

创建前应确认同名文件不存在,并将脚本设置为可执行。不要使用无条件重启 Nginx 的续期钩子,否则错误配置可能导致服务中断。

sudo chmod 0755 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx

HSTS 不建议在首次切换 HTTPS 时立即加入。只有确认所有子域、第三方回调和历史链接都支持 HTTPS 后再启用,尤其不要贸然使用 includeSubDomains

让代理日志能够回答“慢在哪里”

只记录 HTTP 状态码不足以区分 Nginx 慢、应用慢还是上游连接失败。可以在 /etc/nginx/conf.d/site-log-format.conf 中增加包含请求时间和上游时间的日志格式:

log_format site_main
    '$remote_addr [$time_local] "$request_method $uri $server_protocol" '
    'status=$status bytes=$body_bytes_sent '
    'request_time=$request_time upstream_time=$upstream_response_time '
    'upstream_addr=$upstream_addr request_id=$request_id '
    'referer="$http_referer" agent="$http_user_agent"';

然后把 HTTPS 虚拟主机中的访问日志改为:

access_log /var/log/nginx/site.access.log site_main;

执行 sudo nginx -t 后再 reload。应用也应记录同一个 X-Request-ID,这样可以从 Nginx 的一条 502 或慢请求继续定位到应用日志。

常用观察命令如下:

sudo tail -f /var/log/nginx/site.access.log
sudo tail -f /var/log/nginx/site.error.log
sudo journalctl -u site-app.service -f
sudo logrotate -d /etc/logrotate.d/nginx

logrotate -d 只用于调试轮转规则,不会真正轮转。还应检查 journald 和 Nginx 日志的磁盘上限,避免访问量增长后写满系统盘。日志中不要记录密码、完整令牌、支付参数或不必要的查询字符串。

备份必须覆盖数据、配置和恢复链路

生产备份不能只复制网站代码。代码通常可以重新发布,真正难以重建的是数据库、用户上传文件、运行配置和密钥。

备份对象 推荐方式 关键检查
数据库 数据库原生逻辑备份或一致性物理备份 能否在隔离环境中恢复,事务和字符集是否正确
上传文件 文件级备份、对象存储复制或一致性快照 数据库记录与文件版本是否对应
Nginx、systemd 配置 版本管理加加密备份 路径、权限和服务账号是否保留
应用密钥与环境变量 加密备份并限制访问身份 是否具备轮换和撤销机制
ACME 证书目录 保留权限的加密备份 私钥不得进入公开仓库
备份清单与校验值 随备份保存 能否发现传输或存储损坏

以 PostgreSQL 为例,可以在维护窗口执行一次逻辑备份。以下数据库名和目录需要按实际环境修改:

set -euo pipefail
STAMP=$(date +%Y%m%d-%H%M%S)
DEST="/var/backups/site/${STAMP}"

sudo install -d -m 0700 "$DEST"

sudo -u postgres pg_dump -Fc shopdb \
  | sudo tee "${DEST}/shopdb.dump" >/dev/null

sudo tar --acls --xattrs -czf "${DEST}/uploads.tar.gz" \
  -C /srv/site/shared uploads

sudo sha256sum "${DEST}/shopdb.dump" "${DEST}/uploads.tar.gz" \
  | sudo tee "${DEST}/SHA256SUMS" >/dev/null

MySQL 或 MariaDB 应使用相应的 mysqldumpmariadb-dump 或物理备份工具,认证信息不要直接写在命令行参数中。--single-transaction 只适合支持事务一致性的表,不能把它视为所有存储引擎的通用保证。

本地 /var/backups 只能作为临时落地点。完整备份还应由独立凭据传输到服务器之外,并设置加密、保留周期和失败告警。服务器磁盘损坏、账号被入侵或误删除时,本机备份往往会一起丢失。

恢复验证应在隔离环境中进行,至少确认:

  1. 压缩包和校验值可以读取。
  2. 数据库备份能够导入空数据库。
  3. 上传目录的权限、属主和符号链接正确。
  4. 恢复后的应用能读取数据库和文件。
  5. 备份所需时间、恢复顺序和负责人员已经记录。

不要用“备份任务显示成功”代替恢复测试。

给进程、磁盘和请求设置资源边界

资源限制不是数值越小越安全。设置前应先观察应用在正常流量、发布和备份期间的占用,再为操作系统、Nginx、数据库和恢复任务保留空间。

systemd 常见边界包括:

  • MemoryHigh:接近该值时开始施加内存压力,适合作为预警边界。
  • MemoryMax:硬性上限,超过后服务可能被终止,设置过低会直接造成请求中断。
  • TasksMax:限制线程和子进程数量,需要考虑应用 worker 模型。
  • CPUQuota:限制 CPU 使用比例,过紧会把短时高峰变成长时间排队。
  • LimitNOFILE:限制文件描述符,必须与应用连接池和 Nginx 并发设置配合。

可分配给应用的内存上限,应从总内存中扣除操作系统、Nginx、数据库、备份峰值和安全余量,而不是复制其他服务器的固定数值。修改限制后执行:

sudo systemctl daemon-reload
sudo systemctl restart site-app.service
sudo systemctl show site-app.service \
  -p MemoryCurrent -p MemoryHigh -p MemoryMax -p TasksCurrent -p TasksMax

重启会中断当前进程,应在维护窗口执行。磁盘方面至少监控系统盘、数据库目录、上传目录和日志目录,备份任务也不能把源服务器磁盘占满。

上线验证与回滚触发条件

切换完成后,应从本机代理、外部域名、证书链和应用日志四个层面检查,而不是只打开一次首页。

curl -I http://example.com/
curl -sS -o /dev/null \
  -w 'HTTP %{http_code} time=%{time_total}s\n' \
  https://example.com/

openssl s_client \
  -connect example.com:443 \
  -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

sudo nginx -t
sudo systemctl is-active nginx
sudo systemctl is-active site-app.service
sudo journalctl -u site-app.service -S -30min --no-pager

还要实际验证登录、表单提交、文件上传、后台任务、邮件回调和第三方接口。涉及写操作时使用测试账号,避免污染正式订单和客户数据。

出现以下情况时,不应继续叠加修改,而应暂停变更并评估回滚:

  • 502、504 或应用 5xx 持续出现。
  • 登录状态、回调地址或 HTTPS 跳转异常。
  • 证书域名不匹配、证书链不完整或续期演练失败。
  • 应用进程反复重启,内存、任务数或磁盘持续逼近上限。
  • 新配置导致上传、WebSocket、长请求等原有功能失效。
  • 备份任务失败,或者新版本包含不可逆的数据迁移。

回滚 Nginx 时,先恢复变更前的配置文件,再执行 sudo nginx -t;只有检查通过后才能 reload。回滚 systemd 单元后需要 daemon-reload,重启应用前应评估连接中断。若涉及数据库迁移,必须按照已验证的迁移回退方案处理,不能直接用旧程序连接不兼容的新结构。

生产变更后的观察期至少应覆盖一次业务高峰、一次证书续期演练和一次完整备份任务。只有代理错误率、应用日志、资源占用和备份结果都处于可解释状态,外贸网站服务器才算完成了从“能够访问”到“可以持续运行和恢复”的切换。

上一篇 Kubernetes集群上线前如何加固:API端口、身份认证、RBAC与审计检查

LHIDC 产品中心

继续查看可购买的海外服务器产品

文章用于辅助选型,最终价格、库存与配置请以产品详情页和下单页面展示为准。

查看产品 查看方案