diff --git a/core/core.services.yml b/core/core.services.yml
index e39252d..560036d 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -16,6 +16,7 @@ parameters:
       tags: []
   factory.keyvalue:
     default: keyvalue.database
+  http.cacheability_headers.send: false
   factory.keyvalue.expirable:
     default: keyvalue.expirable.database
   filter_protocols:
@@ -638,7 +639,7 @@ services:
       - { name: http_middleware, priority: 400 }
   http_middleware.reverse_proxy:
     class: Drupal\Core\StackMiddleware\ReverseProxyMiddleware
-    arguments: ['@settings']
+    arguments: ['@settings', '%http.cacheability_headers.send%']
     tags:
       - { name: http_middleware, priority: 300 }
   http_middleware.kernel_pre_handle:
diff --git a/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php b/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php
index c6b49ab..4291a5b 100644
--- a/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php
+++ b/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php
@@ -30,16 +30,26 @@ class ReverseProxyMiddleware implements HttpKernelInterface {
   protected $settings;
 
   /**
+   * Whether to send cacheability headers.
+   *
+   * @var bool
+   */
+  protected $httpCacheabilityHeadersSend = FALSE;
+
+  /**
    * Constructs a ReverseProxyMiddleware object.
    *
    * @param \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel
    *   The decorated kernel.
    * @param \Drupal\Core\Site\Settings $settings
    *   The site settings.
+   * @param bool $http_cacheability_headers_send
+   *   (optional) Whether to send cacheability headers.
    */
-  public function __construct(HttpKernelInterface $http_kernel, Settings $settings) {
+  public function __construct(HttpKernelInterface $http_kernel, Settings $settings, $http_cacheability_headers_send = FALSE) {
     $this->httpKernel = $http_kernel;
     $this->settings = $settings;
+    $this->httpCacheabilityHeadersSend = $http_cacheability_headers_send;
   }
 
   /**
@@ -55,7 +65,18 @@ public function handle(Request $request, $type = self::MASTER_REQUEST, $catch =
         $request::setTrustedProxies($proxies);
       }
     }
-    return $this->httpKernel->handle($request, $type, $catch);
+
+    $response = $this->httpKernel->handle($request, $type, $catch);
+
+    // Strip X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags header
+    // respectively, when either a reverse proxy is being used (so the reverse
+    // proxy or CDN can be invalidated when appropriate) or when
+    // developing/debugging.
+    if (!($this->settings->get('reverse_proxy', FALSE) || $this->httpCacheabilityHeadersSend)) {
+      $response->headers->remove('X-Drupal-Cache-Tags');
+      $response->headers->remove('X-Drupal-Cache-Contexts');
+    }
+    return $response;
   }
 
 }
diff --git a/core/modules/page_cache/src/Tests/PageCacheTest.php b/core/modules/page_cache/src/Tests/PageCacheTest.php
index a2278e7..3e89ffe 100644
--- a/core/modules/page_cache/src/Tests/PageCacheTest.php
+++ b/core/modules/page_cache/src/Tests/PageCacheTest.php
@@ -50,6 +50,10 @@ protected function setUp() {
    * persisted.
    */
   function testPageCacheTags() {
+    // Ensure that the sending out of the cache tags / contexts is independent
+    // from the page cache.
+    $this->setCacheabilityHeaders(FALSE);
+
     $config = $this->config('system.performance');
     $config->set('cache.page.max_age', 300);
     $config->save();
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index 5b62c50..705e287 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -812,6 +812,8 @@ protected function initSettings() {
     // TestBase::restoreEnvironment() will delete the entire site directory.
     // Not using File API; a potential error must trigger a PHP warning.
     chmod(DRUPAL_ROOT . '/' . $this->siteDirectory, 0777);
+
+    $this->setCacheabilityHeaders();
   }
 
   /**
@@ -3019,4 +3021,14 @@ protected function assertNoCacheTag($cache_tag) {
     $this->assertFalse(in_array($cache_tag, $cache_tags), "'" . $cache_tag . "' is absent in the X-Drupal-Cache-Tags header.");
   }
 
+  /**
+   * Enables/disables the cacheability headers.
+   *
+   * @param bool $value
+   *   (optional) Should the cache headers be send.
+   */
+  protected function setCacheabilityHeaders($value = TRUE) {
+    $this->setContainerParameter('http.cacheability_headers.send', $value);
+  }
+
 }
diff --git a/core/tests/Drupal/Tests/Core/StackMiddleware/ReverseProxyMiddlewareTest.php b/core/tests/Drupal/Tests/Core/StackMiddleware/ReverseProxyMiddlewareTest.php
index f92109b..e65feb7 100644
--- a/core/tests/Drupal/Tests/Core/StackMiddleware/ReverseProxyMiddlewareTest.php
+++ b/core/tests/Drupal/Tests/Core/StackMiddleware/ReverseProxyMiddlewareTest.php
@@ -11,10 +11,13 @@
 use Drupal\Core\StackMiddleware\ReverseProxyMiddleware;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
 
 /**
  * Unit test the reverse proxy stack middleware.
  *
+ * @coversDefaultClass \Drupal\Core\StackMiddleware\ReverseProxyMiddleware
+ *
  * @group StackMiddleware
  */
 class ReverseProxyMiddlewareTest extends UnitTestCase {
@@ -44,8 +47,59 @@ public function testNoProxy() {
     // setTrustedHeaderName() should never fire.
     $request->expects($this->never())
       ->method('setTrustedHeaderName');
+
+    $response = new Response();
+    $this->mockHttpKernel->expects($this->any())
+      ->method('handle')
+      ->willReturn($response);
+
     // Actually call the check method.
-    $middleware->handle($request);
+    $result = $middleware->handle($request);
+    $this->assertEquals($response, $result);
+  }
+
+  /**
+   * @covers ::handle
+   */
+  public function testCacheabilityHeadersEnabled() {
+    $middleware = new ReverseProxyMiddleware($this->mockHttpKernel, new Settings([]), TRUE);
+
+    $request = new Request();
+
+    $response = new Response();
+    $response->headers->set('X-Drupal-Cache-Tags', 'node:123 node_list');
+    $response->headers->set('X-Drupal-Cache-Contexts', 'languages:language_interface route');
+
+    $this->mockHttpKernel->expects($this->any())
+      ->method('handle')
+      ->willReturn($response);
+
+    $result = $middleware->handle($request);
+    $this->assertEquals('node:123 node_list', $result->headers->get('X-Drupal-Cache-Tags'));
+    $this->assertEquals('languages:language_interface route', $result->headers->get('X-Drupal-Cache-Contexts'));
+  }
+
+  /**
+   * @covers ::handle
+   */
+  public function testCacheabilityHeadersDisabled() {
+    $settings = new Settings([]);
+
+    $middleware = new ReverseProxyMiddleware($this->mockHttpKernel, $settings, FALSE);
+
+    $request = new Request();
+
+    $response = new Response();
+    $response->headers->set('X-Drupal-Cache-Tags', 'node:123 node_list');
+    $response->headers->set('X-Drupal-Cache-Contexts', 'languages:language_interface route');
+
+    $this->mockHttpKernel->expects($this->any())
+      ->method('handle')
+      ->willReturn($response);
+
+    $result = $middleware->handle($request);
+    $this->assertFalse($result->headers->has('X-Drupal-Cache-Tags'));
+    $this->assertFalse($result->headers->has('X-Drupal-Cache-Contexts'));
   }
 
   /**
diff --git a/sites/default/default.services.yml b/sites/default/default.services.yml
index 4ab0662..048aceb 100644
--- a/sites/default/default.services.yml
+++ b/sites/default/default.services.yml
@@ -142,3 +142,7 @@ parameters:
     - sftp
     - webcal
     - rtsp
+
+  # Send cacheablity headers for debugging purposes.
+  # By default, cacheability headers are only sent when behind a reverse proxy.
+  # http.cacheability_headers.send: false
