《Nginx 反向代理 + HTTPS 入门实战:一个入口接管「网页 + 接口」》

举报
yd_274623194 发表于 2026/10/28 11:03:31 2026/10/28
【摘要】 关键词:Nginx 反向代理、proxy_pass、HTTPS、Certbot、Docker Compose前两篇我们把服务跑起来了,也用数据卷保住了数据。但现在还有个别扭的地方:网页占 80 端口,接口占 8000 端口,浏览器访问接口要跨端口,地址栏里还挂着两个端口号。正式对外提供服务时,通常只留一个入口:Nginx 站在最前面,网页请求自己处理,接口请求悄悄转发给后端。这就是反向代理。...

关键词:Nginx 反向代理、proxy_pass、HTTPS、Certbot、Docker Compose

前两篇我们把服务跑起来了,也用数据卷保住了数据。但现在还有个别扭的地方:网页占 80 端口,接口占 8000 端口,浏览器访问接口要跨端口,地址栏里还挂着两个端口号。正式对外提供服务时,通常只留一个入口:Nginx 站在最前面,网页请求自己处理,接口请求悄悄转发给后端。这就是反向代理。

本文接着前面的 my-app 结构讲:web 是静态网页服务,api 是 8000 端口的接口服务,假设服务器上已经装好 Docker 和 Docker Compose。

一、目标架构:只暴露 80 和 443

改动前,浏览器要记两个地址:

  • 网页:http://服务器 IP/(web 的 80 端口)
  • 接口:http://服务器 IP:8000/(api 的 8000 端口)

改动后,只留一个入口:

  • 网页:http://域名/ → 网关 Nginx → web 容器
  • 接口:http://域名/api/ → 网关 Nginx → api 容器

web 和 api 不再直接对外暴露端口,只在 Compose 内部网络里互相可见。端口少了,攻击面小了,前端也不用再处理跨域和端口问题。

二、加一个网关服务

在 docker-compose.yml 里加一个 gateway 服务,用官方 Nginx 镜像,挂载一份我们自己写的配置:

services:
  gateway:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./gateway/nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - web
      - api
  web:
    build: ./web
    # 不再写 ports,改由网关转发
  api:
    build: ./api
    # 同样不再对外暴露 8000

注意:web 和 api 去掉 ports 之后,宿主机上 curl localhost:8000 就不通了,这是正常的——以后统一走网关的 /api/。

三、写网关配置:两条 location 分流

./gateway/nginx.conf 的核心就两条规则:

server {
    listen 80;
    server_name example.com;  # 换成你自己的域名

    location / {
        proxy_pass http://web:80;
        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;
    }

    location /api/ {
        proxy_pass http://api:8000/;
        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;
    }
}

两个细节最容易写错:

1. /api/ 后面那个斜杠不能省

proxy_pass http://api:8000/; 结尾带 /,表示把 /api/ 前缀剥掉再转发:浏览器请求 /api/users,后端收到的是 /users。如果写成 http://api:8000(不带斜杠),后端收到的还是完整的 /api/users,接口大概率 404。

2. 转发头要补齐

不写 X-Real-IP 和 X-Forwarded-For,后端看到的客户端 IP 永远是网关容器的内网 IP,日志和限流都会失真。X-Forwarded-Proto 则告诉后端原始请求是 http 还是 https,避免后端生成错误的跳转地址。

改完启动并验证:

docker compose up -d
curl http://localhost/        # 应返回网页
curl http://localhost/api/    # 应返回接口的响应

两条都通,代理就通了。

四、加上 HTTPS:先有域名,再谈证书

HTTPS 有一个硬性前提:需要一个指向这台服务器的域名。Let’s Encrypt 这类免费证书只发给域名,不给裸 IP 办法,所以如果现在手头只有 IP,先把上面反向代理的部分跑通,HTTPS 这一步等域名解析好再做,不用硬上。

域名就绪后,流程是三步:

1. 在宿主机上用 Certbot 申请证书

# 以 Debian/Ubuntu 为例
sudo apt install certbot
sudo mkdir -p /var/www/certbot
sudo certbot certonly --webroot -w /var/www/certbot \
  -d example.com

证书会落在宿主机的 /etc/letsencrypt/,有效期 90 天,到期前记得续期。

2. 把证书挂载进网关,并加 443 配置

docker-compose.yml 里给 gateway 再加一行挂载(只读):

    volumes:
      - ./gateway/nginx.conf:/etc/nginx/conf.d/default.conf:ro
      - /etc/letsencrypt:/etc/letsencrypt:ro
      - /var/www/certbot:/var/www/certbot:ro  # 供 80 端口的续期验证路径使用

配置里再加一个 443 的 server,并把 80 的请求跳转过去:

server {
    listen 80;
    server_name example.com;
    # Certbot 续期要走 http 验证,先放行验证路径,其余跳转 https
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://web:80;
        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;
    }

    location /api/ {
        proxy_pass http://api:8000/;
        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;
    }
}

3. 续期后重载 Nginx,不要重启容器

证书续期只是换了文件,Nginx 要重新读一次配置才生效:

sudo certbot renew
docker compose exec gateway nginx -s reload

只重载、不重启,正在处理的请求不会被打断。

五、两个新手最容易踩的坑

1. 80 端口被旧服务占着,网关起不来

如果宿主机上之前还有一个直接跑的 Nginx(比如 10-24 那篇里手动装的那个),gateway 会因为 80 端口冲突启动失败。先停掉旧的,再起 Compose,或者把网关改到别的端口测试。

2. 浏览器缓存了旧的 http 跳转

从 http 切到 https 后,浏览器可能还缓存着旧地址或旧的 301 跳转,改配置后看着"没生效"。先用 curl -v 验证服务端行为,确认服务端没问题再清浏览器缓存排查。

结语

从单容器、Compose 编排、数据卷,到今天的反向代理和 HTTPS,这条线就真正像一个能对外提供服务的部署了:一个入口、内外分层、传输加密。下一篇可以往运维方向走一步:给这套服务加上日志查看和健康检查,出问题先知道去哪看,而不是凭感觉重启。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。