XenForo Forum with Nginx fastcgi_cache full page guest caching

Status
Not open for further replies.

rdn

Well-known member
Nginx includes a FastCGI module which has directives for caching dynamic content that are served from the PHP backend. Setting this up removes the need for additional page caching solutions like reverse proxies (think Varnish) or application specific plugins. Content can also be excluded from caching based on the request method, URL, cookies, or any other server variable.
Credits to @eva2000 @hungphutho @MattW and @Floren for their guidance with I started digging it (y).

1st, required addon: https://xenforo.com/community/resources/logged-in-cookie.4961/
To have persistent cookie for Login Members.

Then add this code into your Nginx Config.

nginx.conf
below http { block
or just selected domain config you may have above server{ block.
Code:
### FastCGI Cache ################
map $http_cookie $nocachecookie {
     default                   0;
    ~xf_fbUid                  1;
    ~xf_user                   1;
    ~xf_logged_in              1;
}
     
map $request_uri $nocacheuri {
       default              0;
    ~^/register             1;
    ~^/login                1;
    ~^/validate-field       1;
    ~^/captcha              1;
    ~^/lost-password        1;
    ~^/two-step             1;
}

fastcgi_cache_path              /tmp/nginx_fastcgi_cache levels=1:2 keys_zone=fastcgicache:200m inactive=30m;
fastcgi_cache_key               $scheme$request_method$host$request_uri;
fastcgi_cache_lock              on;
fastcgi_cache_use_stale         error timeout invalid_header updating http_500;
fastcgi_ignore_headers          Cache-Control Expires Set-Cookie;
### FastCGI Cache ################

php.conf
above the last line }.
or at the very bottom of this block
location ~ \.php$ {
Code:
### fastcgi_cache ###
fastcgi_cache           fastcgicache;
fastcgi_cache_bypass    $nocachecookie $nocacheuri;
fastcgi_no_cache        $nocachecookie $nocacheuri;
fastcgi_cache_valid     200 202 302 404 403 5m;
fastcgi_cache_valid     301 1h;
fastcgi_cache_valid     any 1m;
add_header X-Cache      $upstream_cache_status;
### fastcgi_cache end ###

Save and then restart Nginx and PHP-FPM.


Optional, to have xf_user cookie on every Login Members.

Modify template helper_login_form and login_bar_form.
Replace:
Code:
<label class="rememberPassword"><input type="checkbox" name="remember" value="1" id="ctrl_pageLogin_remember" tabindex="3" /> {xen:phrase stay_logged_in}</label>
With this:
Code:
<input type="hidden" name="remember" checked="checked" value="1" />

Benefits?
Same as Varnish and LiteSpeed Full Page Cache :).


More Info:
http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_cache
https://www.digitalocean.com/community/tutorials/how-to-setup-fastcgi-caching-with-nginx-on-your-vps
https://www.scalescale.com/tips/nginx/configure-nginx-fastcgi-cache/
 
Last edited:
Minimal Config :).

nginx.conf
below http { block
or just selected domain config you may have above server{ block.
Code:
### FastCGI Cache ################
map $http_cookie $nocachecookie {
     default                   0;
    ~xf_logged_in              1;
}

fastcgi_cache_path              /tmp/nginx_fastcgi_cache levels=1:2 keys_zone=fastcgicache:200m inactive=30m;
fastcgi_cache_key               $scheme$request_method$host$request_uri;
fastcgi_cache_lock              on;
fastcgi_cache_use_stale         error timeout invalid_header updating http_500;
fastcgi_ignore_headers          Cache-Control Expires Set-Cookie;
### FastCGI Cache ################

php.conf
above the last line }.
or at the very bottom of this block
location ~ \.php$ {
Code:
### fastcgi_cache ###
fastcgi_cache           fastcgicache;
fastcgi_cache_bypass    $nocachecookie;
fastcgi_no_cache        $nocachecookie;
fastcgi_cache_valid     5m;
add_header X-Cache      $upstream_cache_status;
### fastcgi_cache end ###
 
Last edited:
This is great, thank you! Will try it out :) do you happen to know how the performance compares to apache + varnish or litespeed + lscache?
 
Hi @RoldanLT

Thanks for your examples.
I was thinking, shouldn't we map the request method too with something like this?

Code:
map $request_method $nocachemethod {
     default                   1;
     GET                       0;
}
 
Last edited:
I installed the plugin then go to modify the nginx and php.conf but i take errors, nginx can't restart

Code:
[root@server ~]# ngxrestart
Restarting nginx (via systemctl):  Job for nginx.service failed because the control process exited with error code. See "systemctl status nginx.service" and "journalctl -xe" for details.
                                                           [FAILED]

Then i run the journalctl -xe command, output:
Code:
[root@server ~]# journalctl -xe
Jan 20 14:46:34 server polkitd[1053]: Registered Authentication Agent for unix-process:3047:
Jan 20 14:46:34 server systemd[1]: Stopping SYSV: Nginx is an HTTP(S) server, HTTP(S) revers
-- Subject: Unit nginx.service has begun shutting down
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit nginx.service has begun shutting down.
Jan 20 14:46:34 server nginx[3053]: Stopping nginx: [  OK  ]
Jan 20 14:46:34 server systemd[1]: Starting SYSV: Nginx is an HTTP(S) server, HTTP(S) revers
-- Subject: Unit nginx.service has begun start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit nginx.service has begun starting up.
Jan 20 14:46:34 server nginx[3062]: Starting nginx: nginx: [emerg] "map" directive is not al
Jan 20 14:46:34 server nginx[3062]: [FAILED]
Jan 20 14:46:34 server systemd[1]: nginx.service: control process exited, code=exited status
Jan 20 14:46:34 server systemd[1]: Failed to start SYSV: Nginx is an HTTP(S) server, HTTP(S)
-- Subject: Unit nginx.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit nginx.service has failed.
--
-- The result is failed.

Problem is "map" directive is not allowed error while restarting nginx.

I tried both minimal and normal config on nginx.conf and domain.conf files too. But it gives same error. Also i modified the php.conf too (code added bottom)

P.S: Nginx 1.9.9 and php 7.0.2

@RoldanLT
 
Also @maxicep , did you put the above code in the server file (or default) or nginx.conf? It should all go in your server file:

/etc/nginx/sites-available/yoursite

By default, the file is:
/etc/nginx/sites-available/default

I didn't need to make any changes to nginx.conf or php.conf

Basically, your default file can look like this (with no changes to other files) - ignore my SSL and static caching stuff.

Code:
### FastCGI Cache ################
map $http_cookie $nocachecookie {
     default                   0;
    ~xf_fbUid                  1;
    ~xf_user                   1;
    ~xf_logged_in              1;
}

map $request_uri $nocacheuri {
       default              0;
    ~^/register             1;
    ~^/login                1;
    ~^/validate-field       1;
    ~^/captcha              1;
    ~^/lost-password        1;
    ~^/two-step             1;
}

fastcgi_cache_path              /tmp/nginx_fastcgi_cache levels=1:2 keys_zone=fastcgicache:50m inactive=2m;
fastcgi_cache_key               $scheme$request_method$host$request_uri;
fastcgi_cache_lock              on;
fastcgi_cache_use_stale         error timeout invalid_header updating http_500;
fastcgi_ignore_headers          Cache-Control Expires Set-Cookie;
### FastCGI Cache ################

server {
        # listen 80 default_server;
        # listen [::]:80 default_server ipv6only=on;
       listen 443 ssl;

        server_name mysite.com;

        ssl_certificate /etc/letsencrypt/live/mysite.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/mysite.com/privkey.pem;

        root /usr/share/nginx/html;

        index index.php index.html index.htm;

        # Cache Static Content
        location ~* \.(?:jpg|jpeg|gif|png|ico|mp4|css|js)$ {
                expires 1y;
                access_log off;
                add_header Cache-Control "public";
        }

        error_page 404 /404.html;
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
               root /usr/share/nginx/html;
        }

        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_index index.php;
                include fastcgi_params;

             ### fastcgi_cache ###
             fastcgi_cache           fastcgicache;
             fastcgi_cache_bypass    $nocachecookie $nocacheuri;
             fastcgi_no_cache        $nocachecookie $nocacheuri;
             fastcgi_cache_valid     200 202 302 404 403 5m;
             fastcgi_cache_valid     301 1h;
             fastcgi_cache_valid     any 1m;
             add_header X-Cache      $upstream_cache_status;
             ### fastcgi_cache end ###
        }
}
 
Last edited:
  • Like
Reactions: rdn
P.S: Nginx 1.9.9 and php 7.0.2
I know you are also using Centminmod, so here's how I do it.

nginx.conf
below http {

Code:
### FastCGI Cache ################

map $http_cookie $nocachecookie {
     default                   0;
    ~xf_fbUid                  1;
    ~xf_user                   1;
    ~xf_logged_in              1;
}
   
map $request_uri $nocacheuri {
       default              0;
    ~^/register             1;
    ~^/login                1;
    ~^/validate-field       1;
    ~^/captcha              1;
    ~^/lost-password        1;
    ~^/two-step             1;
}

fastcgi_cache_path              /tmp/nginx_fastcgi_cache levels=1:2 keys_zone=fastcgicache:200m inactive=30m;
fastcgi_cache_key               $scheme$request_method$host$request_uri;
fastcgi_cache_lock              on;
fastcgi_cache_use_stale         error timeout invalid_header updating http_500;
fastcgi_ignore_headers          Cache-Control Expires Set-Cookie;
### FastCGI Cache ################

7UXz2rl.png





php.conf
above the last line }.

Code:
### fastcgi_cache ###
fastcgi_cache           fastcgicache;
fastcgi_cache_bypass    $nocachecookie $nocacheuri;
fastcgi_no_cache        $nocachecookie $nocacheuri;
fastcgi_cache_valid     200 202 302 404 403 5m;
fastcgi_cache_valid     301 1h;
fastcgi_cache_valid     any 1m;
add_header X-Cache      $upstream_cache_status;
### fastcgi_cache end ###
KemDQcl.png



Then on SSH, run nprestart.

 
It worked when i put the map strings to outside of server block in domain.conf

If i put map strings after http block, nginx restart fails. I have custom map file too maybe it does that i dont understand..

However, i have some problems after enabled. Firstly, page load faster than before. But i have custom add-on for mobile style switch. It is using a cookie i think for check and switch mobile/desktop style so all visitors going to desktop site now of that cache enabled.

Can i exclude this cookie and prevent this problem? Because i must use different styles for mobile visitors . I dont prefer responsive
 
Thank you for this feature @Peace @eva2000 @hungphutho @MattW and @Floren and in my tests, need a modify for who using different styles (desktop and mobile) Because, it cache only one version of the forum pages, it is desktop or mobile (which style first run)

Firstly, I have 2 different style (desktop and mobile) and I have a custom mobile switcher add-on for switch mobile visitors to mobile style. I don't use xenforo mobile style for my mobile visitors.

So, for example if you reset cache then open the forum page on iphone device, it caches the mobile style page to nginx_fastcgi_cache folder. Later if you visit that page from desktop pc, it shows the forum based on mobile style. Possible have a reverse situation too. If first visit from desktop pc, then mobile visitor shows the page as desktop style not mobile.

In my researches, i tried to modify/add custom parameters for fastcgi_cache_key and it is =>
fastcgi_cache_key $scheme$request_method$host$request_uri$mobile_request;

Also, added to server block in domain.conf =>
set $mobile_request 0;​
if ($http_user_agent ~* "(android|iphone)") {
set $mobile_request 1;
}​
So, i tell nginx that if user agent is mobile then mobile_request is 1 and caching based on this.

But still same... Nothing changed.

Some sources;
https://www.alpine.link/2015/04/24/wordpress-page-caching-mobile-users/
http://community.rtcamp.com/t/fastcgi-cache-mobile-theme-purge/1558
 
If you don't want to cache Mobile visitors, you can exclude them by this method.
On your domain.com.conf, below
root /home/nginx/domains/domain.com/public;
Code:
### Fastcgi_Cache
    set $is_mobile    0;
  
    if ($http_user_agent ~* "(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino") {
    set $is_mobile    1;
    }
  
    if ($http_user_agent ~* "^(1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-)") {
    set $is_mobile    1;
    }
    ### Fastcgi_Cache


Then your php.conf code will be:
Code:
### fastcgi_cache ###
fastcgi_cache           fastcgicache;
fastcgi_cache_bypass    $nocachecookie $nocacheuri $is_mobile;
fastcgi_no_cache        $nocachecookie $nocacheuri $is_mobile;
fastcgi_cache_valid     200 202 302 404 403 5m;
fastcgi_cache_valid     301 1h;
fastcgi_cache_valid     any 1m;
add_header X-Cache      $upstream_cache_status;
### fastcgi_cache end ###
 
I want cache them seperately both. Is it possible ? In my researches, yes someone do it especially on wordpress side.
 
Anyone have any idea for caching multiple user agents with this way ? I didn't fix that problem still. However, i think one way is add a string (desktop/mobile check string) to fastcgi_cache_key value.

And if i found a solution like add custom cookie to visitors who coming from xenforo mobile check = 1 so i can add a parameter to fastcgi_cache_key value so xenforo mobile / desktop may caching differently on nginx fastcgi cache module ... @RoldanLT
 
Anyone have any idea for caching multiple user agents with this way ? I didn't fix that problem still. However, i think one way is add a string (desktop/mobile check string) to fastcgi_cache_key value.

And if i found a solution like add custom cookie to visitors who coming from xenforo mobile check = 1 so i can add a parameter to fastcgi_cache_key value so xenforo mobile / desktop may caching differently on nginx fastcgi cache module ... @RoldanLT
I'm on my phone right now but check out the Vary:User-Agent header. You can cache separately for every user agent, or group by mobile/desktop

https://www.fastly.com/blog/best-practices-for-using-the-vary-header
 
Status
Not open for further replies.
Top Bottom