dunglas / frankenphp

🧟 The modern PHP app server
https://frankenphp.dev
MIT License
6.7k stars 220 forks source link

Unable to connect with STARTTLS: stream_socket_enable_crypto(): SSL operation failed with code 5 #582

Open range-of-motion opened 7 months ago

range-of-motion commented 7 months ago

What happened?

Not sure if this is due to FrankenPHP, but I don't have this issue using PHP-FPM. Whenever I try and send an e-mail using Laravel to Postmark, I get this. I already tried setting MAIL_ENCRYPTION=null, but no luck.

Build Type

Standalone binary

Worker Mode

Yes

Operating System

GNU/Linux

CPU Architecture

x86_64

Relevant log output

[2024-02-17 21:29:14] production.ERROR: Unable to connect with STARTTLS: stream_socket_enable_crypto(): SSL operation failed with code 5. OpenSSL Error messages:
error:80000002:system library::No such file or directory
error:80000002:system library::No such file or directory
error:80000002:system library::No such file or directory
error:0A000086:SSL routines::certificate verify failed {"userId":1,"exception":"[object] (Symfony\\Component\\Mailer\\Exception\\TransportException(code: 0): Unable to connect with STARTTLS: stream_socket_enable_crypto(): SSL operation failed with code 5. OpenSSL Error messages:
error:80000002:system library::No such file or directory
error:80000002:system library::No such file or directory
error:80000002:system library::No such file or directory
error:0A000086:SSL routines::certificate verify failed at /var/www/spark-plug/vendor/symfony/mailer/Transport/Smtp/Stream/SocketStream.php:171)
withinboredom commented 7 months ago

Are we missing ca-certificates @dunglas... that's a pretty weird error.

dunglas commented 7 months ago

This look like the same problem as https://github.com/beyondcode/expose/issues/391#issuecomment-1866184348 (Herd also uses static-php-cli under the hood as far as I know).

As the standalone binary doesn't bundle certificates, you need to point OpenSSL to your local certificates installation in your php.ini file (you can add one in the root of your app).

This is something that we need to document (help welcome).

SiebeVE commented 6 months ago

Hi,

I've also run into this issue (building on mac). I've added my own cacert.pem into my embeded project that I then want to add to the php.ini.

I need it working on cli (./frankenphp-mac-arm64 php-cli bin/console test:https-request).

I'm building by cloning the project and running:

EMBED=/my-project ./build-static.sh

Neither when adding a php.ini to the root of the embedded project nor adding the PHP_INI_SCAN_DIR to the build-static command works for me.

Any clue how I can add the cacert.pem path?

dunglas commented 6 months ago

This likely doesn't work because it's impossible to reference the PEM file because the app is decompressed in a temporary directory with a random name.

Using a script to copy the PEM file in a known path (like /cacert.pem) could work as a workaround, but we need to figure out a better solution.

hongfanmeng commented 6 months ago

Hi, I also encountered the same problem

Are there any guides on how to resolve this issue?

dunglas commented 5 months ago

Here is what I think we should do:

  1. Embed the latest version of the "official" cURL CA bundle when building the binary (allow the user to provide its own)
  2. Extract the embedded bundle as a known path of it doesn't already exists
  3. Change the default php.ini settings for cURL and OpenSSL to reference this bundle
LukeAbell commented 5 months ago

@dunglas Any chance there's a workaround in the meantime until this is resolved?

dunglas commented 5 months ago

Copying the CA bundle at a known path and hardcoding this absolute path in php.ini should work.

I'll try to take a look soon.

SimonMacIntyre commented 2 months ago

In case it helps anyone in the future, this caused me quite some headaches. In the end, I fixed it with these simple changes to my dockerfile:

RUN apk update && apk add --no-cache ca-certificates && rm -rf /var/cache/apk/*

ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
ENV SSL_CERT_DIR=/etc/ssl/certs

I was very confused why laravel tinker was working to send emails, but the web browser running frank was not. Then I noticed after dumping openssl_get_cert_locations() in both places that the results differed, which is where I saw frank was using the above environment variables.

dunglas commented 2 months ago

@SimonMacIntyre thanks! Would you mind opening a docs PR about that? I'm sure this will help a lot of people. In this file for instance: https://github.com/dunglas/frankenphp/blob/main/docs/known-issues.md

SimonMacIntyre commented 2 months ago

I'd be happy to!