Header RSS Feed
 
If you only want to see the articles of a certain category, please click on the desired category below:
ALL Android Backup BSD Database Hacks Hardware Internet Linux Mail MySQL Monitoring Network Personal PHP Proxy Shell Solaris Unix Virtualization VMware Windows Wyse

Empty page returned from Nginx with fastcgi caching (HEAD vs GET)
Friday - Apr 21st 2017 - by - (0 comments)

A while ago I wrote about Enable caching in Nginx Reverse Proxy (and solve cache MISS only). The article back then was focusing on caching on a reverse proxy setup, meaning it was a proxy_cache. But Nginx also has the possibility to cache FastCGI backends.

For a customer I wanted to enable this kind of caching (fastcgi_cache) for the PHP backend using PHP-FPM. The setup is pretty much the same as proxy_cache - just call it fastcgi_cache instead ;-)

In Nginx's http section:

    ##
    # Caching settings
    ##
    fastcgi_cache_path  /var/www/cache levels=1:2 keys_zone=cachecool:100m max_size=1000m inactive=60m;
    fastcgi_cache_key "$scheme$host$request_uri";

And in the vhost config file within the .php file extension location:

  location ~ \.php$ {
    try_files $uri =404;
    default_type text/html; charset utf-8;
    fastcgi_split_path_info ^(.+\.php)(.*)$;
    fastcgi_pass unix:/run/php5-fpm.sock;
    fastcgi_next_upstream error timeout invalid_header http_500 http_503;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    fastcgi_param HTTP_X_REAL_IP $remote_addr;

    # FastCGI Caching
    fastcgi_cache cachecool;
    fastcgi_cache_valid 200 60m;
    fastcgi_cache_methods GET;
    add_header X-Cache $upstream_cache_status;
  }

Then reload Nginx.

So far so good, caching seems to work which I was able to test with curl:

$ curl -I https://app.example.com/phpinfo.php -v
* Hostname was NOT found in DNS cache
*   Trying 1.2.3.4...
* Connected to app.example.com (1.2.3.4) port 443 (#0)
[...ssl stuff...]
> HEAD /phpinfo.php HTTP/1.1
> User-Agent: curl/7.35.0
> Host: app.example.com
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
* Server nginx/1.10.3 is not blacklisted
< Server: nginx/1.10.3
Server: nginx/1.10.3
< Date: Fri, 21 Apr 2017 06:16:56 GMT
Date: Fri, 21 Apr 2017 06:16:56 GMT
< Content-Type: text/html; charset=UTF-8
Content-Type: text/html; charset=UTF-8
< Connection: keep-alive
Connection: keep-alive
< Vary: Accept-Encoding
Vary: Accept-Encoding
< X-Cache: MISS
X-Cache: MISS

Second curl request:

$ curl -I https://app.example.com/phpinfo.php -v
* Hostname was NOT found in DNS cache
*   Trying 1.2.3.4...
* Connected to app.example.com (1.2.3.4) port 443 (#0)
[...ssl stuff...]
> HEAD /phpinfo.php HTTP/1.1
> User-Agent: curl/7.35.0
> Host: app.example.com
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
* Server nginx/1.10.3 is not blacklisted
< Server: nginx/1.10.3
Server: nginx/1.10.3
< Date: Fri, 21 Apr 2017 06:16:57 GMT
Date: Fri, 21 Apr 2017 06:16:57 GMT
< Content-Type: text/html; charset=UTF-8
Content-Type: text/html; charset=UTF-8
< Connection: keep-alive
Connection: keep-alive
< Vary: Accept-Encoding
Vary: Accept-Encoding
< X-Cache: HIT
X-Cache: HIT

The X-Cache header confirmed me: I hit the cache. So it's working.

But when I wanted to check the same URL in the browser, I got slapped in the face:

Cached php page empty in browser 

The page is empty?!

I manually removed the Nginx cache...

$ rm -rf /var/www/cache/*

... and then refreshed the browser. phpinfo.php was shown correctly now!
What's the difference between my curl and my browser request? Note the -I parameter after the curl command. This uses the HEAD request method. HEAD only returns the HTTP headers, no body. Accessing a website in the browser (usually) uses the GET method. So here we have the difference and also the explanation why the body was empty, resulting in an empty page.

So how do I solve this? The solution (found on ServerFault.com) is actually pretty self-explanatory: The caching key also needs to contain the request method. Remember the setup in Nginx's http section?

    fastcgi_cache_key "$scheme$host$request_uri";

 Here I only set the $scheme (https), the $host (app.example.com) and the $request_uri (/phpinfo.php). The caching mechanism doesn't differ between a GET, a HEAD or even another request method like POST. So let's add this:

    fastcgi_cache_key "$scheme$request_method$host$request_uri";

After a Nginx reload, I tried to reproduce the empty cache problem:

  • Removed the cache (rm -rf /var/www/cache/*)
  • Launched the curl command with HEAD request method (curl -I) from above - X-Cache was a MISS
  • Launched the same curl command again - X-Cache was a HIT
  • Opened the same URL in browser: phpinfo was shown correctly

Solved!

 

Add a comment

Show form to leave a comment

Comments (newest first):

No comments yet.

Go to Homepage home
Linux Howtos how to's
Monitoring Plugins monitoring plugins
Links links

Valid HTML 4.01 Transitional
Valid CSS!
[Valid RSS]

7423 Days
until Death of Computers
Why?