This is a very old thread, but easily found and most appropriate to my Flarum 1.8 caching woes, so:
I had to add to my Flarum extension:
- A hook so when a user submits login, I refresh the CSRF token.
- Add a cookie to know when a user is logged in.
flarum_remember only works for logged in users that checked "Remember me".
$document->head[] = <<<'HTML'
<script>
(function () {
var loggedin = window.loggedin = window.loggedin || {};
var refreshing;
function setCookie(loggedIn) {
document.cookie = 'loggedin=' + (loggedIn ? '1' : '') + '; Domain=.example.com; Path=/; Max-Age=' + (loggedIn ? 31536000 : 0) + '; Secure; SameSite=Lax';
}
loggedin.refreshCsrfToken = function () {
if (!refreshing) {
refreshing = fetch(app.forum.attribute('apiUrl') + '?_loggedin_csrf=' + Date.now(), {
credentials: 'same-origin',
cache: 'no-store',
headers: {'X-Requested-With': 'XMLHttpRequest'}
}).then(function (response) {
var token = response.headers.get('X-CSRF-Token');
if (token) app.session.csrfToken = token;
}, function () {}).then(function () {
refreshing = null;
});
}
return refreshing;
};
function install() {
var login = app.session.login.bind(app.session);
app.session.login = function (params, options) {
return loggedin.refreshCsrfToken().then(function () {
return login(params, options);
}).then(function (result) {
setCookie(true);
return result;
});
};
app.session.login.loggedin = true;
if (app.session.logout && !app.session.logout.loggedin) {
var logout = app.session.logout.bind(app.session);
app.session.logout = function () {
setCookie(false);
return logout();
};
app.session.logout.loggedin = true;
}
}
if (document.readyState === 'loading')
document.addEventListener('DOMContentLoaded', install);
else
install();
})();
</script>
HTML;
In extend:
(new Extend\Frontend('forum'))
->content(Frontend\Content::class),
Then over in nginx land:
fastcgi_cache_bypass $forum_skipcache_auth $arg__loggedin_csrf;
fastcgi_no_cache $forum_skipcache_auth $arg__loggedin_csrf;
map $http_cookie $forum_skipcache_auth {
~flarum_remember 1; # "Remember me" was checked, no cache so server can auto login.
~loggedin=1 1; # Extension sets this cookie for logged in users. A user can be logged in without checking "Remember me".
default 0;
}
That cryptic garbage says:
- Don't cache if there is a
flarum_remember or loggedin cookie.
- Don't cache if there is a query param
_loggedin_csrf. This is needed so /api?_loggedin_csrf to refresh the token doesn't give a cached result.
The rest is standard nginx junk:
fastcgi_cache_path /path/to/nginx-cache levels=1:2 keys_zone=forum:25m inactive=6h max_size=4096m;
fastcgi_cache_key "$request_method$scheme$host$http_proxy_host$request_uri";
location ~ \.php$ {
include /path/to/php.conf;
try_files $uri =404;
fastcgi_cache forum;
fastcgi_cache_bypass $forum_skipcache_auth $arg__loggedin_csrf;
fastcgi_no_cache $forum_skipcache_auth $arg__loggedin_csrf;
fastcgi_cache_methods GET HEAD;
fastcgi_cache_valid 200 301 302 2h;
fastcgi_cache_lock on;
fastcgi_cache_use_stale updating error timeout invalid_header http_500;
fastcgi_pass_header Set-Cookie;
fastcgi_pass_header Cookie;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
# add_header X-Cache-Status $upstream_cache_status;
}
This is all a big pain. It'd be amazing if Flarum 2.0 can make this easier!
The benefits are HUGE. Previously crawlers would absolutely hammer my site, sometimes bringing it down. Blocking and rate limiting them isn't feasible, there are always more bots with different agent strings. With this caching, bots can go nuts and my server doesn't even notice.