DEV Community

Allan
Allan

Posted on

2

Cheat Sheet: Enabling HTTPS on a Fresh Laravel Sail App with MacOS

When developing Laravel applications locally using Sail and Docker, you might need to enable HTTPS to integrate with third-party services like Google, Dropbox, or other OAuth2 providers. These services often require secure HTTPS callbacks for authentication and API interactions. Enabling HTTPS in your local development environment ensures you can test these integrations effectively and securely.

This guide will show you how to set up HTTPS in your Laravel Sail environment by configuring Nginx as a reverse proxy and forcing HTTPS within your application.

Table of Contents

  1. Create a Fresh Laravel Sail Application
  2. Update the .env File
  3. Add Custom Domain to /etc/hosts
  4. Configure Docker for HTTPS
  5. Create an Nginx Configuration
  6. Modify AppServiceProvider to Force HTTPS
  7. Rebuild and Restart Sail
  8. Clear Laravel Cache
  9. Test HTTPS Setup
  10. Done!

1. Create a Fresh Laravel Sail Application

curl -s "https://laravel.build/my-app" | bash
cd my-app
./vendor/bin/sail up
Enter fullscreen mode Exit fullscreen mode

This creates a fresh Laravel app with Sail and brings up the Docker containers.

2. Update the .env File

Edit your .env file to set the APP_URL to your custom domain with https://:

APP_URL=https://my-app.test
Enter fullscreen mode Exit fullscreen mode

This ensures Laravel generates URLs using HTTPS instead of HTTP.

3. Add Custom Domain to /etc/hosts

Map your custom domain to 127.0.0.1 in /etc/hosts:

sudo nano /etc/hosts
Enter fullscreen mode Exit fullscreen mode

Add the following line:

127.0.0.1 my-app.test
Enter fullscreen mode Exit fullscreen mode

This allows your machine to resolve my-app.test to localhost.

4. Configure Docker for HTTPS

Edit the docker-compose.yml file to expose both 80 (HTTP) and 443 (HTTPS) ports for Nginx:

services:
  laravel.test:
    ports:
      - '80:80'
      - '443:443'  # HTTPS port

  nginx:
    image: nginx:alpine
    ports:
      - '80:80'
      - '443:443'  # Expose HTTPS port for Nginx
    volumes:
      - .:/var/www/html
      - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf  # Nginx configuration
      - ./docker/nginx/ssl:/etc/nginx/ssl  # SSL certificate
    networks:
      - sail
Enter fullscreen mode Exit fullscreen mode

This config ensures that both the Laravel application and Nginx are set up to handle HTTP and HTTPS traffic. Exposing port 443 allows Nginx to listen for HTTPS requests which it will then proxy to your Laravel application.

5. Create an Nginx Configuration

In this step we'll set up Nginx as a reverse proxy to handle the HTTPS requests and forward them to our Laravel application running in Docker. We'll generate a self-signed SSL certificate for local development purposes.

Create a directory for Nginx configuration:

mkdir -p docker/nginx/ssl
Enter fullscreen mode Exit fullscreen mode

Generate a self-signed SSL certificate:

openssl req -newkey rsa:2048 -nodes -keyout docker/nginx/ssl/my-app.key -x509 -days 365 -out docker/nginx/ssl/my-app.crt
Enter fullscreen mode Exit fullscreen mode

This creates a self-signed SSL certificate for local HTTPS support.

Create a new Nginx config file in docker/nginx/nginx.conf:

user nginx;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
worker_connections 1024;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

    server {
        listen 80;
        listen 443 ssl;
        server_name my-app.test;

        ssl_certificate /etc/nginx/ssl/my-app.crt;
        ssl_certificate_key /etc/nginx/ssl/my-app.key;

        root /var/www/html/public;
        index index.php index.html;

        location / {
            proxy_pass http://laravel.test:80;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }

    sendfile on;
    keepalive_timeout 65;
}
Enter fullscreen mode Exit fullscreen mode

This config sets up Nginx as a reverse proxy, forwarding HTTPS requests to Laravel’s built-in web server that's provided by the laravel.test Docker container.

6. Modify AppServiceProvider to Force HTTPS

Edit app/Providers/AppServiceProvider.php and add URL::forceScheme('https'):

use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        URL::forceScheme('https');  // Force HTTPS in development
    }
}
Enter fullscreen mode Exit fullscreen mode

This ensures that Laravel generates all URLs with HTTPS.

7. Rebuild and Restart Sail

Rebuild the Docker containers to apply your changes:

sail down
sail build --no-cache
sail up -d
Enter fullscreen mode Exit fullscreen mode

8. Clear Laravel Cache

After making changes to Laravel, clear the cache:

sail php artisan config:clear
sail php artisan route:clear
sail php artisan cache:clear
Enter fullscreen mode Exit fullscreen mode

9. Test HTTPS Setup

Run the following command to test the HTTPS connection:

curl -v https://my-app.test --insecure
Enter fullscreen mode Exit fullscreen mode

A successful result should show:

  • Connected to port 443:
  * Connected to my-app.test (127.0.0.1) port 443
Enter fullscreen mode Exit fullscreen mode
  • Successful SSL handshake:
  * SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
Enter fullscreen mode Exit fullscreen mode
  • HTTP 200 OK or 302 Redirect:
  < HTTP/1.1 200 OK
Enter fullscreen mode Exit fullscreen mode

or

  < HTTP/1.1 302 Found
  < Location: https://my-app.test/login
Enter fullscreen mode Exit fullscreen mode

These indicate that HTTPS is working and Laravel is correctly generating secure URLs.

10. Done!

Congratulations 🎉 You've successfully configured HTTPS for your Laravel Sail app! You can now visit https://my-app.test in your browser. This setup should enable you to:

  • Test integrations with OAuth2 providers that require secure HTTPS callbacks.
  • Develop and debug third-party APIs that require HTTPS.
  • Ensure your local dev environment closely mirrors production in terms of security.

Image of Datadog

Create and maintain end-to-end frontend tests

Learn best practices on creating frontend tests, testing on-premise apps, integrating tests into your CI/CD pipeline, and using Datadog’s testing tunnel.

Download The Guide

Top comments (2)

Collapse
 
robmarcopolo profile image
robMarcoPolo

Appreciate the effort putting this together. I'm having an issue at step 7. When I bring the containers back up, I get a conflcit on Port 80 (and 443). My guess is it's because both the laravel.test service and nginx services are trying to use those ports?

I've dumped my docker-compose.yml below - which I believe reflects the edits you set out in your instructions. I'd really appreciate any help you can give!

services:
    laravel.test:
        build:
            context: './vendor/laravel/sail/runtimes/8.4'
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: 'sail-8.4/app'
        extra_hosts:
            - 'host.docker.internal:host-gateway'
        ports:
            - '80:80'
            - '443:443'  # HTTPS port
            - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
        environment:
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
            XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
            XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
            IGNITION_LOCAL_SITES_PATH: '${PWD}'
        volumes:
            - '.:/var/www/html'
        networks:
            - sail
        depends_on:
            - mysql
            - redis
            - meilisearch
            - mailpit
            - selenium
    nginx:
        image: nginx:alpine
        ports:
            - '80:80'
            - '443:443'  # Expose HTTPS port for Nginx
        volumes:
            - .:/var/www/html
            - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf  # Nginx configuration
            - ./docker/nginx/ssl:/etc/nginx/ssl  # SSL certificate
        networks:
            -   sail
    mysql:
        image: 'mysql/mysql-server:8.0'
        ports:
            - '${FORWARD_DB_PORT:-3306}:3306'
        environment:
            MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ROOT_HOST: '%'
            MYSQL_DATABASE: '${DB_DATABASE}'
            MYSQL_USER: '${DB_USERNAME}'
            MYSQL_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ALLOW_EMPTY_PASSWORD: 1
        volumes:
            - 'sail-mysql:/var/lib/mysql'
            - './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
        networks:
            - sail
        healthcheck:
            test:
                - CMD
                - mysqladmin
                - ping
                - '-p${DB_PASSWORD}'
            retries: 3
            timeout: 5s
    redis:
        image: 'redis:alpine'
        ports:
            - '${FORWARD_REDIS_PORT:-6379}:6379'
        volumes:
            - 'sail-redis:/data'
        networks:
            - sail
        healthcheck:
            test:
                - CMD
                - redis-cli
                - ping
            retries: 3
            timeout: 5s
    meilisearch:
        image: 'getmeili/meilisearch:latest'
        ports:
            - '${FORWARD_MEILISEARCH_PORT:-7700}:7700'
        environment:
            MEILI_NO_ANALYTICS: '${MEILISEARCH_NO_ANALYTICS:-false}'
        volumes:
            - 'sail-meilisearch:/meili_data'
        networks:
            - sail
        healthcheck:
            test:
                - CMD
                - wget
                - '--no-verbose'
                - '--spider'
                - 'http://127.0.0.1:7700/health'
            retries: 3
            timeout: 5s
    mailpit:
        image: 'axllent/mailpit:latest'
        ports:
            - '${FORWARD_MAILPIT_PORT:-1025}:1025'
            - '${FORWARD_MAILPIT_DASHBOARD_PORT:-8025}:8025'
        networks:
            - sail
    selenium:
        image: selenium/standalone-chromium
        extra_hosts:
            - 'host.docker.internal:host-gateway'
        volumes:
            - '/dev/shm:/dev/shm'
        networks:
            - sail
networks:
    sail:
        driver: bridge
volumes:
    sail-mysql:
        driver: local
    sail-redis:
        driver: local
    sail-meilisearch:
        driver: local

Enter fullscreen mode Exit fullscreen mode
Collapse
 
acairns profile image
Andrew Cairns

Nice Alan, thanks for sharing! 🙌

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more