- 
      
- 
        Save ivanionut/d400ea6d1e46e2b66fbdaf68c9cc0315 to your computer and use it in GitHub Desktop. 
Revisions
- 
        anthumchris revised this gist Aug 7, 2018 . 1 changed file with 9 additions and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -55,10 +55,18 @@ The cache is cleared by deleting all files/folders withing the specified cache f ```bash #!/bin/bash sudo /root/scripts/nginx-clear-cache.php "$@" ``` [nginx-clear-cache.php](#nginx-clear-cache.php) is called as `sudo` because Nginx creates the files as `root:root` and I found no way of immediately changing this behavior in Nginx’s configuration files. The script requires `sudo` privileges to delete the cached files. It also requires 1 parameter indicating which cache key to clear. I decided to use a combination of HTTP hostname and explicit key name to be used for the same cache. The HTTP hostname allows more flexibility when WordPress triggers the script by dynamically passing the hostname, which indicates the environment (e.g. Prod, Stage) the application is deployed in. #### Authorizing Sudo Access without Authentication Because `sudo` is used and called by non-root processes (PHP and application deployment processes), the cache-clearing script must be authorized to run without requiring users to authenticate. Using the `$ visudo` command, the following line was added: ``` ALL ALL=(ALL) NOPASSWD: /root/scripts/nginx-clear-cache.php ``` **NOTE:** This is security vulnerability if not used wisely. ### Rethinking the Solution Ideally, it would be better if Nginx could be configured to create cache files with permissions that do not require `sudo` to be used. It would also be nice to consolidate the two cache-clearing scripts into one script that recursively calls itself as `sudo` if not initiated as `sudo`. 
- 
        anthumchris revised this gist Aug 7, 2018 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -9,7 +9,7 @@ Our Nginx servers run as an HTTP proxy for multiple PHP/MySQL-backed WordPress s ### Site Cache Configuration The example below shows how PHP response caching is configured for a site (other nginx configuration details are excluded for brevity). A cache named `cachedemo-prod` is defined to store cached HTML files in folder `/var/cache/nginx/cachedemo-prod`. **nginx.conf** ```nginx fastcgi_cache_path /var/cache/nginx/cachedemo-prod levels=1:2 keys_zone=cachedemo-prod:10m max_size=100m inactive=1y use_temp_path=off; 
- 
        anthumchris revised this gist Aug 7, 2018 . 1 changed file with 2 additions and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -9,6 +9,7 @@ Our Nginx servers run as an HTTP proxy for multiple PHP/MySQL-backed WordPress s ### Site Cache Configuration The example below shows how PHP response caching is configured for a site (other nginx configuration details are excluded for brevity). A cache named `cachedemo-prod` is defined to store cached HTML files in folder `/var/cache/nginx/cachedemo-prod`. *nginx.conf* ```nginx fastcgi_cache_path /var/cache/nginx/cachedemo-prod levels=1:2 keys_zone=cachedemo-prod:10m max_size=100m inactive=1y use_temp_path=off; @@ -52,7 +53,7 @@ While changes could be small, one CSS change may affect a header layout, which s The cache is cleared by deleting all files/folders withing the specified cache folder. When one of the Cache-Clearing events occur, a trigger executes to initialize the cache-clearing script at `/usr/share/nginx-clear-cache-init.sh`: ```bash #!/bin/bash sudo nginx-clear-cache.php "$@" ``` 
- 
        anthumchris revised this gist Aug 7, 2018 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,7 +2,7 @@ I recently implemented Nginx HTTP content caching on our WordPress web servers to improve page load speeds and eliminate redundant, unneeded server-side page rendering. Caching the pages was relatively straightforward, but clearing the cache required a custom workaround. Nginx comes in two versions: free and “Nginx Plus” at $2,500/year. The free version of Nginx does not offer the needed cache-clearing features of Nginx Plus, and I wasn’t comfortable paying $20,000 for 8 instances without trying to build my own solution. Our Nginx servers run as an HTTP proxy for multiple PHP/MySQL-backed WordPress sites. The goal was to cache the dynamic PHP HTML responses in Nginx and serve the HTML pages from Nginx to avoid redundant, CPU-intensive PHP renders. 
- 
        anthumchris revised this gist Aug 7, 2018 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -60,4 +60,4 @@ sudo nginx-clear-cache.php "$@" [nginx-clear-cache.php](#nginx-clear-cache.php) is called as `sudo` because Nginx creates the files as `root:root` and I found no way of immediately changing this behavior in Nginx’s configuration files. The script requires `sudo` privileges to delete the cached files. It also requires 1 parameter indicating which cache key to clear. I decided to use a combination of HTTP hostname and explicit key name to be used for the same cache. The HTTP hostname allows more flexibility when WordPress triggers the script by dynamically passing the hostname, which indicates the environment (e.g. Prod, Stage) the application is deployed in. ### Rethinking the Solution Ideally, it would be better if Nginx could be configured to create cache files with permissions that do not require `sudo` to be used. It would also be nice to consolidate the two cache-clearing scripts into one script that recursively calls itself as `sudo` if not initiated as `sudo`. 
- 
        anthumchris revised this gist Aug 7, 2018 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -32,6 +32,7 @@ 2 => array("pipe", "w"), // stderr ); // execute Linux system process $process = proc_open("find \"$siteCachePath\" -type f -exec rm -v {} \; | wc -l", $descriptorspec, $pipes, dirname(__FILE__), null); $stdout = stream_get_contents($pipes[1]); 
- 
        anthumchris revised this gist Aug 7, 2018 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,11 +4,11 @@ // Define duplicate cache keys to accommodate both label (static) and actual hostname (dynamic) calls $sites = array( "cachedemo-prod" => "/var/cache/nginx/cachedemo-prod", "cachedemo.example.com" => "/var/cache/nginx/cachedemo-prod", "cachedemo-stage" => "/var/cache/nginx/cachedemo-stage", "cachedemo-stage.example.com" => "/var/cache/nginx/cachedemo-stage", ); $siteArg = isset($argv[1])? $argv[1] : null; 
- 
        anthumchris revised this gist Aug 7, 2018 . 1 changed file with 6 additions and 6 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,7 +7,7 @@ Nginx comes in two versions: free and “Nginx Plus” at $2,500/year. The free Our Nginx servers run as an HTTP proxy for multiple PHP/MySQL-backed WordPress sites. The goal was to cache the dynamic PHP HTML responses in Nginx and serve the HTML pages from Nginx to avoid redundant, CPU-intensive PHP renders. ### Site Cache Configuration The example below shows how PHP response caching is configured for a site (other nginx configuration details are excluded for brevity). A cache named `cachedemo-prod` is defined to store cached HTML files in folder `/var/cache/nginx/cachedemo-prod`. ```nginx fastcgi_cache_path /var/cache/nginx/cachedemo-prod levels=1:2 keys_zone=cachedemo-prod:10m max_size=100m inactive=1y use_temp_path=off; @@ -41,23 +41,23 @@ server { } ``` ### Cache-Clearing Events To achieve a balance between performance benefits and minimizing configuration overhead, I simplified matters by clearing the website's entire cache when: 1. Admins Change Content in WordPress (content added, modified, removed) 1. Developers Deploy New Releases (CSS, HTML, JavaScript, images, etc) While changes could be small, one CSS change may affect a header layout, which subsequently affects all pages using that header. It seemed like a fail-safe and defensive strategy to prevent stale content by invalidating all pages. ### Clearing a Site’s Cache The cache is cleared by deleting all files/folders withing the specified cache folder. When one of the Cache-Clearing events occur, a trigger executes to initialize the cache-clearing script at `/usr/share/nginx-clear-cache-init.sh`: ``` #!/bin/bash sudo nginx-clear-cache.php "$@" ``` [nginx-clear-cache.php](#nginx-clear-cache.php) is called as `sudo` because Nginx creates the files as `root:root` and I found no way of immediately changing this behavior in Nginx’s configuration files. The script requires `sudo` privileges to delete the cached files. It also requires 1 parameter indicating which cache key to clear. I decided to use a combination of HTTP hostname and explicit key name to be used for the same cache. The HTTP hostname allows more flexibility when WordPress triggers the script by dynamically passing the hostname, which indicates the environment (e.g. Prod, Stage) the application is deployed in. ### Rethinking the Solution Ideally, it would be better if Nginx could be configured to create cache files with permissions that do not require `sudo` to be used. It would also be nice to consolidate the 2 cache-clearing files into 1 file that recursively calls itself as `sudo` if not initiated as `sudo`. 
- 
        anthumchris revised this gist Aug 7, 2018 . 1 changed file with 1 addition and 5 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -57,11 +57,7 @@ When one of the above events occur, a trigger executes to initialize the cache-c sudo nginx-clear-cache.php "$@" ``` [nginx-clear-cache.php](#nginx-clear-cache.php) is called as `sudo` because Nginx creates the files as `root:root` and I found no way of immediately changing this in Nginx’s configuration files. The script requires `sudo` privileges to delete the cached files. It also requires 1 parameter indicating which cache key to clear. I decided to use a combination of HTTP hostname and explicit key name to be used for the same cache. The HTTP hostname allows more flexibility when WordPress triggers the script by dynamically passing the hostname, which indicates the environment (e.g. Prod, Stage) the application is deployed in. ### Rethinking the Solution Ideally, it would be better if Nginx could be configured to create cache files with permissions that do not require `sudo` to be used. It would also be nice to consolidate the 2 cache-clearing files into 1 file that recursively calls itself as `sudo` if not initiated as `sudo`. 
- 
        anthumchris revised this gist Aug 7, 2018 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -61,7 +61,7 @@ sudo nginx-clear-cache.php "$@" `nginx-clear-cache.php` requires 1 parameter indicating the cache key to clear. I decided to use a combination of HTTP hostname and explicit key name to be used for the same cache. The HTTP hostname allows more flexibility when WordPress triggers the script by dynamically passing the hostname, which indicates the deployment environment (e.g. Prod, Stage, Etc). [nginx-clear-cache.php](nginx-clear-cache.php) ### Rethinking the Solution Ideally, it would be better if Nginx could be configured to create cache files with permissions that do not require `sudo` to be used. It would also be nice to consolidate the 2 cache-clearing files into 1 file that recursively calls itself as `sudo` if not initiated as `sudo`. 
- 
        anthumchris created this gist Aug 7, 2018 .There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,67 @@ # Clearing Nginx's HTTP Cache I recently implemented Nginx HTTP content caching on our WordPress web servers to improve page load speeds and eliminate redundant, unneeded server-side page rendering. Caching the pages was relatively straightforward, but clearing the cache required a custom workaround. Nginx comes in two versions: free and “Nginx Plus” at $2,500/year. The free version of Nginx does not offer the needed cache-clearing features of Nginx Plus, and I wasn’t comfortable paying $20,000 for 4 instances without trying to build my own solution. Our Nginx servers run as an HTTP proxy for multiple PHP/MySQL-backed WordPress sites. The goal was to cache the dynamic PHP HTML responses in Nginx and serve the HTML pages from Nginx to avoid redundant, CPU-intensive PHP renders. ### Site Cache Configuration The example below shows how PHP response caching is configured for a site (other nginx configuration details are excluded for brevity). A cache named `cachedemo-prod` is configured to stores cached HTML files in folder `cachedemo-prod` in `/var/cache/nginx/cachedemo-prod`. ```nginx fastcgi_cache_path /var/cache/nginx/cachedemo-prod levels=1:2 keys_zone=cachedemo-prod:10m max_size=100m inactive=1y use_temp_path=off; server { ... # Configure cache fastcgi_cache cachedemo-prod; fastcgi_cache_key $request_method$scheme$host$request_uri; # Disable cached responses if admins are logged in (admin session cookie exists) fastcgi_cache_bypass $cookie_wordpress_logged_in_abcdefg1234567890 $cookie_wordpress_sec_abcdefg1234567890; # forward all *.php URIs to PHP service location ~ \.php$ { # Keep cached pages for 90 days fastcgi_cache_valid 200 90d; fastcgi_read_timeout 300; try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } ... } ``` ### When to Clear the Cache? To achieve a balance between performance benefits and minimizing configuration overhead, I simplified matters by clearing the websites entire cache when: 1. Admins Change Content in WordPress (content added, modified, removed) 1. Developers Deploy New Releases (CSS, HTML, JavaScript, images, etc) While changes could be small, one CSS change may affect a header layout, which subsequently affects all pages using that header. It seemed like a fail-safe and defensive strategy to prevent stale content. ### Clearing a Site’s Cache When one of the above events occur, a trigger executes to initialize the cache-clearing script at `/usr/share/nginx-clear-cache-init.sh`: ``` #!/bin/bash sudo nginx-clear-cache.php "$@" ``` `nginx-clear-cache.php` is called as `sudo` because Nginx creates the files as `root:root` and I found no way of immediately changing this in Nginx’s configuration files. The script requires `sudo` privileges to delete the cached files. `nginx-clear-cache.php` requires 1 parameter indicating the cache key to clear. I decided to use a combination of HTTP hostname and explicit key name to be used for the same cache. The HTTP hostname allows more flexibility when WordPress triggers the script by dynamically passing the hostname, which indicates the deployment environment (e.g. Prod, Stage, Etc). [nginx-clear-cache.php](./nginx-clear-cache.php) ### Rethinking the Solution Ideally, it would be better if Nginx could be configured to create cache files with permissions that do not require `sudo` to be used. It would also be nice to consolidate the 2 cache-clearing files into 1 file that recursively calls itself as `sudo` if not initiated as `sudo`. This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,52 @@ #!/usr/bin/php <?php // This script should be called by SUDO by another script and return number of items cleared // Define duplicate cache keys to accommodate both label (static) and actual hostname (dynamic) calls $sites = array( "cachedemo-prod" => "/var/cache/nginx/var/cache/nginx/cachedemo-prod", "cachedemo.example.com" => "/var/cache/nginx/var/cache/nginx/cachedemo-prod", "cachedemo-stage" => "/var/cache/nginx/var/cache/nginx/cachedemo-stage", "cachedemo-stage.example.com" => "/var/cache/nginx/var/cache/nginx/cachedemo-stage", ); $siteArg = isset($argv[1])? $argv[1] : null; if (!isset($sites[$siteArg])) { echo "Valid site argument required: \n\n"; foreach ($sites as $key => $value) { echo " $key\n"; } echo "\nInvalid site argument: '$siteArg'"; exit(1); } $siteName = $argv[1]; $siteCachePath = $sites[$siteName]; $log = date("h:i:s A T") . " - $siteName - "; $descriptorspec = array( 0 => array("pipe", "r"), // stdin 1 => array("pipe", "w"), // stdout 2 => array("pipe", "w"), // stderr ); $process = proc_open("find \"$siteCachePath\" -type f -exec rm -v {} \; | wc -l", $descriptorspec, $pipes, dirname(__FILE__), null); $stdout = stream_get_contents($pipes[1]); $stderr = stream_get_contents($pipes[2]); fclose($pipes[1]); fclose($pipes[2]); if ($stderr) { $log .= "ERROR $stderr"; } else { $log .= $stdout; } // Log to file file_put_contents('/var/log/nginx/cache-clear.log', "$log", FILE_APPEND); // Output total cleared echo $stdout;