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


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

<!--more-->

---

## 1. 核心需求
实现一个动态规则：访问 `[端口号].example.com` 时，自动反向代理到本地服务器的 `127.0.0.1:[端口号]`。
例如：
* 访问 `8080.example.com` -> 转发至 `127.0.0.1:8080`
* 访问 `9000.example.com` -> 转发至 `127.0.0.1:9000`



---

## 2. Nginx 配置实现

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

```nginx
# 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;
    }
}
```

---

## 3. 关键技术点说明

### 3.1 正则表达式捕获
在 `server_name` 指令中，我们使用了 PCRE 命名分组语法：
`~^(?<target_port>\d+)\.example\.com$;`
* **`~`**: 告诉 Nginx 这是一个正则表达式匹配。
* **`^` 和 `$`**: 匹配域名的开始和结束，确保匹配的精确性。
* **`(?<target_port>\d+)`**: 匹配任意长度的数字，并将其赋值给变量 `$target_port`。后续在 `proxy_pass` 中可以直接调用该变量。

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

---

## 4. 安全与部署建议

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

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

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

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

---

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