# Static Caching

Using the static file cache can bring your page load time down to <100ms, but you can not use escaping or anything that requires ExpressionEngine processing on each request.

It does this by caching the **entire HTTP response** just before it is sent to the browser.

This response is then built into a PHP template that includes all the code for setting HTTP headers and checking the expiry time.

{% hint style="info" %}
When using Static caching if the `speedy_query_cache_allowlist` config value is changed you will need to clear your site cache to ensure new configuration is used.
{% endhint %}

{% hint style="info" %}
When using Redis with static enabled if the `speedy_query_cache_allowlist` config value is changed or connection settings to the Redis server is changed you will need to clear your site cache to ensure new configuration is used. You will also need to delete the `index_redis_default_site.php` file in the root of your site, then click the prompt below in your control panel to re-generate the index file.
{% endhint %}

{% hint style="info" %}
Static caching works exactly the same when using Coilpack as it does when using the native template language.
{% endhint %}

{% hint style="info" %}
If you experience issues with PHP or tempalte parsing errors, try enabling the [speedy\_static\_use\_html\_file](https://docs.boldminded.com/speedy/docs/configuration) setting.
{% endhint %}

## Installation

To enable the static file cache driver:

* Create a new directory in your document root (where `index.php` is) named `static`.
* Make sure `speedy_static_enabled` is set to `yes`  in your `config.php` file.
* Add the code below to the top of your `.htaccess` file (or create one if it does not exist).&#x20;
* [Complete the installation](https://docs.boldminded.com/speedy/control-panel#static-cache-configuration) in the Speedy control panel page.

At minimum, your config.php file should have the following for static caching to work:

```php
$config['speedy_driver'] = 'static';
$config['speedy_static_enabled'] = 'yes';
```

If you are using Redis as a static caching option, you must change `speedy_driver` to `redis`, and enable it in Redis driver settings page in the control panel, or add the following to your config.php file:

```php
$config['speedy_driver'] = 'redis';
$config['speedy_redis_settings'] = [
    'static' => 'yes',
];
```

{% hint style="warning" %}
**Apache and Nginx configuration is not included with Speedy's support.**&#x20;

The following examples work as provided based on Speedy's default settings. Due to the wide variety of issues that can occur with server configurations and other re-write rules a site may require, debugging and supporting the following configurations on is not included with Speedy's support. These are only provided as a starting point. You may need to modify the rules if they do not work for you as is.
{% endhint %}

Apache .htaccess rewrite rule:

```apacheconf
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/system [NC]
    RewriteCond %{QUERY_STRING} !ACT|URL [NC]
    RewriteCond %{REQUEST_METHOD} !=POST [NC]
    RewriteCond $1 !\.(css|js|gif|jpe?g|png) [NC]
    RewriteCond %{DOCUMENT_ROOT}/static/default_site/static%{REQUEST_URI}/index\.php -f
    RewriteRule ^ /static/default_site/static%{REQUEST_URI}/index\.php [L,QSA]
</IfModule>
```

If using Nginx:

```nginx
if ($request_method !~* GET) {
   set $request_var nonget;
}

if ($args ~* (ACT|URI)) {
    set $uri_var acturl;
}

if (-e  $document_root/static/default_site/static/$request_uri$request_var$uri_var/index.php) {
	rewrite ^(.*) /static/default_site/static/$request_uri/index.php last;
}
```

Once static caching is enabled and configured, simply add the following tag to the pages you want to be cached. This tag can be anywhere in your template, and does not need a closing tag pair.

{% tabs %}
{% tab title="Native" %}

```
{exp:speedy:static}
```

{% endtab %}

{% tab title="Twig" %}

```
{{ exp.speedy.static() }}
```

{% endtab %}
{% endtabs %}

`{exp:speedy:static}` accepts the following parameters:

* `ttl` The number of seconds before this cache item with expire. If left blank the default TTL (1 hour) will be used. Use `ttl="0"` to cache this item until the cache it broken. (Default: `""`)
* `tags` A pipe-separated list of tags to apply to this item. Tags can be used in the cache breaking settings. (Default: `""`)
* `url_override` Override the url used as part of the key for non-global items. (Default: `""`)
* `url_prefix` Add a prefix to the key. Useful for multi-lingual sites, e.g. `url_prefix="{publisher:current_language_code}"` (Default: `""`)
  * If using Publisher, and you are not displaying the default language segment in the URL, you may need a conditional similar to `url_prefix="{if publisher:current_language_id != publisher:default_language_id}{publisher:current_language_code}{/if}"`

{% hint style="info" %}
N**ote:** The `key` parameter is not valid in static caching because static cache files are keyed solely by the page URL.
{% endhint %}

### When using Publisher

If you're using the Publisher add-on with Speedy's static caching and need to view a draft on the front-end of your site you may need to include the following (or similar) to bypass the cached file and directly request a fresh page render from ExpressionEngine.

```apacheconf
RewriteCond %{QUERY_STRING} ^(.*?)publisher_status=.*$ [NC] 
RewriteRule ^/(.*) /index.php?q=$1 [L]
```

## Advanced Customization

If you want to customise the path to the static file directory, you can set the `speedy_static_path` option in your `config.php`. If you do this, you must update your `.htaccess` file.

If you are using the MSM module, or have a different site short name for whatever reason you must update your `.htaccess` file.

Replace `STATIC_PATH` and `SITE_NAME` in the following template:

Apache .htaccess rewrite rule:

```apacheconf
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/system [NC]
    RewriteCond %{QUERY_STRING} !ACT|URL [NC]
    RewriteCond %{REQUEST_METHOD} !=POST [NC]
    RewriteCond $1 !\.(css|js|gif|jpe?g|png) [NC]
    RewriteCond %{DOCUMENT_ROOT}/STATIC_PATH/SITE_NAME/static%{REQUEST_URI}/index\.php -f
    RewriteRule ^ /STATIC_PATH/SITE_NAME/static%{REQUEST_URI}/index\.php [L,QSA]
</IfModule>
```

If using Nginx:

```nginx
if ($request_method !~* GET) {
   set $request_var nonget;
}

if ($args ~* (ACT|URI)) {
    set $uri_var acturl;
}

if (-e  $document_root/STATIC_PATH/SITE_NAME/static/$request_uri$request_var$uri_var/index.php) {
	rewrite ^(.*) /STATIC_PATH/SITE_NAME/static/$request_uri/index.php last;
}
```

## Query String Caching

Query string caching will only work when using the static driver if the requested page is cached without the query string. For example, if the url `/products/shirt?size=small` is requested by the user and cached, it will not display the cached contents to any user until `/products/shirt` is also cached.

Note this is not the case when using the Redis cache driver with static enabled.

If the `speedy_query_cache_allowlist` config value is defined and contains an array of values, query string caching will be enabled. Speedy will only cache unique pages that contain query strings keys defined in `speedy_query_cache_allowlist`.

## Redis as Static driver

If you are using Redis with static caching, your .htaccess re-write rules will look a little different. The `index_redis_default_site.php` file will be auto-generated by Speedy during the setup process. If this file does not exist you will be prompted in Speedy's control panel page to generate the file.

```apacheconf
RewriteCond %{REQUEST_URI} !^/admin.php [NC]
RewriteCond %{QUERY_STRING} !ACT|URL [NC]
RewriteCond %{REQUEST_METHOD} !=POST [NC]
RewriteCond %{REQUEST_URI} !^/~ [NC]
RewriteCond $1 !\.(css|js|gif|jpe?g|png) [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/index_redis_default_site\.php -f
RewriteRule ^(.*)$ index_redis_default_site\.php?%{REQUEST_URI} [L,QSA]
```

## CSRF tokens

When static caching is enabled, the CSRF tokens in forms will be invalid. Each user gets a CSRF token, thus if every user gets the same cached page forms will not submit due to an invalid token. Speedy will update the CSRF token field in any form that is generated by ExpressionEngine. If you are building your own forms, make sure your `csrf_token` field matches the following format.

```html
<input type="hidden" name="csrf_token" value="[token value]">
```

A `csrf_token` field updated by Speedy will have the `data-updated` attribute added t it. If you do not see this attribute on the `csrf_token` fields in cached output, then Speedy was not able to update the value for the current user.

```html
<input type="hidden" name="csrf_token" value="[token value]" data-updated="true" />
```

## Debugging

You can put Speedy into debug mode, which will output some additional information as html comments in your cached output. To enable debugging, just add `?speedy_debug=1` to any page request. This currently only works with Static caching.
