version: 1.0.0
Nginx is a widely used web server. However, when a web application become complicated, it is a nightmare to maintain the Nginx configuration. For example:
- It is hard find the location a certain request matched within hundreds of locations, which will lead to mis-configured the Nginx conf and make your service down.
- It is hard to make sure your rewrite rules are well written.
- It help user debug nginx conf: find the location a request matched, or point out the url after rewrite
- Can be used in online environment and develop environment, and no need to
build different binary:
- When used in online environment, it make no difference to business request
- When used in develop environment, it can debug the nginx configuration without other dependency, espeically proxy scene
- It is easy to be integrate into an auto test platform for large scale configuration management.
- Not to modify Nginx's official open source code for the convenience of adapting to all version of Nginx.
request -----
O -----------> | |
-|- |Nginx|
/ \ <----------- | |
conf info -----
Especially, when Nginx is used as a proxy
Debug mode: Whether our module working or not, it should not impact on Nginx's normal function.
-----
O request | | request ----------
-|- -----------> |Nginx| ----------> | Upstream |
/ \ | | ----------
-----
or
request -----
O -----------> | | request ----------
-|- |Nginx| ----------> | Upstream |
/ \ <----------- | | ----------
conf info -----
Interrupt mode:
request -----
O -----------> | | request ----------
-|- |Nginx| -----X-----> | Upstream |
/ \ <----------- | | ----------
conf info -----
The whole process of module must be:
- Find the correct config for current request matched
- Save the matching result
- Output conf message
NGX_HTTP_ACCESS_PHASE is the best choice for ngx_http_conf_debug_module because:
- It may interrupt the whole request
- It will not influence normal request processing
For most scene consideration, we don't take nested location and @name location into account.
Parsing and saving location config is impletmented in ngx_http_core_location function. location infomation is stored in clcf(ngx_http_core_loc_conf_t), core properties are as followed:
- name
- exact_match
- noregex
- regex
- named(for @name scene, not cared)
As Nginx doesn't have any data stucture to store location mode information, we need to find it through reduction. Nginx has 5 location mode, and :
- =, exact_match == 1, noregex == 0, regex == NULL
- ~, exact_match == 0, noregex == 0, regex != NULL, pcre_fullinfo(regex->regex->code, PCRE_INFO_OPTIONS) & PCRE_CASELESS == 0
- ~*, exact_match == 0, noregex == 0, regex != NULL pcre_fullinfo(regex->regex->code, PCRE_INFO_OPTIONS) & PCRE_CASELESS == 1
- ^~, exact_match == 0, noregex == 1, regex == NULL
- , exact_match == 0, noregex == 0, regex == NULL
Since $proxy_host variable are not available until NGX_HTTP_CONTENT_PHASE, we need to get ngx_http_proxy_module configuration, which is not visible for ngx_http_conf_debug_module. Therefore, we need to redefine a data structure to get proxy_host's value ahead. Keey in mind, redefined data structure must keep same as definition in ngx_http_proxy_module.
The resule above base on assumption: macro NGX_HTTP_CASELESS_FILESYSTEM hasn't been defined(if defined, Nginx will take ~ as caseless)
According to Nginx architecture, variable is a common ways for comunication between modules. For the convenience for decoupling the output ways, variable is a good choice.
In order to manager easily, there must be a variable name scheme to:
- Identify the variable providing module.
- Add more varible as ngx_http_conf_debug_module supporting more and more config debuging needs.
Variable name starts with: $conf_debug_, follow by config name and property. For example:
- $conf_debug_location_mode
- $conf_debug_location_name
- ...
ngx_http_conf_debug_module is used in to scene:
- Interrupt normal request
- Not Interrupt normal request
Considering:
- Debug message need to places in http header becase http body is defined by upstream and has no extendibility.
- Reusing current Nginx response editing ability is the best choice.
If a request match a normal prefix mode location, such as "location / {}", "blank" will be set as variable's value because some middleware will remove the header when its value is "".
User must use "add_header" directive to add debug message in response header. Header add by user is recommended to start with: X-Conf-Debug-. For example:
add_header X-Conf-Debug-Location-Mode $conf_debug_location_mode always;
"always" is needed becase in "Not interrupt normal request" scene, upstream server may reseponse various of http status code, which may make add header failed
By the way, in "Not interrupt notmal request" scene, we strongly recommend user to add some network isolation(for example: iptables) to prevent nginx from sending the offline request to online server.