diff -u b/README.md b/README.md
--- b/README.md
+++ b/README.md
@@ -83,3 +83,12 @@
 
 $settings['flysystem'] = $schemes;
 ```
+
+## Private ACL
+If using a bucket with a private ACL, i.e. you have set 
+`$settings['flysystem']['s3']['config']['options']['ACL'] = 'private'` from above.
+You must then add the following to your settings.php file:
+```php
+$config['image.settings']['suppress_itok_output'] = TRUE;
+```
+As the itok parameter will interfere with the signature in the url.
\ No newline at end of file
diff -u b/src/Flysystem/S3.php b/src/Flysystem/S3.php
--- b/src/Flysystem/S3.php
+++ b/src/Flysystem/S3.php
@@ -8,7 +8,6 @@
 use Aws\S3\S3ClientInterface;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Logger\RfcLogLevel;
-use Drupal\Core\PageCache\ResponsePolicy\KillSwitch;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\Utility\Error;
@@ -91,11 +90,4 @@
 
   /**
-   * The kill switch response policy.
-   *
-   * @var \Drupal\Core\PageCache\ResponsePolicy\KillSwitch
-   */
-  protected $killSwitch;
-
-  /**
    * Whether the stream is set to public.
    *
@@ -114,10 +106,8 @@
    *   The Drupal renderer used to set cache expiration.
    * @param \Psr\Log\LoggerInterface $logger
    *   The system logger.
-   * @param \Drupal\Core\PageCache\ResponsePolicy\KillSwitch $kill_switch
-   *   (optional) Service to disable page caching when presigned URLs are used.
    */
-  public function __construct(S3ClientInterface $client, Config $config, RendererInterface $renderer, LoggerInterface $logger, KillSwitch $kill_switch = NULL) {
+  public function __construct(S3ClientInterface $client, Config $config, RendererInterface $renderer, LoggerInterface $logger) {
     $this->client = $client;
     $this->bucket = $config->get('bucket', '');
     $this->prefix = $config->get('prefix', '');
@@ -129,7 +119,6 @@
 
     $this->renderer = $renderer;
     $this->logger = $logger;
-    $this->killSwitch = $kill_switch;
   }
 
   /**
@@ -241,7 +230,7 @@
     $target = $this->getTarget($uri);
 
     if (strpos($target, 'styles/') === 0 && !$this->getAdapter()->has($target)) {
-      return $this->generateImageUrl($target);
+      $this->generateImageStyle($target);
     }
 
     // This method can only return FALSE if the wrapper does not exist, and not
@@ -258,27 +247,6 @@
         ]);
         $request = $this->client->createPresignedRequest($command, $this->expires);
 
-        // This informs the render system that the request has a cache
-        // dependency on the time this URL is valid for.
-        // TODO: The page cache does not currently respect max-age cache
-        // headers. We can't set proper max-age based on the signing time until
-        // https://www.drupal.org/node/2352009 is fixed. Unfortunately, this
-        // also means we can't cache any pages with signed URLs at all. When we
-        // can implement this, we should parse out max-age from the generated
-        // URL as suggested at https://github.com/aws/aws-sdk-php/issues/1052.
-        $build = [
-          '#cache' => [
-            'max-age' => 0,
-          ],
-        ];
-        $this->renderer->renderRoot($build);
-
-        // Since the above bug means this max-age isn't respected, we have to
-        // kill the general page cache.
-        if ($this->killSwitch) {
-          $this->killSwitch->trigger();
-        }
-
         return (string) $request->getUri();
       }
     }
only in patch2:
unchanged:
--- a/flysystem_s3.module
+++ b/flysystem_s3.module
@@ -5,6 +5,10 @@
  * Contains flysystem_s3.module.
  */
 
+use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\Site\Settings;
+use Drupal\Core\StreamWrapper\StreamWrapperManager;
+use Drupal\file\FileInterface;
 use Drupal\flysystem_s3\S3CorsManagedFileHelper;
 
 /**
@@ -13,3 +17,29 @@ use Drupal\flysystem_s3\S3CorsManagedFileHelper;
 function flysystem_s3_element_info_alter(array &$types) {
   S3CorsManagedFileHelper::alterInfo($types);
 }
+
+/**
+ * Implements hook_ENTITY_TYPE_load().
+ *
+ * Set a max-age for s3 urls that contain a time sensitive signature.
+ */
+function flysystem_s3_file_load(array $entities) {
+  foreach ($entities as $entity) {
+    assert($entity instanceof FileInterface);
+    $settings = Settings::get('flysystem');
+    $url = $entity->get('uri');
+    $scheme = StreamWrapperManager::getScheme($url->value);
+    if (isset($settings[$scheme]) && isset($settings[$scheme]['config']['expires'])) {
+      $entity->addCacheableDependency(
+        (new CacheableMetadata())->setCacheMaxAge((int)$settings[$scheme]['config']['expires'])
+      );
+    }
+    // TODO: The page cache does not currently respect max-age cache
+    // headers. We can't set proper max-age based on the signing time until
+    // https://www.drupal.org/node/2352009 is fixed. Unfortunately, this
+    // also means we can't cache any pages with signed URLs at all. When we
+    // can implement this, we should parse out max-age from the generated
+    // URL as suggested at https://github.com/aws/aws-sdk-php/issues/1052.
+    \Drupal::service('page_cache_kill_switch')->trigger();
+  }
+}
