feat: support include other nginx config (#2803)

Close #2565
Close #1620
diff --git a/.travis/apisix_cli_test.sh b/.travis/apisix_cli_test.sh
index 299647d..9ea1c7c 100755
--- a/.travis/apisix_cli_test.sh
+++ b/.travis/apisix_cli_test.sh
@@ -560,6 +560,61 @@
 
 echo "passed: found 'my_dict' in nginx.conf"
 
+# allow injecting configuration snippets
+
+echo '
+apisix:
+    node_listen: 9080
+    enable_admin: true
+    port_admin: 9180
+    stream_proxy:
+        tcp:
+            - 9100
+nginx_config:
+    main_configuration_snippet: |
+        daemon on;
+    http_configuration_snippet: |
+        chunked_transfer_encoding on;
+    http_server_configuration_snippet: |
+        set $my "var";
+    http_admin_configuration_snippet: |
+        log_format admin "$request_time $pipe";
+    stream_configuration_snippet: |
+        tcp_nodelay off;
+' > conf/config.yaml
+
+make init
+
+grep "daemon on;" -A 2 conf/nginx.conf | grep "configuration snippet ends" > /dev/null
+if [ ! $? -eq 0 ]; then
+    echo "failed: can't inject main configuration"
+    exit 1
+fi
+
+grep "chunked_transfer_encoding on;" -A 2 conf/nginx.conf | grep "configuration snippet ends" > /dev/null
+if [ ! $? -eq 0 ]; then
+    echo "failed: can't inject http configuration"
+    exit 1
+fi
+
+grep 'set $my "var";' -A 2 conf/nginx.conf | grep "configuration snippet ends" > /dev/null
+if [ ! $? -eq 0 ]; then
+    echo "failed: can't inject http server configuration"
+    exit 1
+fi
+
+grep 'log_format admin "$request_time $pipe";' -A 2 conf/nginx.conf | grep "configuration snippet ends" > /dev/null
+if [ ! $? -eq 0 ]; then
+    echo "failed: can't inject admin server configuration"
+    exit 1
+fi
+
+grep 'tcp_nodelay off;' -A 2 conf/nginx.conf | grep "configuration snippet ends" > /dev/null
+if [ ! $? -eq 0 ]; then
+    echo "failed: can't inject stream configuration"
+    exit 1
+fi
+
 # check disable cpu affinity
 git checkout conf/config.yaml
 
diff --git a/apisix/cli/ngx_tpl.lua b/apisix/cli/ngx_tpl.lua
index 3d0440a..893b84c 100644
--- a/apisix/cli/ngx_tpl.lua
+++ b/apisix/cli/ngx_tpl.lua
@@ -48,6 +48,12 @@
 {% end %}
 {% end %}
 
+# main configuration snippet starts
+{% if main_configuration_snippet then %}
+{* main_configuration_snippet *}
+{% end %}
+# main configuration snippet ends
+
 {% if stream_proxy then %}
 stream {
     lua_package_path  "$prefix/deps/share/lua/5.1/?.lua;$prefix/deps/share/lua/5.1/?/init.lua;]=]
@@ -62,6 +68,12 @@
     resolver {% for _, dns_addr in ipairs(dns_resolver or {}) do %} {*dns_addr*} {% end %} valid={*dns_resolver_valid*};
     resolver_timeout {*resolver_timeout*};
 
+    # stream configuration snippet starts
+    {% if stream_configuration_snippet then %}
+    {* stream_configuration_snippet *}
+    {% end %}
+    # stream configuration snippet ends
+
     upstream apisix_backend {
         server 127.0.0.1:80;
         balancer_by_lua_block {
@@ -208,6 +220,12 @@
     {% end %}
     {% end %}
 
+    # http configuration snippet starts
+    {% if http_configuration_snippet then %}
+    {* http_configuration_snippet *}
+    {% end %}
+    # http configuration snippet ends
+
     upstream apisix_backend {
         server 0.0.0.1;
         balancer_by_lua_block {
@@ -258,6 +276,13 @@
         listen {* port_admin *};
         {%end%}
         log_not_found off;
+
+        # admin configuration snippet starts
+        {% if http_admin_configuration_snippet then %}
+        {* http_admin_configuration_snippet *}
+        {% end %}
+        # admin configuration snippet ends
+
         location /apisix/admin {
             {%if allow_admin then%}
                 {% for _, allow_ip in ipairs(allow_admin) do %}
@@ -341,6 +366,12 @@
         {% end %}
         {% end %}
 
+        # http server configuration snippet starts
+        {% if http_server_configuration_snippet then %}
+        {* http_server_configuration_snippet *}
+        {% end %}
+        # http server configuration snippet ends
+
         {% if with_module_status then %}
         location = /apisix/nginx_status {
             allow 127.0.0.0/24;
diff --git a/conf/config-default.yaml b/conf/config-default.yaml
index 6eaee36..db8fbbc 100644
--- a/conf/config-default.yaml
+++ b/conf/config-default.yaml
@@ -130,6 +130,26 @@
     worker_connections: 10620
   #envs:                            # allow to get a list of environment variables
   #  - TEST_ENV
+
+  # As user can add arbitrary configurations in the snippet,
+  # it is user's responsibility to check the configurations
+  # don't conflict with APISIX.
+  main_configuration_snippet: |
+    # Add custom Nginx main configuration to nginx.conf.
+    # The configuration should be well indented!
+  http_configuration_snippet: |
+    # Add custom Nginx http configuration to nginx.conf.
+    # The configuration should be well indented!
+  http_server_configuration_snippet: |
+    # Add custom Nginx http server configuration to nginx.conf.
+    # The configuration should be well indented!
+  http_admin_configuration_snippet: |
+    # Add custom Nginx admin server configuration to nginx.conf.
+    # The configuration should be well indented!
+  stream_configuration_snippet: |
+    # Add custom Nginx stream configuration to nginx.conf.
+    # The configuration should be well indented!
+
   http:
     enable_access_log: true        # enable access log or not, default true
     access_log: "logs/access.log"
diff --git a/doc/README.md b/doc/README.md
index 829dfaf..f2ea095 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -31,6 +31,7 @@
 * [Stand Alone Model](stand-alone.md): Supports to load route rules from local yaml file, it is more friendly such as under the kubernetes(k8s).
 * [Stream Proxy](stream-proxy.md)
 * [gRPC Proxy](grpc-proxy.md)
+* [Customize Nginx Configuration](./customize-nginx-configuration.md)
 * [Changelog](../CHANGELOG.md)
 * [Benchmark](benchmark.md)
 * [Code Style](../CODE_STYLE.md)
diff --git a/doc/customize-nginx-configuration.md b/doc/customize-nginx-configuration.md
new file mode 100644
index 0000000..d65fd8e
--- /dev/null
+++ b/doc/customize-nginx-configuration.md
@@ -0,0 +1,59 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+[中文](./zh-cn/customize-nginx-configuration.md)
+
+# Customize Nginx configuration
+
+The Nginx configuration used by APISIX is generated via the template file `apisix/ngx_tpl.lua` and the options from `conf/config-default.yaml` / `conf/config.yaml`.
+
+You can take a look at the generated Nginx configuration in `conf/nginx.conf` after running `./bin/apisix start`.
+
+If you want to customize the Nginx configuration, please read through the `nginx_config` in `conf/config-default.yaml`. You can override the default value in the `conf/config.yaml`. For instance, you can inject some snippets in the `conf/nginx.conf` via configuring the `xxx_snippet` entries:
+
+```yaml
+...
+# put this in config.yaml:
+nginx_config:
+    main_configuration_snippet: |
+        daemon on;
+    http_configuration_snippet: |
+        server
+        {
+            listen 45651;
+            server_name _;
+            access_log off;
+
+            location /ysec_status {
+                req_status_show;
+                allow 127.0.0.1;
+                deny all;
+            }
+        }
+
+        chunked_transfer_encoding on;
+
+    http_server_configuration_snippet: |
+        set $my "var";
+    http_admin_configuration_snippet: |
+        log_format admin "$request_time $pipe";
+    stream_configuration_snippet: |
+        tcp_nodelay off;
+...
+```
diff --git a/doc/zh-cn/README.md b/doc/zh-cn/README.md
index 6a2e7af..5d83b0b 100644
--- a/doc/zh-cn/README.md
+++ b/doc/zh-cn/README.md
@@ -30,6 +30,7 @@
 * [独立运行模型](stand-alone.md): 支持从本地 yaml 格式的配置文件启动,更适合 Kubernetes(k8s) 体系。
 * [TCP/UDP 动态代理](stream-proxy.md)
 * [gRPC 代理](grpc-proxy.md)
+* [自定义 Nginx 配置](./customize-nginx-configuration.md)
 * [变更日志](../../CHANGELOG_CN.md)
 * [压力测试](benchmark.md)
 * [代码风格](../../CODE_STYLE_CN.md)
diff --git a/doc/zh-cn/customize-nginx-configuration.md b/doc/zh-cn/customize-nginx-configuration.md
new file mode 100644
index 0000000..5b34f19
--- /dev/null
+++ b/doc/zh-cn/customize-nginx-configuration.md
@@ -0,0 +1,59 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+[English](../customize-nginx-configuration.md)
+
+# 自定义 Nginx 配置
+
+APISIX 会通过 `apisix/ngx_tpl.lua` 这个模板和 `conf/config-default.yaml` 加 `conf/config.yaml` 的配置生成 Nginx 配置文件。
+
+在执行完 `./bin/apisix start`,你可以在 `conf/nginx.conf` 看到生成的 Nginx 配置文件。
+
+在自定义 Nginx 配置文件之前,烦请仔细阅读 `conf/config-default.yaml`。你可以在 `conf/config.yaml` 里面覆盖掉默认值。举个例子,你可以通过 `xxx_snippet` 之类的配置,在 `conf/nginx.conf` 里面注入你的自定义配置:
+
+```yaml
+...
+# config.yaml 里面的内容
+nginx_config:
+    main_configuration_snippet: |
+        daemon on;
+    http_configuration_snippet: |
+        server
+        {
+            listen 45651;
+            server_name _;
+            access_log off;
+
+            location /ysec_status {
+                req_status_show;
+                allow 127.0.0.1;
+                deny all;
+            }
+        }
+
+        chunked_transfer_encoding on;
+
+    http_server_configuration_snippet: |
+        set $my "var";
+    http_admin_configuration_snippet: |
+        log_format admin "$request_time $pipe";
+    stream_configuration_snippet: |
+        tcp_nodelay off;
+...
+```