diff --git a/README.md b/README.md
index b3c8c86f4add45c8efdc3e5639c1d2adb934fe14..ff2dc49263fe8839494c8e17cbf2ededcb668059 100644
--- a/README.md
+++ b/README.md
@@ -100,6 +100,14 @@ Kalendář se stáhne při uložení modelu obsahujícího `CalendarMixin`.
 Appka přidává management command `update_callendars`, který stahuje a updatuje
 kalendáře. Je třeba ho pravidelně volat na pozadí (přes CRON).
 
+### Stránka 404
+
+Pokud je třeba vlastní 404 pro web, stačí do kořenové `xxxHomePage` webu
+definovat metodu `get_404_response` vracející Django HTTP Reponse objekt.
+
+    def get_404_response(self, request):
+        return HttpResponse("Stránka nenalezena", status=404)
+
 ## Deployment
 
 ### Konfigurace
diff --git a/majak/urls.py b/majak/urls.py
index 5f18ce5c3ba675f7e3978438e710e24b55fd2e87..1dbbebe03a1396b71c1f1748269f9429bbb11ff2 100644
--- a/majak/urls.py
+++ b/majak/urls.py
@@ -10,6 +10,8 @@ from wagtail.documents import urls as wagtaildocs_urls
 from elections2021 import views as elections2021_views
 from search import views as search_views
 
+handler404 = "shared.views.page_not_found"
+
 urlpatterns = [
     url(r"^django-admin/", admin.site.urls),
     url(r"^admin/", include(wagtailadmin_urls)),
diff --git a/shared/views.py b/shared/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..b0f8579f4e2d5dc72cb8c4011e5d7a06c39bfe19
--- /dev/null
+++ b/shared/views.py
@@ -0,0 +1,18 @@
+from django.http import HttpResponse
+from wagtail.core.models import Site
+
+
+def page_not_found(request, exception=None):
+    try:
+        site = Site.find_for_request(request)
+        root_page = site.root_page.specific
+    except:
+        root_page = None
+
+    if root_page and hasattr(root_page, "get_404_response"):
+        return root_page.get_404_response(request)
+
+    return HttpResponse(
+        "<h1>Stránka nenalezena</h1><a href='/'>pokračovat na úvod</a>",
+        status=404,
+    )