Nginx反向代理配置实战:单域名多端口服务统一入口与HTTPS部署

📅 2026/7/31 8:58:53
Nginx反向代理配置实战:单域名多端口服务统一入口与HTTPS部署
1. 项目缘起一个域名多个服务如何优雅地统一入口最近在折腾自己的个人服务器场景很典型一台云主机上跑了不止一个应用。比如一个主站博客跑在 3000 端口一个后台管理面板跑在 8080 端口可能还有个文件上传服务跑在 9000 端口。直接通过IP:端口访问不仅难记而且显得很不专业更别提安全问题了——尤其是那个后台管理面板直接暴露端口风险不小。更关键的是现在 HTTPS 已经是网站的标配。浏览器对非 HTTPS 站点的“不安全”警告足以劝退大部分访客。给每个端口的服务都单独申请证书、配置 HTTPS想想就头大管理成本太高。这时候Nginx 的价值就凸显出来了。它不仅仅是一个高性能的 Web 服务器更是一个强大的“流量调度员”。我们可以通过配置 Nginx实现用户只需访问一个主域名例如www.yourdomain.comNginx 根据不同的访问路径Path或子域名Subdomain将请求透明地转发到服务器内部不同的端口服务上并且全程使用 HTTPS 加密。对外用户看到的是一个统一、安全的域名对内我们的服务可以各自安好互不干扰。这个方案的好处显而易见统一入口提升体验用户只需记住一个域名通过不同的路径访问不同服务逻辑清晰。集中化管理 HTTPS只需要为这一个主域名申请和配置 SSL 证书Nginx 负责统一的 TLS 终止后端服务可以继续使用 HTTP简化了后端服务的配置。增强安全与可控性可以在 Nginx 层统一设置访问控制、限流、防火墙规则隐藏后端服务的真实端口降低被直接攻击的风险。负载均衡与高可用未来如果某个服务需要扩展可以轻松在 Nginx 配置中 upstream 多个后端实例实现负载均衡。接下来我就手把手带你完成这个“一个域名多端口HTTPS”的经典配置。我会假设你已经在服务器上安装好了 Nginx并且拥有一个已经解析到该服务器 IP 的域名。2. 核心原理Nginx 作为反向代理与 HTTPS 终结者在动手之前我们必须搞清楚 Nginx 在这个架构里扮演的两个核心角色反向代理Reverse Proxy和SSL/TLS 终结者SSL Termination。理解了这个配置起来就不会迷糊。2.1 反向代理流量的智能路由器你可以把 Nginx 想象成公司大楼的前台。访客客户端来到大楼只认识前台Nginx监听 80/443 端口。访客说“我要找技术部的张三对应访问/api路径”。前台查了一下内部通讯录Nginx 的配置规则发现技术部张三在 3 楼 301 房间后端服务器 localhost:3000。于是前台内部电话联系了 301 房间把访客的需求转达过去再把张三的回复转交给访客。在这个过程中访客永远只和前台打交道他不知道张三具体在哪个房间。前台根据访客的请求内容如 URL 路径决定将请求转发给内部的哪个服务。内部服务张三只需要处理前台转交过来的“纯业务”请求不用直接面对外部的复杂网络。在技术层面Nginx 通过proxy_pass指令实现这个功能。例如location /api/ { proxy_pass http://localhost:3000; }这表示所有以/api/开头的请求都会被 Nginx 转发到本机3000端口上运行的服务。2.2 HTTPS 终结集中化的加密门卫HTTPS 涉及复杂的 SSL/TLS 握手、证书验证和对称加密解密过程。如果让每个后端服务比如 Node.js、Python Flask、Java Spring Boot 应用都自己处理 HTTPS不仅每个应用都要配置证书还会消耗大量的 CPU 资源进行加解密。Nginx 的SSL Termination模式解决了这个问题。它让 Nginx 充当那个面对外界的“加密门卫”外部客户端与 Nginx 建立安全的 HTTPS 连接使用我们为域名配置的 SSL 证书。Nginx 完成 TLS 握手解密收到的 HTTPS 请求得到明文的 HTTP 请求。Nginx 根据配置规则将这个明文 HTTP 请求通过内部网络转发proxy_pass给后端的某个服务。后端服务处理这个普通的 HTTP 请求返回 HTTP 响应。Nginx 收到后端响应后再将其加密通过 HTTPS 连接发回给客户端。这样做的好处是证书管理简化只需在 Nginx 一处配置和维护 SSL 证书。后端服务轻量化后端服务可以专注于业务逻辑无需处理 SSL通常使用 HTTP 协议即可配置更简单。性能优化Nginx 非常擅长高效的 SSL/TLS 处理并且可以启用会话复用等优化降低延迟。一个重要的安全实践Nginx 与后端服务之间的内部通信虽然通常是 HTTP但因为它发生在服务器内部localhost 或内网所以风险可控。如果你对安全有极致要求可以在内网也使用 HTTPS 或其它安全通道但这会引入额外的证书管理和性能开销对于大多数个人或中小型项目HTTP over localhost 是常见且可接受的方案。3. 实战配置从零搭建多服务网关理论清晰了我们进入实战环节。我将以一个典型场景为例假设我们有一个域名example.com需要将流量分发到三个服务主网站前端运行在localhost:3000REST API 接口运行在localhost:8080管理后台运行在localhost:9000并且我们要为example.com配置 HTTPS。3.1 基础环境与证书准备首先确保你的 Nginx 已安装并运行。通过nginx -v可以查看版本。Nginx 的配置文件通常位于/etc/nginx/nginx.conf而具体的站点配置放在/etc/nginx/sites-available/目录下并通过软链接到/etc/nginx/sites-enabled/。第一步获取 SSL 证书现在获取免费 SSL 证书最方便的方式是使用 Let‘s Encrypt 的 certbot 工具。这里以 Ubuntu 系统为例# 安装 certbot 和 Nginx 插件 sudo apt update sudo apt install certbot python3-certbot-nginx # 为你的域名申请证书certbot 会自动修改 Nginx 配置来验证域名所有权 sudo certbot --nginx -d example.com -d www.example.com执行命令后按照交互提示操作即可。Certbot 会自动完成证书申请、验证并修改你的 Nginx 配置以启用 HTTPS。它会将证书文件通常包括fullchain.pem和privkey.pem保存在/etc/letsencrypt/live/example.com/目录下。注意运行 certbot 前请确保你的域名example.com的 A 记录已经正确解析到当前服务器的公网 IP并且服务器的 80 端口HTTP和 443 端口HTTPS已在防火墙中开放。第二步规划配置结构我们不建议直接修改默认的default配置。更好的做法是为你的站点创建一个独立的配置文件。sudo nano /etc/nginx/sites-available/example.com我们将在这个文件中编写完整的配置。3.2 编写核心 Nginx 配置下面是一个完整且注释详细的配置示例。请根据你的实际情况修改域名、证书路径和后端端口。# /etc/nginx/sites-available/example.com # 1. 定义上游服务器组可选为未来负载均衡做准备 # 这里我们先以单机为例实际上 upstream 可以包含多个 server。 upstream backend_website { server 127.0.0.1:3000; # 可以添加更多服务器实现负载均衡 # server 127.0.0.1:3001; # keepalive 32; # 保持连接池提升性能 } upstream backend_api { server 127.0.0.1:8080; } upstream backend_admin { server 127.0.0.1:9000; } # 2. 主服务器块监听 80 端口HTTP强制跳转到 HTTPS server { listen 80; listen [::]:80; server_name example.com www.example.com; # 将所有 HTTP 请求重定向到 HTTPS return 301 https://$server_name$request_uri; } # 3. 主服务器块监听 443 端口HTTPS server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name example.com www.example.com; # SSL 证书配置使用 certbot 自动生成的路径 ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # SSL 性能与安全优化配置可复用 certbot 生成的推荐配置 # 以下是一些关键参数certbot 通常会配置好 ssl_protocols TLSv1.2 TLSv1.3; # 禁用不安全的 TLS 版本 ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512; ssl_prefer_server_ciphers off; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # 根路径 / - 转发到主网站前端 location / { proxy_pass http://backend_website; # 使用 upstream 名称 # 以下是一系列重要的代理设置确保后端服务能正确获取客户端信息 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; # 告诉后端这是通过 https 来的 # 连接超时设置 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; # 禁用缓冲适用于 Server-Sent Events 或 WebSocket 等流式响应 # proxy_buffering off; } # API 接口路径 /api/ - 转发到 API 服务 location /api/ { proxy_pass http://backend_api/; # 注意结尾的斜杠很重要。 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; # 如果 API 需要处理较长的请求体或响应时间可以调整超时 # proxy_read_timeout 120s; # client_max_body_size 10M; # 允许更大的文件上传 } # 管理后台路径 /admin/ - 转发到管理后台服务 location /admin/ { proxy_pass http://backend_admin/; 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; # 可以在此处添加基础认证增加一层安全防护 # auth_basic Admin Area; # auth_basic_user_file /etc/nginx/.htpasswd; } # 静态文件服务优化可选如果前端有独立静态资源 location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$ { expires 1y; add_header Cache-Control public, immutable; # 如果静态文件由前端服务提供则不需要 proxy_pass # 如果放在 Nginx 本地可以用 root 或 alias 指令 # root /var/www/example.com/static; } # 错误页面配置 error_page 404 /404.html; location /404.html { root /usr/share/nginx/html; internal; } error_page 500 502 503 504 /50x.html; location /50x.html { root /usr/share/nginx/html; internal; } }3.3 配置详解与关键陷阱上面的配置看起来不少但核心就是几个location块。我们来拆解几个最容易出错的点1.proxy_pass结尾的斜杠/这是新手最常踩的坑。proxy_pass指令中URL 结尾是否有斜杠行为完全不同。proxy_pass http://backend_api/;有斜杠请求https://example.com/api/users转发给后端时Nginx 会移除匹配的/api/部分。后端实际收到的请求路径是/usersproxy_pass http://backend_api;无斜杠请求https://example.com/api/users转发给后端时Nginx 会保留完整的/api/路径。后端实际收到的请求路径是/api/users如何选择这取决于你的后端服务期望的路径。如果你的后端 API 根路径就是/api那么你应该用无斜杠的写法或者将location改为location /api不带结尾斜杠。通常为了让 Nginx 的配置更清晰充当纯粹的网关剥离路径前缀推荐使用带斜杠的写法并让后端服务监听在根路径上。2.proxy_set_header的重要性没有这几行你的后端服务就像“瞎了”一样Host $host告诉后端请求原始的主机名example.com否则后端可能收到localhost:8080这样的 Host导致生成错误的链接。X-Real-IP $remote_addr将客户端的真实 IP 传递给后端。否则在后端日志里所有请求都来自127.0.0.1Nginx 的 IP。X-Forwarded-For $proxy_add_x_forwarded_for如果请求经过多层代理这个头会记录整个代理链的 IP。X-Forwarded-Proto $scheme告诉后端请求的原始协议是https。这对于需要生成绝对 URL 或进行重定向的后端应用至关重要。3. 超时与缓冲区配置默认的 Nginx 超时设置可能对某些长连接应用如文件上传、WebSocket、Server-Sent Events不友好。如果你的应用有这类需求需要调整proxy_connect_timeoutproxy_send_timeoutproxy_read_timeout 以及考虑proxy_buffering off。3.4 启用配置与测试配置写好后需要创建软链接到sites-enabled目录并测试配置语法最后重载 Nginx。# 创建软链接 sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/ # 测试 Nginx 配置语法是否正确 sudo nginx -t # 如果看到 nginx: configuration file /etc/nginx/nginx.conf test is successful 则说明语法正确。 # 重载 Nginx 使配置生效 sudo systemctl reload nginx # 或者 sudo nginx -s reload现在你可以打开浏览器访问https://example.com它应该指向你的3000端口服务访问https://example.com/api/xxx应该指向8080端口访问https://example.com/admin/应该指向9000端口。并且所有连接都是安全的 HTTPS。4. 进阶配置与深度优化基础功能跑通后我们可以考虑一些进阶配置让这个网关更强大、更安全。4.1 基于子域名的路由除了用路径/api,/admin区分服务更清晰的做法是使用子域名。例如www.example.com- 主站 (3000)api.example.com- API 服务 (8080)admin.example.com- 管理后台 (9000)这种配置更符合 RESTful 风格并且后端服务完全不需要关心路径前缀。配置起来也很简单为每个子域名设置一个独立的server块即可。# API 子域名 server { listen 443 ssl http2; server_name api.example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # 可以使用通配符证书 *.example.com ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; location / { proxy_pass http://localhost:8080; # ... 其他代理头设置 } } # Admin 子域名 server { listen 443 ssl http2; server_name admin.example.com; # ... SSL 配置 location / { proxy_pass http://localhost:9000; # 强烈建议在此处增加额外的认证如 HTTP Basic Auth 或 IP 白名单 # allow 192.168.1.0/24; # deny all; # auth_basic Restricted; # auth_basic_user_file /etc/nginx/.htpasswd_admin; } }使用子域名需要配置 DNS为api.example.com和admin.example.com添加 A 记录指向服务器 IP。证书方面可以申请一张通配符证书*.example.com这样所有子域名都能使用。4.2 负载均衡与健康检查当某个服务流量增大时单实例可能成为瓶颈。Nginx 的upstream模块可以轻松实现负载均衡。我们之前已经定义了upstream现在可以扩展它。upstream backend_website { # 默认是轮询 (round-robin) server 127.0.0.1:3000 weight2; # weight 设置权重权重越高被分配到的请求越多 server 127.0.0.1:3001; server 127.0.0.1:3002 backup; # backup 服务器只有当其他服务器都不可用时才启用 # 其他负载均衡方法 # least_conn; # 最少连接数 # ip_hash; # 基于客户端 IP 的哈希实现会话保持注意这不是真正的会话粘滞后端需要共享会话状态 # hash $request_uri consistent; # 基于请求 URI 的哈希 # 健康检查需要 Nginx Plus 或使用开源模块如 nginx_upstream_check_module # check interval3000 rise2 fall5 timeout1000 typehttp; # check_http_send HEAD /health HTTP/1.0\r\n\r\n; # check_http_expect_alive http_2xx http_3xx; }在开源版 Nginx 中可以通过max_fails和fail_timeout参数实现基本的被动健康检查upstream backend_api { server 127.0.0.1:8080 max_fails3 fail_timeout30s; server 127.0.0.1:8081 max_fails3 fail_timeout30s; }这表示如果 Nginx 在 30 秒内连续 3 次连接到该服务器失败则会将其标记为不可用 30 秒。4.3 安全加固与性能调优安全加固隐藏 Nginx 版本信息在http块或server块中添加server_tokens off;防止泄露版本号。设置安全响应头add_header X-Frame-Options SAMEORIGIN always; # 防止点击劫持 add_header X-Content-Type-Options nosniff always; # 禁止 MIME 类型嗅探 add_header Referrer-Policy strict-origin-when-cross-origin always; # 控制 Referer 信息 # 内容安全策略 (CSP) 根据你的站点内容仔细配置 # add_header Content-Security-Policy default-src self; always;限制请求方法对于 API 接口可以只允许必要的 HTTP 方法。location /api/ { limit_except GET POST PUT DELETE { deny all; } # ... proxy_pass 等配置 }速率限制防止恶意刷接口。# 在 http 块中定义限制区 # http { # limit_req_zone $binary_remote_addr zoneapi_limit:10m rate10r/s; # } location /api/ { limit_req zoneapi_limit burst20 nodelay; # ... 其他配置 }性能调优启用 HTTP/2我们在listen指令中已经加了http2这能显著提升多资源加载性能。启用 Gzip 压缩压缩文本响应节省带宽。gzip on; gzip_vary on; gzip_min_length 1024; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xmlrss application/atomxml image/svgxml;调整缓冲区根据你的平均响应大小调整代理缓冲区避免磁盘 IO。proxy_buffers 16 32k; proxy_buffer_size 64k; proxy_busy_buffers_size 128k;连接保持在upstream中设置keepalive连接数减少频繁建立后端 TCP 连接的开销。upstream backend_api { server 127.0.0.1:8080; keepalive 32; } # 同时在 location 中需要设置 location /api/ { proxy_http_version 1.1; proxy_set_header Connection ; # ... 其他配置 }5. 常见问题排查与调试技巧即使配置看起来完美实际运行中也可能遇到各种问题。这里分享一些排查经验和技巧。问题一访问出现 502 Bad Gateway 或 504 Gateway Timeout这是最常见的问题意味着 Nginx 无法连接到后端服务或后端服务响应超时。检查后端服务是否运行sudo systemctl status your-service或ps aux | grep node/python/java。检查端口是否正确sudo netstat -tlnp | grep :3000确认服务在监听你配置的端口。检查防火墙确保服务器本地的防火墙如ufw没有阻止 Nginx运行在www-data或nginx用户下连接到后端的本地端口。对于本地回环localhost通信通常没问题但如果服务绑定在0.0.0.0而非127.0.0.1且防火墙规则严格可能会出问题。调整超时时间如 3.3 节所述适当增加proxy_connect_timeoutproxy_send_timeoutproxy_read_timeout的值。查看 Nginx 错误日志这是最直接的线索。日志通常在/var/log/nginx/error.log。使用sudo tail -f /var/log/nginx/error.log实时查看。问题二后端服务收到的请求 URL 或 Headers 不对检查proxy_pass结尾斜杠重温 3.3 节的内容这是元凶之一。检查proxy_set_header确保设置了HostX-Forwarded-Proto等头。可以在后端服务中打印接收到的所有 Headers 来验证。检查 Web 框架配置许多 Web 框架如 Express Flask Spring Boot需要显式配置信任代理才能正确解析X-Forwarded-For等头。例如在 Express 中需要设置app.set(trust proxy, true)。问题三静态资源CSS JS 图片加载 404路径问题如果前端是单页应用SPA 如 React Vue并且使用了前端路由如/dashboard直接刷新页面或访问深链接时Nginx 会把这个路径当作后端路由去匹配。解决方案是添加一个回退到index.html的规则。location / { try_files $uri $uri/ /index.html; # 先找文件再找目录最后回退到 index.html proxy_pass http://backend_website; # ... 代理设置 }注意try_files和proxy_pass在同一个location中通常不能共存因为try_files会检查文件系统。对于 SPA 代理更常见的做法是让 Nginx 直接服务打包后的静态文件或者确保后端服务能处理前端路由。如果必须代理可能需要更复杂的配置或者由前端服务自身处理 404 回退。MIME 类型错误确保 Nginx 能正确识别文件类型。检查/etc/nginx/mime.types文件是否包含对应的类型。问题四WebSocket 连接失败WebSocket 连接在握手成功后需要升级协议并保持长连接。Nginx 需要额外配置。location /ws/ { # 你的 WebSocket 路径 proxy_pass http://backend_website; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; 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_read_timeout 3600s; proxy_send_timeout 3600s; }关键就是Upgrade和Connection upgrade这两个头它们告诉 Nginx 这是 WebSocket 连接需要特殊处理。调试利器Nginx 日志养成看日志的习惯。你可以在location块中添加自定义日志格式来调试log_format proxy_log $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $upstream_addr $upstream_response_time; access_log /var/log/nginx/proxy_access.log proxy_log;这样在proxy_access.log中你就能看到请求被转发到了哪个上游服务器$upstream_addr以及响应时间$upstream_response_time对于排查负载均衡和性能问题非常有用。配置 Nginx 作为多服务网关和 HTTPS 终结者是一个运维和开发人员必备的技能。它看似复杂但核心逻辑清晰监听、匹配、转发。从最基础的路径转发开始逐步叠加子域名、负载均衡、安全策略等特性最终构建出一个稳健、高效、安全的服务入口。这个过程充满了细节一个斜杠、一个头信息都可能让服务行为异常但每一次排错都是对网络流量理解的一次加深。我的经验是写好配置后先用nginx -t测试再reload然后第一时间查看错误日志并打开浏览器开发者工具的“网络”选项卡仔细观察每一个请求的响应状态码和 Header 信息这套组合拳能解决大部分初期问题。