如何将 Nginx 中的(大多数)子域名重写为 API/代理的虚拟路径

如何将 Nginx 中的(大多数)子域名重写为 API/代理的虚拟路径

我有一个租户设置,其中未知数量的公司可以创建此类帐户company.app.com

后端服务器将它们视为: 5000/company/....,那么如何在 nginx 中重写(而不是重定向!)?这就是我所拥有的:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    ssl        on;
    ssl_certificate         /etc/ssl/certs/cert.pem;
    ssl_certificate_key     /etc/ssl/private/key.pem;

    server_name ????.app.com; <-- How?
    
    charset    utf-8;
    
    location / {
        proxy_pass         http://0.0.0.0:5000;
        proxy_http_version 1.1;
        proxy_set_header   Connection "";
        proxy_connect_timeout       300;
        proxy_send_timeout          300;
        proxy_read_timeout          300;
        send_timeout                300;            
        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-Host $server_name;
    }
}

现在的问题是我需要排除一小部分子域名(www、dash、mail),那么该如何做呢?

答案1

可以将Host标头/TLS SNI 字段的一部分捕获到变量中,如下server_name所示:

server_name ~^(?<company>.+)\.app\.com;

稍后,该变量可以在proxy_pass目标中使用它:

proxy_pass http://192.168.100.100:5000/$company/;

了解匹配规则很有用,这些规则在nginx 服务器名称文档

答案2

我的评论太长了,请原谅。

参考NGINX文档:

通配符名称只能在名称的开头或结尾处包含星号,并且只能在点边框上包含星号。名称“www..example.org” 和 “w.example.org” 是无效的。但是,可以使用正则表达式指定这些名称,例如“~^www..+.example.org$”和“~^w..example.org$”。星号可以匹配多个名称部分。名称“.example.org” 不仅匹配www.example.orgwww.sub.example.org也一样。

按名称搜索虚拟服务器时,如果名称与多个指定的变体匹配(例如,通配符名称和正则表达式匹配),则将按照以下优先顺序选择第一个匹配的变体:

  • 确切名称
  • 以星号开头的最长通配符名称,例如“*.example.org”
  • 以星号结尾的最长通配符名称,例如“mail.*”
  • 第一个匹配的正则表达式(按配置文件中出现的顺序)

形式为“.example.org”的特殊通配符名称可用于匹配精确名称“example.org”和通配符名称“*.example.org”。

由于 NGINX 支持通配符,因此它可以是这样的:

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl        on;
ssl_certificate         /etc/ssl/certs/cert.pem;
ssl_certificate_key     /etc/ssl/private/key.pem;

server_name *.app.com;

charset    utf-8;

location / {
    proxy_pass         http://0.0.0.0:5000;
    proxy_http_version 1.1;
    proxy_set_header   Connection "";
    proxy_connect_timeout       300;
    proxy_send_timeout          300;
    proxy_read_timeout          300;
    send_timeout                300;            
    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-Host $server_name;
}
}

甚至:

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl        on;
ssl_certificate         /etc/ssl/certs/cert.pem;
ssl_certificate_key     /etc/ssl/private/key.pem;

server_name *corp.app.com;

charset    utf-8;

location / {
    proxy_pass         http://0.0.0.0:5000;
    proxy_http_version 1.1;
    proxy_set_header   Connection "";
    proxy_connect_timeout       300;
    proxy_send_timeout          300;
    proxy_read_timeout          300;
    send_timeout                300;            
    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-Host $server_name;
}
}

两者都应该有效。

相关内容