Answers.Body: <p>As highlighted in Brad Bell's answer, those headers are likely set by PHP. By default PHP has the <code>session_cache_limiter()</code> method set to <code>nocache</code>. You can verify this in your Craft admin panel under <code>Utilities &gt; PHP Info &gt; session.cache_limiter</code>.</p>
  
  <p>If you change this value to <code>public</code>, it will set a cache expiry according to the value of <code>session.cache_expire</code> (set to <code>180</code> by default). This is explained <a href="https://www.php.net/manual/en/function.session-cache-limiter.php" rel="nofollow noreferrer">here</a> in the PHP docs.</p>
  
  <p>I did not heed Brandon Kelly's advice, and I set <code>session.cache_limiter=public</code> in my php.ini file. I do not know which unintended consequences he speaks of, but I like to live dangerously.</p>
  
  <p>Here are the new headers I get:</p>
  
  <pre><code>Cache-Control: public, max-age=10800
  Expires: Wed, 27 Nov 2019 11:54:38 GMT (180 minutes from now)
  </code></pre>
  
  <p>If you do this, it will break a few things in the admin. Admin pages won't always load properly because the wrong things will be cached. It works perfectly on the website though.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-11-27T08:51:50.437Z
Answers.LastActivityDate: 2020-02-13T15:01:35.623Z
Answers.LastEditDate: 2020-02-13T15:01:35.623Z
Answers.UserDisplayName: nicbou
Answers.Body: <p>This had me confused for a while: if you're using <a href="https://getnitro.sh/" rel="nofollow noreferrer">Craft Nitro</a>, the Nginx config adds <code>Cache-Control: no-store, no-cache ...</code> headers which cannot by overridden from PHP or Twig.</p>
  <p>In Nitro 1.x you could SSH into the machine and edit the Nginx config to not add the headers. I haven't been able to get Nitro 2.0 to work and have switched to Docker Compose which is simpler and doesn't have this caching problem.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-08T09:14:38.900Z
Answers.LastActivityDate: 2021-03-08T09:14:38.900Z
Answers.UserDisplayName: Tamlyn
Answers.Body: <p>Craft doesn't explicitly set <em>any</em> caching headers in the response, but you can control exactly how you want your caching headers to behave from your templates with the <a href="http://buildwithcraft.com/docs/templating/header" rel="noreferrer">{% header %}</a> tag.</p>
  
  <p>For example:</p>
  
  <pre><code>{# Tell the browser to cache this page for 30 days #}
  {% set expiry = now|date_modify('+30 days') %}
  
  {% header "Cache-Control: max-age=" ~ expiry.timestamp %}
  {% header "Pragma: cache" %}
  {% header "Expires: " ~ expiry|date('D, d M Y H:i:s', 'GMT') ~ " GMT" %}
  </code></pre>
  
  <p>By default PHP has the <a href="http://php.net/manual/en/function.session-cache-limiter.php" rel="noreferrer">session_cache_limiter()</a> method set to <code>nocache</code>, which is probably what you're seeing.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T01:45:45.460Z
Answers.Text: Hmmm...It seems like _something_ is (Yii or Craft) unless I'm confused.
  
  Request headers for a static (non-craft request):
  ```HTTP/1.1 200 OK
  Date: Thu, 18 Sep 2014 01:44:49 GMT
  Server: Apache
  Last-Modified: Thu, 18 Sep 2014 01:44:48 GMT
  Accept-Ranges: bytes
  Cache-Control: max-age=0
  Expires: Thu, 18 Sep 2014 01:44:49 GMT
  Vary: Accept-Encoding
  Content-Encoding: gzip
  X-UA-Compatible: IE=edge
  Content-Length: 26
  Keep-Alive: timeout=5, max=100
  Connection: Keep-Alive
  Content-Type: text/html; charset=utf-8```
  
  Here's one from Craft:
  ```
Answers.UserDisplayName: Tim Kelty
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T01:49:27.857Z
Answers.Text: Maybe Apache sets them by default if nothing has already been set?
Answers.UserDisplayName: Brad Bell
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T01:51:11.480Z
Answers.Text: Response header examples below (non-pertinent headers removed)
  
  Response headers for a static (non-Craft request):
  ```HTTP/1.1 200 OK
  Date: Thu, 18 Sep 2014 01:44:49 GMT
  Last-Modified: Thu, 18 Sep 2014 01:44:48 GMT
  Cache-Control: max-age=0
  Expires: Thu, 18 Sep 2014 01:44:49 GMT
  ```
  
  Here's one from Craft:
  ```HTTP/1.1 200 OK
  Max-Age=300; path=/
  Expires: Thu, 19 Nov 1981 08:52:00 GMT
  Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
  Pragma: no-cache
  ```
Answers.UserDisplayName: Tim Kelty
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T01:52:43.140Z
Answers.Text: The only related header I've seen Apache set by default is `Cache-Control: max-age=0`
Answers.UserDisplayName: Tim Kelty
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T01:55:08.953Z
Answers.Text: If you look at craft/app/services/TemplateService->renderTemplate(), you can see the headers Craft will set when rendering a template.
Answers.UserDisplayName: Brad Bell
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T01:55:33.410Z
Answers.Text: Maybe a php.ini thing?  Really strange.
Answers.UserDisplayName: Brad Bell
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T01:59:21.197Z
Answers.Text: http://php.net/manual/en/session.configuration.php#ini.session.cache-limiter
Answers.UserDisplayName: Brad Bell
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T04:59:22.660Z
Answers.Text: Weird. I tested it by just bailing out of the top of index.php with an `exit('Hello');` - no no-cache headers. Once I let Craft run though, I see them. Are you not seeing the Cache-Control/Pragma headers on your Craft installs?
Answers.UserDisplayName: Tim Kelty
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T04:59:44.540Z
Answers.Text: For the hell of it I checked the response headers on http://straightupcraft.com/ and I see the same thing.
Answers.UserDisplayName: Tim Kelty
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T05:02:59.247Z
Answers.Text: Right... because session_cache_limiter() kicks in as soon as PHP's session_start() gets called, which won't have happened at the top of the root index.php. Craft/Yii will call that as soon as HttpSessionService->init() gets invoked in a request.
Answers.UserDisplayName: Brad Bell
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T05:12:56.457Z
Answers.Text: You're right :). Same result with this in index.php:
  ```<?php
  session_start();
  exit('Sorry, Brad.);
  ```
Answers.UserDisplayName: Tim Kelty
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T05:14:31.443Z
Answers.Text: So I suppose the moral of the story is... if you don't like the default behavior, you can change it in your php.ini file. :)
Answers.UserDisplayName: Brad Bell
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T05:17:41.577Z
Answers.Text: Yep! Sorry for wasting your time.
  
  The whole reason this came up is I was playing around with Varnish w/ Craft and by default it bypasses when it gets a `Cache-control: no-cache` response.
Answers.UserDisplayName: Tim Kelty
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T05:19:34.087Z
Answers.Text: Not a waste at all. We both learned something!
Answers.UserDisplayName: Brad Bell
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T13:50:06.677Z
Answers.Text: @TimKelty I would definitely recommend **not** changing this from php.ini as it will have unintended consequences. If you don’t like PHP’s default behavior you should just start explicitly setting what you want using the [{% header %}](http://buildwithcraft.com/docs/templating/header) tag.
Answers.UserDisplayName: Brandon Kelly
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-18T18:05:51.797Z
Answers.Text: Pfft... LIVE ON THE EDGE!
Answers.UserDisplayName: Brad Bell
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-17T21:09:24.087Z
Answers.LastActivityDate: 2014-09-18T02:04:51.450Z
Answers.LastEditDate: 2014-09-18T02:04:51.450Z
Answers.UserDisplayName: Brad Bell
Body: <p>Craft seems to be setting headers to tell the browser not to cache anything it serves, which seems bad.</p>
  
  <p><code>Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0</code></p>
  
  <p>Why it do dat?</p>
  
Tags: <cache>
Title: Why does Craft set no-cache headers for all requests?
ThreadText: # Why does Craft set no-cache headers for all requests?
  
  (Asked by: username_0 on 2014-09-17)
  
  Craft seems to be setting headers to tell the browser not to cache anything it serves, which seems bad.
  
  `Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0`
  
  Why it do dat?
  
  **Tags:** cache
  
  
  ---
  
  ## 3 answers
  
  ### Answer by username_3 on 2014-09-17. Score: 10 | Accepted answer
  
  Craft doesn't explicitly set *any* caching headers in the response, but you can control exactly how you want your caching headers to behave from your templates with the [{% header %}](http://buildwithcraft.com/docs/templating/header) tag.
  
  For example:
  
  ```
  {# Tell the browser to cache this page for 30 days #}
  {% set expiry = now|date_modify('+30 days') %}
  
  {% header "Cache-Control: max-age=" ~ expiry.timestamp %}
  {% header "Pragma: cache" %}
  {% header "Expires: " ~ expiry|date('D, d M Y H:i:s', 'GMT') ~ " GMT" %}
  
  ```
  
  By default PHP has the [session\_cache\_limiter()](http://php.net/manual/en/function.session-cache-limiter.php) method set to `nocache`, which is probably what you're seeing.
  
  > **Comments:**
  > **username_0**: Hmmm...It seems like _something_ is (Yii or Craft) unless I'm confused.  Request headers for a static (non-craft request): ```HTTP/1.1 200 OK Date: Thu, 18 Sep 2014 01:44:49 GMT Server: Apache Last-Modified: Thu, 18 Sep 2014 01:44:48 GMT Accept-Ranges: bytes Cache-Control: max-age=0 Expires: Thu, 18 Sep 2014 01:44:49 GMT Vary: Accept-Encoding Content-Encoding: gzip X-UA-Compatible: IE=edge Content-Length: 26 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html; charset=utf-8```  Here's one from Craft: ```  
  > **username_3**: Maybe Apache sets them by default if nothing has already been set?  
  > **username_0**: Response header examples below (non-pertinent headers removed)  Response headers for a static (non-Craft request): ```HTTP/1.1 200 OK Date: Thu, 18 Sep 2014 01:44:49 GMT Last-Modified: Thu, 18 Sep 2014 01:44:48 GMT Cache-Control: max-age=0 Expires: Thu, 18 Sep 2014 01:44:49 GMT ```  Here's one from Craft: ```HTTP/1.1 200 OK Max-Age=300; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache ```  
  > **username_0**: The only related header I've seen Apache set by default is `Cache-Control: max-age=0`  
  > **username_3**: If you look at craft/app/services/TemplateService->renderTemplate(), you can see the headers Craft will set when rendering a template.  
  > **username_3**: Maybe a php.ini thing?  Really strange.  
  > **username_3**: http://php.net/manual/en/session.configuration.php#ini.session.cache-limiter  
  > **username_0**: Weird. I tested it by just bailing out of the top of index.php with an `exit('Hello');` - no no-cache headers. Once I let Craft run though, I see them. Are you not seeing the Cache-Control/Pragma headers on your Craft installs?  
  > **username_0**: For the hell of it I checked the response headers on http://straightupcraft.com/ and I see the same thing.  
  > **username_3**: Right... because session_cache_limiter() kicks in as soon as PHP's session_start() gets called, which won't have happened at the top of the root index.php. Craft/Yii will call that as soon as HttpSessionService->init() gets invoked in a request.  
  > **username_0**: You're right :). Same result with this in index.php: ```<?php session_start(); exit('Sorry, username_3.); ```  
  > **username_3**: So I suppose the moral of the story is... if you don't like the default behavior, you can change it in your php.ini file. :)  
  > **username_0**: Yep! Sorry for wasting your time.  The whole reason this came up is I was playing around with Varnish w/ Craft and by default it bypasses when it gets a `Cache-control: no-cache` response.  
  > **username_3**: Not a waste at all. We both learned something!  
  > **username_4**: @username_0 I would definitely recommend **not** changing this from php.ini as it will have unintended consequences. If you don’t like PHP’s default behavior you should just start explicitly setting what you want using the [{% header %}](http://buildwithcraft.com/docs/templating/header) tag.  
  > **username_3**: Pfft... LIVE ON THE EDGE!  
  
  ---
  
  ### Answer by username_1 on 2019-11-27. Score: 2
  
  As highlighted in username_3 username_3's answer, those headers are likely set by PHP. By default PHP has the `session_cache_limiter()` method set to `nocache`. You can verify this in your Craft admin panel under `Utilities > PHP Info > session.cache_limiter`.
  
  If you change this value to `public`, it will set a cache expiry according to the value of `session.cache_expire` (set to `180` by default). This is explained [here](https://www.php.net/manual/en/function.session-cache-limiter.php) in the PHP docs.
  
  I did not heed username_4's advice, and I set `session.cache_limiter=public` in my php.ini file. I do not know which unintended consequences he speaks of, but I like to live dangerously.
  
  Here are the new headers I get:
  
  ```
  Cache-Control: public, max-age=10800
  Expires: Wed, 27 Nov 2019 11:54:38 GMT (180 minutes from now)
  
  ```
  
  If you do this, it will break a few things in the admin. Admin pages won't always load properly because the wrong things will be cached. It works perfectly on the website though.
  
  
  ---
  
  ### Answer by username_2 on 2021-03-08. Score: 0
  
  This had me confused for a while: if you're using [Craft Nitro](https://getnitro.sh/), the Nginx config adds `Cache-Control: no-store, no-cache ...` headers which cannot by overridden from PHP or Twig.
  
  In Nitro 1.x you could SSH into the machine and edit the Nginx config to not add the headers. I haven't been able to get Nitro 2.0 to work and have switched to Docker Compose which is simpler and doesn't have this caching problem.
  
  
  ---
  
  