feedc0de 4a68a78f0a
Validate and deploy error pages / Validate manifests (push) Failing after 25s
Validate and deploy error pages / Deploy to Kubernetes (push) Has been skipped
Initial commit
2026-08-08 20:42:38 +02:00
2026-08-08 20:42:38 +02:00
2026-08-08 20:42:38 +02:00
2026-08-08 20:42:38 +02:00
2026-08-08 20:42:38 +02:00
2026-08-08 20:42:38 +02:00
2026-08-08 20:42:38 +02:00
2026-08-08 20:42:38 +02:00
2026-08-08 20:42:38 +02:00
2026-08-08 20:41:02 +02:00
2026-08-08 20:42:38 +02:00
2026-08-08 20:42:38 +02:00
2026-08-08 20:42:38 +02:00
2026-08-08 20:42:38 +02:00
2026-08-08 20:42:38 +02:00

Traefik error pages

A small, portable Kubernetes deployment that replaces Traefik-generated HTTP 5xx response bodies with a Cloudflare-style diagnostic page while preserving the original status code. API clients still receive 500, 502, 503, or 504; only the response body and diagnostic headers are replaced.

The page reports the browser, reverse proxy, optional ForwardAuth provider, and upstream states. Routes without ForwardAuth omit the authentication stage entirely. Every generated response includes an X-Error-ID header and the same identifier in the HTML footer.

Repository contents

  • values.yaml: portable defaults with authentication integration disabled.
  • values-brunner-ninja.yaml: the live brunner.ninja branding and Authentik integration.
  • templates/: ConfigMap, nginx Deployment, Service, Traefik Errors middleware, and optional ForwardAuth chain.
  • install.sh: validates, renders, applies, and waits for a healthy rollout.
  • test.sh: renders both the generic and brunner.ninja configurations locally.
  • ci-deployer.yaml: restricted Gitea Actions ServiceAccount and token request.
  • create-ci-kubeconfig.sh: bootstraps that identity and prints the one-line CI kubeconfig secret.
  • .gitea/workflows/deploy.yml: validates every push and deploys main.
  • examples/: global and per-Ingress Traefik attachment examples.

No credential value or generated kubeconfig belongs in this repository.

Prerequisites

  • Kubernetes with a working Traefik installation.
  • Traefik's middlewares.traefik.io CRD.
  • Helm 3 or 4 for local rendering.
  • kubectl access with permission to create the initial namespaced resources.

The nginx image is pinned by digest. No registry credentials, persistent volumes, cert-manager resources, or public Ingress are required.

Install on brunner.ninja

Run the first installation with an administrator kubeconfig:

./install.sh

The script uses namespace default and values-brunner-ninja.yaml by default. It performs a server-side dry run before changing anything, then waits for the new pod to become Ready.

To use another namespace or values file:

NAMESPACE=traefik VALUES_FILE=values.yaml ./install.sh

The target namespace must already exist. If fullnameOverride is changed, also pass the resulting Deployment name through DEPLOYMENT_NAME.

Connect it to Traefik

Installing the chart creates the error backend and middleware but does not edit an independently managed Traefik release. Attach the middleware globally to the HTTPS entrypoint in Traefik's Helm values:

ports:
  websecure:
    http:
      middlewares:
        - default-upstream-errors@kubernetescrd

The reference format is <namespace>-<middleware>@kubernetescrd. The included examples/traefik-values.yaml contains this configuration. Restart or upgrade Traefik after changing its static entrypoint configuration.

To use the page only on selected routes, omit the global entrypoint middleware and use the annotation shown in examples/ingress.yaml, or add this middleware to an IngressRoute:

middlewares:
  - name: upstream-errors
    namespace: default

Traefik's Errors middleware preserves the original status. It asks this service for /{status}.html, replaces the body, and returns the original 5xx code.

Optional ForwardAuth diagnostics

Generic installations leave auth.enabled: false. Direct upstream failures then render three stages and contain no authentication-provider wording.

The brunner.ninja values enable a generated chain named authentik:

  1. authentik-error-context marks the request and clears spoofed completion headers.
  2. authentik-forward calls Authentik.
  3. authentik-error-checked marks a successful access check.

Existing routes continue to reference:

default-authentik@kubernetescrd

If Authentik fails, the page shows brunner.ninja Auth as failed and the upstream as not accessed. If Authentik succeeds but the application fails, Auth is shown as working. Customize these resources through the auth and branding sections of the values file.

Validate and update manually

Run local rendering tests before committing:

./test.sh

Update values-brunner-ninja.yaml or a template, then deploy with the same idempotent command used for installation:

./install.sh

The Deployment contains a hash of the rendered ConfigMap. HTML or nginx changes therefore create a rolling update automatically. With one replica, maxUnavailable: 0 keeps the old healthy pod until the replacement passes its readiness probe. A broken nginx configuration should fail the rollout without removing the last working pod.

Rollback by reverting the Git commit and running ./install.sh again.

Automatic deployment with Gitea Actions

The workflow validates all pushes and pull requests. A successful push to main renders values-brunner-ninja.yaml, applies the fixed set of resources, and polls the Deployment for up to two minutes.

CI deliberately does not use helm upgrade. It cannot read or write Helm release Secrets. Its Role can only patch the already-created ConfigMap, Deployment, Service, and five named Traefik Middleware objects. It cannot create or delete workloads, read Secrets, or modify Traefik itself.

One-time CI setup

  1. Install the application manually with ./install.sh.

  2. With your administrator kubeconfig active, generate the restricted CI kubeconfig:

    ./create-ci-kubeconfig.sh
    

    The script applies ci-deployer.yaml, waits for Kubernetes to populate the service-account token, and prints one base64 line.

  3. Create the Gitea Actions repository secret KUBE_CONFIG_BASE64 and paste that line into it. Never add the output to a file in Git.

  4. Confirm KUBERNETES_API and KUBERNETES_TLS_SERVER_NAME in .gitea/workflows/deploy.yml match the networking seen by the runner.

  5. Protect the main branch. Merging to it changes the globally used error backend.

The committed ci-deployer.yaml is safe: it contains only RBAC declarations and an empty service-account-token Secret request. Kubernetes populates the actual credential only inside the cluster.

To revoke the CI credential:

kubectl --namespace default delete secret traefik-error-pages-deployer-token

Remove or replace KUBE_CONFIG_BASE64 in Gitea immediately afterward. Running ./create-ci-kubeconfig.sh again recreates a token and prints a replacement kubeconfig.

Making another cluster-specific configuration

Copy the generic values and edit only the override:

cp values.yaml values-my-cluster.yaml
./test.sh values-my-cluster.yaml

In practice, keep values.yaml as the reusable base and create a small override containing only branding and optional ForwardAuth settings, like values-brunner-ninja.yaml. Do not put API tokens, passwords, TLS keys, or kubeconfigs into a values file.

S
Description
This helm chart renders nicer cloudflare-like error pages in case the upstream service behind the traefik reverse proxy doesnt respond.
Readme GPL-3.0
66 KiB
Languages
Shell 85.4%
Go Template 14.6%