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 %}
}
}