[PATCH] docs: generate a static 404 page

From: Rito Rhymes

Date: Sun Mar 29 2026 - 11:21:12 EST


Broken links in static deployments currently fall back to a
generic web server 404 page, which leaves users on an orphaned
error page with no direct way to continue navigating the
documentation site. Add a dedicated not-found page so deployments
can serve a project-specific 404 instead.

It keeps the normal documentation layout around the error state so
users still have the search box, table of contents, footer links,
and a clear route back to the documentation root. The penguin
logo makes it less generic and adds character to what is
otherwise a frustrating page to encounter.

Actual 404 handling remains a web server concern.

Signed-off-by: Rito Rhymes <rito@xxxxxxxxxxxxxx>
Assisted-by: Codex:GPT-5.4
---
For 404 handling to work in nginx, the generated page must be
enabled there as well: point the site root at the built
documentation tree, then use error_page 404 /404.html;
together with a standard try_files $uri $uri/ =404;
location block.

I've tested the setup locally with nginx and it works fine.

These screenshots show the generated 404 page being served live in
Chrome on desktop and mobile.

Desktop screenshot:
https://github.com/user-attachments/assets/085eff0b-8661-4919-a651-6109e505ff05

Mobile screenshot:
https://github.com/user-attachments/assets/85a171f7-c2ff-483d-bc35-6719202a70e1

The screenshots above are hosted in a GitHub issue. For
convenience, anyone is welcome to post additional screenshots
there and reference them from the mailing list for discussion of
this patch:
https://github.com/ritovision/linux-kernel-docs/issues/4

Documentation/conf.py | 6 +++
Documentation/sphinx-static/custom.css | 69 +++++++++++++++++++++++++
Documentation/sphinx/templates/404.html | 16 ++++++
3 files changed, 91 insertions(+)
create mode 100644 Documentation/sphinx/templates/404.html

diff --git a/Documentation/conf.py b/Documentation/conf.py
index 679861503..e315a68e0 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -437,6 +437,12 @@ sys.stderr.write("Using %s theme\n" % html_theme)
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["sphinx-static"]

+# Generate a simple static 404 page. Serving it for missing paths is left to
+# the front-end web server configuration.
+html_additional_pages = {
+ "404": "404.html",
+}
+
# If true, Docutils "smart quotes" will be used to convert quotes and dashes
# to typographically correct entities. However, conversion of "--" to "—"
# is not always what we want, so enable only quotes.
diff --git a/Documentation/sphinx-static/custom.css b/Documentation/sphinx-static/custom.css
index db24f4344..c4d28e1d4 100644
--- a/Documentation/sphinx-static/custom.css
+++ b/Documentation/sphinx-static/custom.css
@@ -169,3 +169,72 @@ a.manpage {
font-weight: bold;
font-family: "Courier New", Courier, monospace;
}
+
+/* Center the 404 body copy without affecting normal pages.
+ * This minimum height ensures the footer remains positioned
+ * visibly at the bottom of the page despite most of the page
+ * being empty.
+ * 100% width allows for contained centering of inner contents */
+div.kernel-404-page {
+ align-items: center;
+ box-sizing: border-box;
+ display: flex;
+ justify-content: center;
+ min-height: 90vh;
+ padding: 2rem 1rem;
+ width: 100%;
+}
+
+/* Group the content as a vertical stack */
+div.kernel-404-content {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+ max-width: 28rem;
+}
+
+a.kernel-404-logo-link {
+ align-self: stretch;
+ border-bottom: none;
+}
+
+a.kernel-404-logo-link:hover {
+ border-bottom: none;
+}
+
+img.kernel-404-logo {
+ display: block;
+ height: auto;
+ margin-inline: auto;
+}
+
+div.kernel-404-content h1,
+div.kernel-404-content p {
+ margin: 0;
+}
+
+/* Make the header larger and more prominent. */
+div.kernel-404-content h1 {
+ font-size: 300%;
+}
+
+p.kernel-404-home {
+ margin-top: 0.5rem;
+ text-align: center;
+}
+
+@media screen and (max-width: 65em) {
+ /* Less viewport height because the mobile sidebar is taking
+ * up large chunk of the screen already */
+ div.kernel-404-page {
+ min-height: 40vh;
+ }
+
+ img.kernel-404-logo {
+ width: 70%;
+ }
+
+ div.kernel-404-content h1 {
+ font-size: 240%;
+ }
+}
diff --git a/Documentation/sphinx/templates/404.html b/Documentation/sphinx/templates/404.html
new file mode 100644
index 000000000..3a8a15f49
--- /dev/null
+++ b/Documentation/sphinx/templates/404.html
@@ -0,0 +1,16 @@
+{# SPDX-License-Identifier: GPL-2.0-only #}
+{% extends "layout.html" %}
+{% set title = "404 Not Found" %}
+
+{% block body %}
+ <div class="kernel-404-page">
+ <div class="kernel-404-content">
+ <a class="kernel-404-logo-link" href="{{ pathto(master_doc) }}" aria-label="Return home">
+ <img class="kernel-404-logo" src="{{ pathto('_static/logo.svg', 1) }}" alt="" />
+ </a>
+ <h1>404 Not Found</h1>
+ <p>The page you are searching for doesn't exist.</p>
+ <p class="kernel-404-home"><a href="{{ pathto(master_doc) }}">Return home</a></p>
+ </div>
+ </div>
+{% endblock %}
--
2.51.0