Skip to content

Frankenphp misses the leading slash in PHP_SELF when root directive is omitted in a Caddyfile #2166

@mrchrisadams

Description

@mrchrisadams

What happened?

Hi there.

I'm opening this issue but I don't know if this is just something to fix in the documentation, or if it's something that needs to be fixed in the code of FrankenPHP/Caddy itself.

When experimenting with using FrankenPHP and WordPress, I noticed that on some URLs, even if you are an admin, you can't access certain admin pages.

After a few hours of digging through code and eventually relying on some rubber ducking with an LLM, I figured out that the issue was actually related to Frankenphp and the Caddyfile. There's a subtle bug that occurs if you do not have a root directive set, and follow the instructions in the docs here:

https://frankenphp.dev/docs/wordpress/#minimal-installation

I have created a set of steps that you can follow to reproduce the issue that I found, at the gist below:

https://gist.github.com/mrchrisadams/bb6c0a22b538f3a9ccafe9c5883fc78b

There is a lot of detail in that gist, so I'll try sharing the TLDR here - without a root directive, some redirects seem to break in hard to debug ways.

This Caddyfile here - it works fine when we visit http://localhost:9000

:9000 {
	root * /path/to/wordpress/project

	# Execute PHP files in the current directory and serve assets
	php_server
        # log requests
	log
}

But this one fails miserably:

# BAD example, redirects do not work because the beginning slash is missing, after the root directive is commented out.

:9000 {
	# root * /path/to/wordpress/project

	# Execute PHP files in the current directory and serve assets
	php_server
        # log requests
	log
}

In the logs, when you have no root directive, you can see the caddy trying to redirect to http://localhost:9000index.php/wp-admin/install.php, which fails because there should be a slash between localhost:9000 and index.php/wp-admin/install.php

In other projects, permission checks break as well, because internally WordPress checks for the existence of /wp-admin in various regexes, not wp-admin.

What to fix

As a starting point, I think this can actually be fixed in the docs without really needing to make much in the way of changes to the code, simply by updating the code examples, and adding something to the known issues page below:

https://frankenphp.dev/docs/known-issues/

Would you accept a PR to update the docs for those, or does it make sense to change the behaviour internally?

I can do the first easily, but the second is beyond my skills - I don't know golang or C.

Build Type

Static binary

Worker Mode

No

Operating System

GNU/Linux

CPU Architecture

x86_64

PHP configuration

System	Darwin cambozola.local 25.2.0 Darwin Kernel Version 25.2.0: Tue Nov 18 21:09:55 PST 2025; root:xnu-12377.61.12~1/RELEASE_ARM64_T8103 arm64
Build Date	Jan 4 2026 01:21:59
Build System	Darwin sat12-bq158-f139c3f4-8029-4168-8275-72f4caf8c199-8EC345080BF8.local 24.6.0 Darwin Kernel Version 24.6.0: Wed Oct 15 21:12:37 PDT 2025; root:xnu-11417.140.69.703.14~1/RELEASE_ARM64_VMAPPLE arm64
Build Provider	static-php-cli 2.7.11
Compiler	clang 17.0.0
Configure Command	'./configure' '--prefix=' '--with-valgrind=no' '--enable-shared=no' '--enable-static=yes' '--disable-all' '--disable-phpdbg' '--disable-cli' '--disable-fpm' '--enable-embed=static' '--disable-micro' '--disable-cgi' '--with-config-file-path=/usr/local/etc/php' '--with-config-file-scan-dir=/usr/local/etc/php/conf.d' '--enable-zts' '--disable-zend-signals' '--with-amqp' '--with-librabbitmq-dir=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--enable-apcu' '--enable-ast' '--enable-bcmath' '--enable-brotli' '--with-bz2=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--enable-calendar' '--enable-ctype' '--with-curl' '--enable-dba' '--enable-dom' '--enable-exif' '--enable-fileinfo' '--enable-filter' '--enable-ftp' '--with-zlib' '--enable-gd' '--with-freetype' '--with-jpeg' '--with-webp' '--with-avif' '--with-gmp=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--with-gettext=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--with-iconv=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--enable-session' '--enable-igbinary' '--with-imagick=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' 'ac_cv_func_omp_pause_resource_all=no' '--enable-intl' '--with-ldap=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--enable-lz4' '--with-lz4-includedir=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--enable-mbstring' '--enable-mbregex' '--enable-memcache' '--enable-memcached' '--with-zlib-dir=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--with-libmemcached-dir=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--disable-memcached-sasl' '--enable-memcached-json' '--with-zstd' '--enable-memcached-igbinary' '--enable-memcached-session' '--with-system-fastlz' '--enable-mysqlnd' '--with-mysqli' '--enable-opcache' '--enable-opcache-jit' '--with-password-argon2' '--enable-parallel' '--enable-pcntl' '--enable-pdo' '--with-pdo-mysql' '--with-pgsql' 'PGSQL_CFLAGS=-I/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot/include' 'PGSQL_LIBS=-L/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot/lib -liconv -lcharset -lresolv -lc++ -llzma -liconv -lcharset -lresolv -lc++ -lz -lresolv -lc++ -lxml2 -lm -lz -llzma -liconv -lcharset -lresolv -lc++ -lssl -lcrypto -lz -lresolv -lc++ -lncurses -lresolv -lc++ -ledit -lncurses -lresolv -lc++ -licuio -licui18n -licuuc -licudata -lpthread -lm -lresolv -lc++ -lxslt -lexslt -lxml2 -lm -lz -llzma -liconv -lcharset -lresolv -lc++ -lgmp -lresolv -lc++ -lsodium -lresolv -lc++ -lldap -llber -lresolv -lsodium -lgmp -lssl -lcrypto -lz -lresolv -lc++ -lzstd -lresolv -lc++ -lpq -lpgcommon -lpgport -lzstd -lldap -llber -lresolv -lsodium -lgmp -lxslt -lexslt -licuio -licui18n -licuuc -licudata -lpthread -ledit -lncurses -lssl -lcrypto -lxml2 -lm -lz -llzma -liconv -lcharset -lresolv -lc++' '--with-pdo-pgsql=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--with-sqlite3=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--with-pdo-sqlite' '--enable-sqlsrv' '--with-pdo-sqlsrv' '--enable-phar' '--enable-posix' '--enable-protobuf' '--with-libedit' '--without-readline' '--enable-redis' '--enable-redis-session' '--enable-redis-igbinary' '--disable-redis-msgpack' '--enable-redis-zstd' '--enable-redis-lz4' '--with-liblz4=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--enable-shmop' '--enable-simplexml' '--enable-xml' '--enable-soap' '--enable-sockets' '--with-sodium' '--with-ssh2=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--enable-sysvmsg' '--enable-sysvsem' '--enable-sysvshm' '--with-tidy=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--enable-tokenizer' '--with-zip=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--with-xlswriter' '--enable-reader' '--with-openssl=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--enable-xmlreader' '--enable-xmlwriter' '--with-libxml=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--with-xsl=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--with-xz' '--with-yaml=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' '--enable-zstd' '--with-libzstd=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot' 'PKG_CONFIG=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/pkgroot/aarch64-darwin/bin/pkg-config' 'PKG_CONFIG_PATH=/Users/runner/work/frankenphp/frankenphp/dist/static-php-cli/buildroot/lib/pkgconfig' 'PHP_BUILD_PROVIDER=static-php-cli 2.7.11' 'PHP_BUILD_COMPILER=clang 17.0.0'
Server API	FrankenPHP
Virtual Directory Support	enabled
Configuration File (php.ini) Path	/usr/local/etc/php
Loaded Configuration File	(none)
Scan this dir for additional .ini files	/usr/local/etc/php/conf.d
Additional .ini files parsed	(none)
PHP API	20240924
PHP Extension	20240924
Zend Extension	420240924
Zend Extension Build	API420240924,TS
PHP Extension Build	API20240924,TS
PHP Integer Size	64 bits
Debug Build	no
Thread Safety	enabled
Thread API	POSIX Threads
Zend Signal Handling	disabled
Zend Memory Manager	enabled
Zend Multibyte Support	provided by mbstring
Zend Max Execution Timers	disabled
IPv6 Support	enabled
DTrace Support	disabled
Registered PHP Streams	https, ftps, compress.zlib, compress.brotli, compress.bzip2, php, file, glob, data, http, ftp, phar, sqlsrv, ssh2.shell, ssh2.exec, ssh2.tunnel, ssh2.scp, ssh2.sftp, compress.lzma, zip, compress.zstd
Registered Stream Socket Transports	tcp, udp, unix, udg, ssl, tls, tlsv1.0, tlsv1.1, tlsv1.2, tlsv1.3
Registered Stream Filters	zlib.*, bzip2.*, convert.iconv.*, string.rot13, string.toupper, string.tolower, convert.*, consumed, dechunk

Relevant log output

2026/02/04 17:37:57.993 INFO    http.log.access handled request {"request": {"remote_ip": "::1", "remote_port": "65159", "client_ip": "::1", "proto": "HTTP/1.1", "method": "GET", "host": "localhost:9000", "uri": "/", "headers": {"Accept-Encoding": ["gzip, deflate, br, zstd"], "Dnt": ["1"], "User-Agent": ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"], "Upgrade-Insecure-Requests": ["1"], "Sec-Fetch-Site": ["none"], "Connection": ["keep-alive"], "Sec-Ch-Ua": ["\"Not(A:Brand\";v=\"8\", \"Chromium\";v=\"144\", \"Google Chrome\";v=\"144\""], "Sec-Ch-Ua-Platform": ["\"macOS\""], "Sec-Fetch-User": ["?1"], "Accept-Language": ["en-GB,en;q=0.9"], "Sec-Ch-Ua-Mobile": ["?0"], "Sec-Fetch-Mode": ["navigate"], "Sec-Fetch-Dest": ["document"]}}, "bytes_read": 0, "user_id": "", "duration": 0.086276584, "size": 0, "status": 302, "resp_headers": {"Cache-Control": ["no-cache, must-revalidate, max-age=0, no-store, private"], "X-Redirect-By": ["WordPress"], "Location": ["http://localhost:9000index.php/wp-admin/install.php"], "Content-Type": ["text/html; charset=UTF-8"], "Server": ["FrankenPHP Caddy"], "X-Powered-By": ["PHP/8.4.16"], "Expires": ["Wed, 11 Jan 1984 05:00:00 GMT"]}}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions