diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..b0a3531
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,33 @@
+---
+name: Bug report
+about: Create a report to help us improve
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+
+**Versions**
+What version of Nginx are you using ?
+What version of Rocket-Nginx are you using ?
+What version of WP Rocket are you using ?
+Are you using Nginx as a reverse proxy (with Apache for instance) ?
+
+**To Reproduce**
+Steps to reproduce the behaviour:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+Did you activate the debug in Rocket-Nginx ? Please do and include any headers.
+
+Make sure you include ALL Nginx configuration files you are using. Remove any sensitive information before submitting.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.gitignore b/.gitignore
index e69de29..d5f3253 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1,4 @@
+; Ignore all ini files
+*.ini
+*.conf
+conf.d/
diff --git a/README.md b/README.md
index 9a60f29..e32c33b 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,16 @@
Rocket-Nginx
============
-Rocket-Nginx is a [Nginx](http://nginx.org) configuration for the [WordPress](http://wordpress.org) cache plugin [WP-Rocket](http://wp-rocket.me). It enables Nginx to serve directly previously cached files without calling WordPress or any PHP. It also adds headers to cache CSS, JS and medias in order to leverage browser's cache by reducing request to your web server.
+Rocket-Nginx is a [Nginx](https://nginx.org) configuration for the [WordPress](https://wordpress.org) cache plugin [WP Rocket](https://wp-rocket.me). It enables Nginx to serve directly previously cached files without calling WordPress or any PHP. It also adds headers to cache CSS, JS and medias in order to leverage browser's cache by reducing request to your web server.
+
+**You might ask yourself: "How good is this configuration?".**
+
+Let's just say that WP Rocket themselves use it on their website to make it even faster!
+
+This project is sponsored by SatelliteWP, a [WordPress maintenance service](https://www.satellitewp.com/en) located near Montreal, Canada. Our service is offered in both English and French. SatelliteWP fait de l'[entretien de sites WordPress](https://www.satellitewp.com/?utm_source=rocket-nginx).
+
+[](https://www.satellitewp.com/en?utm_source=rocket-nginx)
+
## Table of Contents
@@ -10,12 +19,13 @@ Rocket-Nginx is a [Nginx](http://nginx.org) configuration for the [WordPress](ht
1. [Installation](#installation)
1. [Configuration](#configuration)
1. [Debug](#debug)
- 1. [FAQ](#css)
+ 1. [Limitations](#limitations)
+ 1. [FAQ](#faq)
1. [License](#license)
## Contributors
-The configuration was created and is maintained by [Maxime Jobin](http://www.maximejobin.com) ([@maximejobin](http://twitter.com/maximejobin)).
+The configuration was created by [Maxime Jobin](https://www.maximejobin.com) ([@maximejobin](https://github.com/maximejobin)) and is now maintained by [SatelliteWP](https://www.satellitewp.com/en?utm_source=rocket-nginx).
## Before You Start
As the configuration's goal is to serve cached files directly without having to execute any PHP from WordPress, this may cause your scheduled jobs to not be called. As you may already know, WP-Cron jobs are not real cron jobs and are executed only when you have visits on your site.
@@ -23,44 +33,53 @@ As the configuration's goal is to serve cached files directly without having to
In order to make sure your scheduled tasks run when they should, it is strongly suggested to disable WordPress cron jobs and create a real cron job.
To disable WordPress cron job, add the following line to your `wp-config.php`:
-`define('DISABLE_WP_CRON', true);`
+
+ define( 'DISABLE_WP_CRON', true );
Then, manually a cron job every 15 minutes (it should be enough for most websites):
-`*/15 * * * * wget -q -O - http://www.website.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1`
+ */15 * * * * wget -q -O - http://www.website.com/wp-cron.php?doing_wp_cron &>/dev/null
or
-`*/15 * * * * curl http://www.website.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1`
+ */15 * * * * curl http://www.website.com/wp-cron.php?doing_wp_cron &>/dev/null
or
-`*/15 * * * * cd /home/user/public_html; php wp-cron.php > /dev/null 2>&1`
+ */15 * * * * cd /home/user/public_html; php wp-cron.php &>/dev/null
Make sure you test that your tasks still run after this change!
## Installation
-In order to use the script, you must include it in your actual configuration. If your WordPress website is not yet configured to run with Nginx, you can check the [Nginx configuration for WordPress](https://github.com/maximejobin/rocket-nginx/wiki/Nginx-configuration-for-WordPress) documentation.
+To use the script, you must include it in your actual configuration. If your WordPress website is not yet configured to run with Nginx, you can check the [Nginx configuration for WordPress](https://github.com/satellitewp/rocket-nginx/wiki/Nginx-configuration-for-WordPress) documentation.
-Only one instance of Rocket-Nginx is needed for all your WordPress websites using WP-Rocket.
+Only one instance of Rocket-Nginx is needed for all your WordPress websites using WP Rocket. You can generate as many configuration files as needed.
You can create a folder `rocket-nginx` directory in your Nginx configuration directory. If you are using Ubuntu, your Nginx configuration (nginx.conf) should be found in: `/etc/nginx/`.
To install, you can:
```
cd /etc/nginx
- git clone https://github.com/maximejobin/rocket-nginx.git
+ git clone https://github.com/satellitewp/rocket-nginx.git
```
-Then, in your configuration file, you must [include](http://nginx.org/en/docs/ngx_core_module.html#include) the configuration. If your websites configurations are in `/etc/nginx/sites-available`, you need to alter your configuration:
+Since version 2.0, the configuration must be generated. To generate the default configuration, you must rename the disabled ini file and run the configuration parser:
+```
+cd rocket-nginx
+cp rocket-nginx.ini.disabled rocket-nginx.ini
+php rocket-parser.php
+```
+This will generate the `default.conf` configuration that can be included for all websites. If you need to alter the default configuration, you can edit the ini file and add another section at the bottom of the file.
+
+Then, in your Nginx configuration file, you must [include](https://nginx.org/en/docs/ngx_core_module.html#include) the generated configuration. If your websites configurations are in `/etc/nginx/sites-available`, you need to alter your configuration:
```
server {
...
# Rocket-Nginx configuration
- include rocket-nginx/rocket-nginx.conf;
+ include rocket-nginx/conf.d/default.conf;
...
}
@@ -77,44 +96,82 @@ That's it.
## Configuration
There is no configuration to do. It will work out of the box. But, you can edit a couple of things...
-#### Cache expiration
-By default, files such as CSS, JS and medias (images, fonts, ...) are cached until December 31st, 2037 (`expires max;`). As of the latest Nginx stable version, it is not possible to set these values into variables. You can manually change the values if needed.
-
-#### HTTP Strict Transport Security (HSTS)
-By default, HSTS (see [HTTP Strict Transport Security](https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security)) is enabled by default for all subdomains and the cache will expire after 1 year. If you want to overwrite the default value, you can simply insert your desired value between the quotes of the `$rocket_hsts_value` variable at the top of the `rocket-nginx.conf` file.
+Just open the `rocket-nginx.ini` file and see all the options in it.
-If you leave the variable as-is:
+You can add a new section based on the default configuration like this:
+```
+# This creates the new section and will generate a new configuration
+[example.com : default]
- set $rocket_hsts_value "";
+# This will add a value to invalidate the cache with a cookie
+cookie_invalidate[] = "my_custom_cookie"
+```
-Rocket-Nginx will display the default HSTS header:
+Once you edit the ini file, you must regenerate your Nginx configuration file by running the parser:
- Strict-Transport-Security: max-age=16070400; includeSubDomains
+```
+php rocket-parser.php
+```
-If you change the variable value with another value:
+Then, newly added or modified sections will generate update configuration file (*.conf).
- set $rocket_hsts_value "my-value-here";
+Finally, **each time** you generate (or regenerate) the configurations files, you have to:
-Rocket-Nginx will display the following HSTS header:
+1. Test it to make sure it did not produce any error:
- Strict-Transport-Security: my-value-here
+ `nginx -t`
+1. Reload the configuration:
+
+ `service nginx reload`
+
+Starting at version 3.0, a `conf.d`folder is created. For each different profile you create, a subfolder is created inside that folder. In it, you can create files that will be included within the generated configuration file.
+
+You can include configuration files at different times.
+
+### Before Rocket-Nginx starts
+
+In the default profile, create a file in the `conf.d/default/` having the following filename pattern : `start.*.conf`.
+
+### Globally in every section
+
+In the default profile, create a file in the `conf.d/default/` having the following filename pattern : `global.*.conf`.
+
+### In the HTTP section
+
+In the default profile, create a file in the `conf.d/default/` having the following filename pattern : `http.*.conf`.
+
+### Preprocess (after all variables to use are set)
+
+In the default profile, create a file in the `conf.d/default/` having the following filename pattern : `preprocess.*.conf`.
+
+### In the CSS section
+
+In the default profile, create a file in the `conf.d/default/` having the following filename pattern : `css.*.conf`.
+
+### In the JS section
+
+In the default profile, create a file in the `conf.d/default/` having the following filename pattern : `js.*.conf`.
+
+### In the Media section
+
+In the default profile, create a file in the `conf.d/default/` having the following filename pattern : `media.*.conf`.
## Debug
-You may want to check if your files are served directly by Nginx and not calling any PHP. To do that, open the `rocket-nginx.conf` file and change the debug value from:
+You may want to check if your files are served directly by Nginx and not calling any PHP. To do that, open the `rocket-nginx.ini` file and change the debug value from:
-`set $rocket_debug 0;`
+`debug = false`
To:
-`set $rocket_debug 1;`
-
-The following header is present no matter if debug is set to 0 or 1:
- * **X-Rocket-Nginx-Bypass**: Did the configuration served the cached file directly (did it bypass WordPress): Yes or No.
+`debug = true`
+The following header is present no matter if debug is set to true or false:
+ * **X-Rocket-Nginx-Serving-Static**: Did the configuration served the cached file directly : HIT, MISS, BYPASS.
This will add the following headers to your response request:
- * **X-Rocket-Nginx-Reason**: If Bypass is set to "No", what is the reason for calling WordPress. If "Yes", what is the file used (URL).
- * **X-Rocket-Nginx-File**: If "Yes", what is the file used (path on disk).
+ * **X-Rocket-Nginx-Reason**: If serving static is not set to "HIT", what is the reason for calling WordPress. If "HIT", what is the file used (URL).
+ * **X-Rocket-Nginx-File**: If "HIT", what is the file used (path on disk).
+ * **X-Rocket-Nginx-Device**: What device was used to call the server ("desktop" or "mobile").
Reasons for not serving a cached file:
@@ -122,17 +179,56 @@ Reasons for not serving a cached file:
* **Arguments found**: One or more argument was found in the request (e.g. ?page=2).
* **Maintenance mode**: The .maintenance file was found. Therefore, let's WordPress handle what should be displayed.
* **Cookie**: A specific cookie was found and tells to not serve the cached page (e.g. user is logged in, post with password).
+ * **Specific mobile cache activated**: If you activated specific cache (one for mobile and one for desktop) in WP Rocket, HTML files (pages, posts, ...) won't be served directly because Rocket-Nginx cannot know if the request was made by mobile or desktop device.
* **File not cached**: No cached file was found for that request.
+## Limitations
+Is Rocket-Nginx perfect? No, it's not! We tried to make it as perfect as possible, but Nginx's scripting language does not offer all possibilities offered by a language like PHP, for instance. Therefore, there are some limitations.
+
+❌**Encoded slugs**
+
+Short answer: An encoded slug cannot be served by Rocket-Nginx.
+
+Due to Nginx's scripting limitations, slugs like 'جزازة العشب' are encoded and the file is stored by WP Rocket as '%d8%ac%d8%b2%d8%a7%d8%b2%d8%a9%20%d8%a7%d9%84%d8%b9%d8%b4%d8%a8' (lowercase). Some browsers, like Google Chrome, will send the request as '%D8%AC%D8%B2%D8%A7%D8%B2%D8%A9%20%D8%A7%D9%84%D8%B9%D8%B4%D8%A8' (uppercase). Using a language like PHP, it would be easy to compare these strings as equal. With Nginx, this is not possible unless a third party module (like Perl or Lua) is needed. To make Rocket-Nginx as generic as possible, it was decided to not add a module dependency. If you want to support encoded slugs and add the missing code, note that version 3.1.0 (and later) offers a new configuration include named "preprocess" to modify the `$rocket_uri_path` variable case (force lowercase).
+
+❌**WEBP Compatibility**
+
+Short answer: Rocket-Nginx won't serve the WebP caching files generated by WP Rocket if you activate the [WebP Compatibility feature](https://docs.wp-rocket.me/article/1282-webp).
+
+WP Rocket is able to create a specific cache if you used a tool to convert your images (JPG, PNG, ...) to WebP. Unfortunately, the Nginx's scripting language is not powerful enough to achieve the validation correctly. Therefore, if you activate this feature, Rocket-Nginx will let WP Rocket handle the request and serve the right cached page, depending on the context.
+
## FAQ
+**Is Rocket-Nginx compatible with BF Cache (Back/forward cache)?**
+
+Yes! If your website does not display sensitive data and is a good match for Back/forward caching, you must must edit your Rocket-Nginx configuration by following the [BF Cache discussion](https://github.com/SatelliteWP/rocket-nginx/issues/197#issuecomment-1693584964) in the issues.
+
+**How do I upgrade from version 1 or 2 to version 3?**
+
+We suggest that you save your previous configuration and start over. Take this opportunity to review everything as many things have changed. Officially, version 3.x is not backward-compatible with previous versions. Starting from scratch should not take more than 15 minutes.
+
+
+**What is new in version 3.x?**
+
+Many things!
+
+- Query strings to cache are supported via the ini file. See the WP Rocket [Cache query strings](https://docs.wp-rocket.me/article/971-caching-query-strings?utm_source=rocket-nginx) documentation for configuration.
+- Query string to ignore are supported. See the WP Rocket [Cache query strings to ignore](https://docs.wp-rocket.me/article/971-caching-query-strings?utm_source=rocket-nginx#ignored-parameters) documentation for configuration.
+- Default HSTS value was removed.
+- Custom configurations can be included in every sections
+- Custom expiration are supported for CSS, JS and medias
+- Allowing adding headers from the config file was removed.
+
+
**Do you have any benchmark about the project ?**
-No. People love benchmark as much as they hate them. All benchmarks have people claiming that X or Y or Z could have been done to improve the outcome. In this project, the benchmark would depend on how many plugins you have that are affecting the page even if the output is in cache (e.g. WP-Rocket executes PHP even when a file is in cache). What we can say though is that you will go from **NGINX → PHP-FPM → PHP → Static file** to **NGINX → Static file**. In other words, you are serving the static file directly from NGINX instead of passing the request to FPM then to PHP (for WP-Rocket... at least) before serving the static file.
+No. People love benchmark as much as they hate them. All benchmarks have people claiming that X or Y or Z could have been done to improve the outcome. In this project, the benchmark would depend on how many plugins you have that are affecting the page even if the output is in cache (e.g. WP Rocket executes PHP even when a file is in cache). What we can say though is that you will go from **NGINX → PHP-FPM → WordPress (PHP and Database) → Static file** to **NGINX → Static file**. In other words, you are serving the static file directly from NGINX instead of passing the request to FPM then to PHP (for WP Rocket... at least) before serving the static file.
+
**Will Rocket-Nginx work if my website uses a SSL certificate (https) ?**
Yes! Rocket-Nginx will detect if the request was made through HTTP or HTTPS and serve the right file depending on the request type. Both protocols are handled automagically since version 1.0.
+
## License
-Released under the [GPL](http://www.gnu.org/licenses/gpl.html). See the link for details.
+Released under the MIT License. See the license file for details.
diff --git a/license.md b/license.md
new file mode 100644
index 0000000..88fadad
--- /dev/null
+++ b/license.md
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016-2020 Maxime Jobin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/rocket-nginx.conf b/rocket-nginx.conf
deleted file mode 100644
index 5f77227..0000000
--- a/rocket-nginx.conf
+++ /dev/null
@@ -1,168 +0,0 @@
-###################################################################################################
-# Rocket-Nginx
-#
-# Rocket-Nginx is a NGINX configuration to speedup your WordPress
-# website with the cache plugin WP-Rocket (http://wp-rocket.me)
-#
-# Author: Maxime Jobin
-# URL: https://github.com/maximejobin/rocket-nginx
-#
-# Tested with WP-Rocket version: 2.6.15
-# Tested with NGINX: 1.8.0 (stable)
-#
-# Version 1.1
-#
-###################################################################################################
-
-set $rocket_debug 0; # Add debug information into header
-set $rocket_hsts_value ""; # HTTP Strict Transport Security (to overwrite default)
-
-###################################################################################################
-# Do not alter theses values
-#
-set $rocket_bypass 1; # Should NGINX bypass WordPress and call cache file directly ?
-set $rocket_encryption ""; # Is GZIP accepted by client ?
-set $rocket_file ""; # Filename to use
-set $rocket_is_bypassed "No"; # Header text added to check if the bypass worked or not. Header: X-Rocket-Nginx-Bypass
-set $rocket_reason ""; # Reason why cache file was not used. If cache file is used, what file was used
-set $rocket_https_prefix ""; # HTTPS prefix to use when cached files are using HTTPS
-set $rocket_hsts 0; # Is HSTS is off (0) by default. Will be turned on (1) if request is HTTPS
-
-# HSTS Default value : 1 year, include subdomains.
-set $rocket_hsts_value_default "max-age=31536000; includeSubDomains";
-
-###################################################################################################
-# PAGE CACHE
-#
-
-# Is GZIP accepted by client ?
-if ($http_accept_encoding ~ gzip) {
- set $rocket_encryption "_gzip";
-}
-
-# Is SSL request ?
-if ($https = "on") {
- set $rocket_https_prefix "-https";
- set $rocket_hsts 1;
-}
-
-# If HSTS value is not set, use default value
-if ($rocket_hsts_value = "") {
- set $rocket_hsts_value "$rocket_hsts_value_default";
-}
-
-# If HSTS is disabled, unset HSTS set for Rocket-Nginx configuration
-if ($rocket_hsts = "0") {
- set $rocket_hsts_value "";
-}
-
-# File/URL to return IF we must bypass WordPress
-set $rocket_url "/wp-content/cache/wp-rocket/$http_host/$request_uri/index$rocket_https_prefix.html$rocket_encryption";
-set $rocket_file "$document_root$rocket_url";
-
-
-# Do not bypass if it's a POST request
-if ($request_method = POST) {
- set $rocket_bypass 0;
- set $rocket_reason "POST request";
-}
-
-# Do not bypass if arguments are found (e.g. ?page=2)
-if ($args != "") {
- set $rocket_bypass 0;
- set $rocket_reason "Arguments found";
-}
-
-# Do not bypass if the site is in maintenance mode
-if (-f "$document_root/.maintenance") {
- set $rocket_bypass 0;
- set $rocket_reason "Maintenance mode";
-}
-
-# Do not bypass if one of those cookie if found
-# wordpress_logged_in_[hash] : When a user is logged in, this cookie is created (we'd rather let WP-Rocket handle that)
-# wp-postpass_[hash] : When a protected post requires a password, this cookie is created.
-if ($http_cookie ~* "(wordpress_logged_in_|wp\-postpass_)") {
- set $rocket_bypass 0;
- set $rocket_reason "Cookie";
-}
-
-# Do not bypass if the cached file does not exist
-if (!-f "$rocket_file") {
- set $rocket_bypass 0;
- set $rocket_reason "File not cached";
-}
-
-# If the bypass token is still on, let's bypass WordPress with the cached URL
-if ($rocket_bypass = 1) {
- set $rocket_is_bypassed "Yes";
- set $rocket_reason "$rocket_url";
-}
-
-# Clear variables if debug is not needed
-if ($rocket_debug = 0) {
- set $rocket_reason "";
- set $rocket_file "";
-}
-
-# If the bypass token is still on, rewrite according to the file linked to the request
-if ($rocket_bypass = 1) {
- rewrite .* "$rocket_url" last;
-}
-
-# Add header to HTML cached files
-location ~ /wp-content/cache/wp-rocket/.*html$ {
- add_header Vary "Accept-Encoding, Cookie";
- add_header X-Rocket-Nginx-Bypass $rocket_is_bypassed;
- add_header X-Rocket-Nginx-Reason $rocket_reason;
- add_header X-Rocket-Nginx-File $rocket_file;
- add_header Strict-Transport-Security "$rocket_hsts_value";
- expires 30d;
-}
-
-# Do not gzip cached files that are already gzipped
-location ~ /wp-content/cache/wp-rocket/.*_gzip$ {
- gzip off;
- types {}
- default_type text/html;
- add_header Content-Encoding gzip;
- add_header Vary "Accept-Encoding, Cookie";
- add_header X-Rocket-Nginx-Bypass $rocket_is_bypassed;
- add_header X-Rocket-Nginx-Reason $rocket_reason;
- add_header X-Rocket-Nginx-File $rocket_file;
- add_header Strict-Transport-Security "$rocket_hsts_value";
- expires 30d;
-}
-
-# Debug header (when file is not cached)
-add_header X-Rocket-Nginx-Bypass $rocket_is_bypassed;
-add_header X-Rocket-Nginx-Reason $rocket_reason;
-add_header X-Rocket-Nginx-File $rocket_file;
-
-# No HSTS header added here. We suppose it's correctly added in the site configuration
-
-
-###################################################################################################
-# BROWSER CSS CACHE
-#
-location ~ /wp-content/cache/min/.*\.css$ {
- gzip_vary on;
- expires max;
-}
-
-
-###################################################################################################
-# BROWSER JS CACHE
-#
-location ~ /wp-content/cache/min/.*\.js$ {
- gzip_vary on;
- expires max;
-}
-
-
-###################################################################################################
-# BROWSER MEDIA CACHE
-#
-location ~* \.(ico|gif|jpe?g|png|svg|eot|otf|woff|woff2|ttf|ogg)$ {
- expires max;
-}
diff --git a/rocket-nginx.ini.disabled b/rocket-nginx.ini.disabled
new file mode 100644
index 0000000..ad82931
--- /dev/null
+++ b/rocket-nginx.ini.disabled
@@ -0,0 +1,123 @@
+; Rocket-Nginx configuration file
+; Maintainer: SatelliteWP
+; URL: https://github.com/satellitewp/rocket-nginx
+;
+; Original author: Maxime Jobin
+; URL: https://www.maximejobin.com
+; Version: 3.1.0
+
+; Default configuration
+[default]
+
+; Enable debug information
+; This adds debug headers to help understand what is going on when a problem occurs with the configuration
+; Expected values: true, false
+; Default value: false
+debug = false
+
+; WP-Content folder
+; Default value: wp-content
+wp_content_folder = wp-content
+
+; HTML Cache-Control
+; Cache control header to use for html files
+html_cache_control = "no-cache, no-store, must-revalidate"
+
+; Cookies
+; Cookies can be specified to avoid serving a cached file. Some plugins may need to bypass the use of a
+; file that was previously cached. List all cookies that must invalidate the use of cache.
+; The cookie name must contain the text value set.
+; Note that each value will be used in a REGEX. Make sure characters are escaped when needed.
+; Example: cookie_invalidate[] = "wordpress_logged_in_"
+cookie_invalidate[] = "wordpress_logged_in_"
+cookie_invalidate[] = "wp\-postpass_"
+cookie_invalidate[] = "woocommerce_items_in_cart"
+cookie_invalidate[] = "woocommerce_cart_hash"
+cookie_invalidate[] = "wptouch_switch_toogle"
+cookie_invalidate[] = "comment_author_"
+cookie_invalidate[] = "comment_author_email_"
+
+; Query strings to ignore
+; Query strings invalidate the caching process made by Rocket-Nginx. But some strings are added, for instance,
+; for JavaScript and do not influence the output provided by the server. List all query strings that won't
+; invalidate the use of a cached page.
+; Reference: https://docs.wp-rocket.me/article/971-caching-query-strings
+; Google Analytics and Ads:
+query_string_ignore[] = "utm_source"
+query_string_ignore[] = "utm_campaign"
+query_string_ignore[] = "utm_medium"
+query_string_ignore[] = "utm_expid"
+query_string_ignore[] = "utm_term"
+query_string_ignore[] = "utm_content"
+query_string_ignore[] = "utm_id"
+query_string_ignore[] = "utm_source_platform"
+query_string_ignore[] = "utm_creative_format"
+query_string_ignore[] = "utm_marketing_tactic"
+query_string_ignore[] = "_ga"
+query_string_ignore[] = "gclid"
+query_string_ignore[] = "campaignid"
+query_string_ignore[] = "adgroupid"
+query_string_ignore[] = "adid"
+query_string_ignore[] = "gbraid"
+query_string_ignore[] = "wbraid"
+; Google DoubleClick
+query_string_ignore[] = "gclsrc"
+; Adobe Advertising Cloud
+query_string_ignore[] = "ef_id"
+; Facebook
+query_string_ignore[] = "fb_action_ids"
+query_string_ignore[] = "fb_action_types"
+query_string_ignore[] = "fb_source"
+query_string_ignore[] = "fbclid"
+; Mailchimp
+query_string_ignore[] = "mc_cid"
+query_string_ignore[] = "mc_eid"
+; Matomo
+query_string_ignore[] = "mtm_source"
+query_string_ignore[] = "mtm_medium"
+query_string_ignore[] = "mtm_campaign"
+query_string_ignore[] = "mtm_keyword"
+query_string_ignore[] = "mtm_cid"
+query_string_ignore[] = "mtm_content"
+; Klavyo
+query_string_ignore[] = "_ke"
+; Other
+query_string_ignore[] = "age-verified"
+query_string_ignore[] = "ao_noptimize"
+query_string_ignore[] = "usqp"
+query_string_ignore[] = "cn-reloaded"
+query_string_ignore[] = "sscid"
+query_string_ignore[] = "msclkid"
+
+; Query strings to cache
+; Query strings invalidate the caching process made by Rocket-Nginx. Some strings may need to be cached.
+; List all query strings that needs to be cached as found in the WP Rocket configuration.
+; Reference: https://docs.wp-rocket.me/article/971-caching-query-strings
+;query_string_cache[] = "country"
+
+; Medias extensions
+; Medias extensions for images, icons, fonts and other cachable medias. All extensions are separated
+; by pipes (|).
+; Default value: ico|gif|jpe?g|png|svg|eot|otf|woff|woff2|ttf|ogg|webp
+media_extensions = "ico|gif|jpe?g|png|svg|eot|otf|woff|woff2|ttf|ogg|webp"
+
+; Cache expiration delay
+; Cache expiration delay for CSS, JS and media files
+; Default value: 30d
+css_expiration = "30d"
+js_expiration = "30d"
+media_expiration = "30d"
+
+; Mobile user agents
+; Mobile user agents regex pattern. By design, a tablet is not a mobile.
+; Default value: (?:phone|windows\s+phone|ipod|blackberry|(?:android|bb\d+|meego|silk|googlebot) .+? mobile|palm|windows\s+ce|opera mini|avantgo|mobilesafari|docomo|kaios)
+mobile_ua_devices = "(?:phone|windows\s+phone|ipod|blackberry|(?:android|bb\d+|meego|silk|googlebot) .+? mobile|palm|windows\s+ce|opera mini|avantgo|mobilesafari|docomo|kaios)"
+
+
+; Multiple sections can be created for multiple websites with different configurations.
+; It is recommended to use the default values as a base for custom validations. A new configuration
+; file will be created for each new section created.
+
+; In the following example, the 'default' configuration is used and added a custom cookie invalidation.
+;[example.com : default]
+;cookie_invalidate[] = "my_custom_cookie"
diff --git a/rocket-nginx.tmpl b/rocket-nginx.tmpl
new file mode 100644
index 0000000..e2e978d
--- /dev/null
+++ b/rocket-nginx.tmpl
@@ -0,0 +1,276 @@
+###################################################################################################
+# Rocket-Nginx
+#
+# Rocket-Nginx is a NGINX configuration to speedup your WordPress
+# website with the cache plugin WP-Rocket (http://wp-rocket.me)
+#
+# Author: Maxime Jobin
+# Maintainer: SatelliteWP.com
+# URL: https://github.com/satellitewp/rocket-nginx
+#
+# Tested with WP-Rocket version: 3.16.2.1
+# Tested with NGINX: 1.26.1 (mainline)
+#
+# Version 3.1.0
+#
+###################################################################################################
+
+# Add debug information into header
+set $rocket_debug #!# DEBUG #!#;
+
+
+###################################################################################################
+# Do not alter theses values
+#
+set $rocket_bypass 1; # Should NGINX bypass WordPress and call cache file directly ?
+set $rocket_encryption ""; # Is GZIP accepted by client ?
+set $rocket_file ""; # Filename to look for
+set $rocket_is_bypassed "MISS"; # Header text added to check if the bypass worked or not. Header: X-Rocket-Nginx-Serving-Static
+set $rocket_reason ""; # Reason why cache file was not used. If cache file is used, what file was used
+set $rocket_https_prefix ""; # HTTPS prefix to use when cached files are using HTTPS
+set $rocket_mobile_prefix ""; # Mobile prefix to use when mobile device is detected and mobile cache is activated
+set $rocket_is_https 0; # Checks if the request is HTTPS
+set $rocket_dynamic ""; # Dynamic value to add to cached filename
+set $rocket_device "desktop"; # Device type (desktop or mobile)
+
+###################################################################################################
+# PAGE CACHE
+#
+
+# Start includes
+#!# INCLUDE_START #!#
+
+# Define Rocket-Nginx $is_args
+set $rocket_is_args $is_args;
+
+# Get query string without the parameters (before the '?')
+set $rocket_uri_path $request_uri;
+if ($request_uri ~* "^([^?]*)(\?.+)$") {
+ set $rocket_uri_path $1;
+}
+
+# Is GZIP accepted by client ?
+if ($http_accept_encoding ~ gzip) {
+ set $rocket_encryption "_gzip";
+}
+
+# Is Brotli accepted by client ?
+if ($http_accept_encoding ~ br) {
+ set $rocket_encryption "";
+}
+
+# Is HTTPS request ?
+if ($https = "on") { set $rocket_is_https 1; }
+if ($http_x_forwarded_proto = "https") { set $rocket_is_https 1; }
+if ($http_front_end_https = "on") { set $rocket_is_https 1; }
+if ($http_x_forwarded_protocol = "https") { set $rocket_is_https 1; }
+if ($http_x_forwarded_ssl = "on") { set $rocket_is_https 1; }
+if ($http_x_url_scheme = "https") { set $rocket_is_https 1; }
+if ($http_forwarded ~ /proto=https/) { set $rocket_is_https 1; }
+
+if ($rocket_is_https = "1") {
+ set $rocket_https_prefix "-https";
+}
+
+# Set mobile detection file path
+# This variable contains a file to look for. If it exists, WP Rocket is set to
+# generate both Desktop and Mobile cache.
+set $rocket_mobile_detection "$document_root/#!# WP_CONTENT_URI #!#/cache/wp-rocket/$http_host/$request_uri/.mobile-active";
+
+# Query strings to ignore
+#!# QUERY_STRING_IGNORE #!#
+
+# Adjust $rocket_is_args after processing query strings to ignore
+if ($rocket_args = "") {
+ set $rocket_is_args "";
+}
+
+# Query string to cache
+#!# QUERY_STRING_CACHE #!#
+
+# Check if device is Mobile
+if ($http_user_agent ~* "#!# MOBILE_USER_AGENT #!#") {
+ set $rocket_device "mobile";
+}
+
+# Set mobile prefix if mobile mode is activated
+if (-f "$rocket_mobile_detection") {
+ set $rocket_mobile_prefix "-mobile";
+}
+
+if ($rocket_device != "mobile") {
+ set $rocket_mobile_prefix "";
+}
+
+# File/URL to return IF we must bypass WordPress
+# Desktop: index.html
+# Gzip: index.html_gzip
+# HTTPS: index-https.html
+# Mobile: index-mobile-https.html
+set $rocket_file_start "index$rocket_mobile_prefix$rocket_https_prefix";
+
+# Pre-process includes
+#!# INCLUDE_PREPROCESS #!#
+
+set $rocket_pre_url "/#!# WP_CONTENT_URI #!#/cache/wp-rocket/$http_host/$rocket_uri_path/$rocket_args/";
+set $rocket_pre_file "$document_root/#!# WP_CONTENT_URI #!#/cache/wp-rocket/$http_host/$rocket_uri_path/$rocket_args/";
+
+# Standard cache file format
+set $rocket_url "$rocket_pre_url$rocket_file_start$rocket_dynamic.html";
+set $rocket_file "$rocket_pre_file$rocket_file_start$rocket_dynamic.html";
+
+# Check if gzip version cached file is available
+if (-f "$rocket_file$rocket_encryption") {
+ set $rocket_file "$rocket_file$rocket_encryption";
+ set $rocket_url "$rocket_url$rocket_encryption";
+}
+
+# Do not bypass if the cached file does not exist
+if (!-f "$rocket_file") {
+ set $rocket_bypass 0;
+ set $rocket_is_bypassed "MISS";
+ set $rocket_reason "File not cached";
+}
+
+# Do not bypass if it's a POST request
+if ($request_method = POST) {
+ set $rocket_bypass 0;
+ set $rocket_is_bypassed "BYPASS";
+ set $rocket_reason "POST request";
+}
+
+# Do not bypass if arguments are found (e.g. ?page=2)
+if ($rocket_is_args) {
+ set $rocket_bypass 0;
+ set $rocket_is_bypassed "BYPASS";
+ set $rocket_reason "Arguments found";
+}
+
+# Do not bypass if the site is in maintenance mode
+if (-f "$document_root/.maintenance") {
+ set $rocket_bypass 0;
+ set $rocket_is_bypassed "BYPASS";
+ set $rocket_reason "Maintenance mode";
+}
+
+# Do not bypass if one of those cookie if found
+# wordpress_logged_in_[hash] : When a user is logged in, this cookie is created (we'd rather let WP-Rocket handle that)
+# wp-postpass_[hash] : When a protected post requires a password, this cookie is created.
+if ($http_cookie ~* "(#!# COOKIE_INVALIDATE #!#)") {
+ set $rocket_bypass 0;
+ set $rocket_is_bypassed "BYPASS";
+ set $rocket_reason "Cookie";
+}
+
+# If the bypass token is still on, let's bypass WordPress with the cached URL
+if ($rocket_bypass = 1) {
+ set $rocket_is_bypassed "HIT";
+ set $rocket_reason "$rocket_url";
+}
+
+# Clear variables if debug is not needed
+if ($rocket_debug = 0) {
+ set $rocket_reason "";
+ set $rocket_file "";
+ set $rocket_device "";
+}
+
+# If the bypass token is still on, rewrite according to the file linked to the request
+if ($rocket_bypass = 1) {
+ rewrite .* "$rocket_url" last;
+}
+
+# Add header to HTML cached files
+location ~ /#!# WP_CONTENT_URI #!#/cache/wp-rocket/.*html$ {
+ etag on;
+ add_header Vary "Accept-Encoding, Cookie";
+ add_header Cache-Control "#!# HTML_CACHE_CONTROL #!#";
+ add_header X-Rocket-Nginx-Serving-Static $rocket_is_bypassed;
+ add_header X-Rocket-Nginx-Reason $rocket_reason;
+ add_header X-Rocket-Nginx-File $rocket_file;
+ add_header X-Rocket-Nginx-Device $rocket_device;
+
+ # Global includes
+ #!# INCLUDE_GLOBAL #!#
+
+ # HTTP includes
+ #!# INCLUDE_HTTP #!#
+}
+
+# Do not gzip cached files that are already gzipped
+location ~ /#!# WP_CONTENT_URI #!#/cache/wp-rocket/.*_gzip$ {
+ etag on;
+ gzip off;
+ types {}
+ default_type text/html;
+ add_header Content-Encoding gzip;
+ add_header Vary "Accept-Encoding, Cookie";
+ add_header Cache-Control "#!# HTML_CACHE_CONTROL #!#";
+ add_header X-Rocket-Nginx-Serving-Static $rocket_is_bypassed;
+ add_header X-Rocket-Nginx-Reason $rocket_reason;
+ add_header X-Rocket-Nginx-File $rocket_file;
+ add_header X-Rocket-Nginx-Device $rocket_device;
+
+ # Global includes
+ #!# INCLUDE_GLOBAL #!#
+
+ # HTTP includes
+ #!# INCLUDE_HTTP #!#
+}
+
+# Debug header (when file is not cached)
+add_header X-Rocket-Nginx-Serving-Static $rocket_is_bypassed;
+add_header X-Rocket-Nginx-Reason $rocket_reason;
+add_header X-Rocket-Nginx-File $rocket_file;
+add_header X-Rocket-Nginx-Device $rocket_device;
+
+# Global includes
+#!# INCLUDE_GLOBAL #!#
+
+
+
+###################################################################################################
+# BROWSER CSS CACHE
+#
+location ~* \.css$ {
+ etag on;
+ gzip_vary on;
+ expires #!# CSS_EXPIRATION #!#;
+
+ # Global includes
+ #!# INCLUDE_GLOBAL #!#
+
+ # CSS includes
+ #!# INCLUDE_CSS #!#
+}
+
+
+###################################################################################################
+# BROWSER JS CACHE
+#
+location ~* \.js$ {
+ etag on;
+ gzip_vary on;
+ expires #!# JS_EXPIRATION #!#;
+
+ # Global includes
+ #!# INCLUDE_GLOBAL #!#
+
+ # JS includes
+ #!# INCLUDE_JS #!#
+}
+
+
+###################################################################################################
+# BROWSER MEDIA CACHE
+#
+location ~* \.(#!# MEDIA_EXTENSIONS #!#)$ {
+ etag on;
+ expires #!# MEDIA_EXPIRATION #!#;
+
+ # Global includes
+ #!# INCLUDE_GLOBAL #!#
+
+ # Media includes
+ #!# INCLUDE_MEDIA #!#
+}
diff --git a/rocket-parser.php b/rocket-parser.php
new file mode 100644
index 0000000..d0e0f87
--- /dev/null
+++ b/rocket-parser.php
@@ -0,0 +1,326 @@
+configFile, true);
+ $config = array();
+
+ foreach($data as $namespace => $properties) {
+ $parts = explode(':', $namespace);
+ $name = trim($parts[0]);
+ $extends = isset($parts[1]) ? trim($parts[1]) : null;
+
+ // create namespace if necessary
+ if (!isset($config[$name])) {
+ $config[$name] = array();
+ }
+
+ // inherit base namespace
+ if (isset($data[$extends])) {
+ foreach($data[$extends] as $prop => $val) {
+ $config[$name][$prop] = $val;
+ }
+ }
+ // overwrite / set current namespace values
+ foreach($properties as $prop => $val) {
+ $config[$name][$prop] = $val;
+ }
+ }
+
+ return $config;
+ }
+
+ /**
+ * Generate all configuration files
+ *
+ * @param array $config Configuration data
+ */
+ protected function generateConfigurationFiles($config) : void {
+
+ // Load template
+ $template = $this->getTemplate();
+
+ foreach($config as $name => $section) {
+ $output = $template;
+
+ // Debug
+ $debug = false;
+ if (isset($section['debug']) && $section['debug'] === '1') {
+ $debug = true;
+ }
+ $output = str_replace('#!# DEBUG #!#', $debug ? '1' : '0', $output);
+
+ // WP Content URI
+ $wp_content_folder = 'wp-content';
+ if (isset($section['wp_content_folder']) && !empty($section['wp_content_folder'])) {
+ $wp_content_folder = $section['wp_content_folder'];
+ }
+ $output = str_replace('#!# WP_CONTENT_URI #!#', $wp_content_folder, $output);
+
+ // Cache Control
+ $html_cache_control = '';
+ if (isset($section['html_cache_control']) && !empty($section['html_cache_control'])) {
+ $html_cache_control = $section['html_cache_control'];
+ }
+ $output = str_replace('#!# HTML_CACHE_CONTROL #!#', $html_cache_control, $output);
+
+ // Cookies
+ $cookies = '';
+ if (isset($section['cookie_invalidate']) && is_array($section['cookie_invalidate'])) {
+ $cookies = implode('|', $section['cookie_invalidate']);
+ }
+ $output = str_replace('#!# COOKIE_INVALIDATE #!#', $cookies, $output);
+
+ // Query strings to ignore
+ $query_strings_ignore = '# None';
+ if (isset($section['query_string_ignore']) && is_array($section['query_string_ignore'])) {
+ $query_strings_ignore = $this->getGeneratedQueryStringsToIgnore($section['query_string_ignore']);
+ }
+ $output = str_replace('#!# QUERY_STRING_IGNORE #!#', $query_strings_ignore, $output);
+
+ // Query strings to cache
+ $query_strings_cache = '# None';
+ if (isset($section['query_string_cache']) && is_array($section['query_string_cache'])) {
+ $query_strings_cache = $this->getGeneratedQueryStringsToCache($section['query_string_cache']);
+ }
+ $output = str_replace('#!# QUERY_STRING_CACHE #!#', $query_strings_cache, $output);
+
+ // CSS expiration delay
+ $css_expiration = '30d';
+ if (isset($section['css_expiration']) && !empty($section['css_expiration'])) {
+ $css_expiration = $section['css_expiration'];
+ }
+ $output = str_replace('#!# CSS_EXPIRATION #!#', $css_expiration, $output);
+
+ // JS expiration delay
+ $js_expiration = '30d';
+ if (isset($section['js_expiration']) && !empty($section['js_expiration'])) {
+ $js_expiration = $section['js_expiration'];
+ }
+ $output = str_replace('#!# JS_EXPIRATION #!#', $js_expiration, $output);
+
+ // Media expiration delay
+ $media_expiration = '30d';
+ if (isset($section['media_expiration']) && !empty($section['media_expiration'])) {
+ $media_expiration = $section['media_expiration'];
+ }
+ $output = str_replace('#!# MEDIA_EXPIRATION #!#', $media_expiration, $output);
+
+ // Start include
+ $include_start = $this->getGeneratedInclude($name, 'start');
+ $output = str_replace('#!# INCLUDE_START #!#', $include_start, $output);
+
+ // Preprocess include
+
+ $preprocess_start = $this->getGeneratedInclude($name, 'preprocess');
+ $output = str_replace('#!# INCLUDE_PREPROCESS #!#', $preprocess_start, $output);
+
+ // Global include
+ $include_global = $this->getGeneratedInclude($name, 'global');
+ $output = str_replace('#!# INCLUDE_GLOBAL #!#', $include_global, $output);
+
+ // HTTP include
+ $include_http = $this->getGeneratedInclude($name, 'http');
+ $output = str_replace('#!# INCLUDE_HTTP #!#', $include_http, $output);
+
+ // CSS headers
+ $include_css = $this->getGeneratedInclude($name, 'css');
+ $output = str_replace('#!# INCLUDE_CSS #!#', $include_css, $output);
+
+ // JS headers
+ $include_js = $this->getGeneratedInclude($name, 'js');
+ $output = str_replace('#!# INCLUDE_JS #!#', $include_js, $output);
+
+ // Media headers
+ $include_media = $this->getGeneratedInclude($name, 'media');
+ $output = str_replace('#!# INCLUDE_MEDIA #!#', $include_media, $output);
+
+ // Media extensions
+ $media_extensions = '';
+ if (isset($section['media_extensions']) && !empty($section['media_extensions'])) {
+ $media_extensions = $section['media_extensions'];
+ }
+ $output = str_replace('#!# MEDIA_EXTENSIONS #!#', $media_extensions, $output);
+
+ // Mobile devices
+ $mobile_ua_devices = 'not_v_a_l_i_d';
+ if (isset($section['mobile_ua_devices']) && !empty($section['mobile_ua_devices'])) {
+ $mobile_ua_devices = $section['mobile_ua_devices'];
+ }
+ $output = str_replace('#!# MOBILE_USER_AGENT #!#', $mobile_ua_devices, $output);
+
+
+ // Create main configuration folder if it doesn't exist
+ $main_confd = 'conf.d';
+ if (!is_dir($main_confd)) {
+ mkdir( $main_confd, 0770 );
+ }
+
+ // Create configuration folder
+ $confd = $main_confd . '/' . $name;
+ if (!is_dir($confd)) {
+ mkdir( $confd, 0770 );
+ }
+
+ // Output the file
+ $filename = $main_confd . '/' . $name . ".conf";
+
+ if (!$handle = fopen($filename, 'w')) {
+ echo "Cannot open file: {$filename}.\n";
+ continue;
+ }
+
+ if (fwrite($handle, $output) === FALSE) {
+ echo "Cannot write to file {$filename}.\n";
+ continue;
+ }
+
+ fclose($handle);
+ }
+ }
+
+ /**
+ * Returns generated query strings statement to ignore
+ *
+ * @param array $queryStrings Query strings to ignore
+ *
+ * @return string Nginx "if" statements
+ */
+ protected function getGeneratedQueryStringsToIgnore(array $queryStrings) : string {
+ $result = '';
+
+ if (isset($queryStrings) && is_array($queryStrings)) {
+ $iteration = 1;
+
+ $result .= 'set $rocket_args $args;' . "\n";
+ foreach ($queryStrings as $name => $value) {
+ $result .= 'if ($rocket_args ~ (.*)(?:&|^)' . $value . '=[^&]*(.*)) { ';
+ $result .= 'set $rocket_args $1$2; ';
+ $result .= "}\n";
+
+ $iteration++;
+ }
+
+ $result .= "\n";
+ $result .= '# Remove & at the beginning (if needed)' . "\n";
+ $result .= 'if ($rocket_args ~ ^&(.*)) { set $rocket_args $1; }' . "\n";
+ $result .= "\n";
+ $result .= '# Do not count arguments if part of caching arguments' . "\n";
+ $result .= 'if ($rocket_args ~ ^\?$) {' . "\n";
+ $result .= "\t" . 'set $rocket_is_args "";' . "\n";
+ $result .= '}';
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns generated query strings statement to cache
+ *
+ * @param array $queryStrings Query strings to cache
+ *
+ * @return string Nginx "if" statements
+ */
+ protected function getGeneratedQueryStringsToCache(array $queryStrings) : string {
+ $result = '';
+ $iteration = 1;
+
+ $result .= 'set $rocket_args_tmp $rocket_args;' . "\n";
+ foreach ($queryStrings as $name => $value) {
+ $result .= 'if ($rocket_args_tmp ~ (.*)(?:&|^)' . $value . '=[^&]*(.*)) { ';
+ $result .= 'set $rocket_has_query_cache 1; ';
+ $result .= "}\n";
+
+ $iteration++;
+ }
+
+ $result .= "\n";
+ $result .= 'if ($rocket_has_query_cache = 1) {' . "\n";
+ $result .= "\t" . 'set $rocket_args "#$rocket_args";' . "\n";
+ $result .= "\t" . 'set $rocket_is_args "";' . "\n";
+ $result .= '}';
+
+ return $result;
+ }
+
+ /**
+ * Returns generated include for a section headers
+ *
+ * @param string $config Configuration name
+ * @param string $section Section name
+ *
+ * @return string Include statement
+ */
+ protected function getGeneratedInclude(string $config, string $section) : string {
+ $dir = dirname(__FILE__);
+ $result = "include {$dir}/conf.d/{$config}/{$section}.*.conf;";
+
+ return $result;
+ }
+
+ /**
+ * Get the template file if it exists
+ */
+ protected function getTemplate() : string {
+
+ if (file_exists($this->templateFile) === false) {
+ die("Error: the file 'rocket-nginx.ini' could not be found to generate the configuration. " .
+ "You must rename the orginal 'rocket-nginx.ini.disabled' file to 'rocket-nginx.ini' and run this script again.");
+ }
+
+ return file_get_contents('rocket-nginx.tmpl');
+ }
+
+ /**
+ * Check if configuration file exists
+ */
+ protected function checkConfigurationFile() : void {
+ if (file_exists($this->configFile) === false) {
+ die("Error: the file 'rocket-nginx.ini' could not be found to generate the configuration. " .
+ "You must rename the orginal 'rocket-nginx.ini.disabled' file to 'rocket-nginx.ini' and run this script again.");
+ }
+ }
+
+ /**
+ * Generate configuration files
+ */
+ public function go() : void {
+ $this->checkConfigurationFile();
+
+ $data = $this->parseIniFile();
+ $this->generateConfigurationFiles($data);
+ }
+}
+
+// If this file is included (using 'include' or 'require'), we assume it will call
+// the class automatically. Otherwise, let's generate the configuration files.
+$includedFiles = count(get_included_files());
+
+if ($includedFiles === 1) {
+ error_reporting(-1);
+
+ $rp = new RocketParser();
+ $rp->go();
+}
diff --git a/tests/go.php b/tests/go.php
new file mode 100644
index 0000000..1642e24
--- /dev/null
+++ b/tests/go.php
@@ -0,0 +1,277 @@
+ $headers, 'body' => $body];
+}
+echo "****************************************************************************\n";
+echo "* Rocket-Nginx automated testing\n";
+echo "****************************************************************************\n";
+echo "Let's go!\n";
+
+// Home - Should be a HIT
+$response = call_url(https://github.com/$base_url);
+
+if (!isset($response['headers']['x-rocket-nginx-reason'])) {
+ die('Please set debug to true before running the tests...');
+}
+$homepage_cached = false;
+echo "Getting cached homepage...";
+if ($response['headers']['x-rocket-nginx-serving-static'][0] == 'HIT') {
+ echo "OK\n";
+ $homepage_cached = true;
+}
+else {
+ echo "FAILED (Cache was not primed)\n";
+}
+
+// Retesting as cache might not be primed yet
+if (!$homepage_cached) {
+ $response = call_url(https://github.com/$base_url);
+
+ echo "Getting cached homepage again...";
+ if ($response['headers']['x-rocket-nginx-serving-static'][0] == 'HIT') {
+ echo "OK\n";
+ $homepage_cached = true;
+ }
+ else {
+ echo "FAILED\n";
+ exit;
+ }
+}
+
+// Home with a valid argument - Should be a HIT
+$response = call_url(https://github.com/$base_url%20.%20'?country=canada');
+
+$homepage_cached = false;
+echo "Getting cached homepage with a valid argument...";
+if ($response['headers']['x-rocket-nginx-serving-static'][0] == 'HIT') {
+ echo "OK\n";
+ $homepage_cached = true;
+}
+else {
+ echo "FAILED (Cache was not primed)\n";
+}
+
+// Retesting as cache might not be primed yet
+if (!$homepage_cached) {
+ $response = call_url(https://github.com/$base_url%20.%20'?country=canada');
+
+ echo "Getting cached homepage with a valid argument again...";
+ if ($response['headers']['x-rocket-nginx-serving-static'][0] == 'HIT') {
+ echo "OK\n";
+ $homepage_cached = true;
+ }
+ else {
+ echo "FAILED\n";
+ exit;
+ }
+}
+
+// Never cached - Should be a MISS
+$response = call_url(https://github.com/$base_url%20.%20'never-cached/');
+
+if (!isset($response['headers']['x-rocket-nginx-reason'])) {
+ die('Please set debug to true before running the tests...');
+}
+$homepage_cached = false;
+echo "Getting never cached page...";
+if ($response['headers']['x-rocket-nginx-serving-static'][0] == 'MISS') {
+ echo "OK\n";
+}
+else {
+ echo "FAILED\n";
+ $homepage_cached = true;
+}
+
+// Retesting as cache might not be primed yet
+if ($homepage_cached) {
+ $response = call_url(https://github.com/$base_url%20.%20'never-cached/');
+
+ echo "Getting never cached page again...";
+ if ($response['headers']['x-rocket-nginx-serving-static'][0] == 'MISS') {
+ echo "OK\n";
+ $homepage_cached = true;
+ }
+ else {
+ echo "FAILED\n";
+ exit;
+ }
+}
+
+// Home - With an argument
+$response = call_url(https://github.com/$base_url,%20'rocket=nginx');
+echo "Getting cached homepage with an argument...";
+if ($response['headers']['x-rocket-nginx-serving-static'][0] == 'BYPASS') {
+ echo "OK\n";
+}
+else {
+ echo "FAILED\n";
+ exit;
+}
+
+// Home - With an allowed ignored argument
+$response = call_url(https://github.com/$base_url,%20'utm_source=nginx');
+echo "Getting cached homepage with an allowed argument...";
+if ($response['headers']['x-rocket-nginx-serving-static'][0] == 'HIT') {
+ echo "OK\n";
+}
+else {
+ echo "FAILED\n";
+ exit;
+}
+
+// Home - With both ignored allowed and unallowed arguments
+$response = call_url(https://github.com/$base_url,%20'rocket=nginx&utm_source=rocket');
+echo "Getting cached homepage with an argument...";
+if ($response['headers']['x-rocket-nginx-serving-static'][0] == 'BYPASS') {
+ echo "OK\n";
+}
+else {
+ echo "FAILED\n";
+ exit;
+}
+
+// Home - With an unallowed cookie
+$response = call_url(https://github.com/$base_url,%20null,%20null,%20'woocommerce_items_in_cart=yes');
+echo "Getting cached homepage with an unallowed cookie...";
+if ($response['headers']['x-rocket-nginx-serving-static'][0] == 'BYPASS') {
+ echo "OK\n";
+}
+else {
+ echo "FAILED\n";
+ exit;
+}
+
+// Home - With post data
+$response = call_url(https://github.com/$base_url,%20null,%20['post'%20=%3E%20'data']);
+echo "Getting cached homepage with POST data...";
+if ($response['headers']['x-rocket-nginx-serving-static'][0] == 'BYPASS') {
+ echo "OK\n";
+}
+else {
+ echo "FAILED\n";
+ exit;
+}
+
+// CSS - Checking expiration
+$response = call_url(https://github.com/$base_url%20.%20'wp-includes/css/dashicons.min.css');
+echo "Getting CSS file with expiration...";
+if (isset($response['headers']['expires'])) {
+ $now = new DateTime();
+ $expiration = new DateTime($response['headers']['expires'][0]);
+
+ $interval = $expiration->diff($now);
+ $days = $interval->format('%a');
+
+ if ($days == '370') {
+ echo "OK\n";
+ }
+ else {
+ echo "FAILED\n";
+ exit;
+ }
+}
+else {
+ echo "FAILED\n";
+ exit;
+}
+
+// JS - Checking expiration
+$response = call_url(https://github.com/$base_url%20.%20'wp-includes/js/wp-embed.min.js');
+echo "Getting JS file with expiration...";
+if (isset($response['headers']['expires'])) {
+ $now = new DateTime();
+ $expiration = new DateTime($response['headers']['expires'][0]);
+
+ $interval = $expiration->diff($now);
+ $days = $interval->format('%a');
+
+ if ($days == '740') {
+ echo "OK\n";
+ }
+ else {
+ echo "FAILED\n";
+ exit;
+ }
+}
+else {
+ echo "FAILED\n";
+ exit;
+}
+
+// Media - Checking expiration
+$response = call_url(https://github.com/$base_url%20.%20'wp-admin/images/wordpress-logo.svg');
+echo "Getting media file with expiration...";
+if (isset($response['headers']['expires'])) {
+ $now = new DateTime();
+ $expiration = new DateTime($response['headers']['expires'][0]);
+
+ $interval = $expiration->diff($now);
+ $days = $interval->format('%a');
+
+ if ($days == '1110') {
+ echo "OK\n";
+ }
+ else {
+ echo "FAILED\n";
+ exit;
+ }
+}
+else {
+ echo "FAILED\n";
+ exit;
+}
+
+echo "All tests successful!\n";
+#var_dump($response['headers']);
+#function call_url(https://github.com/$baseUrl,%20$queryString%20=%20null,%20$post_data%20=%20null%20,%20$cookies%20=%20null)