From 6ecff985e843f2f93f2138981afb19467f3d4e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20C=C3=B4t=C3=A9-Tremblay?= Date: Tue, 2 May 2017 10:48:32 -0400 Subject: [PATCH 1/2] Implementing FastCGI cache to NGINX virtual host Benchmarking shows a significant increase of server response from 100ms to 10ms using FastCGI Cache. FastCGI Cache will make NGINX cache the page as static once generated, so the server will respond amazingly fast. You can enable FastCGI Cache by setting `php_fastcgi_cache_enabled` to `true`. If you want to clear the cache, you need to call from the same machine this corresponding URL : `http://[[php_base_name]].purge.cache.fastcgi.nginx.local/` More information about caching features can be found in `defaults/main.yml`. --- README.md | 9 ++++++++ defaults/main.yml | 21 +++++++++++++++++ tasks/nginx.yml | 21 +++++++++++++++++ templates/cache-clear-script.conf | 2 ++ templates/nginx.conf | 38 +++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+) create mode 100644 templates/cache-clear-script.conf diff --git a/README.md b/README.md index ffea823..e549665 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,13 @@ This role supports uninstalling cleanly. If you run the role with `php_uninstall resources created by the role will be removed. This however, excludes system packages because we want to avoid removing packages that another role might need. +## FastCGI Cache + +You can enable FastCGI Cache by setting `php_fastcgi_cache_enabled` to `true`. +If you want to clear the cache, you need to call from the same machine this +corresponding URL : `http://[[php_base_name]].purge.cache.fastcgi.nginx.local/` + +More information about caching features can be found in `defaults/main.yml`. + + [ansible-nginx]: https://github.com/savoirfairelinux/ansible-nginx diff --git a/defaults/main.yml b/defaults/main.yml index 5035f6c..530684e 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -77,3 +77,24 @@ php_http_basic_auth_accounts: [] # password: whatever42 # - username: alice # password: rocknroll42 + +# Enable FastCGI cache +php_fastcgi_cache_enabled: false + +# set fastcgi cache storage path +php_fastcgi_cache_storage_path: "/dev/shm/nginx_fastcgi_cache_{{ php_base_name }}" + +# maximum size of cache in Mb +php_fastcgi_cache_max_size_mb: 256 + +# minutes before cached page expiration +php_fastcgi_cache_expiration_minutes: 10080 + +# the request uris regexes to not cache +php_fastcgi_cache_ignored_uri_regex_matches: [] + +# if you want to not cache post requests +php_fastcgi_cache_ignore_post_requests: true + +# where you want to save the cache clear script +php_fastcgi_cache_purge_script_path: "" diff --git a/tasks/nginx.yml b/tasks/nginx.yml index bde6df9..8f6a665 100644 --- a/tasks/nginx.yml +++ b/tasks/nginx.yml @@ -20,3 +20,24 @@ - name: Create config for site template: "src=nginx.conf dest=/etc/nginx/sites-enabled/{{ php_base_name }}.conf" notify: nginx restart + +# Older versions of nginx shipped with package manager does not support +# fastcgi_cache_purge, and fastcgi refuses to give rights over cache files to +# particular users, and LXDock sets nosuid so we required to workaround this +# by creating a simple script owned by www-data that delete the cache by itself. +# For this version, the whole cache will be cleared because it do the +# job for what we need. May be required to upgrade this method in the future. +- name: Ensure a script that www-data can execute to clear FastCGI Cache + template: + src: cache-clear-script.conf + dest: "{{ php_fastcgi_cache_purge_script_path }}" + mode: 0050 + owner: root + group: www-data + when: php_fastcgi_cache_enabled + +- name: Ensure that the FastCGI Cache clear URL is reachable + lineinfile: + path: /etc/hosts + line: "127.0.0.1 {{ php_base_name }}.purge.cache.fastcgi.nginx.local" + when: php_fastcgi_cache_enabled diff --git a/templates/cache-clear-script.conf b/templates/cache-clear-script.conf new file mode 100644 index 0000000..0a703dd --- /dev/null +++ b/templates/cache-clear-script.conf @@ -0,0 +1,2 @@ + Date: Tue, 2 May 2017 11:11:10 -0400 Subject: [PATCH 2/2] Implements NGINX limit_req for security A dynamic website without limit_req or something similar, is a website that can be thrown down just by holding F5 button in a web browser, overloading the resources of the server. limit_req permits to set a maximum number of requests per number of seconds per client IP address, amazingly increasing security against denial of services. Once a client reach it's limit, a status code "429 Too Many Requests" is responded (RFC6585#4) Only two parameters over the role are required in order to set up limit_req : ```yaml php_limitreq_enabled: true php_limitreq_per_second: 10 ``` --- defaults/main.yml | 6 ++++++ templates/nginx.conf | 13 +++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/defaults/main.yml b/defaults/main.yml index 530684e..977cddf 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -98,3 +98,9 @@ php_fastcgi_cache_ignore_post_requests: true # where you want to save the cache clear script php_fastcgi_cache_purge_script_path: "" + +# if nginx requests per second limit must be enabled (outer static assets) +php_limitreq_enabled: false + +# the maximum requests per second per client IP address to throw HTTP error +php_limitreq_per_second: 15 diff --git a/templates/nginx.conf b/templates/nginx.conf index d850c88..57c0c57 100644 --- a/templates/nginx.conf +++ b/templates/nginx.conf @@ -21,8 +21,12 @@ server { } {% endfor %} +{% if php_limitreq_enabled %} +limit_req_zone $binary_remote_addr zone=limit_req_{{ php_base_name }}:10m rate={{ php_limitreq_per_second }}r/s; +{% endif %} + {% if php_fastcgi_cache_enabled %} -fastcgi_cache_path {{ php_fastcgi_cache_storage_path }} levels=1:2 keys_zone={{ php_base_name }}:{{ php_fastcgi_cache_max_size_mb }}m inactive={{ php_fastcgi_cache_expiration_minutes }}m; +fastcgi_cache_path {{ php_fastcgi_cache_storage_path }} levels=1:2 keys_zone=fastcgi_cache_{{ php_base_name }}:{{ php_fastcgi_cache_max_size_mb }}m inactive={{ php_fastcgi_cache_expiration_minutes }}m; fastcgi_cache_key "$scheme$request_method$host$request_uri"; fastcgi_cache_use_stale error timeout invalid_header http_500; fastcgi_ignore_headers Cache-Control Expires Set-Cookie; @@ -98,9 +102,14 @@ server { {% if php_fastcgi_cache_enabled %} fastcgi_cache_bypass $skip_cache; fastcgi_no_cache $skip_cache; - fastcgi_cache {{ php_base_name }}; + fastcgi_cache fastcgi_cache_{{ php_base_name }}; fastcgi_cache_valid {{ php_fastcgi_cache_expiration_minutes }}m; {% endif %} + {% if php_limitreq_enabled %} + limit_req zone=limit_req_{{ php_base_name }} burst={{ php_limitreq_per_second }} nodelay; + limit_req_log_level error; + limit_req_status 429; + {% endif %} } {% endif %} }