技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTBE

Nginx 反向代理 Docker Nuxt 项目的完整配置过程

所属馆藏
Backend
文件格式
Markdown
原始路径
Backend/Nginx 反向代理 Docker Nuxt 项目的完整配置过程
本文目录18 个章节
  1. 一、整体架构
  2. 二、部署前检查
  3. 三、安装和启动 Nginx
  4. 四、准备 SSL 证书
  5. 五、理解 sites-available 和 sites-enabled
  6. 六、创建完整 Nginx 配置
  7. 七、逐项解释配置
  8. 八、启用站点
  9. 九、停用默认站点
  10. 十、检查并应用配置
  11. 十一、验证部署结果
  12. 十二、缓存与登录态注意事项
  13. 十三、常见故障排查
  14. 十四、查看访问日志和错误日志
  15. 十五、更新应用
  16. 十六、手动更新 SSL 证书
  17. 十七、最终检查清单
  18. 总结

Nginx 反向代理 Docker Nuxt 项目的完整配置过程

Category(分类): Backend Status: 已验证

本文记录一次完整的生产部署实践:Nuxt 应用运行在 Docker 容器中,宿主机使用 Nginx 提供公网入口、HTTP 到 HTTPS 跳转、TLS 证书加载和反向代理。

案例使用以下参数:

项目
操作系统Ubuntu / Debian 系 Linux
公网域名articlet.rivers.pub
Nuxt 容器端口3031
宿主机监听地址127.0.0.1:3031
HTTPS 入口Nginx 443 端口
HTTP 入口Nginx 80 端口,重定向到 HTTPS
证书文件/etc/nginx/ssl/articlet.rivers.pub_bundle.crt
私钥文件/etc/nginx/ssl/articlet.rivers.pub.key

本文假设 Nuxt 已经通过 Docker Compose 启动。Nginx 不运行在容器中,而是直接安装在宿主机上。

一、整体架构

请求链路如下:

浏览器
  │
  │ https://articlet.rivers.pub:443
  ▼
宿主机 Nginx
  │
  │ http://127.0.0.1:3031
  ▼
Docker 端口映射
  │
  ▼
Nuxt / Nitro 容器

这种结构有几个优点:

  1. Nginx 统一处理 TLS、域名和公网端口;
  2. Nuxt 容器只需要处理应用请求;
  3. 应用端口只绑定到 127.0.0.1,不会直接暴露到公网;
  4. 更新应用容器通常不需要修改 Nginx;
  5. 手动替换证书后只需重新加载 Nginx,无须重启应用。

Docker Compose 中建议这样映射端口:

services:
  app:
    ports:
      - '127.0.0.1:3031:3031'

不要写成下面这样:

ports:
  - '3031:3031'

后者会让 3031 监听宿主机所有网卡。即使云安全组暂时没有放行,也没有必要增加额外的公网暴露面。

二、部署前检查

1. 检查域名解析

在服务器执行:

getent hosts articlet.rivers.pub

结果应该指向当前云服务器的公网 IP。也可以在本地检查:

nslookup articlet.rivers.pub

如果域名解析尚未生效,应先在 DNS 服务商处添加 A 记录:

articlet.rivers.pub → 云服务器公网 IPv4

2. 检查云安全组

腾讯云安全组至少需要允许:

协议端口用途
TCP22SSH 管理服务器
TCP80HTTP 访问及跳转 HTTPS
TCP443HTTPS 访问

不需要开放 3031,因为该端口只允许宿主机 Nginx 访问。

3. 检查 Nuxt 容器

进入项目目录:

cd /root/techArticle_nuxt

检查容器:

docker compose ps
docker compose logs --tail=100 app

正常情况下应该看到类似输出:

STATUS: Up
Listening on http://0.0.0.0:3031

从宿主机直接访问 Nuxt:

curl --noproxy '*' -I http://127.0.0.1:3031/

预期返回:

HTTP/1.1 200 OK

这里显式使用 --noproxy '*',可以避免服务器 Shell 中的 HTTP 代理干扰本地回环地址测试。

在本地端口尚未返回正常响应前,不要继续配置 Nginx,否则最终只会得到 502 Bad Gateway

三、安装和启动 Nginx

Ubuntu 或 Debian 可以执行:

apt update
apt install -y nginx

设置开机启动并立即启动:

systemctl enable --now nginx

检查状态:

systemctl status nginx --no-pager
nginx -v

检查端口占用:

ss -lntp | grep -E ':80|:443|:3031'

预期结构是:

  • Nginx 监听 0.0.0.0:800.0.0.0:443
  • Docker 映射只监听 127.0.0.1:3031

四、准备 SSL 证书

本案例手动维护 SSL 证书,已有文件为:

/etc/nginx/ssl/articlet.rivers.pub_bundle.crt
/etc/nginx/ssl/articlet.rivers.pub.key

文件不要求必须重命名为 fullchain.pemprivkey.pem。Nginx 只关心配置中的路径是否准确、证书格式是否正确,以及证书与私钥是否匹配。

1. 创建目录

mkdir -p /etc/nginx/ssl

2. 上传证书

在本地电脑执行:

scp articlet.rivers.pub_bundle.crt \
  root@服务器公网IP:/etc/nginx/ssl/articlet.rivers.pub_bundle.crt

scp articlet.rivers.pub.key \
  root@服务器公网IP:/etc/nginx/ssl/articlet.rivers.pub.key

3. 设置权限

chmod 644 /etc/nginx/ssl/articlet.rivers.pub_bundle.crt
chmod 600 /etc/nginx/ssl/articlet.rivers.pub.key

证书可以公开读取,但私钥不应允许普通用户读取。私钥也绝对不能提交到 Git 仓库。

4. 检查证书信息

openssl x509 \
  -in /etc/nginx/ssl/articlet.rivers.pub_bundle.crt \
  -noout -subject -issuer -dates

检查证书是否覆盖当前域名:

openssl x509 \
  -in /etc/nginx/ssl/articlet.rivers.pub_bundle.crt \
  -noout -checkhost articlet.rivers.pub

预期输出:

Certificate will match

5. 检查证书与私钥是否匹配

分别计算证书公钥和私钥公钥的摘要:

openssl x509 \
  -in /etc/nginx/ssl/articlet.rivers.pub_bundle.crt \
  -pubkey -noout | openssl sha256

openssl pkey \
  -in /etc/nginx/ssl/articlet.rivers.pub.key \
  -pubout | openssl sha256

两条命令输出的 SHA256 必须一致。否则说明证书与私钥不是一对,Nginx 无法正常加载。

五、理解 sites-available 和 sites-enabled

Ubuntu、Debian 的 Nginx 通常采用以下目录结构:

/etc/nginx/sites-available/   存放所有站点配置
/etc/nginx/sites-enabled/     存放当前启用站点的符号链接

仅在 sites-available 中创建配置,并不代表站点已经启用。还需要在 sites-enabled 中创建符号链接:

/etc/nginx/sites-enabled/techarticle
  → /etc/nginx/sites-available/techarticle

这种设计允许保留站点配置,同时通过添加或删除符号链接快速启用、停用站点。

六、创建完整 Nginx 配置

创建配置文件:

nano /etc/nginx/sites-available/techarticle

写入以下内容:

server {
    listen 80;
    listen [::]:80;

    server_name articlet.rivers.pub;

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

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name articlet.rivers.pub;

    ssl_certificate     /etc/nginx/ssl/articlet.rivers.pub_bundle.crt;
    ssl_certificate_key /etc/nginx/ssl/articlet.rivers.pub.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    location / {
        proxy_pass http://127.0.0.1:3031;
        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-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header Connection "";

        proxy_connect_timeout 10s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}

也可以通过 Here Document 一次写入:

cat > /etc/nginx/sites-available/techarticle <<'EOF'
server {
    listen 80;
    listen [::]:80;

    server_name articlet.rivers.pub;

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

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name articlet.rivers.pub;

    ssl_certificate     /etc/nginx/ssl/articlet.rivers.pub_bundle.crt;
    ssl_certificate_key /etc/nginx/ssl/articlet.rivers.pub.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    location / {
        proxy_pass http://127.0.0.1:3031;
        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-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header Connection "";

        proxy_connect_timeout 10s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}
EOF

七、逐项解释配置

1. HTTP 跳转 HTTPS

server {
    listen 80;
    server_name articlet.rivers.pub;
    return 301 https://$host$request_uri;
}

访问:

http://articlet.rivers.pub/articles/example

会跳转到:

https://articlet.rivers.pub/articles/example

$request_uri 会保留原始路径和查询参数。

2. 加载证书

ssl_certificate     /etc/nginx/ssl/articlet.rivers.pub_bundle.crt;
ssl_certificate_key /etc/nginx/ssl/articlet.rivers.pub.key;

ssl_certificate 应使用包含完整证书链的 bundle 文件,否则部分浏览器或客户端可能提示证书链不完整。

3. 反向代理

proxy_pass http://127.0.0.1:3031;

这里的 127.0.0.1:3031 是宿主机上的 Docker 映射端口。由于 Nginx 运行在宿主机上,所以不能写 Compose 服务名 app:3031

只有当 Nginx 也运行在同一个 Docker Compose 网络中时,才使用:

proxy_pass http://app:3031;

4. 保留原始域名

proxy_set_header Host $host;

Nuxt 收到的 Host 将保持为 articlet.rivers.pub,而不是 127.0.0.1:3031

5. 传递客户端 IP

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

应用可以通过这些请求头获取客户端来源 IP。登录限流、访问日志和审计通常会使用这些信息。

6. 告诉应用原请求是 HTTPS

proxy_set_header X-Forwarded-Proto $scheme;

浏览器与 Nginx 之间使用 HTTPS,但 Nginx 到 Nuxt 使用本地 HTTP。该请求头用于告诉 Nuxt:外部原始协议是 HTTPS。

生产环境中的安全 Cookie 配置通常还需要:

NUXT_AUTH_COOKIE_SECURE=true

Secure Cookie 只能通过 HTTPS 发送,因此登录功能应使用正式域名验证,不应使用 HTTP IP 地址验证。

7. 超时时间

proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
  • proxy_connect_timeout:Nginx 连接 Nuxt 的超时;
  • proxy_send_timeout:Nginx 向 Nuxt 发送请求的超时;
  • proxy_read_timeout:Nginx 等待 Nuxt 响应数据的超时。

八、启用站点

创建符号链接:

ln -s /etc/nginx/sites-available/techarticle \
  /etc/nginx/sites-enabled/techarticle

为了避免重复执行时报错,可以写成:

test -L /etc/nginx/sites-enabled/techarticle \
  || ln -s /etc/nginx/sites-available/techarticle \
    /etc/nginx/sites-enabled/techarticle

其中:

  • test -L 检查符号链接是否存在;
  • || 表示前面的检查失败时才执行后面的命令;
  • ln -s 创建符号链接。

查看启用结果:

ls -l /etc/nginx/sites-enabled/

应该看到:

techarticle -> /etc/nginx/sites-available/techarticle

九、停用默认站点

Nginx 安装后通常启用了默认站点:

/etc/nginx/sites-enabled/default

可以删除默认站点的符号链接:

test -L /etc/nginx/sites-enabled/default \
  && unlink /etc/nginx/sites-enabled/default

其中:

  • && 表示链接存在时才执行 unlink
  • unlink 只删除 sites-enabled 中的符号链接;
  • /etc/nginx/sites-available/default 原始配置不会被删除。

停用默认站点可以避免域名匹配异常时显示 Nginx 默认欢迎页。

十、检查并应用配置

任何 Nginx 配置变更都应该先执行:

nginx -t

正常输出类似:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

确认成功后重新加载:

systemctl reload nginx

也可以合并为:

nginx -t && systemctl reload nginx

使用 reload 而不是 restart,Nginx 会平滑加载新配置,通常不会中断现有连接。

检查运行状态:

systemctl status nginx --no-pager

查看 Nginx 最终加载的完整配置:

nginx -T

十一、验证部署结果

1. 验证 HTTP 跳转

curl --noproxy '*' -I http://articlet.rivers.pub

预期结果:

HTTP/1.1 301 Moved Permanently
Location: https://articlet.rivers.pub/

2. 验证 HTTPS

curl --noproxy '*' -I https://articlet.rivers.pub

预期返回 200 OK。如果客户端和 Nginx 支持 HTTP/2,也可能显示:

HTTP/2 200

3. 验证证书

openssl s_client \
  -connect articlet.rivers.pub:443 \
  -servername articlet.rivers.pub </dev/null

重点检查:

  • 证书域名是否正确;
  • 证书链是否完整;
  • 验证结果是否为 Verify return code: 0 (ok)
  • 到期时间是否正确。

4. 浏览器验证

依次检查:

  1. http://articlet.rivers.pub 是否自动跳转 HTTPS;
  2. 首页是否正常渲染;
  3. 静态资源是否正常加载;
  4. 公开文章是否可以访问;
  5. 登录 Cookie 是否带有 Secure 属性;
  6. 登录后私有文章是否可见;
  7. 登出后私有内容是否重新隐藏;
  8. 中文、空格和特殊字符文章路径是否正常。

十二、缓存与登录态注意事项

该 Nuxt 项目的页面内容会根据登录 Cookie 区分公开内容和私有内容,因此不要在 Nginx 中为 HTML 或 /api/ 配置共享 proxy_cache

危险示例:

location / {
    proxy_cache my_cache;
    proxy_pass http://127.0.0.1:3031;
}

如果缓存键没有正确包含身份信息,登录用户看到的私有页面可能被缓存后返回给匿名用户。

Nginx 默认不会自动开启 proxy_cache。没有明确需求时,保持不配置即可。公开静态资源可以根据应用返回的 Cache-Control 交给浏览器缓存。

十三、常见故障排查

1. 502 Bad Gateway

含义:Nginx 无法连接上游 Nuxt。

检查:

curl --noproxy '*' -I http://127.0.0.1:3031/
cd /root/techArticle_nuxt
docker compose ps
docker compose logs --tail=100 app

常见原因:

  • 容器没有启动;
  • Nuxt 启动失败;
  • 端口映射不是 3031
  • proxy_pass 地址写错;
  • 容器正在重新构建或重启。

2. Nginx 配置测试失败

执行:

nginx -t

常见原因:

  • 配置缺少分号;
  • 花括号不匹配;
  • 证书路径错误;
  • 私钥格式错误;
  • 证书与私钥不匹配;
  • 同一地址和域名存在冲突配置。

3. 显示 Nginx 默认欢迎页

检查启用目录:

ls -l /etc/nginx/sites-enabled/

确认:

  • techarticle 链接存在;
  • 默认站点已停用;
  • server_name 拼写正确;
  • 修改后已经执行 nginx -t && systemctl reload nginx

4. HTTPS 无法访问

检查监听:

ss -lntp | grep ':443'

检查云安全组是否放行 TCP 443,并查看日志:

tail -n 100 /var/log/nginx/error.log

检查:

  • 是否通过 https://articlet.rivers.pub 访问;
  • Compose 是否设置 NUXT_AUTH_COOKIE_SECURE=true
  • Nginx 是否传递 X-Forwarded-Proto $scheme
  • 浏览器中是否存在过期 Cookie;
  • 认证数据库目录是否可写。

查看应用日志:

cd /root/techArticle_nuxt
docker compose logs --tail=100 app

6. curl 输出受到代理影响

服务器可能设置了 HTTP_PROXYHTTPS_PROXYALL_PROXY。测试本机和正式域名时可以显式绕过代理:

curl --noproxy '*' -I http://127.0.0.1:3031/
curl --noproxy '*' -I https://articlet.rivers.pub/

十四、查看访问日志和错误日志

实时查看访问日志:

tail -f /var/log/nginx/access.log

实时查看错误日志:

tail -f /var/log/nginx/error.log

查看最近 100 行:

tail -n 100 /var/log/nginx/access.log
tail -n 100 /var/log/nginx/error.log

查看 Nuxt 日志:

cd /root/techArticle_nuxt
docker compose logs -f app

排查请求问题时,可以同时观察 Nginx 和 Nuxt 日志,确认请求是停在公网入口、反向代理层,还是应用层。

十五、更新应用

代码推送到 Git 仓库后,服务器执行:

cd /root/techArticle_nuxt

git pull --ff-only origin main

docker compose --progress=plain build app \
  && docker compose up -d

检查:

docker compose ps
docker compose logs --tail=100 app
curl --noproxy '*' -I http://127.0.0.1:3031/
curl --noproxy '*' -I https://articlet.rivers.pub/

应用更新通常不需要重新加载 Nginx。只有域名、证书、上游端口或 Nginx 配置发生变化时,才需要:

nginx -t && systemctl reload nginx

十六、手动更新 SSL 证书

新证书签发后,替换:

/etc/nginx/ssl/articlet.rivers.pub_bundle.crt
/etc/nginx/ssl/articlet.rivers.pub.key

替换前先检查新证书:

openssl x509 \
  -in /etc/nginx/ssl/articlet.rivers.pub_bundle.crt \
  -noout -subject -issuer -dates \
  -checkhost articlet.rivers.pub

然后检查并平滑加载:

nginx -t && systemctl reload nginx

查看当前证书到期时间:

openssl x509 \
  -in /etc/nginx/ssl/articlet.rivers.pub_bundle.crt \
  -noout -enddate

更新证书不需要重启 Docker 容器。

十七、最终检查清单

部署完成后逐项确认:

  • 域名解析到正确公网 IP;
  • 腾讯云安全组放行 TCP 80、443;
  • Nuxt 容器处于 Up 状态;
  • 127.0.0.1:3031 返回 200
  • 3031 没有直接暴露到公网;
  • 证书覆盖 articlet.rivers.pub
  • 证书与私钥匹配;
  • sites-enabled/techarticle 符号链接存在;
  • Nginx 默认站点已停用;
  • nginx -t 检查成功;
  • HTTP 自动跳转 HTTPS;
  • HTTPS 页面返回 200
  • 登录、登出和私有文章权限正常;
  • HTML 和 /api/ 没有启用共享代理缓存;
  • 已记录证书到期时间和更新流程。

总结

宿主机 Nginx 反向代理 Docker Nuxt 的核心步骤是:

  1. Nuxt 容器只绑定 127.0.0.1:3031
  2. Nginx 监听公网 80443
  3. HTTP 请求通过 301 跳转 HTTPS;
  4. Nginx 加载证书和私钥;
  5. HTTPS 请求转发到 http://127.0.0.1:3031
  6. 通过 X-Forwarded-* 请求头保留域名、协议和客户端 IP;
  7. sites-enabled 中创建符号链接启用站点;
  8. 每次修改后先执行 nginx -t,成功后再 reload;
  9. 登录态页面和 API 不启用共享代理缓存;
  10. 证书更新只需替换文件并重新加载 Nginx。

对于单机部署的 Nuxt SSR 应用,这种结构简单、清晰,既保留了 Docker 的环境隔离,也利用了 Nginx 成熟的 TLS 和反向代理能力。

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS