Skip to content

Instantly share code, notes, and snippets.

@gilbitron
Created June 16, 2021 10:55
Show Gist options
  • Save gilbitron/36d48eb751875bebdf43da0a91c9faec to your computer and use it in GitHub Desktop.
Save gilbitron/36d48eb751875bebdf43da0a91c9faec to your computer and use it in GitHub Desktop.
Enabling HTTPS (SSL) for Laravel Sail using Caddy
<?php
# app/Http/Controllers/CaddyController.php
namespace App\Http\Controllers;
use App\Store;
use Illuminate\Http\Request;
class CaddyController extends Controller
{
public function check(Request $request)
{
$authorizedDomains = [
'laravel.test',
'www.laravel.test',
// Add subdomains here
];
if (in_array($request->query('domain'), $authorizedDomains)) {
return response('Domain Authorized');
}
// Abort if there's no 200 response returned above
abort(503);
}
}
# docker/Caddyfile
{
on_demand_tls {
ask http://laravel.test/caddy-check
}
local_certs
}
:443 {
tls internal {
on_demand
}
reverse_proxy laravel.test {
header_up Host {host}
header_up X-Real-IP {remote}
header_up X-Forwarded-For {remote}
header_up X-Forwarded-Port {server_port}
header_up X-Forwarded-Proto {scheme}
health_timeout 5s
}
}
services:
caddy:
image: caddy:latest
restart: unless-stopped
ports:
- '80:80'
- '443:443'
volumes:
- './docker/Caddyfile:/etc/caddy/Caddyfile'
- sailcaddy:/data
- sailcaddy:/config
networks:
- sail
# Remove "ports" from laravel.test service
volumes:
sailcaddy:
driver: local
<?php
# routes/web.php
Route::get('/caddy-check', 'CaddyController@check');
@Maxime-Missichini
Copy link

Maxime-Missichini commented Dec 2, 2022

@Nilpo Hi, it may be a late reply but I managed to solve the same error, here is what I did :
Inside CaddyController:
$authorizedDomains = [ 'localhost', // Add subdomains here ];
This way I can access via https://localhost
Then the error was because of the Caddyfile, as you said when this error occurs we don't even reach the controller.
Here is my Caddyfile:


{
    on_demand_tls {
        ask http://laravel.test/caddy-check
    }
    local_certs
}

:443 {
    tls internal {
        on_demand
    }

    reverse_proxy laravel.test {
        header_up Host {host}
        header_up X-Real-IP {remote}
        header_up X-Forwarded-For {remote}
        header_up X-Forwarded-Port {server_port}
        header_up X-Forwarded-Proto {scheme}

        health_timeout 5s
    }
}

Notice that laravel.test is the name of the reverse proxy service !
My on_demand_tls was set to : ask http://localhost/caddy-check, which caused the failure ...
Don't forget to delete and rebuild your container after modifications on the Caddyfile, otherwise it will keep the old one.

@Nilpo
Copy link

Nilpo commented Dec 3, 2022

Hi @Maxime-Missichini Thanks for the reply. This still causes the same redirect loop. I've even tried modifying the authorized domains as follows, which accounts for every possibility.

$authorizedDomains = [
    env('APP_SERVICE'),
    'www.' . env('APP_SERVICE'),
    'localhost',
];

But as I mentioned in my last comment, this has no effect because the Caddy handler never gets called. Caddy kills the request with an SSL error and never hands the request off to Laravel for routing.

For the record, APP_SERVICE and the Sail service name are both the same (laravel.test, localhost, or other) and the test domain is resolvable. The failure is with Caddy.

You can view my fork for more details.

The problems is ultimately that the ask URL cannot contain an https protocol, but Caddy refuses to complete the request if it doesn't.

I'm using Laravel Sail in Laravel 9 based on the PHP 8.1 image and Ubuntu 22.04

I'll create an empty project that reproduces this error and create a GitHub repo.

EDIT:

Here's the sample repo.

https://github.com/Nilpo/caddy-laravelsail

@franz-deleon
Copy link

franz-deleon commented Dec 4, 2022

@Nilpo
try changing your APP_PORT env variable (or whatever that new variable is called now) to a different port like
APP_PORT=8080

referencing the docker-compose.yml

 services:
    laravel.test:
       ports:
            - '${APP_PORT:-80}:80' 

@Nilpo
Copy link

Nilpo commented Dec 4, 2022

Well, here's a weird one. I wonder if this is a Mac issue.

If you clone the sample repo I made (or start with a clean Laravel project), the first build doesn't work. But if you immediately force a rebuild with no changes, it works. (I'm starting with a clean Docker install. No locally downloaded images or containers. The strange thing is that the rebuild shouldn't actually change anything. The volumes are all the same too since there's no file changes.

git clone https://github.com/Nilpo/caddy-laravelsail
cd caddy-laravelsail && composer install
./vendor/bin/sail up -d
    # opening https://caddy-laravelsail.test fails
./vendor/bin/sail up --build -d
    # opening https://caddy-laravelsail.test succeeds

@ethanclevenger91
Copy link

If the domains are going to be hard-coded into that controller anyway, why not put them in the Caddyfile?

# docker/Caddyfile

laravel.test, www.laravel.test {
    tls internal

    reverse_proxy laravel.test {
        header_up Host {host}
        header_up X-Real-IP {remote}
        header_up X-Forwarded-For {remote}
        header_up X-Forwarded-Port {server_port}
        header_up X-Forwarded-Proto {scheme}

        health_timeout 5s
    }
}

@mreduar
Copy link

mreduar commented Mar 23, 2023

Is there any way to do it without creating code in the application? In theory development things should not have to be in the production project. Also, not everyone in the team necessarily has to use docker or sail. It causes me noise to create a route and a controller

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment