diff --git a/README.md b/README.md
index 03711926..975067ac 100644
--- a/README.md
+++ b/README.md
@@ -301,6 +301,8 @@ are detailed in the readme file below.
To proxy HTTP headers from requests to responses, utilize the `--proxy-headers` flag or environment variable
(comma-separated list of headers).
+### 🔌 Integrations with Traefik, Nginx, Kubernetes (and more)
+
🚀 Start the HTTP server with my custom template (theme)
@@ -583,6 +585,179 @@ defaultBackend:
+
+ 🚀 Kubernetes (K8s) & Ingress Traefik
+
+There are various ways to set up "error pages" in Kubernetes with Traefik. One of the most common scenarios is when
+you already have Traefik installed as an Ingress Controller with all the necessary CRDs. In this case, you still
+need to install the "error pages" as a separate service, register a middleware that will use it, and apply this
+middleware to all relevant routers.
+
+> To install Traefik using Helm, you may add the following lines to your `Chart.yaml` file:
+>
+> ```yaml
+> dependencies:
+> - name: traefik
+> version: 34.1.0 # change to the latest version
+> repository: https://helm.traefik.io/traefik
+> ```
+
+I prefer to install each component in a separate namespace and use Helm to manage the installation process. So
+before we begin, let's define the following settings in the `values.yaml` file:
+
+```yaml
+errorPages:
+ enabled: true
+ appName: error-pages
+ namespace: error-pages
+ version: 3.3.1 # https://github.com/tarampampam/error-pages/releases
+ themeName: shuffle
+```
+
+Next, create the following Helm chart templates:
+
+```yaml
+# file: error-pages/namespace.yaml
+
+{{ with .Values.errorPages }}
+{{- if .enabled }}
+apiVersion: v1
+kind: Namespace
+
+metadata: {name: "{{ .namespace }}"}
+{{- end }}
+{{- end }}
+```
+
+```yaml
+# file: error-pages/deployment.yaml
+
+{{ with .Values.errorPages }}
+{{- if .enabled }}
+apiVersion: apps/v1
+kind: Deployment
+
+metadata:
+ name: "{{ .appName }}"
+ namespace: {{ .namespace }}
+ labels: {app: "{{ .appName }}"}
+
+spec:
+ replicas: 1
+ selector: {matchLabels: {app: "{{ .appName }}"}}
+ template:
+ metadata: {labels: {app: "{{ .appName }}"}}
+ spec:
+ automountServiceAccountToken: false
+ containers:
+ - name: "{{ .appName }}"
+ image: "ghcr.io/tarampampam/error-pages:{{ .version | default "latest" }}"
+ env:
+ - {name: TEMPLATE_NAME, value: "{{ .themeName | default "app-down" }}"}
+ securityContext:
+ runAsNonRoot: true
+ runAsUser: 10001
+ runAsGroup: 10001
+ readOnlyRootFilesystem: true
+ ports:
+ - {name: http, containerPort: 8080, protocol: TCP}
+ livenessProbe:
+ httpGet: {port: http, path: /healthz}
+ periodSeconds: 10
+ readinessProbe:
+ httpGet: {port: http, path: /healthz}
+ periodSeconds: 10
+ resources:
+ limits: {memory: 64Mi, cpu: 200m} # change if needed
+ requests: {memory: 16Mi, cpu: 20m}
+{{- end }}
+{{- end }}
+```
+
+```yaml
+# file: error-pages/service.yaml
+
+{{ with .Values.errorPages }}
+{{- if .enabled }}
+apiVersion: v1
+kind: Service
+
+metadata:
+ name: {{ .appName }}-service
+ namespace: {{ .namespace }}
+ labels: {app: "{{ .appName }}"}
+
+spec:
+ type: ClusterIP
+ selector: {app: "{{ .appName }}"}
+ ports: [{name: http, protocol: TCP, port: 8080, targetPort: 8080}]
+{{- end }}
+{{- end }}
+```
+
+```yaml
+# file: error-pages/middleware.yaml
+
+{{ with .Values.errorPages }}
+{{- if .enabled }}
+apiVersion: traefik.io/v1alpha1
+kind: Middleware
+
+metadata:
+ name: {{ .appName }}
+ namespace: {{ .namespace }}
+
+spec: # https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#kind-middleware
+ errors:
+ status: ["401", "403", "404", "500-599"]
+ service: {name: "{{ .appName }}-service", port: 8080}
+ query: "/{status}.html"
+{{- end }}
+{{- end }}
+```
+
+If everything was configured correctly, you should see the new middleware in your Traefik dashboard:
+
+
+
+Since our middleware is in a separate namespace, and in Traefik >=2.5, cross-namespace references for resources
+like middlewares are restricted by default, we need to enable this feature. To do so, add the following lines to
+your Traefik Helm chart values:
+
+
+```diff
+ traefik:
+ # ...
+- globalArguments: []
++ globalArguments: ["--providers.kubernetescrd.allowCrossNamespace=true"]
+ # ...
+```
+
+Now, you can apply the middleware to the necessary ingress routes:
+
+```diff
+ apiVersion: traefik.io/v1alpha1
+ kind: IngressRoute
+
+ metadata:
+ name: some-app-http
+ namespace: some-app
+
+ spec: # https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#kind-ingressroute
+ entryPoints: [websecure]
+ routes:
+ - match: Host(`kube.iddqd.uk`) && PathPrefix(`/`)
+ services: [{name: "some-app-service", namespace: some-app, port: 8080}]
++ {{- with $.Values.errorPages }}{{ if .enabled }}
++ middlewares: [{name: "{{ .appName }}", namespace: "{{ .namespace }}"}]
++ {{- end }}{{ end }}
+```
+
+Although this approach is quite verbose, it allows for full control over the configuration. If you have a
+better alternative, feel free to submit a PR!
+
+
+
## 🦾 Performance
Hardware used: