Add rate limiting scheme for proxies
diff --git a/README.rst b/README.rst
index cbf35a8..4df896c 100644
--- a/README.rst
+++ b/README.rst
@@ -213,6 +213,42 @@
               name: gitlab.domain.com
               port: 80
 
+Proxy with rate limiting scheme:
+
+.. code-block:: yaml
+
+    _dollar: '$'
+    nginx:
+      server:
+        site:
+          nginx_proxy_site01:
+            enabled: true
+            type: nginx_proxy
+            name: site01
+            proxy:
+              host: local.domain.com
+              port: 80
+              protocol: http
+            host:
+              name: gitlab.domain.com
+              port: 80
+            limit:
+              enabled: True
+              ip_whitelist:
+              - 127.0.0.1
+              burst: 600
+              rate: 10r/s
+              nodelay: True
+              subfilters:
+                heavy_url:
+                  input: ${_dollar}{binary_remote_addr}${_dollar}{request_uri}
+                  mode: blacklist
+                  items:
+                  - "~.*servers/detail[?]name=.*&status=ACTIVE"
+                  rate: 2r/m
+                  burst: 2
+                  nodelay: True
+
 Gitlab server with user for basic auth
 
 .. code-block:: yaml
diff --git a/nginx/files/_limit.conf b/nginx/files/_limit.conf
new file mode 100644
index 0000000..43e4315
--- /dev/null
+++ b/nginx/files/_limit.conf
@@ -0,0 +1,29 @@
+{%- if site.get('limit', {}).get('enabled', False) %}
+# Create whitelist for ip addresses
+geo $geo_{{site_name}} {
+    default "enforce";
+{%-   for ip in site.limit.get('ip_whitelist', []) %}
+    {{ip}} "whitelist";
+{%-   endfor %}
+}
+
+# First, map all whitelisted IP's to the request query
+map $geo_{{site_name}} $limit_{{site_name}} {
+    default {{site.limit.get('query', '$binary_remote_addr')}};
+    "whitelist" "";
+}
+limit_req_zone $limit_{{site_name}} zone={{site_name}}:{{site.limit.get('size', '100m')}} rate={{site.limit.get('rate', '30r/m')}};
+
+{%-   for subfilter_name, subfilter in site.limit.get('subfilters', {}).items() %}
+
+map "${geo_{{site_name}}}{{ subfilter.get('input', '$limit_{{site_name}}') }}" $limit_{{site_name}}_{{subfilter_name}} {
+    default {% if subfilter.get('mode', 'whitelist') == "whitelist" %}"{{ subfilter.get('input', '$limit_{{site_name}}') }}";{% else %}""{% endif %};
+    "~^whitelist" "";  # Allow previously whitelisted results.
+{%-     for match in subfilter.get('items', []) %}
+    "{{match}}" {% if subfilter.get('mode', 'whitelist') == 'whitelist' %}""{% else %}"{{ subfilter.get('input', '$limit_{{site_name}}') }}"{% endif %};
+{%-     endfor %}
+}
+limit_req_zone $limit_{{site_name}}_{{subfilter_name}} zone={{site_name}}_{{subfilter_name}}:{{subfilter.get('size', site.limit.get('size', '100m'))}} rate={{subfilter.get('rate', site.limit.get('rate', '30r/m'))}};
+{%-   endfor %}
+
+{%- endif %}
diff --git a/nginx/files/nginx.conf b/nginx/files/nginx.conf
index 703fc2e..9f19e7d 100644
--- a/nginx/files/nginx.conf
+++ b/nginx/files/nginx.conf
@@ -26,6 +26,8 @@
         server_names_hash_bucket_size 128;
         # server_name_in_redirect off;
 
+        variables_hash_bucket_size {{server.get('variables_hash_bucket_size', '128') }};
+
         include /etc/nginx/mime.types;
         default_type application/octet-stream;
 
diff --git a/nginx/files/proxy.conf b/nginx/files/proxy.conf
index eb3c06c..8888549 100644
--- a/nginx/files/proxy.conf
+++ b/nginx/files/proxy.conf
@@ -1,5 +1,7 @@
 {%- set site = salt['pillar.get']('nginx:server:site:'+site_name) %}
 
+{%- include "nginx/files/_limit.conf" %}
+
 server {
 
   {%- include "nginx/files/_name.conf" %}
@@ -15,6 +17,12 @@
 
   {%- include "nginx/files/_auth.conf" %}
 
+  {%- if site.get('limit', {}).get('enabled', False) %}
+  limit_req_status {{site.limit.get('status_code', '429')}};
+  limit_conn_status {{site.limit.get('status_code', '429')}};
+  {%- endif %}
+
+
   location / {
       {%- if site.proxy.upstream_proxy_pass is defined %}
       proxy_pass {{ site.proxy.upstream_proxy_pass }};
@@ -95,6 +103,12 @@
       {%- endif %}
       {%- endif %}
 
+      {%- if site.get('limit', {}).get('enabled', False) %}
+      limit_req zone={{site_name}}{% if site.limit.get('burst', False) %} burst={{site.limit.burst}}{% endif %}{% if site.limit.get('nodelay', False) %} nodelay{% endif %};
+      {%-   for subfilter_name, subfilter in site.limit.get('subfilters', {}).items() %}
+      limit_req zone={{site_name}}_{{subfilter_name}}{% if subfilter.get('burst', False) %} burst={{subfilter.burst}}{% endif %}{% if subfilter.get('nodelay', False) %} nodelay{% endif %};
+      {%-   endfor %}
+      {%- endif %}
   }
 
 }