Introduction

Once you have an SSL certificate configured, the next step is to redirect unencrypted traffic. There are several methods of doing this. Within your application (Laravel), by the web server (Apache or Nginx) or by the frontend (load balancer). This article will redirect HTTP requests to HTTPS in Laravel using middleware.

If you are also deploying a frontend load balancer, configure both HTTP and HTTPS frontends. In most cases, you will forward traffic from the load balancer to the backend (Laravel) via HTTP and not by HTTPS. This is called SSL Offloading. This means your Laravel middleware must detect the protocol (HTTP or HTTPS) that the client connected to the load balancer and ignore the protocol that the load balancer is using to connect to the backend. Otherwise, the middleware will detect HTTP even if the client connected to the load balancer using HTTPS, and the client will go into a redirect loop.

In this article, I will use yourdomain.com. Replace with your domain name.

Laravel middleware only supports files served by routes. Files that are not served by Laravel, such as /js/app.js will NOT be redirected. This is one of the reasons I like to have HTTP Redirection as several layers (load balancer, web server, application framework). Another reason is to ensure that more than one service layer enforces HTTP Redirection.

Configure .env

This article supports two environments, development and production. The development settings will not redirect HTTP to HTTPS. The production environment will redirect. The environment will be detected by the APP_ENV setting.

Production Configuration:

  • APP_ENV=production
  • APP_DEBUG=false
  • APP_URL=https://yourdomain.com

Development Configuration:

  • APP_ENV=local
  • APP_DEBUG=true
  • APP_URL=http://localhost:8000

The application environment labels local and production are used to enable/disable certain features in Laravel.

Initial Testing

Open a web browser and connect to your site via HTTP: http://yourdomain.com. Verify that your site loads correctly, and you are not redirected to HTTPS. Note: some TLD domains such as .dev automatically redirect in browsers. If this is the case for you, use the curl command method below.

Open a command prompt and run this command:

We are interested in the first part of the output which is the HTTP status code. If redirection is disabled, you should receive a 200 response:

For this article, we want a 200 response so that we can implement and test HTTP redirection.

If redirection is enabled, then you will receive a 3xx response with an HTTP Location header:

Before continuing, disable redirects in your web server or frontend (load balancer). Save your changes, so that you can reenable redirection at the frontend or at the web server.

Create the Middleware

Using artisan create the middleware template:

This creates the file app/Http/Middleware/HttpRedirect.php.

Near the top of the file add:

 

Modify the function handle(). Note the following features:

  • Check if the request is using HTTP: !$request->secure()
  • Check if the environment is production: App::environment('production')
  • If both requirements are met, redirect the client to the same URI using HTTPS. Otherwise, proceed to the next handler.

The above redirect will return the HTTP code 302. For permanent HTTP to HTTPS redirects, return HTTP code 301 (permanent redirect):

If you have development, staging and production environments and you want HTTP redirection for both staging and production:

Edit App/Http/Kernel.php and add the middleware to $middleware:

Clear the configuration:

Supporting Proxy Frontends

If you are using a load balancer that connects to your Laravel backend using HTTP, detect the HTTP header X-Forwarded-Proto. Use this code for the handle() function instead:

Warning

If your Laravel application does not have a proxy (load balancer) accepting traffic, do not add the proxy code. A smart hacker could manually add the header X-Forwarded-Proto and bypass the HTTP Redirect feature.

If you allow your Laravel backend to be accessed from a load balancer and directly from the Internet, add logic to only process the X-Forwarded-Proto header if the request arrives from a known frontend. Google Cloud HTTP(S) Load Balancers use the 130.211.0.0/22 and 35.191.0.0/16 IP address ranges.

Additional Options

The above middleware will redirect requests that are handled by Laravel routes. I also recommend that Laravel always generate content using HTTPS based URLs. Examples are JavaScript and CSS references.

Edit app/Providers/AppServiceProvider.php

Near the top add:

Add the following code to the boot function:

Summary

I prefer to implement multiple layers of security. When implementing HTTP Redirection, I try to implement this feature at each service layer. Starting with the backend (Laravel), then with the web server (Apache or Nginx), and finally at the load balancer. Sometimes mistakes are made, and one layer might disable HTTP Redirection. By enabling this feature in more than one service, I have a higher confidence level that clients’ data is and remains encrypted.