<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta content="text/html;charset=UTF-8" http-equiv="Content-Type"></head><body ><div style="font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt;"><div>Dear Members,<br></div><div><br></div><div># HG changeset patch<br></div><div># User devarajan.dk <<a target="_blank" href="mailto:devarajan.dk@zohocorp.com">devarajan.dk@zohocorp.com</a>><br></div><div># Date 1654428592 -19800<br></div><div>#      Sun Jun 05 16:59:52 2022 +0530<br></div><div># Node ID 8d73e94b379091440ad8c836e2a052fb5edda160<br></div><div># Parent  e0cfab501dd11fdd23ad492419692269d3a01fc7<br></div><div><b>Dynamic Virtual Server Selection Based on Host's Cnamed domain</b><br></div><div><br></div><div><b>Use Case:</b><br></div><div>Preventing nginx.conf reload on new customer domain addition.<br></div><div><br></div><div>Many B2B Cloud Services provide option for rebranding customer domains through CNAME.<br></div><div>eg. Customers - mail.schroeppel.me, mail.vey.de cnamed to ghs.googlehosted.com<br></div><div>The hosting Service can be having multiple such services reverse proxied through<br></div><div>same nginx instance. (eg. Virtual Servers - mail.ghost.com, docs.ghost.com, drive.ghost.com, etc.<br></div><div>all virtual services listening on the same IP and port; consider 100s of such virtual services)<br></div><div><br></div><div>While deployment, the cloud service has to add the customer domain name in 'server_name' directive<br></div><div>of corresponding virtual server for the request to reach the right virtual server block.<br></div><div>Also, as the customer has given control to the hosting cloud service, the service will also<br></div><div>purchase certificate for the customer domain and offload through nginx.<br></div><div><br></div><div>As and when the new rebranding customers starts to subscribe for the cloud service, the cloud service<br></div><div>has to add the certificate name & key in ssl_certificate & ssl_certificate_key directives respectively<br></div><div>and customer's domain name in server_name directive of corresponding virtual server.<br></div><div>So the nginx.conf has to be reloaded every time a new customer starts using the service.<br></div><div><br></div><div>As the frequency of new customers joining the service increases, the hosting service<br></div><div>may suffer from frequent nginx reloads and may not scale well.<br></div><div>(consider 100s of customers joining the service every hour)<br></div><div>Thanks to the Dynamic Certificate Loading feature in nginx that uses $ssl_server_name variable<br></div><div>to dynamically select the certificate on runtime and no need to reload conf after deploying certificate.<br></div><div>But still there is a need to reload the conf due to the addition of customer's domain name in server_name directive.<br></div><div><br></div><div>To prevent this reload, we can dynamically choose Virtual server based on the cname of the customer domains.<br></div><div>Only the cnamed domain ie. mail.ghost.com will be written in the server_name directive of the virtual server.<br></div><div>All customer domains cnamed to mail.ghost.com will be routed to right virtual server based on the cname.<br></div><div>This cname check can be turned on/off by a http level directive - 'resolve_cname' (off by default)<br></div><div><br></div><div>Note:<br></div><div>1. Similar to Dynamic Certificate Loading, the pros of dynamic Virtual Server selection come <br></div><div>   at the cost of increase in latency during request processing time due to DNS lookup.<br></div><div>2. The cloud service can choose to deploy their customer domains in hybrid mode too. <br></div><div>   (ie. old customers domains can be explicitly configured in server_name and <br></div><div>   customer domains who newly subscribed for the cloud service in between two nginx.conf reloads<br></div><div>   can be deployed in nginx dynamically)<br></div><div><br></div><div><br></div><div>diff -r e0cfab501dd1 -r 8d73e94b3790 src/http/ngx_http_core_module.c<br></div><div>--- a/src/http/ngx_http_core_module.c   Tue May 31 00:14:11 2022 +0300<br></div><div>+++ b/src/http/ngx_http_core_module.c   Sun Jun 05 16:59:52 2022 +0530<br></div><div>@@ -252,6 +252,13 @@<br></div><div>       offsetof(ngx_http_core_srv_conf_t, large_client_header_buffers),<br></div><div>       NULL },<br></div><div> <br></div><div>+    { ngx_string("resolve_cname"),<br></div><div>+      NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG,<br></div><div>+      ngx_conf_set_flag_slot,<br></div><div>+      NGX_HTTP_MAIN_CONF_OFFSET,<br></div><div>+      offsetof(ngx_http_core_main_conf_t, resolve_cname),<br></div><div>+      NULL },<br></div><div>+<br></div><div>     { ngx_string("ignore_invalid_headers"),<br></div><div>       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,<br></div><div>       ngx_conf_set_flag_slot,<br></div><div>@@ -3404,6 +3411,7 @@<br></div><div>     cmcf->variables_hash_max_size = NGX_CONF_UNSET_UINT;<br></div><div>     cmcf->variables_hash_bucket_size = NGX_CONF_UNSET_UINT;<br></div><div> <br></div><div>+    cmcf->resolve_cname = NGX_CONF_UNSET;<br></div><div>     return cmcf;<br></div><div> }<br></div><div> <br></div><div>diff -r e0cfab501dd1 -r 8d73e94b3790 src/http/ngx_http_core_module.h<br></div><div>--- a/src/http/ngx_http_core_module.h   Tue May 31 00:14:11 2022 +0300<br></div><div>+++ b/src/http/ngx_http_core_module.h   Sun Jun 05 16:59:52 2022 +0530<br></div><div>@@ -172,6 +172,8 @@<br></div><div> <br></div><div>     ngx_array_t               *ports;<br></div><div> <br></div><div>+    ngx_flag_t                 resolve_cname;<br></div><div>+<br></div><div>     ngx_http_phase_t           phases[NGX_HTTP_LOG_PHASE + 1];<br></div><div> } ngx_http_core_main_conf_t;<br></div><div> <br></div><div>diff -r e0cfab501dd1 -r 8d73e94b3790 src/http/ngx_http_request.c<br></div><div>--- a/src/http/ngx_http_request.c       Tue May 31 00:14:11 2022 +0300<br></div><div>+++ b/src/http/ngx_http_request.c       Sun Jun 05 16:59:52 2022 +0530<br></div><div>@@ -8,6 +8,7 @@<br></div><div> #include <ngx_config.h><br></div><div> #include <ngx_core.h><br></div><div> #include <ngx_http.h><br></div><div>+#include<netdb.h><br></div><div> <br></div><div> <br></div><div> static void ngx_http_wait_request_handler(ngx_event_t *ev);<br></div><div>@@ -36,6 +37,8 @@<br></div><div> static ngx_int_t ngx_http_find_virtual_server(ngx_connection_t *c,<br></div><div>     ngx_http_virtual_names_t *virtual_names, ngx_str_t *host,<br></div><div>     ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp);<br></div><div>+    <br></div><div>+static void ngx_http_find_cname(ngx_str_t* host, ngx_str_t* cname, ngx_http_request_t *r);<br></div><div> <br></div><div> static void ngx_http_request_handler(ngx_event_t *ev);<br></div><div> static void ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc);<br></div><div>@@ -2269,6 +2272,27 @@<br></div><div>     return NGX_OK;<br></div><div> }<br></div><div> <br></div><div>+static void<br></div><div>+ngx_http_find_cname(ngx_str_t* host, ngx_str_t* cname, ngx_http_request_t *r)<br></div><div>+{<br></div><div>+    struct hostent *he;<br></div><div>+    char **alias_list;<br></div><div>+<br></div><div>+    if ( (he = gethostbyname( (char*) host->data ) ) == NULL) {<br></div><div>+        return;<br></div><div>+    }<br></div><div>+<br></div><div>+    alias_list = (char **) he->h_aliases;<br></div><div>+<br></div><div>+    for(int i = 0; alias_list[i] != NULL; i++) {<br></div><div>+        if (alias_list[i+1] == NULL) {<br></div><div>+            cname->data = (u_char *) alias_list[i];<br></div><div>+            cname->len = ngx_strlen(cname->data);<br></div><div>+        }<br></div><div>+    }<br></div><div>+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,<br></div><div>+                   "Host - %s cnamed to %s", host->data, cname->data);<br></div><div>+}<br></div><div> <br></div><div> static ngx_int_t<br></div><div> ngx_http_find_virtual_server(ngx_connection_t *c,<br></div><div>@@ -2290,6 +2314,24 @@<br></div><div>         return NGX_OK;<br></div><div>     }<br></div><div> <br></div><div>+    ngx_http_core_main_conf_t *cmcf;<br></div><div>+<br></div><div>+    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);<br></div><div>+<br></div><div>+    if(cmcf->resolve_cname) {<br></div><div>+        ngx_str_t cname = ngx_null_string;<br></div><div>+        ngx_http_find_cname(host, &cname, r);<br></div><div>+        if (cname.data != NULL) {<br></div><div>+            cscf = ngx_hash_find_combined(&virtual_names->names,<br></div><div>+                                      ngx_hash_key(cname.data, cname.len),<br></div><div>+                                      cname.data, cname.len);<br></div><div>+            if (cscf) {<br></div><div>+                *cscfp = cscf;<br></div><div>+                return NGX_OK;<br></div><div>+            }<br></div><div>+        }<br></div><div>+    }<br></div><div>+<br></div><div> #if (NGX_PCRE)<br></div><div> <br></div><div>     if (host->len && virtual_names->nregex) {<br></div><div><br></div><div><br></div><div class="zmail_signature_below"><div id="" data-zbluepencil-ignore="true" data-sigid="795269000000038001"><div>Thanks & Regards,<br></div><div>Devarajan D.,<br></div><div>Member Technical Staff,<br></div><div>ZOHO Corporation Pvt. Ltd.<br></div></div></div><div><br></div></div><br></body></html>