Repository navigation
feat(caddy): show DDEV 403 and 404 error pages, fixes #70 - #74
Merged
Merged
Conversation
## Short Summary (TL;DR) Caddy now serves DDEV's 403 and 404 error pages, matching nginx and Apache in DDEV v1.25.4+, instead of an empty response. ## The Issue - Fixes #70 DDEV v1.25.4 added explanatory 403 and 404 pages for nginx and Apache (ddev/ddev#8590, ddev/ddev#8641). With FrankenPHP, Caddy still returned an empty 403 or 404, for example when `docroot` is wrong or `index.php` is missing. ## How This PR Solves The Issue Adds `handle_errors 403 404` to the shared Caddyfile snippet. It serves `/usr/local/share/ddev-webserver-{403,404}-error.html` from the ddev-webserver image with an `X-Ddev-40x-Source: ddev-webserver (frankenphp)` header. `handle_errors` only fires for errors that Caddy produces itself, so 403 and 404 responses from PHP (Laravel, Symfony, etc.) pass through unchanged. A `file` matcher applies the page and header only when the page file exists. On DDEV older than v1.25.4 it doesn't, so the response stays an empty 403 or 404 as before, without the header. Also removes a blank line at the top of the Caddyfile that caused a "Caddyfile input is not formatted" warning in `ddev logs`. ## Manual Testing Instructions ```bash mkdir my-laravel-site && cd my-laravel-site ddev config --project-type=laravel --docroot=public ddev add-on get ddev/ddev-frankenphp --pr REPLACE_ME_WITH_THIS_PR_NUMBER ddev start ddev composer create-project laravel/laravel echo "Route::get('/forbidden', fn () => abort(403));" >> routes/web.php # Laravel's own 404 and 403 pages, without the X-Ddev-*-Source header curl -sI https://my-laravel-site.ddev.site/missing curl -sI https://my-laravel-site.ddev.site/forbidden # Without index.php, the 404 comes from Caddy and shows the DDEV page mv public/index.php public/index.php.bak curl -sI https://my-laravel-site.ddev.site/missing mv public/index.php.bak public/index.php # On DDEV v1.25.3, the same request returns an empty 404 without the X-Ddev-404-Source header ddev utility download-ddev --tag v1.25.3 export PATH="$HOME/tmp/ddev-download-ddev/v1.25.3:$PATH" ddev restart mv public/index.php public/index.php.bak curl -sI https://my-laravel-site.ddev.site/missing mv public/index.php.bak public/index.php ``` Open the same URLs in a browser to see the pages themselves. ## Automated Testing Overview `health_checks` requests `app-error.php`, which returns 404 or 403 from PHP, and checks that the app's body passes through without the DDEV error page. It then temporarily moves `index.php` away and checks for the 404 page on a missing file and the 403 page on an unreadable file, then restores `index.php`. ## Release/Deployment Notes Needs DDEV v1.25.4+ for the pages to show. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
stasadev
force-pushed
the
20261008_stasadev_error_pages
branch
from
October 8, 2026 11:27
563c048 to
d67deea
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Short Summary (TL;DR)
Caddy now serves DDEV's 403 and 404 error pages, matching nginx and Apache in DDEV v1.25.4+, instead of an empty response.
The Issue
DDEV v1.25.4 added explanatory 403 and 404 pages for nginx and Apache (ddev/ddev#8590, ddev/ddev#8641). With FrankenPHP, Caddy still returned an empty 403 or 404, for example when
docrootis wrong orindex.phpis missing.How This PR Solves The Issue
Adds
handle_errors 403 404to the shared Caddyfile snippet. It serves/usr/local/share/ddev-webserver-{403,404}-error.htmlfrom the ddev-webserver image with anX-Ddev-40x-Source: ddev-webserver (frankenphp)header.handle_errorsonly fires for errors that Caddy produces itself, so 403 and 404 responses from PHP (Laravel, Symfony, etc.) pass through unchanged. Afilematcher applies the page and header only when the page file exists. On DDEV older than v1.25.4 it doesn't, so the response stays an empty 403 or 404 as before, without the header.Also removes a blank line at the top of the Caddyfile that caused a "Caddyfile input is not formatted" warning in
ddev logs.Manual Testing Instructions
Open the same URLs in a browser to see the pages themselves.
Automated Testing Overview
health_checksrequestsapp-error.php, which returns 404 or 403 from PHP, and checks that the app's body passes through without the DDEV error page. It then temporarily movesindex.phpaway and checks for the 404 page on a missing file and the 403 page on an unreadable file, then restoresindex.php.Release/Deployment Notes
Needs DDEV v1.25.4+ for the pages to show.
🤖 Generated with Claude Code