Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proxying FrankenPHP to Caddy (technically Caddy to Caddy) not working #778

Open
7system7 opened this issue May 12, 2024 · 3 comments
Open
Labels
bug Something isn't working

Comments

@7system7
Copy link

7system7 commented May 12, 2024

What happened?

I think I tried everything, included the web help and forums. After that I am not sure the problem is here or in my code.

I have a project, based on API Platform, w/ the newest versions of deps on frontend and backend . (That can possible right now.)

The backend deps

$ composer outdated
Color legend:
- patch or minor release available - update recommended
- major release available - update possible

Direct dependencies required in composer.json:
doctrine/orm                     2.19.5 3.1.3 Object-Relational-Mapper for PHP

Transitive dependencies not required in composer.json:
doctrine/dbal                    3.8.4  4.0.2 Powerful PHP database abstraction layer (DBAL) with many features for database schem...
paragonie/constant_time_encoding 2.7.0  3.0.0 Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)
phenx/php-font-lib               0.5.6  1.0.0 A library to read, parse, export and make subsets of different types of font files.
phenx/php-svg-lib                0.5.4  1.0.0 A library to read, parse and export to PDF SVG files.

Frontend deps

$ pnpm outdated
┌──────────────────────┬─────────┬────────┐
│ Package              │ Current │ Latest │
├──────────────────────┼─────────┼────────┤
│ eslint (dev)         │ 8.57.0  │ 9.2.0  │
├──────────────────────┼─────────┼────────┤
│ postcss-loader (dev) │ 7.3.4   │ 8.1.1  │
└──────

I would like to use the FrankenPHP in worker mode as a standalone binary. So, I build the frontend to production

$ pnpm build

and I create the binary file. For that, I have a Makefile entry point what is based on the FrankenPHP's docs.

Binary logs

$ make build-binary
docker build -t static-app -f static-build.Dockerfile .
[+] Building 45.9s (10/10) FINISHED                                                                                                                                                                                                                          docker:default
 => [internal] load build definition from static-build.Dockerfile                                                                                                                                                                                                      0.0s
 => => transferring dockerfile: 342B                                                                                                                                                                                                                                   0.0s
 => [internal] load metadata for docker.io/dunglas/frankenphp:static-builder                                                                                                                                                                                           0.5s
 => [internal] load .dockerignore                                                                                                                                                                                                                                      0.0s
 => => transferring context: 2B                                                                                                                                                                                                                                        0.0s
 => [1/5] FROM docker.io/dunglas/frankenphp:static-builder@sha256:8b22271a16e7958f580af7e922bbcd211d491eefcf14f777c4b349ffbcf6be98                                                                                                                                     0.0s
 => [internal] load build context                                                                                                                                                                                                                                      2.1s
 => => transferring context: 22.53MB                                                                                                                                                                                                                                   2.0s
 => CACHED [2/5] WORKDIR /go/src/app/dist/app                                                                                                                                                                                                                          0.0s
 => CACHED [3/5] COPY . .                                                                                                                                                                                                                                              0.0s
 => CACHED [4/5] WORKDIR /go/src/app/                                                                                                                                                                                                                                  0.0s
 => [5/5] RUN EMBED=dist/app/     NO_COMPRESS=1     PHP_EXTENSIONS=ctype,iconv,simplexml,tokenizer,session,pdo_mysql,opcache,apcu,curl,dom,openssl     ./build-static.sh                                                                                              20.6s
 => exporting to image                                                                                                                                                                                                                                                22.5s 
 => => exporting layers                                                                                                                                                                                                                                               22.4s 
 => => writing image sha256:ca6a61e1e8932cab08b47d8159d8f9bf6e3683e3c70b4e5d65f556f63b951bef                                                                                                                                                                           0.0s 
 => => naming to docker.io/library/static-app                                                                                                                                                                                                                          0.0s 
docker cp b2fe9a88d0fe65f8e7912430661a9d6dadc931992838756c3264ced32d6d6a8c:/go/src/app/dist/frankenphp-linux-x86_64 yc-api-binary ; docker rm static-app-tmp                                                                                                                
Successfully copied 1.07GB to /var/www/splendid/yc-api/yc-api-binary
static-app-tmp

I do not use compressing (because it is so slow) and I do not remove the unnecessary dirs and files yet. But for production build, I will use these recommendations on the production server.

Until this, everything works as expected, the problem is to reach the site. Even if I do the recommended things I mentioned above.


The 1st approach

I try to use the binary alone without another Caddy. For that, w/ default settings I have to run the binary w/ sudo beacuse the 443 port cannot binded. (Permission error)

$ sudo ./yc-api-binary php-server
The server starts as expected

2024/05/12 10:02:37.094	INFO	using provided configuration	{"config_file": "/tmp/frankenphp_fd3f9cdbef5d517ff0c6fb2814407066  app.tar/Caddyfile", "config_adapter": ""}
2024/05/12 10:02:37.094	WARN	Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies	{"adapter": "caddyfile", "file": "/tmp/frankenphp_fd3f9cdbef5d517ff0c6fb2814407066  app.tar/Caddyfile", "line": 2}
2024/05/12 10:02:37.094	WARN	admin	admin endpoint disabled
2024/05/12 10:02:37.094	INFO	http.auto_https	server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS	{"server_name": "srv0", "https_port": 443}
2024/05/12 10:02:37.094	INFO	http.auto_https	enabling automatic HTTP->HTTPS redirects	{"server_name": "srv0"}
2024/05/12 10:02:37.094	INFO	tls.cache.maintenance	started background certificate maintenance	{"cache": "0xc00059ca80"}
2024/05/12 10:02:37.095	INFO	FrankenPHP started 🐘	{"php_version": "8.3.7"}
2024/05/12 10:02:37.095	INFO	embedded PHP app 📦	{"path": "/tmp/frankenphp_fd3f9cdbef5d517ff0c6fb2814407066  app.tar"}
2024/05/12 10:02:37.105	INFO	tls	cleaning storage unit	{"storage": "FileStorage:/root/.local/share/caddy"}
2024/05/12 10:02:37.105	INFO	tls	certificate expired beyond grace period; cleaning up	{"storage": "FileStorage:/root/.local/share/caddy", "asset_key": "certificates/local/localhost/localhost.crt", "expired_for": 1341850.105486614, "grace_period": 1209600}
2024/05/12 10:02:37.105	INFO	tls	deleting asset because resource expired	{"storage": "FileStorage:/root/.local/share/caddy", "asset_key": "certificates/local/localhost/localhost.crt"}
2024/05/12 10:02:37.105	INFO	tls	deleting asset because resource expired	{"storage": "FileStorage:/root/.local/share/caddy", "asset_key": "certificates/local/localhost/localhost.key"}
2024/05/12 10:02:37.105	INFO	tls	deleting asset because resource expired	{"storage": "FileStorage:/root/.local/share/caddy", "asset_key": "certificates/local/localhost/localhost.json"}
2024/05/12 10:02:37.105	INFO	tls	deleting site folder because key is empty	{"storage": "FileStorage:/root/.local/share/caddy", "site_key": "certificates/local/localhost"}
2024/05/12 10:02:37.105	INFO	tls	certificate expired beyond grace period; cleaning up	{"storage": "FileStorage:/root/.local/share/caddy", "asset_key": "certificates/local/yc-api.local/yc-api.local.crt", "expired_for": 2035682.105638877, "grace_period": 1209600}
2024/05/12 10:02:37.105	INFO	tls	deleting asset because resource expired	{"storage": "FileStorage:/root/.local/share/caddy", "asset_key": "certificates/local/yc-api.local/yc-api.local.crt"}
2024/05/12 10:02:37.105	INFO	tls	deleting asset because resource expired	{"storage": "FileStorage:/root/.local/share/caddy", "asset_key": "certificates/local/yc-api.local/yc-api.local.key"}
2024/05/12 10:02:37.105	INFO	tls	deleting asset because resource expired	{"storage": "FileStorage:/root/.local/share/caddy", "asset_key": "certificates/local/yc-api.local/yc-api.local.json"}
2024/05/12 10:02:37.105	INFO	tls	deleting site folder because key is empty	{"storage": "FileStorage:/root/.local/share/caddy", "site_key": "certificates/local/yc-api.local"}
2024/05/12 10:02:37.105	INFO	tls	finished cleaning storage units
2024/05/12 10:02:37.106	INFO	pki.ca.local	root certificate is already trusted by system	{"path": "storage:pki/authorities/local/root.crt"}
2024/05/12 10:02:37.106	INFO	pki	intermediate expires soon; renewing	{"ca": "local", "time_remaining": -780251.106149375}
2024/05/12 10:02:37.106	INFO	pki	renewed intermediate	{"ca": "local", "new_expiration": "2024/05/19 10:02:37.000"}
2024/05/12 10:02:37.106	INFO	http	enabling HTTP/3 listener	{"addr": ":443"}
2024/05/12 10:02:37.106	INFO	http.log	server running	{"name": "srv0", "protocols": ["h1", "h2", "h3"]}
2024/05/12 10:02:37.106	INFO	http.log	server running	{"name": "remaining_auto_https_redirects", "protocols": ["h1", "h2", "h3"]}
2024/05/12 10:02:37.106	INFO	http	enabling automatic TLS certificate management	{"domains": ["localhost"]}
2024/05/12 10:02:37.106	INFO	tls.obtain	acquiring lock	{"identifier": "localhost"}
2024/05/12 10:02:37.107	INFO	autosaved config (load with --resume flag)	{"file": "/root/.config/caddy/autosave.json"}
2024/05/12 10:02:37.115	INFO	tls.obtain	lock acquired	{"identifier": "localhost"}
2024/05/12 10:02:37.115	INFO	tls.obtain	obtaining certificate	{"identifier": "localhost"}
2024/05/12 10:02:37.116	INFO	tls.obtain	certificate obtained successfully	{"identifier": "localhost"}
2024/05/12 10:02:37.116	INFO	tls.obtain	releasing lock	{"identifier": "localhost"}
2024/05/12 10:02:37.116	WARN	tls	stapling OCSP	{"error": "no OCSP stapling for [localhost]: no OCSP server specified in certificate", "identifiers": ["localhost"]}

After this, I can reach the site completely. I can log in the site but after this, the first request crashes the server w/ segfault

[1]    2376515 segmentation fault  sudo ./yc-api-binary php-server

The 2nd approach

This is similar what the production environment would be looks like.

I have a Caddy on production environment. On that, I have a Caddy config what proxies the requests to the FrankenPHP's binary. The Caddy config for the prod server:

yc-franken.local {
    reverse_proxy http://localhost:9081

    log {
        output file /var/log/caddy/yc-franken.access.log {
                roll_size 3MiB
                roll_keep 5
                roll_keep_for 48h
        }
        format console
    }
}

and this is the Caddyfile in the project's root:

{
        http_port 9081
        https_port 9043
        admin off

        frankenphp
        order php_server before file_server
}

localhost {
        root * ./public
        encode zstd br gzip
        php_server
}

If I use the config w/o the http_port and https_port global options, the server obviously not starting, because the port collision. And I do not need the admin, so I switched it off.

With this settings the server starts correctly. But I cannot reach any site because too much redirections

image

So, I use another global option, the auto_https w/ off

{
        http_port 9081
        https_port 9043
        admin off
        auto_https off

        ...
}
...

This is not working too. The problem is that, somehow the script wanted to download the /api/docs.jsonld entry point on http, w/o ssl.

Meanwhile I use the newest @api-platform/admin (3.4.6) and I have this data-provider on HydraAdmin

assets/js/core/data-provider.js

import { fetchHydra, hydraDataProvider } from '@api-platform/admin';
import { parseHydraDocumentation } from '@api-platform/api-doc-parser';
import { dataProviderExtension, ENTRYPOINT } from '@yc/core';

const getHeaders = () => {
  const headers = {};

  const token = window.localStorage.getItem('auth');
  if (token) headers.Authorization = `Bearer ${token}`;

  const locale = window.localStorage.getItem('locale');
  if (locale) headers['X-Locale'] = locale;

  return headers;
};

export const dataProvider = setRedirectToLogin => ({
  ...hydraDataProvider(
    {
      entrypoint: ENTRYPOINT,
      docEntrypoint: `${ENTRYPOINT}/docs.jsonld`,
      httpClient: (url, options = {}) => {
        return fetchHydra(url, {
          ...options,
          headers: getHeaders,
        });
      },
      apiDocumentationParser: async () => {
        try {
          setRedirectToLogin(false);

          return await parseHydraDocumentation(ENTRYPOINT, { headers: getHeaders });
        } catch (result) {
          const { api, response, status } = result;

          if (401 !== status || !response) {
            throw result;
          }

          // Prevent infinite loop if the token is expired
          localStorage.removeItem('token');

          setRedirectToLogin(true);

          return {
            api,
            response,
            status,
          };
        }
      },
    },
  ),
  ...(dataProviderExtension()),
});

In this file the ENTRY_POINT is /api and every entry point works I have defined, except the docs.jsonld. Even if I forced the entry point root to the domain name, i.e.: https://example.com/api..

Build Type

Docker (Alpine)

Worker Mode

Yes

Operating System

GNU/Linux

CPU Architecture

x86_64

PHP configuration

I think, it is irrelevant to the issue.

Relevant log output

These are in the description.
@7system7 7system7 added the bug Something isn't working label May 12, 2024
@withinboredom
Copy link
Collaborator

For the too many redirects issue, take a look at the Location header to try and diagnose where the redirect comes from. I think you need to discover if it is coming from one of the Caddies or your php code.

For the segfault, a stack trace would be useful.

I'm on my mobile atm, so I will have to look up the link and edit this. Or search the other issues for how to do this.

@7system7
Copy link
Author

7system7 commented May 13, 2024

For the segfault, a stack trace would be useful.

How can I give you a dev stack trace from this? I could not find relevant issue.

The console output might be irrelevant, the last couple of rows:

{"message":"User Deprecated: Since doctrine/doctrine-bundle 2.4: The \"connection_override_options\" connection parameter is deprecated","context":{"exception":{"class":"ErrorException","message":"User Deprecated: Since doctrine/doctrine-bundle 2.4: The \"connection_override_options\" connection parameter is deprecated","code":0,"file":"/tmp/frankenphp_23f1d813c2733a7d5fcb222c88804dbf  app.tar/vendor/doctrine/doctrine-bundle/src/ConnectionFactory.php:83"}},"level":200,"level_name":"INFO","channel":"deprecation","datetime":"2024-05-13T08:54:12.070703+00:00","extra":{}}
[2024-05-13T08:54:12.070703+00:00] deprecation.INFO: User Deprecated: Since doctrine/doctrine-bundle 2.4: The "connection_override_options" connection parameter is deprecated {"exception":"[object] (ErrorException(code: 0): User Deprecated: Since doctrine/doctrine-bundle 2.4: The \"connection_override_options\" connection parameter is deprecated at /tmp/frankenphp_23f1d813c2733a7d5fcb222c88804dbf  app.tar/vendor/doctrine/doctrine-bundle/src/ConnectionFactory.php:83)"} []
{"message":"User Deprecated: Since doctrine/doctrine-bundle 2.4: The \"connection_override_options\" connection parameter is deprecated","context":{"exception":{"class":"ErrorException","message":"User Deprecated: Since doctrine/doctrine-bundle 2.4: The \"connection_override_options\" connection parameter is deprecated","code":0,"file":"/tmp/frankenphp_23f1d813c2733a7d5fcb222c88804dbf  app.tar/vendor/doctrine/doctrine-bundle/src/ConnectionFactory.php:83"}},"level":200,"level_name":"INFO","channel":"deprecation","datetime":"2024-05-13T08:54:12.070731+00:00","extra":{}}
[2024-05-13T08:54:12.070731+00:00] deprecation.INFO: User Deprecated: Since doctrine/doctrine-bundle 2.4: The "connection_override_options" connection parameter is deprecated {"exception":"[object] (ErrorException(code: 0): User Deprecated: Since doctrine/doctrine-bundle 2.4: The \"connection_override_options\" connection parameter is deprecated at /tmp/frankenphp_23f1d813c2733a7d5fcb222c88804dbf  app.tar/vendor/doctrine/doctrine-bundle/src/ConnectionFactory.php:83)"} []
{"message":"User Deprecated: Since doctrine/doctrine-bundle 2.4: The \"connection_override_options\" connection parameter is deprecated","context":{"exception":{"class":"ErrorException","message":"User Deprecated: Since doctrine/doctrine-bundle 2.4: The \"connection_override_options\" connection parameter is deprecated","code":0,"file":"/tmp/frankenphp_23f1d813c2733a7d5fcb222c88804dbf  app.tar/vendor/doctrine/doctrine-bundle/src/ConnectionFactory.php:83"}},"level":200,"level_name":"INFO","channel":"deprecation","datetime":"2024-05-13T08:54:12.070807+00:00","extra":{}}
[2024-05-13T08:54:12.070807+00:00] deprecation.INFO: User Deprecated: Since doctrine/doctrine-bundle 2.4: The "connection_override_options" connection parameter is deprecated {"exception":"[object] (ErrorException(code: 0): User Deprecated: Since doctrine/doctrine-bundle 2.4: The \"connection_override_options\" connection parameter is deprecated at /tmp/frankenphp_23f1d813c2733a7d5fcb222c88804dbf  app.tar/vendor/doctrine/doctrine-bundle/src/ConnectionFactory.php:83)"} []
{"message":"Checking for authenticator support.","context":{"firewall_name":"api","authenticators":1},"level":100,"level_name":"DEBUG","channel":"security","datetime":"2024-05-13T08:54:12.071432+00:00","extra":{}}
{"message":"Checking for authenticator support.","context":{"firewall_name":"api","authenticators":1},"level":100,"level_name":"DEBUG","channel":"security","datetime":"2024-05-13T08:54:12.071437+00:00","extra":{}}
{"message":"Checking support on authenticator.","context":{"firewall_name":"api","authenticator":"Lexik\\Bundle\\JWTAuthenticationBundle\\Security\\Authenticator\\JWTAuthenticator"},"level":100,"level_name":"DEBUG","channel":"security","datetime":"2024-05-13T08:54:12.071447+00:00","extra":{}}
{"message":"Checking support on authenticator.","context":{"firewall_name":"api","authenticator":"Lexik\\Bundle\\JWTAuthenticationBundle\\Security\\Authenticator\\JWTAuthenticator"},"level":100,"level_name":"DEBUG","channel":"security","datetime":"2024-05-13T08:54:12.071452+00:00","extra":{}}
{"message":"Checking for authenticator support.","context":{"firewall_name":"api","authenticators":1},"level":100,"level_name":"DEBUG","channel":"security","datetime":"2024-05-13T08:54:12.071453+00:00","extra":{}}
{"message":"Checking support on authenticator.","context":{"firewall_name":"api","authenticator":"Lexik\\Bundle\\JWTAuthenticationBundle\\Security\\Authenticator\\JWTAuthenticator"},"level":100,"level_name":"DEBUG","channel":"security","datetime":"2024-05-13T08:54:12.071475+00:00","extra":{}}
[1]    3033805 segmentation fault  sudo ./yc-api-binary php-server

I think you need to discover if it is coming from one of the Caddies or your php code.

I described the Caddies' config above. If there are any related issues w/ them, pls tell me, because I cannot see any.

@dunglas
Copy link
Owner

dunglas commented May 13, 2024

Can you try to enable the debug symbols and use gdb to gather a stack trace?

@dunglas dunglas changed the title Proxying PrankenPHP to Caddy (technically Caddy to Caddy) not working Proxying FrankenPHP to Caddy (technically Caddy to Caddy) not working May 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants