Textpattern + cache-turbo
August 24, 2026 · View on GitHub
Last researched: 2026-07-26 (Textpattern dev branch).
Textpattern is a strong page-cache fit: public articles are shared HTML, while every successful login produces fixed-name cookies that the proxy can see.
Preset
cache_turbo ct;
cache_turbo_backend textpattern; # implies cache_turbo_cache_control honor
| Check | Values |
|---|---|
| Cookie substrings | txp_login_public=, txp_login= |
| URI prefixes | /textpattern |
| Query args | — |
The cookie choices come from Textpattern's current
txp_auth.php:
the admin cookie and public-path cookie are both written on successful login and
cleared on logout. Public rendering checks txp_login_public in
txplib_misc.php,
so it is the load-bearing frontend rule. Anonymous article reads do not receive
either cookie.
/textpattern is the stock admin directory. Textpattern allows that directory
to be renamed. If you renamed it to /control, add the real path:
cache_turbo_bypass_uri /control;
The login cookie still protects a signed-in editor on public pages; the extra URI rule protects login and admin requests before a cookie exists.
Vhost core
load_module modules/ngx_http_cache_turbo_module.so;
http {
cache_turbo_zone name=ct 256m;
server {
server_name example.com;
root /var/www/textpattern;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
cache_turbo ct;
cache_turbo_backend textpattern;
cache_turbo_key $host$request_uri;
cache_turbo_valid 120s;
cache_turbo_preset balanced;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
}
}
For a subdirectory install, declare it: cache_turbo_backend_prefix /blog/;.
Origin failure: stale-if-error
By default this module can serve a stale cached copy when the origin returns 5xx; nginx turns a refused connection into a 502 and a hung one into a 504, so a dead origin is covered. If the response supplies no stale-if-error, cache_turbo_keep_stale provides the fallback window — it defaults to 24h, and cache_turbo_keep_stale off removes that fallback. An honored response stale-if-error takes precedence, while an honored must-revalidate forbids stale serving. cache_turbo_use_stale selects which statuses count as "down" (default: every 5xx); listing any tokens replaces the default rather than extending it. Nothing was ever cached for a URL ⇒ nothing to serve; error_page 502 503 504 /maintenance.html is the final fallback.
cache_turbo_keep_stale 2h;
cache_turbo_valid 120s;
The copy stays fresh for 120s; if the origin starts failing after that, the expired copy keeps being served for up to 2h (cache_turbo_keep_stale). Past that window, or with nothing cached at all, error_page is the fallback. See the README sections on which failures count as "the origin is down" and what outage handling cannot do.
Verify
# Public article: MISS then HIT.
curl -s -o /dev/null -D- https://example.com/article | grep -i x-cache
curl -s -o /dev/null -D- https://example.com/article | grep -i x-cache
# Editor and admin: never HIT.
curl -s -o /dev/null -D- -H 'Cookie: txp_login_public=token' \
https://example.com/article | grep -i x-cache
curl -s -o /dev/null -D- https://example.com/textpattern/ | grep -i x-cache
Keep TTLs short or purge on publish: the preset separates shared from private traffic; it does not know when an article changed.