diff --git a/config/stage_file_proxy.settings.yml b/config/stage_file_proxy.settings.yml
new file mode 100644
index 0000000..50d0ead
--- /dev/null
+++ b/config/stage_file_proxy.settings.yml
@@ -0,0 +1,4 @@
+hotlink: false
+origin: false
+origin_dir: false
+use_imagecache_root: true
\ No newline at end of file
diff --git a/lib/Drupal/stage_file_proxy/EventSubscriber/ProxySubscriber.php b/lib/Drupal/stage_file_proxy/EventSubscriber/ProxySubscriber.php
new file mode 100644
index 0000000..a0687c9
--- /dev/null
+++ b/lib/Drupal/stage_file_proxy/EventSubscriber/ProxySubscriber.php
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\stage_file_proxy\EventSubscriber\ProxySubscriber.
+ */
+
+namespace Drupal\stage_file_proxy\EventSubscriber;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+
+use Drupal\stage_file_proxy\FetchManagerInterface;
+use Drupal\Component\Utility\String;
+use \Drupal\Component\Utility\Url;
+
+/**
+ * Stage file proxy subscriber for controller requests.
+ */
+class ProxySubscriber implements EventSubscriberInterface {
+
+  /**
+   * The manager used to fetch the file against.
+   *
+   * @var \Drupal\stage_file_proxy\FetchManager
+   */
+  protected $manager;
+
+  /**
+   * Construct the FetchManager.
+   *
+   * @param \Drupal\stage_file_proxy\FetchManager $manager
+   *   The manager used to fetch the file against.
+   */
+  public function __construct(FetchManagerInterface $manager) {
+    $this->manager = $manager;
+  }
+
+  /**
+   * Fetch the file according the its origin.
+   *
+   * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
+   *   The Event to process.
+   */
+  public function checkFileOrigin(GetResponseEvent $event) {
+    $file_dir = $this->manager->filePublicPath();
+    if (strpos(request_path(), $file_dir) !== 0) {
+      return;
+    }
+
+    // Note if the origin server files location is different. This
+    // must be the exact path for the remote site's public file
+    // system path, and defaults to the local public file system path.
+    $remote_file_dir = trim(\Drupal::config('stage_file_proxy.settings')->get('origin_dir'));
+    if (!$remote_file_dir) {
+      $remote_file_dir = $file_dir;
+    }
+
+    $relative_path = drupal_substr(request_path(), drupal_strlen($file_dir) + 1);
+
+    // Get the origin server.
+    $server = \Drupal::config('stage_file_proxy.settings')->get('origin');
+
+    if ($server) {
+      // Is this imagecache? Request the root file and let imagecache resize.
+      if (\Drupal::config('stage_file_proxy.settings')->get('origin') && $original_path = $this->manager->styleOriginalPath($relative_path, TRUE)) {
+        $relative_path = file_uri_target($original_path);
+        if (file_exists($original_path)) {
+          // Imagecache can generate it without our help.
+          return;
+        }
+      }
+
+      $query = \Drupal::request()->query->all();
+      $query_parameters = Url::filterQueryParameters($query);
+
+      if (\Drupal::config('stage_file_proxy.settings')->get('hotlink')) {
+        $location = url("$server/$remote_file_dir/$relative_path", array(
+          'query' => $query_parameters,
+          'absolute' => TRUE,
+        ));
+        header("Location: $location");
+        exit;
+      }
+      elseif ($this->manager->fetch($server, $remote_file_dir, $relative_path)) {
+        // Refresh this request & let the web server work out mime type, etc.
+        $location = url(request_path(), array('query' => $query_parameters));
+        header("Location: $location");
+        exit;
+      }
+      else {
+        watchdog('stage_file_proxy', 'Stage File Proxy encountered an unknown error by retrieving file @file', array('@file' => $server . '/' . drupal_encode_path($remote_file_dir . '/' . $relative_path)), WATCHDOG_ERROR);
+        throw new NotFoundHttpException();
+        exit;
+      }
+    }
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('checkFileOrigin');
+    return $events;
+  }
+
+}
diff --git a/lib/Drupal/stage_file_proxy/FetchManager.php b/lib/Drupal/stage_file_proxy/FetchManager.php
new file mode 100644
index 0000000..bad0f4f
--- /dev/null
+++ b/lib/Drupal/stage_file_proxy/FetchManager.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\stage_file_proxy\FetchManager.
+ */
+
+namespace Drupal\stage_file_proxy;
+
+use Drupal\Component\Utility\Url;
+use Guzzle\Http\ClientInterface;
+
+class FetchManager implements FetchManagerInterface {
+
+  public function __construct(ClientInterface $client) {
+    $this->client = $client;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fetch($server, $remote_file_dir, $relative_path) {
+    // Fetch remote file.
+    $url = $server . '/' . Url::encodePath($remote_file_dir . '/' . $relative_path);
+    $response = $this->client
+      ->get($url)
+      ->send();
+
+    if ($response->getStatusCode() == 200) {
+      // Prepare local target directory and save downloaded file.
+      $file_dir = $this->filePublicPath();
+      $target_dir = $file_dir . '/' . dirname($relative_path);
+      if (file_prepare_directory($target_dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
+        file_put_contents($file_dir . '/' . $relative_path, $response->getBody(TRUE));
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function filePublicPath() {
+    return settings()->get('file_public_path', conf_path() . '/files');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function styleOriginalPath($uri, $style_only = TRUE) {
+    $scheme = file_uri_scheme($uri);
+    if ($scheme) {
+      $path = file_uri_target($uri);
+    }
+    else {
+      $path = $uri;
+      $scheme = file_default_scheme();
+    }
+
+    // It is a styles path, so we extract the different parts.
+    if (strpos($path, 'styles') === 0) {
+      // Then the path is like styles/[style_name]/[schema]/[original_path].
+      return preg_replace('/styles\/.*\/(.*)\/(.*)/U', '$1://$2', $path);
+    }
+    // Else it seems to be the original.
+    elseif ($style_only == FALSE) {
+      return "$scheme://$path";
+    }
+    else {
+      return FALSE;
+    }
+  }
+}
diff --git a/lib/Drupal/stage_file_proxy/FetchManagerInterface.php b/lib/Drupal/stage_file_proxy/FetchManagerInterface.php
new file mode 100644
index 0000000..aeb9e2e
--- /dev/null
+++ b/lib/Drupal/stage_file_proxy/FetchManagerInterface.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\stage_file_proxy\FetchManagerInterface.
+ */
+
+namespace Drupal\stage_file_proxy;
+
+use Guzzle\Http\ClientInterface;
+
+interface FetchManagerInterface {
+
+  public function __construct(ClientInterface $client);
+
+  /**
+   * Downloads a remote file and saves it to the local files directory.
+   *
+   * @param string $server
+   *   The origin server URL.
+   * @param string $remote_file_dir
+   *   The relative path to the files directory on the origin server.
+   * @param string $relative_path
+   *   The path to the requested resource relative to the files directory.
+   *
+   * @return bool
+   *   Returns true if the content was downloaded, otherwise false.
+   */
+  public function fetch($server, $remote_file_dir, $relative_path);
+
+  /**
+   * Helper to retrieve the file directory.
+   */
+  public function filePublicPath();
+
+  /**
+   * Helper to retrieves original path for a styled image.
+   *
+   * @param string $uri
+   *   A uri or path (may be prefixed with scheme)
+   * @param bool $style_only
+   *   Indicates if, the function should only return paths retrieved from style
+   *   paths. Defaults to TRUE.
+   *
+   * @return bool|mixed|string
+   *   A file URI pointing to the given original image.
+   *   If $style_only is set to TRUE and $uri is no style-path, FALSE is returned.
+   */
+  public function styleOriginalPath($uri, $style_only = TRUE);
+}
diff --git a/stage_file_proxy.info b/stage_file_proxy.info
deleted file mode 100644
index eb5ce42..0000000
--- a/stage_file_proxy.info
+++ /dev/null
@@ -1,4 +0,0 @@
-name = Stage File Proxy
-description = Proxies files from production server so you don't have to transfer them manually
-core = 7.x
-version=7.x-0.1-dev
diff --git a/stage_file_proxy.info.yml b/stage_file_proxy.info.yml
new file mode 100644
index 0000000..9f29aa1
--- /dev/null
+++ b/stage_file_proxy.info.yml
@@ -0,0 +1,6 @@
+name: Stage File Proxy
+type: module
+description: 'Proxies files from production server so you do not have to transfer them manually'
+package: Development
+version: VERSION
+core: 8.x
diff --git a/stage_file_proxy.module b/stage_file_proxy.module
index 0dbf925..a7e5e5e 100644
--- a/stage_file_proxy.module
+++ b/stage_file_proxy.module
@@ -4,133 +4,3 @@
  * @file
  * Stage File Proxy Module.
  */
-
-/**
- * Implements hook_init().
- *
- * Intercepts some requests and hotlinks/downloads the remote version.
- */
-function stage_file_proxy_init() {
-  // Make sure we're requesting a file in the files dir.
-  // Currently this only works for PUBLIC files.
-  $file_dir = _stage_file_proxy_file_dir();
-  if (strpos($_GET['q'], $file_dir) !== 0) {
-    return;
-  }
-
-  // Note if the origin server files location is different. This
-  // must be the exact path for the remote site's public file
-  // system path, and defaults to the local public file system path.
-  $remote_file_dir = trim(variable_get('stage_file_proxy_origin_dir', $file_dir), '/');
-
-  $relative_path = drupal_substr($_GET['q'], drupal_strlen($file_dir) + 1);
-
-  // Get the origin server.
-  $server = variable_get('stage_file_proxy_origin', NULL);
-
-  if ($server) {
-    // Is this imagecache? Request the root file and let imagecache resize.
-    if (variable_get('stage_file_proxy_use_imagecache_root', TRUE) && $original_path = _stage_file_proxy_image_style_path_original($relative_path, TRUE)) {
-      $relative_path = file_uri_target($original_path);
-      if (file_exists($original_path)) {
-        // Imagecache can generate it without our help.
-        return;
-      }
-    }
-
-    $query_parameters = drupal_get_query_parameters();
-
-    if (variable_get('stage_file_proxy_hotlink', FALSE)) {
-      $location = url("$server/$remote_file_dir/$relative_path", array(
-        'query' => $query_parameters,
-        'absolute' => TRUE,
-      ));
-      header("Location: $location");
-      exit;
-    }
-    elseif (_stage_file_proxy_fetch($server, $remote_file_dir, $relative_path)) {
-      // Refresh this request & let the web server work out mime type, etc.
-      $location = url("{$_GET['q']}", array('query' => $query_parameters));
-      header("Location: $location");
-      exit;
-    }
-    else {
-      watchdog('stage_file_proxy', 'Stage File Proxy encountered an unknown error by retrieving file @file', array('@file' => $server . '/' . drupal_encode_path($remote_file_dir . '/' . $relative_path)), WATCHDOG_ERROR);
-      drupal_not_found();
-      exit;
-    }
-  }
-}
-
-/**
- * Downloads a remote file and saves it to the local files directory.
- *
- * @param string $server
- *   The origin server URL.
- * @param string $remote_file_dir
- *   The relative path to the files directory on the origin server.
- * @param string $relative_path
- *   The path to the requested resource relative to the files directory.
- *
- * @return bool
- *   Returns true if the content was downloaded, otherwise false.
- */
-function _stage_file_proxy_fetch($server, $remote_file_dir, $relative_path) {
-  // Fetch remote file.
-  $url = $server . '/' . drupal_encode_path($remote_file_dir . '/' . $relative_path);
-  $response = drupal_http_request($url);
-  if ($response->code == 200) {
-    // Prepare local target directory and save downloaded file.
-    $file_dir = _stage_file_proxy_file_dir();
-    $target_dir = $file_dir . '/' . dirname($relative_path);
-    if (file_prepare_directory($target_dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
-      file_put_contents($file_dir . '/' . $relative_path, $response->data);
-      return TRUE;
-    }
-  }
-  return FALSE;
-}
-
-/**
- * Helper to retrieve the file directory.
- */
-function _stage_file_proxy_file_dir() {
-  return variable_get('file_public_path', conf_path() . '/files');
-}
-
-/**
- * Helper to retrieves original path for a styled image.
- *
- * @param string $uri
- *   A uri or path (may be prefixed with scheme)
- * @param bool $style_only
- *   Indicates if, the function should only return paths retrieved from style
- *   paths. Defaults to TRUE.
- *
- * @return bool|mixed|string
- *   A file URI pointing to the given original image.
- *   If $style_only is set to TRUE and $uri is no style-path, FALSE is returned.
- */
-function _stage_file_proxy_image_style_path_original($uri, $style_only = TRUE) {
-  $scheme = file_uri_scheme($uri);
-  if ($scheme) {
-    $path = file_uri_target($uri);
-  }
-  else {
-    $path = $uri;
-    $scheme = file_default_scheme();
-  }
-
-  // It is a styles path, so we extract the different parts.
-  if (strpos($path, 'styles') === 0) {
-    // Then the path is like styles/[style_name]/[schema]/[original_path].
-    return preg_replace('/styles\/.*\/(.*)\/(.*)/U', '$1://$2', $path);
-  }
-  // Else it seems to be the original.
-  elseif ($style_only == FALSE) {
-    return "$scheme://$path";
-  }
-  else {
-    return FALSE;
-  }
-}
diff --git a/stage_file_proxy.services.yml b/stage_file_proxy.services.yml
new file mode 100644
index 0000000..249addc
--- /dev/null
+++ b/stage_file_proxy.services.yml
@@ -0,0 +1,10 @@
+services:
+  stage_file_proxy.fetch_manager:
+    class: Drupal\stage_file_proxy\FetchManager
+    arguments: ['@http_default_client']
+
+  stage_file_proxy.subscriber:
+    class: Drupal\stage_file_proxy\EventSubscriber\ProxySubscriber
+    tags:
+      - { name: event_subscriber }
+    arguments: ['@stage_file_proxy.fetch_manager']
