西雅图服务器用Ubuntu部署Docker网站,Nginx反向代理上线前要检查什么

在一个典型的西雅图服务器上线现场,站长已经把网站容器启动,却在浏览器里看到 502 Bad Gateway。工程人员不会先反复重启服务,而是沿着一条固定链路定位:域名是否指向服务器,公网端口是否能到达 Nginx,Nginx 是否能访问 Docker 容器,容器内的网站是否真正监听了预期端口。
本文采用的目标环境是 Ubuntu 服务器、Docker Compose 运行网站、宿主机 Nginx 负责反向代理。示例将网站容器端口绑定到宿主机 127.0.0.1:8080,公网只开放 Nginx 使用的 80 和 443 端口。正式上线前,至少要完成环境、端口、域名、代理配置、HTTPS、验证和回滚检查。
先确认上线条件和链路
在西雅图服务器上执行部署前,需要先明确以下条件:
| 检查项 | 需要确认的内容 | 未满足时的表现 |
|---|---|---|
| 操作系统 | Ubuntu 版本、架构和软件源可用 | Docker 或 Nginx 安装失败 |
| 登录权限 | 具备 sudo 权限,并保留当前 SSH 会话 | 无法安装软件或修改服务 |
| 域名 | A 记录指向服务器公网 IPv4;使用 IPv6 时再核对 AAAA | 域名访问到旧地址或无法连接 |
| 网络策略 | 云平台安全组、主机防火墙允许 TCP 80/443 | 浏览器超时 |
| Docker 应用 | 容器内部实际监听端口已知 | Nginx 返回 502 |
| Nginx | server_name 与访问域名一致 | 出现默认页面或匹配错误站点 |
| 回滚材料 | 旧配置、旧镜像或旧 Compose 文件可用 | 新版本异常时无法快速恢复 |
应用监听端口和宿主机发布端口不是一回事。例如,容器内部监听 80,可以发布为宿主机的 127.0.0.1:8080;此时 Nginx 的上游地址应是 127.0.0.1:8080,而不是容器内部地址或公网 IP。
在 Ubuntu 上检查并安装运行环境
先查看系统信息,不要仅凭记忆判断 Ubuntu 版本和架构:
cat /etc/os-release
uname -m
dpkg --print-architecture
如果准备使用 Docker 官方软件源,可以按下面方式安装 Docker Engine、Compose 插件和 Buildx:
sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor --yes -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "${VERSION_CODENAME}") stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
sudo docker info
sudo docker compose version
如果 apt update 提示当前 Ubuntu 代号没有对应的软件源,不要绕过校验继续安装,应先核对系统版本和软件源配置。docker info 能正常返回,且 docker compose version 能识别 Compose 插件,才适合继续部署。
首次安装后可以进行一次基础拉取测试:
sudo docker run --rm hello-world
这个命令会拉取测试镜像并启动临时容器。它不能证明业务网站正常,只能说明 Docker 服务和镜像拉取链路基本可用。
不建议为了省略 sudo 就直接把运维账号加入 docker 用户组。Docker 用户组通常拥有接近宿主机管理员的控制能力;如果确实要使用,应先评估账号权限边界,并保留现有 sudo 登录方式。
准备网站容器并限制暴露范围
假设网站部署目录为 /opt/example-site:
sudo mkdir -p /opt/example-site
sudo chown -R "$USER":"$USER" /opt/example-site
cd /opt/example-site
创建 .env 文件,替换为实际网站镜像和容器内部端口:
APP_IMAGE=your-registry/example-web:stable
APP_CONTAINER_PORT=80
这里的 APP_CONTAINER_PORT=80 只适用于网站进程在容器内监听 80 端口的情况。如果应用实际监听 3000、8080 或其他端口,应改成应用真实端口。不要因为宿主机使用 8080,就误把容器内部端口也写成 8080。
创建 compose.yaml:
services:
web:
image: ${APP_IMAGE}
restart: unless-stopped
ports:
- "127.0.0.1:8080:${APP_CONTAINER_PORT}"
这种写法的关键点是 127.0.0.1:8080。它只让宿主机本地的 Nginx访问网站,避免应用端口直接暴露到公网。不要随意改成 0.0.0.0:8080,否则云平台安全组和主机防火墙之外,还会多出一个直接访问应用的入口。
先检查 Compose 展开结果,再启动:
cd /opt/example-site
sudo docker compose config
sudo docker compose pull
sudo docker compose up -d
sudo docker compose ps
如果使用普通用户执行 Docker,会把命令中的 sudo 去掉;但同一项目最好保持权限方式一致,避免 /opt/example-site 下的文件出现难以管理的属主问题。
容器状态正常后,先绕过 Nginx访问上游:
curl -I http://127.0.0.1:8080/
sudo docker compose logs --tail=100 web
sudo ss -lntp | grep -E ':(8080|80|443)\b'
这里的结果需要结合应用特性判断。200、301 或应用预期的其他 HTTP 状态,可能都属于正常响应;如果连接被拒绝,优先检查容器是否运行、端口映射是否正确,以及应用是否在容器内监听了 0.0.0.0 而不是仅监听容器内部的 127.0.0.1。
安装 Nginx并配置反向代理
安装并启动宿主机 Nginx:
sudo apt update
sudo apt install -y nginx
sudo systemctl enable --now nginx
修改下面配置中的域名。配置文件放在 /etc/nginx/sites-available/example.com:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
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_read_timeout 60s;
}
}
配置中的 Host、X-Forwarded-For 和 X-Forwarded-Proto 不应省略。许多应用会依据 Host 判断站点域名,依据 X-Forwarded-Proto 判断原始请求是否为 HTTPS;缺少这些头部时,可能出现跳转循环、生成错误绝对链接或日志中只看到代理地址。
启用站点前先备份 Nginx 配置:
sudo cp -a /etc/nginx "/root/nginx-backup-$(date +%F-%H%M%S)"
sudo ln -s /etc/nginx/sites-available/example.com \
/etc/nginx/sites-enabled/example.com
如果软链接已经存在,不要重复创建;先检查它是否指向预期文件:
readlink -f /etc/nginx/sites-enabled/example.com
测试并加载配置:
sudo nginx -t
sudo systemctl reload nginx
只有 nginx -t 成功后才执行 reload。若测试失败,不要使用 systemctl restart nginx 强行覆盖运行状态,应先根据错误行号修复配置。若服务器没有启用 IPv6,listen [::]:80; 可能导致监听失败,此时应先用 ss -lntp 检查现有监听,再决定是否删除该 IPv6 监听行。
检查域名、防火墙和公网访问
在 DNS 管理处确认域名的 A 记录指向西雅图服务器公网 IPv4。若配置了 AAAA 记录,还要确保服务器确实配置了可用 IPv6;否则部分客户端可能优先访问 AAAA 地址而失败。
在服务器或可访问该 DNS 的环境中检查解析结果:
dig +short A example.com
dig +short AAAA example.com
主机防火墙和云平台安全组需要分别核对。若使用 UFW,先查看当前状态,确认仍能通过 SSH 登录,再放行 Nginx 所需端口:
sudo ufw status verbose
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx HTTP'
准备直接提供 HTTPS 时,再放行:
sudo ufw allow 'Nginx Full'
这些命令会修改主机防火墙规则,执行前应确认 SSH 规则存在,并保留云平台控制台或带外登录方式。云平台安全组也必须允许 TCP 80/443;只修改 UFW 而没有修改外层安全组,公网仍可能无法访问。
DNS完全生效前,可以用 curl --resolve 直接把域名临时指向服务器,用于区分“DNS问题”和“Nginx问题”:
curl -i --resolve example.com:80:SERVER_PUBLIC_IP \
http://example.com/
如果这个请求能返回网站内容,而普通域名访问失败,问题重点在 DNS 或客户端缓存;如果这个请求也失败,则继续检查安全组、UFW、Nginx监听和容器上游。
HTTPS上线前的检查
只有 HTTP 反向代理和域名解析已经正常,才适合申请证书。证书工具会修改 Nginx 配置,操作前应保留刚才的备份:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
只有在 www.example.com 也已解析到同一服务器时,才把它作为证书域名传入。证书申请要求域名能够从公网访问服务器的验证入口,DNS、云防火墙或 UFW 任一环节未放行,都可能导致申请失败。
完成后检查 Nginx 配置和 HTTPS响应:
sudo nginx -t
sudo systemctl reload nginx
curl -I https://example.com/
sudo certbot renew --dry-run
如果网站应用需要 WebSocket,还应在 Nginx 中补充 Upgrade 相关配置;如果应用上传大文件或长轮询,也要根据业务需求检查 client_max_body_size、proxy_read_timeout 等参数,不能直接套用默认值。
按由外到内的顺序处理异常
上线验证时,现场工程人员通常按以下顺序判断,避免把网络问题误判成容器问题:
- 先查 DNS。
dig返回旧 IP,说明域名记录或缓存尚未切换;没有 A/AAAA 结果,说明解析记录不完整。 - 再查公网端口。 浏览器超时,重点看云安全组、UFW和 Nginx 是否监听 80/443;连接被拒绝,重点看服务是否启动或端口是否被其他程序占用。
- 再查 Nginx 配置。
sudo nginx -t失败是语法、路径或重复监听问题;出现默认欢迎页,通常是域名未匹配到目标server_name,可用sudo nginx -T查看最终配置。 - 最后查上游容器。 Nginx 返回
502,常见原因是127.0.0.1:8080没有服务、端口映射错误、容器已退出或应用只监听了错误地址。此时直接执行curl http://127.0.0.1:8080/和docker compose logs。 - 区分应用错误。 Nginx能连到上游但返回
404、403或业务错误时,代理链路可能已经正常,应转而检查应用路由、Host判断、静态文件和应用日志。
新版本异常时如何回滚
升级网站镜像前,至少保存 Compose 文件和 Nginx站点配置:
cd /opt/example-site
cp -a compose.yaml "compose.yaml.backup.$(date +%F-%H%M%S)"
sudo cp -a /etc/nginx/sites-available/example.com \
"/root/example.com.nginx.$(date +%F-%H%M%S)"
正式环境应尽量使用可追溯的镜像标签或摘要,并保留上一版本镜像。发现新版本导致网站异常时,先恢复旧的 Compose 文件,再重新启动服务:
cd /opt/example-site
cp compose.yaml.backup.YYYY-MM-DD-HHMMSS compose.yaml
sudo docker compose config
sudo docker compose up -d
sudo docker compose ps
如果必须停止当前项目,docker compose down 会停止并移除该 Compose 项目管理的容器,但不应随意加 -v;-v 可能删除项目关联的数据卷,数据库或上传文件未完成备份时不能执行。
Nginx 配置异常时,先恢复对应站点文件,再测试并 reload:
sudo cp /root/example.com.nginx.YYYY-MM-DD-HHMMSS \
/etc/nginx/sites-available/example.com
sudo nginx -t
sudo systemctl reload nginx
如果只是误启用了新的站点软链接,应仅处理确认过的那个链接,不要使用通配符删除整个 sites-enabled 目录。回滚完成后,再依次验证本机上游、HTTP域名和 HTTPS域名。
容易被忽略的最后一项,是“服务能启动”不等于“网站已上线”:还要确认应用重启后能自动恢复、证书续期演练没有失败、AAAA记录与IPv6实际状态一致、容器端口没有意外暴露公网,以及旧版本配置和数据确实可以在当前服务器上重新使用。