HTTP/1.1 308 Permanent Redirect

1. The problem I’m having:

I’ve faced something like that

2. Error messages and/or full log output:


curl -v --location http://localhost:8080/health

* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8080...
* Connected to localhost (::1) port 8080
> GET /health HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location: https://localhost/health
< Server: Caddy
< Date: Wed, 18 Jun 2025 19:58:29 GMT
< Content-Length: 0
< 
* Closing connection
* Clear auth, redirects to port from 8080 to 443
* Issue another request to this URL: 'https://localhost/health'
* Host localhost:443 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:443...
* connect to ::1 port 443 from ::1 port 52945 failed: Connection refused
*   Trying 127.0.0.1:443...
* connect to 127.0.0.1 port 443 from 127.0.0.1 port 52946 failed: Connection refused
* Failed to connect to localhost port 443 after 0 ms: Couldn't connect to server
* Closing connection
curl: (7) Failed to connect to localhost port 443 after 0 ms: Couldn't connect to server

3. Caddy version:

FrankenPHP v1.1.0 PHP 8.3.4 Caddy v2.7.6 h1:w0NymbG2m9PcvKWsrXO6EEkY9Ru4FJK8uQbYcev1p3A=

4. How I installed and ran Caddy:

{
    auto_https off
}

:80 {
    root * /app/public
    encode gzip

    php_fastcgi frankenphp

    rewrite /index.php{uri}
    rewrite * /index.php

    log {
        output stdout
        format console
        level DEBUG
    }
}

This is Caddyfile


COPY ./src /app

COPY ./Caddyfile /etc/frankenphp/Caddyfile

# Set working directory
WORKDIR /app

# Install required dependencies
RUN set -xe \
    && apt-get update && apt-get install -y \
        git \
        unzip \
        curl \
        libpng-dev \
        libzip-dev \
        libonig-dev \
        libxml2-dev \
        zlib1g-dev \
        libcurl4-openssl-dev \
        libpq-dev \
        libsqlite3-dev \
        default-mysql-client \
    && docker-php-ext-install \
        pdo \
        pdo_mysql \
        mbstring \
        zip \
        bcmath \
        opcache \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Install Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Configure Composer and install dependencies
RUN composer config --global --auth github-oauth.github.com ghp_xxxxxxx
RUN composer install -v --ignore-platform-reqs

# Create log directory for PHP-FPM
RUN mkdir -p /var/log/php-fpm && ln -sf /dev/stderr /var/log/php-fpm/error.log

# Expose port 80
EXPOSE 80

this is dockerfile-php


services:
  php:
    build:
      context: .
      dockerfile: dockerfile-php
    container_name: realtime_laravel_app
    ports:
      - "8080:80"
    environment:
      FRANKENPHP_CONFIG: /etc/frankenphp/Caddyfile
      DB_CONNECTION: mysql
      DB_HOST: db
      DB_PORT: 3307
      DB_DATABASE: realtime
      DB_USERNAME: realtime
      DB_PASSWORD: realtime
      REDIS_HOST: redis
      REDIS_PORT: 6379
      CACHE_DRIVER: redis
      QUEUE_CONNECTION: redis
    depends_on:
      - db
      - redis
    volumes:
      - ./src:/app

  db:
    image: mysql:8.4
    container_name: realtime_db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: realtime
      MYSQL_USER: realtime
      MYSQL_PASSWORD: realtime
    ports:
      - "3307:3306"
    volumes:
      - dbdata:/var/lib/mysql

  redis:
    image: redis:6.2.1-buster
    container_name: realtime_redis
    ports:
      - "6379:6379"
    restart: unless-stopped

volumes:
  dbdata

This is docker-compose.yml.

How can i approach to fix it?

I don’t think this is the actual Caddyfile that’s running your setup.

I downloaded Caddy 2.7.6 just to double-check for any bugs, and there’s no way you’d be auto-redirected to https:// with auto_https off.

Take a look at your container logs and see if you can find something like this:

{"level":"info","ts":1750356379.9292765,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}

Pay attention to the “config_file” value. It should tell you exactly which Caddyfile is being loaded.

Also, your Dockerfile seems incomplete.

2 Likes

OK, after giving it a second look and doing some digging, it seems you are running that Caddyfile, but the redirect is actually being triggered by Laravel itself.

The /health endpoint looks like a Laravel route, and Laravel is most likely forcing the https scheme internally.

If you want to run Laravel over plain http, check your app for something like this:

UrlGenerator::forceScheme('https');

or:

$url->forceScheme('https');

Comment it out or wrap it in a condition so it only applies in production.

Also, this is probably a better question for the Laravel community.

2 Likes

Could you please explain details more?

CONTAINER ID   IMAGE                           COMMAND                  CREATED         STATUS                   PORTS                                              NAMES
0ad246c62876   hivelo-cloud-realtime-api-php   "docker-php-entrypoi…"   2 minutes ago   Up 2 minutes (healthy)   443/tcp, 2019/tcp, 443/udp, 0.0.0.0:8080->80/tcp   realtime_laravel_app
8fdf625d2f16   mysql:8.4                       "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes             33060/tcp, 0.0.0.0:3307->3306/tcp                  realtime_db
c9f89028960d   redis:6.2.1-buster              "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes             0.0.0.0:6379->6379/tcp                             realtime_redis
➜  ✗ curl -v --location http://localhost:8080                  
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8080...
* Connected to localhost (::1) port 8080
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location: https://localhost/
< Server: Caddy
< Date: Thu, 19 Jun 2025 18:58:15 GMT
< Content-Length: 0
< 
* Closing connection
* Clear auth, redirects to port from 8080 to 443
* Issue another request to this URL: 'https://localhost/'
* Host localhost:443 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:443...
* connect to ::1 port 443 from ::1 port 61519 failed: Connection refused
*   Trying 127.0.0.1:443...
* connect to 127.0.0.1 port 443 from 127.0.0.1 port 61520 failed: Connection refused
* Failed to connect to localhost port 443 after 0 ms: Couldn't connect to server
* Closing connection
curl: (7) Failed to connect to localhost port 443 after 0 ms: Couldn't connect to server
➜   ✗ docker logs 0ad246c62876
{"level":"info","ts":1750359327.3183641,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
{"level":"warn","ts":1750359327.3236384,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":16}
{"level":"info","ts":1750359327.3261642,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//[::1]:2019","//127.0.0.1:2019","//localhost:2019"]}
{"level":"info","ts":1750359327.3268905,"logger":"http.auto_https","msg":"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}
{"level":"info","ts":1750359327.3270512,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1750359327.3274517,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc0002fc880"}
{"level":"info","ts":1750359327.334657,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
{"level":"info","ts":1750359327.335329,"msg":"failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details."}
{"level":"info","ts":1750359327.336563,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
{"level":"info","ts":1750359327.3366406,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
{"level":"info","ts":1750359327.3366458,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["localhost"]}
{"level":"info","ts":1750359327.336812,"msg":"FrankenPHP started 🐘","php_version":"8.3.4"}
{"level":"info","ts":1750359327.3383036,"logger":"tls.obtain","msg":"acquiring lock","identifier":"localhost"}
{"level":"info","ts":1750359327.3401577,"logger":"tls.obtain","msg":"lock acquired","identifier":"localhost"}
{"level":"info","ts":1750359327.3402758,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"localhost"}
{"level":"info","ts":1750359327.34075,"logger":"tls","msg":"cleaning storage unit","storage":"FileStorage:/data/caddy"}
{"level":"info","ts":1750359327.3410044,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"info","ts":1750359327.3428497,"logger":"tls.obtain","msg":"certificate obtained successfully","identifier":"localhost"}
{"level":"info","ts":1750359327.3429813,"logger":"tls.obtain","msg":"releasing lock","identifier":"localhost"}
{"level":"warn","ts":1750359327.3446538,"logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [localhost]: no OCSP server specified in certificate","identifiers":["localhost"]}
{"level":"warn","ts":1750359327.402142,"logger":"pki.ca.local","msg":"installing root certificate (you might be prompted for password)","path":"storage:pki/authorities/local/root.crt"}
{"level":"info","ts":1750359327.405185,"msg":"warning: \"certutil\" is not available, install \"certutil\" with \"apt install libnss3-tools\" or \"yum install nss-tools\" and try again"}
{"level":"info","ts":1750359327.4052188,"msg":"define JAVA_HOME environment variable to use the Java trust"}
{"level":"info","ts":1750359328.325181,"msg":"certificate installed properly in linux trusts"}
{"level":"info","ts":1750359328.3291419,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1750359328.3292086,"msg":"serving initial configuration"}

Here is sample container logs.

Right, so this log shows that you’re NOT using the Caddyfile you think you are. Yours is located at /etc/frankenphp/Caddyfile:

Run this on your server to see the content of the actual Caddyfile being used:

docker exec -ti realtime_laravel_app cat /etc/caddy/Caddyfile

That’s the one your setup is running. Feel free to paste it here if you’d like us to take a look.

 ✗ docker exec -ti realtime_laravel_app cat /etc/caddy/Caddyfile

{
        {$CADDY_GLOBAL_OPTIONS}

        frankenphp {
                #worker /path/to/your/worker.php
                {$FRANKENPHP_CONFIG}
        }

        # https://caddyserver.com/docs/caddyfile/directives#sorting-algorithm
        order mercure after encode
        order vulcain after reverse_proxy
        order php_server before file_server
        order php before file_server
}

{$CADDY_EXTRA_CONFIG}

{$SERVER_NAME:localhost} {
        #log {
        #       # Redact the authorization query parameter that can be set by Mercure
        #       format filter {
        #               wrap console
        #               fields {
        #                       uri query {
        #                               replace authorization REDACTED
        #                       }
        #               }
        #       }
        #}

        root * public/
        encode zstd br gzip

        # Uncomment the following lines to enable Mercure and Vulcain modules
        #mercure {
        #       # Transport to use (default to Bolt)
        #       transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db}
        #       # Publisher JWT key
        #       publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
        #       # Subscriber JWT key
        #       subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
        #       # Allow anonymous subscribers (double-check that it's what you want)
        #       anonymous
        #       # Enable the subscription API (double-check that it's what you want)
        #       subscriptions
        #       # Extra directives
        #       {$MERCURE_EXTRA_DIRECTIVES}
        #}
        #vulcain

        {$CADDY_SERVER_EXTRA_DIRECTIVES}

        php_server
}

Something like that.

Well, there you go, that’s your Caddyfile :slight_smile:

You can refer to environment variables in FrankenPHP documentation:

For example, you can define an environment variable:

CADDY_GLOBAL_OPTIONS=“auto_https off”

which should disable your https redirects.

Also, according to the same documentation, this line is incorrect:

FRANKENPHP_CONFIG: /etc/frankenphp/Caddyfile

That is not a valid frankenphp directive configuration.

2 Likes
➜ ✗ docker ps -a
CONTAINER ID   IMAGE                           COMMAND                  CREATED              STATUS                        PORTS                                              NAMES
2a1c82215adc   hivelo-cloud-realtime-api-app   "docker-php-entrypoi…"   About a minute ago   Up About a minute (healthy)   443/tcp, 2019/tcp, 443/udp, 0.0.0.0:8080->80/tcp   laravel-app
0152bb5f5293   redis:alpine                    "docker-entrypoint.s…"   About a minute ago   Up About a minute             0.0.0.0:6379->6379/tcp                             laravel-redis
786b6e799d18   mysql:8                         "docker-entrypoint.s…"   About a minute ago   Up About a minute             33060/tcp, 0.0.0.0:3307->3306/tcp                  laravel-mysql
➜  ✗ curl -v http://localhost:8080/health
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8080...
* Connected to localhost (::1) port 8080
> GET /health HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location: https://localhost/health
< Server: Caddy
< Date: Wed, 25 Jun 2025 17:33:58 GMT
< Content-Length: 0
< 
* Closing connection
➜ ✗ docker logs 
➜ ✗ docker logs laravel-app
{"level":"info","ts":1750872665.676556,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
{"level":"warn","ts":1750872665.68082,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":16}
{"level":"info","ts":1750872665.6827374,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//127.0.0.1:2019","//localhost:2019","//[::1]:2019"]}
{"level":"info","ts":1750872665.6830971,"logger":"http.auto_https","msg":"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}
{"level":"info","ts":1750872665.6831121,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1750872665.6848764,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc000575f00"}
{"level":"info","ts":1750872665.7003472,"logger":"tls","msg":"cleaning storage unit","storage":"FileStorage:/data/caddy"}
{"level":"info","ts":1750872665.701009,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"warn","ts":1750872665.7419686,"logger":"pki.ca.local","msg":"installing root certificate (you might be prompted for password)","path":"storage:pki/authorities/local/root.crt"}
{"level":"info","ts":1750872665.7468567,"msg":"warning: \"certutil\" is not available, install \"certutil\" with \"apt install libnss3-tools\" or \"yum install nss-tools\" and try again"}
{"level":"info","ts":1750872665.7469351,"msg":"define JAVA_HOME environment variable to use the Java trust"}
{"level":"info","ts":1750872666.8530083,"msg":"certificate installed properly in linux trusts"}
{"level":"info","ts":1750872666.8532894,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
{"level":"info","ts":1750872666.8534482,"msg":"failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details."}
{"level":"info","ts":1750872666.8535628,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
{"level":"info","ts":1750872666.8536122,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
{"level":"info","ts":1750872666.8536463,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["localhost"]}
{"level":"info","ts":1750872666.8538082,"msg":"FrankenPHP started 🐘","php_version":"8.3.4"}
{"level":"info","ts":1750872666.8542845,"logger":"tls.obtain","msg":"acquiring lock","identifier":"localhost"}
{"level":"info","ts":1750872666.8562028,"logger":"tls.obtain","msg":"lock acquired","identifier":"localhost"}
{"level":"info","ts":1750872666.856318,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"localhost"}
{"level":"info","ts":1750872666.8572423,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1750872666.857284,"msg":"serving initial configuration"}
{"level":"info","ts":1750872666.8580806,"logger":"tls.obtain","msg":"certificate obtained successfully","identifier":"localhost"}
{"level":"info","ts":1750872666.8581731,"logger":"tls.obtain","msg":"releasing lock","identifier":"localhost"}
{"level":"warn","ts":1750872666.8584404,"logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [localhost]: no OCSP server specified in certificate","identifiers":["localhost"]}
➜  ✗ 

I’ve faced like this.

FROM dunglas/frankenphp:1.1.0

# Set working directory
WORKDIR /app

# Copy Laravel app
COPY ./src /app

# Copy Caddyfile
COPY ./Caddyfile /etc/frankenphp/Caddyfile

# Set permissions
RUN chown -R www-data:www-data /app && chmod -R 755 /app

RUN set -xe \
    && apt-get update && apt-get install -y \
        git \
        unzip \
        curl \
        libpng-dev \
        libzip-dev \
        libonig-dev \
        libxml2-dev \
        zlib1g-dev \
        libcurl4-openssl-dev \
        libpq-dev \
        libsqlite3-dev \
        default-mysql-client \
    && docker-php-ext-install \
        pdo \
        pdo_mysql \
        mbstring \
        zip \
        bcmath \
        opcache \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN composer config --global --auth github-oauth.github.com ghp_xxx
RUN composer install -v --ignore-platform-reqs

# Laravel setup commands
RUN php artisan config:clear \
 && php artisan route:clear \
 && php artisan view:clear

# Expose the port (FrankenPHP uses 80 by default)
EXPOSE 80

This is dockerfile-php

version: "3.8"

services:
  app:
    build:
      context: .
      dockerfile: dockerfile-php
    container_name: laravel-app
    ports:
      - "8080:80"
    volumes:
      - ./src:/app
      - ./Caddyfile:/etc/frankenphp/Caddyfile:ro # Mount the Caddyfile for FrankenPHP
    environment:
      APP_ENV: local
      APP_DEBUG: true
      APP_KEY: base64:DeB4Unpg4W8oe3uDiBvPRB6lN4Fla91t1ShUuzikLdE=
      DB_CONNECTION: mysql
      DB_HOST: db
      DB_PORT: 3306
      DB_DATABASE: realtime
      DB_USERNAME: realtime
      DB_PASSWORD: realtime
      REDIS_HOST: redis

  db:
    image: mysql:8
    container_name: laravel-mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: realtime
      MYSQL_USER: realtime
      MYSQL_PASSWORD: realtime
    volumes:
      - dbdata:/var/lib/mysql
    ports:
      - "3307:3306"

  redis:
    image: redis:alpine
    container_name: laravel-redis
    ports:
      - "6379:6379"

volumes:
  dbdata:

this is docker-compose.yml

Route::get('/health', function () {
    return response()->json(['status' => 'OK']);
});

I’ve defined a route in web.php

{
    auto_https off
}

:80 {
    root * /app/public
    encode gzip

    php_fastcgi unix//var/run/frankenphp.sock

    rewrite /index.php{uri}
    rewrite * /index.php

    file_server

    log {
        output stdout
        format console
        level DEBUG
    }
}

This is Caddyfile

  hivelo-cloud-realtime-api git:(master) ✗ docker exec -it laravel-app cat /etc/caddy/Caddyfile

{
        {$CADDY_GLOBAL_OPTIONS}

        frankenphp {
                #worker /path/to/your/worker.php
                {$FRANKENPHP_CONFIG}
        }

        # https://caddyserver.com/docs/caddyfile/directives#sorting-algorithm
        order mercure after encode
        order vulcain after reverse_proxy
        order php_server before file_server
        order php before file_server
}

{$CADDY_EXTRA_CONFIG}

{$SERVER_NAME:localhost} {
        #log {
        #       # Redact the authorization query parameter that can be set by Mercure
        #       format filter {
        #               wrap console
        #               fields {
        #                       uri query {
        #                               replace authorization REDACTED
        #                       }
        #               }
        #       }
        #}

        root * public/
        encode zstd br gzip

        # Uncomment the following lines to enable Mercure and Vulcain modules
        #mercure {
        #       # Transport to use (default to Bolt)
        #       transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db}
        #       # Publisher JWT key
        #       publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
        #       # Subscriber JWT key
        #       subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
        #       # Allow anonymous subscribers (double-check that it's what you want)
        #       anonymous
        #       # Enable the subscription API (double-check that it's what you want)
        #       subscriptions
        #       # Extra directives
        #       {$MERCURE_EXTRA_DIRECTIVES}
        #}
        #vulcain

        {$CADDY_SERVER_EXTRA_DIRECTIVES}

        php_server
}

this is docker exec -it laravel-app cat /etc/caddy/Caddyfile

Can you please check and provide any suggestions step by step how to trace?
Thanks you!

^ That is not your Caddyfile.

The folloing is your Caddyfile:

{
        {$CADDY_GLOBAL_OPTIONS}

        frankenphp {
                #worker /path/to/your/worker.php
                {$FRANKENPHP_CONFIG}
        }

        # https://caddyserver.com/docs/caddyfile/directives#sorting-algorithm
        order mercure after encode
        order vulcain after reverse_proxy
        order php_server before file_server
        order php before file_server
}

{$CADDY_EXTRA_CONFIG}

{$SERVER_NAME:localhost} {
        #log {
        #       # Redact the authorization query parameter that can be set by Mercure
        #       format filter {
        #               wrap console
        #               fields {
        #                       uri query {
        #                               replace authorization REDACTED
        #                       }
        #               }
        #       }
        #}

        root * public/
        encode zstd br gzip

        # Uncomment the following lines to enable Mercure and Vulcain modules
        #mercure {
        #       # Transport to use (default to Bolt)
        #       transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db}
        #       # Publisher JWT key
        #       publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
        #       # Subscriber JWT key
        #       subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
        #       # Allow anonymous subscribers (double-check that it's what you want)
        #       anonymous
        #       # Enable the subscription API (double-check that it's what you want)
        #       subscriptions
        #       # Extra directives
        #       {$MERCURE_EXTRA_DIRECTIVES}
        #}
        #vulcain

        {$CADDY_SERVER_EXTRA_DIRECTIVES}

        php_server
}

Take a look at these lines:

        {$CADDY_GLOBAL_OPTIONS}

        frankenphp {
                #worker /path/to/your/worker.php
                {$FRANKENPHP_CONFIG}
        }

What you were calling your Caddyfile, the /etc/frankenphp/Caddyfile file, was actually included via the FRANKENPHP_CONFIG environment variable:

    environment:
      FRANKENPHP_CONFIG: /etc/frankenphp/Caddyfile

So the content of /etc/frankenphp/Caddyfile was being injected right here:

        {$CADDY_GLOBAL_OPTIONS}

        frankenphp {
                #worker /path/to/your/worker.php
                {$FRANKENPHP_CONFIG}  <=== INJECTED HERE
        }

But now, based on your latest docker-compose, you no longer define FRANKENPHP_CONFIG. The /etc/frankenphp/Caddyfile file isn’t even being used in your container anymore.

Honestly, you can completely remove your current /etc/frankenphp/Caddyfile. It’s not in use, and it’s also misconfigured.

I really recommend you go through the FrankenPHP documentation, especially the Environment Variables section. It clearly explains how these variables work and how to set them up correctly.

Here’s a good starting point for your updated docker-compose.yml:

version: "3.8"

services:
  app:
    build:
      context: .
      dockerfile: dockerfile-php
    container_name: laravel-app
    ports:
      - "8080:80"
    volumes:
      - ./src:/app
    environment:
      APP_ENV: local
      APP_DEBUG: true
      APP_KEY: base64:DeB4Unpg4W8oe3uDiBvPRB6lN4Fla91t1ShUuzikLdE=
      DB_CONNECTION: mysql
      DB_HOST: db
      DB_PORT: 3306
      DB_DATABASE: realtime
      DB_USERNAME: realtime
      DB_PASSWORD: realtime
      REDIS_HOST: redis
      CADDY_GLOBAL_OPTIONS: auto_https off

  db:
    image: mysql:8
    container_name: laravel-mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: realtime
      MYSQL_USER: realtime
      MYSQL_PASSWORD: realtime
    volumes:
      - dbdata:/var/lib/mysql
    ports:
      - "3307:3306"

  redis:
    image: redis:alpine
    container_name: laravel-redis
    ports:
      - "6379:6379"

volumes:
  dbdata:

Notice I’ve removed this from the volumes:

- ./Caddyfile:/etc/frankenphp/Caddyfile:ro # Mount the Caddyfile for FrankenPHP`

since you’re no longer using it, and added this into the environment section instead:

CADDY_GLOBAL_OPTIONS: auto_https off

Start with this setup and see where it takes you.

If you decide you really want to use:

    environment:
      FRANKENPHP_CONFIG: /etc/frankenphp/Caddyfile

you need to make sure that your /etc/frankenphp/Caddyfile contains only these settings and nothing else:

num_threads <num_threads> # Sets the number of PHP threads to start. Default: 2x the number of available CPUs.
max_threads <num_threads> # Limits the number of additional PHP threads that can be started at runtime. Default: num_threads. Can be set to 'auto'.
max_wait_time <duration> # Sets the maximum time a request may wait for a free PHP thread before timing out. Default: disabled.
php_ini <key> <value> # Set a php.ini directive. Can be used several times to set multiple directives.
worker {
	file <path> # Sets the path to the worker script.
	num <num> # Sets the number of PHP threads to start, defaults to 2x the number of available CPUs.
	env <key> <value> # Sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables.
	watch <path> # Sets the path to watch for file changes. Can be specified more than once for multiple paths.
	name <name> # Sets the name of the worker, used in logs and metrics. Default: absolute path of worker file
}

You can find more details about this in the FrankenPHP documentation.

1 Like

Thanks you! I’ll try it out.