14

I just created a new Laravel 8 project, following the instructions in their docs. Using Laravel Sail I have the site running locally on my machine just fine using sail up. I have set up an entry in /etc/hosts so the url I go to is http://local.dev.domain.com (substituting domain.com for the actual domain name I own, and pointing to localhost in the /etc/hosts file)...all works great.

However, the site needs to use Facebook Login, and Facebook requires https urls only on referrers. I've tried everything I could find online about setting up SSL certs with docker, but setting up nginx with manually created certs (via mkcert) or trying to use letsencrypt all fails for various reasons (conflicts in ports, letsencrypting wanting the domain to be a real one (and failing on the acme challenge if I do create that subdomain), etc. I've copied the certs to /etc/ssl/certs in the docker image and run update-ca-certificates, tried setting the application port 443 in my .env file as well as opening both ports 80 and 443 in the docker-compose.yml file...but all ends in the browser rejecting the request to https://local.dev.domain.com

I've spent hours trying to get this to work but it doesn't seem like anyone has used the Laravel Sail docker image with SSL.

Any pointers?

[Edit for more info] As pointed out in the comments, you need to set an alias to just use sail ..., but I've already done that:

enter image description here

I also tried without the bash alias using vendor/bin/sail share to no avail:

enter image description here

smenzer
  • 307
  • 1
  • 2
  • 9

4 Answers4

9

Problem

In your case you need a real domain, which you have. A self-signed certificate would not work as Facebook would not acknowledge it as trusted. To get a free ssl certificate for that domain you can use Let's Encrypt, the easiest way to obtain that certificate is using certbot. The problem is that you need to install that certificate on your webserver. Laravel Sail uses the build-in webserver that does not support ssl unfortunatly. You need to put a webserver like nginx in front of the app and install the certificate there.

I'm currently working on a fork that enables what you need, however it's not finished.

Workaround

For now you can use the build in tunnel provided by Expose: https://beyondco.de/docs/expose/server/ssl

This is enable by sail share

It might be easier to use ngrok instead, which is essentialy the same but commercial. Than all you have to do is download, register and run ngrok http --region=eu 9000 and it will create a https link for you for development.

enter image description here

online Thomas
  • 8,864
  • 6
  • 44
  • 85
  • This is super useful, thank you! I'll keep an on your fork, sounds really promising! I've tried using `sail share` but I get an error saying it's not a valid command... – smenzer Dec 15 '20 at 10:49
  • 1
    @smenzer You need to install sail properly to use this short alias: https://laravel.com/docs/8.x/sail#configuring-a-bash-alias otherwise you need `vendor/bin/sail share` – online Thomas Dec 15 '20 at 10:56
  • I did what you mentioned (updated the description with details) but it still didn't work to do `vendor/bin/sail share` – smenzer Dec 15 '20 at 21:07
  • @smenzer maybe it's not possible on windows. However I suggest skipping that part and using ngrok for now. – online Thomas Dec 16 '20 at 06:35
  • 1
    I'm on a mac. but i'm trying to use ngrok now. I had to change the application port in .env to 9000 and then it seems to work and give me https access. Just need to work out the integration with facebook. looking forward to your project being ready! – smenzer Dec 16 '20 at 09:42
  • @smenzer I missed that the docker container changes the port to 80 instead of the usual port 9000 when running `php artisan serve` – online Thomas Dec 16 '20 at 11:14
  • 2
    @onlineThomas an extra thump up for the fork you are working on! sounds great! – Andre W. Dec 30 '20 at 23:37
  • 2
    @smenzer I just saw this on another post. Apparently the version of sail you get by default isn't the latest, you need to use `composer require laravel/sail --dev` found in comments on here https://laracasts.com/series/whats-new-in-laravel-8/episodes/12 – Harvey Dobson Jan 08 '21 at 11:14
5

I solved this problem by using Caddy as a reverse proxy to the Laravel Sail container. Caddy has a feature called automatic HTTPS which can generate local certificates on the fly.

1 - Add Caddy as a service to your docker-compose.yml

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

2 - Create a simple Caddyfile and configure it as a reverse proxy

{
    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
    }
}

3 - Set up an endpoint for Caddy to authorise which domains it generates certificates for

<?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);
    }
}

See this gist for the full code changes involved. This blog post explains how to trust the Caddy root certificates.

Gilbert
  • 311
  • 1
  • 4
  • 6
  • 1
    This looks really promising! I'm wondering if I'm missing anything; setting up the above with a fresh install (via `curl -s "https://laravel.build/example-app" | bash`) and adjusting `laravel.test` to `example-app.test` then trying to reach `example-app.test` returns "This site can’t provide a secure connection \ example-app.test sent an invalid response. \ ERR_SSL_PROTOCOL_ERROR" in Chrome, and similar errors in Safari/FF. Any thoughts? – runofthemill Jun 16 '21 at 20:12
  • Do you mean you changed `laravel.test` in your `docker-compose.yml`? If so, I don't think you can change `laravel.test` as I think Sail uses it internally. But you can update your hosts file to use whatever local domain you want. You might also want to check the logs for the caddy service to see what it's doing. – Gilbert Jun 18 '21 at 08:27
  • Ah interesting! Yeah the Caddy service logs showed it running, but not even acknowledging a request when I made one in the browser. I'll try again w/ `laravel.test`. Cheers! – runofthemill Jun 18 '21 at 20:52
  • 2
    I did as you said even the domain in the hosts file to `laravel.test` but I still get `This site can’t provide a secure connection laravel.test sent an invalid response.` in chrome browser – Ya Basha Jul 09 '21 at 15:12
  • This is neat and it's working! How can we make Laravel Mix webpack devserver also reverse proxy React Fast Refresh or HRM on a different port? For example `http://localhost:8081`. – Christos Lytras Dec 05 '21 at 14:27
  • I did all of this, installed the rootCA by copying it to /etc/local/share/ca-certificates and running `sudo update-ca-certificates` (I'm on Ubuntu). However when visiting https://laravel.test chrome still throws NET::ERR_CERT_AUTHORITY_INVALID. Any ideas? It seems the Expires On date equals the Issued On date... – Ken Aug 04 '22 at 09:54
  • For those having trouble with installing the rootCA and Chrome still throwing NET::ERR_CERT_AUTHORITY_INVALID: export the Caddy rootCA certificate and import it into chrome using its settings (chrome://settings/certificates). So do `sudo docker cp your-caddy-container-name:/config/caddy/pki/authorities/local/root.crt ~/Downloads/caddy-root.crt` (maybe you have to do `sudo chown your-user:your-user ~/Downloads/caddy-root.crt`). And then import that exported certificate as an "Authority" in the chrome settings (check all the boxes). DO NOT DO THIS WITH ANY OTHER CERTS! – Ken Aug 08 '22 at 06:54
  • I've been trying to get this solution working for days. The setup is simple enough, but Caddy can't verify the domains because it creates a redirect loop. Caddy sends a request to `http://laravel.test/caddy-check`, which it then redirects to `https://laravel.test/caddy-check` causing the request to fail with the error `following http redirects is not allowed`. Since there doesn't seem to be a way to exclude that single endpoint, the whole solution is a wash. – Nilpo Oct 28 '22 at 00:29
2

For make "sail share" work you have to set alias and run "composer require laravel/sail --dev" on your project. This will install the latest version of sail, version 0.0.6 includes "share" command

  • 1
    that did the trick. strange that the documented way of starting a laravel project (`curl -s https://laravel.build/example-app | bash` from https://laravel.com/docs/8.x/installation#getting-started-on-macos) doesn't include this by default – smenzer Dec 18 '20 at 21:15
  • Sail is an optional development environment, like Laragon or Valet etc. – Dan Abrey May 17 '21 at 07:34
  • Just a note that Sail is included by default when using the online builder now. If you want to deep dive into the configs you can use `artisan publish:sail`. – Nilpo Oct 28 '22 at 01:53
-1

There is actually an easier way. I did the following:

changed laravel.test port to something else like 8085 do it from .env so u will avoid issues, add APP_PORT env var

then (this step has been done by our sys admin) since laravel sail is actually installing apache in the system, u can manually set a reverse proxy for both port 80 and 443 to port 8085 and that should do the trick.

of course u will have to install certbot on that apache instance.

Mauro
  • 2,175
  • 1
  • 9
  • 17