目录

Nginx 实战:利用正则捕获实现子域名动态端口反向代理

在开发测试环境中,我们经常需要为多个本地服务配置外网访问。手动为每个端口编写 server 块不仅低效,而且难以维护。本文将介绍如何利用 Nginx 的正则表达式捕获功能,实现根据子域名自动转发到对应本地端口的“万能”反代配置。


实现一个动态规则:访问 [端口号].example.com 时,自动反向代理到本地服务器的 127.0.0.1:[端口号]。 例如:

  • 访问 8080.example.com -> 转发至 127.0.0.1:8080
  • 访问 9000.example.com -> 转发至 127.0.0.1:9000

以下是整合了正则捕获与 WebSocket 支持的完整配置模板:

# HTTP 自动跳转 HTTPS (可选)
server {
    listen 80;
    server_name ~^(?<target_port>\d+)\.example\.com$;

    # 引用全局跳转配置
    include extend/http_to_https.conf;
}

# HTTPS 核心配置
server {
    listen 443 ssl;
    
    # 【关键】使用正则命名分组捕获端口号到变量 $target_port
    server_name ~^(?<target_port>\d+)\.example\.com$;

    # 证书配置 (需确保证书支持通配符 *.example.com)
    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;

    # 日志路径建议包含变量,方便排查不同服务的访问记录
    access_log /data/wwwlogs/dynamic_proxy_$target_port_access.log combined;
    error_log /data/wwwlogs/dynamic_proxy_error.log;

    charset utf-8;

    location / {
        # 【关键】动态反代到本地对应的端口
        proxy_pass http://127.0.0.1:$target_port;

        # 标准头部转发与 WebSocket 支持
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        proxy_set_header Host $http_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;
    }
}

server_name 指令中,我们使用了 PCRE 命名分组语法: ~^(?<target_port>\d+)\.example\.com$;

  • ~: 告诉 Nginx 这是一个正则表达式匹配。
  • ^$: 匹配域名的开始和结束,确保匹配的精确性。
  • (?<target_port>\d+): 匹配任意长度的数字,并将其赋值给变量 $target_port。后续在 proxy_pass 中可以直接调用该变量。

通过 proxy_pass http://127.0.0.1:$target_port;,Nginx 不再将请求发往固定的后端,而是根据当前访问的子域名动态决定目标端口。


上述配置会尝试转发任何端口,这可能导致未授权访问服务器内部服务。建议限制端口范围。例如,只允许转发 80008999 之间的端口: server_name ~^(?<target_port>8\d{3})\.example\.com$;

请务必使用通配符证书(如 *.example.com)。单域名证书无法匹配动态生成的子域名。

在某些复杂的 Nginx 版本中,如果在 proxy_pass 中使用了变量,Nginx 启动时可能无法解析地址。虽然转发到 127.0.0.1 通常无须担心,但若转发到域名,请务必在 location 块中添加 resolver 指令: resolver 8.8.8.8 valid=30s;

使用变量作为日志路径(如 access_log /data/wwwlogs/$target_port.log)虽然便于区分,但在并发量极大或端口极多时,会因打开过多文件句柄而消耗系统资源。生产环境下建议汇总到一个文件或定期清理。


总结:这种配置极大地简化了内部测试环境的部署工作,实现了“一劳永逸”的端口映射管理,是 DevOps 和后端开发者的实用小技巧。