Fehlerseiten: 404/500 Middleware (v3.6 errors + nginx errorpages + file-Provider)

This commit is contained in:
2026-08-30 15:51:44 +02:00
parent 8dd7610f33
commit 0ccebc3827
6 changed files with 154 additions and 2 deletions
+1
View File
@@ -0,0 +1 @@
acme/acme.json
+24
View File
@@ -1,4 +1,21 @@
services: services:
errorpages:
image: nginx:1.27-alpine
container_name: errorpages
restart: unless-stopped
expose:
- "80"
volumes:
- ./web:/usr/share/nginx/html:ro
command:
- nginx
- -g
- "daemon off;"
networks:
- traefik-net
labels:
- traefik.enable=true
traefik: traefik:
image: traefik:3.6 # Gepinnt auf Version 3.6 image: traefik:3.6 # Gepinnt auf Version 3.6
container_name: traefik container_name: traefik
@@ -20,13 +37,20 @@ services:
- traefik-net - traefik-net
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
# Dashboard Router - Korrigierte Syntax für Host-Regel
- "traefik.http.routers.dashboard.rule=Host(`traefik.ljh31.de`)" - "traefik.http.routers.dashboard.rule=Host(`traefik.ljh31.de`)"
- "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.tls=true" - "traefik.http.routers.dashboard.tls=true"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt" - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
- "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.service=api@internal"
# Middleware Auswahl: Aktuell ist Basic Auth aktiv
- "traefik.http.routers.dashboard.middlewares=dashboard-auth" - "traefik.http.routers.dashboard.middlewares=dashboard-auth"
# Basic Auth Definition
- "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$xyz$$..." - "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$xyz$$..."
# Keycloak ForwardAuth Middleware (bereitgestellt, aber aktuell nicht im Router zugewiesen)
- "traefik.http.middlewares.keycloak-oauth2.forwardauth.address=http://<OAUTH2_PROXY_URL>/oauth2/auth" - "traefik.http.middlewares.keycloak-oauth2.forwardauth.address=http://<OAUTH2_PROXY_URL>/oauth2/auth"
- "traefik.http.middlewares.keycloak-oauth2.forwardauth.trustForwardHeader=true" - "traefik.http.middlewares.keycloak-oauth2.forwardauth.trustForwardHeader=true"
- "traefik.http.middlewares.keycloak-oauth2.forwardauth.authResponseHeaders=X-Auth-Request-User,X-Auth-Request-Email" - "traefik.http.middlewares.keycloak-oauth2.forwardauth.authResponseHeaders=X-Auth-Request-User,X-Auth-Request-Email"
+18
View File
@@ -0,0 +1,18 @@
http:
services:
errorpages-backend:
loadBalancer:
servers:
- url: "http://errorpages:80"
passHostHeader: false
middlewares:
error-404:
errors:
status: "400-499"
service: errorpages-backend
query: "/{status}.html"
error-500:
errors:
status: "500-599"
service: errorpages-backend
query: "/{status}.html"
+5
View File
@@ -3,6 +3,7 @@ api:
ping: {} # /ping-Endpunkt für Docker Healthcheck ping: {} # /ping-Endpunkt für Docker Healthcheck
entryPoints: entryPoints:
sshtls: sshtls:
address: ":2222" address: ":2222"
@@ -19,6 +20,10 @@ entryPoints:
address: ":9090" address: ":9090"
providers: providers:
file:
filename: "/etc/traefik/dynamic.yaml"
watch: true
debugLogGeneratedTemplate: true
docker: docker:
exposedByDefault: false exposedByDefault: false
+52
View File
@@ -0,0 +1,52 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>404 · Seite nicht gevonden</title>
<style>
:root{color-scheme:dark}
*{margin:0;box-sizing:border-box}
html,body{height:100%}
body{
display:flex;align-items:center;justify-content:center;
background:
radial-gradient(60rem 40rem at 20% -10%, rgba(76,103,255,.16), transparent 60%),
radial-gradient(50rem 35rem at 90% 110%, rgba(0,196,220,.12), transparent 60%),
#070a12;
color:#e8ecf5;
font:16px/1.6 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
}
.card{text-align:center;padding:3rem 2.5rem}
.code{
font-size:clamp(5rem,18vw,8rem);font-weight:800;letter-spacing:-.04em;line-height:1;
background:linear-gradient(120deg,#8aa2ff 0%,#59c8ff 55%,#7ee8c8 100%);
-webkit-background-clip:text;background-clip:text;color:transparent;
}
h1{font-size:1.25rem;font-weight:600;margin:1.25rem 0 .5rem}
p{color:#9aa4bd;max-width:26rem;margin:0 auto 1.75rem}
a.home{
display:inline-block;padding:.6rem 1.25rem;border-radius:.6rem;
border:1px solid rgba(255,255,255,.14);background:rgba(255,255,255,.05);
color:#cdd6ef;text-decoration:none;font-size:.9rem;transition:background .2s,border-color .2s
}
a.home:hover{background:rgba(255,255,255,.1);border-color:rgba(255,255,255,.28)}
.meta{margin-top:3rem;font-size:.72rem;color:#5a…6em;text-transform:uppercase}
.meta b{color:#8b96b3;font-weight:500}
</style>
</head>
<body>
<main class="card">
<div class="code" aria-hidden="true">404</div>
<h1>Seite nicht gefunden</h1>
<p>Die angefragte Adresse ist unter&nbsp;<b id="host"></b>&nbsp;nicht belegt. Vielleicht ein Tippfehler – oder die Seite war nie da.</p>
<a class="home" href="https://homepage.ljh31.de">Zur Startseite &#8594;</a>
<div class="meta"><b>ljh31.de</b> &middot; <span id="clock"></span></div>
</main>
<script>
document.getElementById('host').textContent=window.location.host;
const t=()=>document.getElementById('clock').textContent=new Date().toLocaleTimeString('de-DE');
t();setInterval(t,30000);
</script>
</body>
</html>
+52
View File
@@ -0,0 +1,52 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>500 · Etwas ist schiefgelaufen</title>
<style>
:root{color-scheme:dark}
*{margin:0;box-sizing:border-box}
html,body{height:100%}
body{
display:flex;align-items:center;justify-content:center;
background:
radial-gradient(60rem 40rem at 20% -10%, rgba(255,122,89,.14), transparent 60%),
radial-gradient(50rem 35rem at 90% 110%, rgba(255,190,60,.10), transparent 60%),
#0b0a0e;
color:#e8ecf5;
font:16px/1.6 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
}
.card{text-align:center;padding:3rem 2.5rem}
.code{
font-size:clamp(5rem,18vw,8rem);font-weight:800;letter-spacing:-.04em;line-height:1;
background:linear-gradient(120deg,#ffb27a 0%,#ff7a59 55%,#ff5470 100%);
-webkit-background-clip:text;background-clip:text;color:transparent;
}
h1{font-size:1.25rem;font-weight:600;margin:1.25rem 0 .5rem}
p{color:#9aa4bd;max-width:26rem;margin:0 auto 1.75rem}
a.home{
display:inline-block;padding:.6rem 1.25rem;border-radius:.6rem;
border:1px solid rgba(255,255,255,.14);background:rgba(255,255,255,.05);
color:#cdd6ef;text-decoration:none;font-size:.9rem;transition:background .2s,border-color .2s
}
a.home:hover{background:rgba(255,255,255,.1);border-color:rgba(255,255,255,.28)}
.meta{margin-top:3rem;font-size:.72rem;color:#5a…6em;text-transform:uppercase}
.meta b{color:#8b96b3;font-weight:500}
</style>
</head>
<body>
<main class="card">
<div class="code" aria-hidden="true">500</div>
<h1>Etwas ist schiefgelaufen</h1>
<p>Der Dienst hinter&nbsp;<b id="host"></b>&nbsp;meldet einen internen Fehler. Das ist meist nur vorübergehend – ein späterer Versuch führt weiter.</p>
<a class="home" href="https://homepage.ljh31.de">Zur Startseite &#8594;</a>
<div class="meta"><b>ljh31.de</b> &middot; <span id="clock"></span></div>
</main>
<script>
document.getElementById('host').textContent=window.location.host;
const t=()=>document.getElementById('clock').textContent=new Date().toLocaleTimeString('de-DE');
t();setInterval(t,30000);
</script>
</body>
</html>