Error pages let you replace dply's default 404 and 500 responses with your own HTML, and turn on maintenance mode, which answers every request with a 503 page until you turn it off. Everything is served from the edge, so changes apply on the next request with no rebuild or redeploy.
Edit error pages
- Open your app and choose Error pages. Each page (404, 500 and maintenance) is listed with its source: Custom, From dply.yaml or Built-in.
- Click a page. Paste full HTML, or start from a template, which fills just that page. The 404, blocked-country and maintenance pages offer Minimal, Friendly and Enterprise. The 500 page offers eleven designs: Default (the built-in page), Quiet, Request path, Auto-retry, Receipt, Poster, Terminal, Unplugged, Owner hint, Signal lost and Ghost layout. A live preview shows the result beside the editor.
- Choose Save. The new page is live on the next request, with no redeploy.
To go back to dply's default, open the page and choose Use the built-in page. Cancel discards unsaved edits.
Each page can be up to 200,000 characters.
Tip
Keep error pages self-contained, with inline CSS and no external scripts or fonts. They're shown when something is wrong, and links back into your app may be what's failing.
When each page is shown
404 page
Shown with status 404 when a request doesn't match a file in your deploy, for static and hybrid apps.
Note
With SPA fallback on (the default for new apps), a missing path serves your index.html with status 200 instead, so your front-end router can handle it, and the 404 page isn't shown. Turn SPA fallback off in Build if you want real 404s. For SSR and container apps, your app returns its own 404s.
Without a custom 404 page, dply returns a plain-text Object not found.
Blocked-country page
Shown with status 403 when your Firewall turns a visitor away by country. Without one, visitors get the plain-text Forbidden — content is not available in this region (XX). This page is set in the dashboard only; dply.yaml has no key for it.
500 page
- SSR and container apps: when your app returns a
5xxHTML response, dply replaces the body with your 500 page (or dply's default error page) and keeps the status code. JSON and other non-HTML error responses pass through unchanged. - All apps: shown if dply's edge itself hits an unexpected error while handling the request. Without a custom 500 page, visitors see dply's default error page. The error details are logged for dply, never shown to visitors.
A 500 page can include these placeholders. dply fills them on every request:
| Placeholder | Filled with |
|---|---|
{{dply.ref}} |
A reference for the request (Cloudflare's ray ID) |
{{dply.host}} |
The hostname the visitor asked for |
{{dply.path}} |
The path the visitor asked for |
{{dply.colo}} |
The edge location that served it, such as ORD |
{{dply.time}} |
The time of the error, in UTC |
Seeing your app's own error page
When your app runs with APP_DEBUG on (or sends the response header x-dply-app-debug: 1), visitors get your app's own error page, stack trace included, instead of the 500 page. Turn it on with Show full errors (APP_DEBUG) under Error pages, and turn it off before real visitors arrive.
- The 500 page drops any
Content-Security-Policyheader, whether your app sent it or a dply header rule added it, so the page's own styles always work. Your other headers stay.
For a hybrid app's origin, the Failover HTML under Delivery is shown instead when the origin is down or times out. See Static & hybrid sites.
Opening a failed request
Click any row under Live requests (on the overview or under Traffic) to see that request: status, time taken, cache, country and its reference. For a 5xx from your app, dply keeps the response it returned (headers and body, up to 1 MB) for 7 days, sealed with your error-details password, and shows it there. With APP_DEBUG on, that's the full stack trace. For Laravel container apps it also shows the stack trace, rebuilt from your app's logs, so you don't need APP_DEBUG on. Laravel logs uncaught exceptions to stderr in dply containers, and after a 5xx dply's PHP image logs the request's reference beside the exception, so the trace shown is that request's own. Apps deployed before this get the exceptions logged closest to the request instead. Other container apps get their error lines from within 30 seconds of the request. Logs → App output has the full log.
- Only people who can change the app can see saved responses.
- dply saves at most one response every 5 seconds per path, so a burst of the same error keeps the first.
- After Make a new password, older saved responses can no longer be opened.
Maintenance mode
Turn on Maintenance mode to answer every request with your maintenance page (or dply's default "We'll be right back." page):
HTTP/1.1 503 Service Unavailable
Retry-After: 120
Cache-Control: no-store, max-age=0
Maintenance mode runs before every other rule, including the firewall and access control. The checkbox takes effect right away. Turn it off to bring the app back.
Note
If your organization is paused for billing, dply shows a billing notice in place of your app in the same way. Your own maintenance setting is left unchanged. See Paused accounts.
Error pages in dply.yaml
Declare pages inline or as files in your repository:
error_pages:
html_404_path: public/404.html
html_500_path: public/500.html
maintenance:
enabled: false
html_path: public/maintenance.html
Use html_404, html_500 and maintenance.html for inline HTML instead of paths. Paths are relative to the repository root and are read at build time.
When both are set:
- For the 404, 500 and maintenance HTML, the dashboard value is used.
- Maintenance mode is on if either the dashboard or the repository turns it on. If
maintenance.enabled: trueis in your repository, you have to change the file and redeploy to turn maintenance off.
The Advanced section of the Error pages page shows what your repository declares.