Nginx

如何將 nginx 中的(大多數)子域重寫為 API/代理的虛擬路徑

  • July 2, 2020

我有一個租戶設置,其中未知數量的公司可以創建此類帳戶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),那麼這是如何完成的呢?

可以將部分Host標頭/TLS SNI 欄位擷取到一個變數中,server_name如下所示:

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

稍後,該變數可以在proxy_pass目的地中使用:

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

了解匹配規則很有用,這些規則在nginx 伺服器名稱文件中進行了說明。

我的評論會很長,請原諒。

參考 NGINX 文件:

萬用字元名稱只能在名稱的開頭或結尾包含星號,並且只能在點邊框上。名稱“www. .example.org”和“w .example.org”無效。但是,可以使用正則表達式指定這些名稱,例如“~^www..+.example.org$”和“~^w. .example.org$”。一個星號可以匹配多個名稱部分。名稱“ .example.org”不僅匹配www.example.org,還匹配www.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;
}
}

兩者都應該工作。

引用自:https://serverfault.com/questions/1023489