Skip to content

필사 모드: The Complete Traefik Guide — IngressRoute, Middleware, and Dynamic Configuration

English
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

Introduction

When you run a Kubernetes cluster, you inevitably need an ingress point that routes external traffic to internal services. The standard Ingress resource alone struggles to express requirements like path rewriting, authentication, and rate limiting, and because each controller uses its own annotation syntax, portability suffers.

Traefik is a cloud-native edge router that solves these limitations through the concepts of dynamic configuration and middleware. Written in Go as a single binary, it watches multiple providers at once (Kubernetes CRDs, the standard Ingress, Docker, Consul, and more) and reconfigures routing rules in real time. There is no need to reload a config file or restart the process.

In this article, we will work through Traefik's core concepts, then explore IngressRoute CRDs, middleware chaining, automatic TLS with Let's Encrypt, the dashboard, and Traefik's relationship to the Gateway API, which has become the standard in 2026. We close with Helm deployment and the pitfalls you are likely to encounter.

This article is for the following readers.

- Those evaluating Traefik as an alternative to ingress-nginx on Kubernetes

- Those who want to escape the annotation hell of standard Ingress

- Those who want to manage automatic TLS and middleware chaining declaratively

- Those weighing a migration path from Ingress to the Gateway API

Traefik Architecture at a Glance

Traefik's routing model consists of four core objects. Once you understand the flow from an incoming request to a backend pod, the rest of the configuration becomes far easier.

Internet / external clients

|

v

+-------------------------------------------------+

| EntryPoint |

| (listens on :80 web / :443 websecure) |

+-------------------------------------------------+

|

v

+-------------------------------------------------+

| Router |

| rule match: Host(`app.example.com`) && Path |

| on match, hand off to the Middleware chain |

+-------------------------------------------------+

|

v

+-------------------------------------------------+

| Middleware chain (in order) |

| auth -> redirect -> ratelimit -> stripprefix |

+-------------------------------------------------+

|

v

+-------------------------------------------------+

| Service |

| load-balancing target (k8s Service / pods) |

+-------------------------------------------------+

|

v

backend Pod

EntryPoint

An EntryPoint is the network entry point where Traefik receives traffic. It is usually defined in the static configuration, specifying a port and protocol. By convention, port 80 is called web and port 443 is called websecure.

traefik.yml (static configuration)

entryPoints:

web:

address: ":80"

http:

redirections:

entryPoint:

to: websecure

scheme: https

permanent: true

websecure:

address: ":443"

http:

tls: {}

metrics:

address: ":9100"

In the example above, every HTTP request arriving on web is permanently redirected to websecure (HTTPS). Applying a global redirect at the EntryPoint level is a very common pattern.

Router

A Router defines the rules used to match incoming requests. You can combine various matchers such as Host, Path, Header, and Method using logical operators.

dynamic configuration example

http:

routers:

my-app:

rule: "Host(`app.example.com`) && PathPrefix(`/api`)"

entryPoints:

- websecure

middlewares:

- strip-api-prefix

service: my-app-service

tls:

certResolver: letsencrypt

The rule is expressed as a backtick-wrapped value. Priority is automatically computed based on rule length by default, but you can also set it explicitly with the priority field.

Middleware

Middleware is the stage that transforms requests or responses between the Router and the Service. Dozens of built-in middlewares are provided for authentication, header injection, path rewriting, rate limiting, compression, and more, and you can connect several of them into a chain. The order of the chain directly affects behavior, so designing the order carefully matters.

Service

A Service points to the actual backend and defines options such as the load-balancing strategy (weighted round robin), health checks, and sticky sessions. On Kubernetes it usually maps to a cluster Service resource.

Provider

A Provider is the source from which Traefik reads its configuration. The key point is that Traefik watches multiple providers simultaneously. In a Kubernetes environment you mainly use two.

| Provider | Description | Resources used |

| --- | --- | --- |

| kubernetesCRD | Based on Traefik-specific CRDs | IngressRoute, Middleware, etc. |

| kubernetesIngress | Handles the standard Ingress resource | Ingress, IngressClass |

| kubernetesGateway | Handles the Gateway API standard | Gateway, HTTPRoute |

enable providers in the static configuration

providers:

kubernetesCRD:

allowCrossNamespace: false

kubernetesIngress:

ingressClass: traefik

kubernetesGateway: {}

Ingress vs. IngressRoute CRD

This is the point that confuses Traefik newcomers the most. Both approaches route traffic, but they differ greatly in expressiveness and portability.

Limitations of Standard Ingress

The standard Ingress is an official Kubernetes resource, so it is highly portable, but the spec itself only standardizes host- and path-based routing. Every other advanced feature (rewriting, authentication, rate limiting, and so on) depends on controller-specific annotations.

apiVersion: networking.k8s.io/v1

kind: Ingress

metadata:

name: my-app

annotations:

traefik.ingress.kubernetes.io/router.middlewares: default-auth@kubernetescrd

traefik.ingress.kubernetes.io/router.entrypoints: websecure

spec:

ingressClassName: traefik

rules:

- host: app.example.com

http:

paths:

- path: /

pathType: Prefix

backend:

service:

name: my-app-service

port:

number: 80

As you can see, attaching middleware relies on annotation strings, and this syntax cannot be carried over to another controller as is. As of 2026 the standard Ingress API is frozen. In other words, no new features will be added, and the community's direction has shifted to the Gateway API.

IngressRoute CRD

IngressRoute is a CRD defined by Traefik that expresses routing rules, middleware, and TLS settings as explicit YAML fields instead of annotations.

apiVersion: traefik.io/v1alpha1

kind: IngressRoute

metadata:

name: my-app

namespace: default

spec:

entryPoints:

- websecure

routes:

- match: Host(`app.example.com`) && PathPrefix(`/api`)

kind: Rule

priority: 10

middlewares:

- name: api-auth

- name: strip-api-prefix

services:

- name: my-app-service

port: 80

tls:

certResolver: letsencrypt

The table below compares the two approaches.

| Aspect | Standard Ingress | IngressRoute CRD |

| --- | --- | --- |

| Portability | High (k8s standard) | Low (Traefik-only) |

| Middleware expression | Annotation strings | Native fields |

| Matching rules | Mostly host / path | Rich: Host, Header, Method |

| TCP / UDP routing | Not supported | IngressRouteTCP / UDP |

| Priority control | Limited | Explicit priority field |

| Future standard | Frozen | Tied to Traefik |

In short, if portability is the top priority, choose the standard Ingress or the Gateway API; if you want to use every Traefik feature, choose IngressRoute. That said, for a new project it is reasonable in 2026 to consider the Gateway API first, which we describe later.

Middleware Chaining in Practice

Middleware is Traefik's most powerful feature. You define each middleware as an independent CRD and reference them in order from an IngressRoute to build a chain. Let's look at four commonly used ones.

1. Basic Authentication (BasicAuth)

First create a Secret holding the credentials, then reference it from the middleware.

apiVersion: v1

kind: Secret

metadata:

name: dashboard-auth-secret

namespace: default

type: Opaque

stringData:

users: |

admin:$apr1$abcd1234$encryptedpasswordhash

apiVersion: traefik.io/v1alpha1

kind: Middleware

metadata:

name: api-auth

namespace: default

spec:

basicAuth:

secret: dashboard-auth-secret

removeHeader: true

The users value must be in the hash format generated by htpasswd. Setting removeHeader to true prevents the Authorization header from being forwarded to the backend after authentication.

2. Redirect (RedirectScheme / RedirectRegex)

You can force HTTP to HTTPS or send a specific path pattern elsewhere.

apiVersion: traefik.io/v1alpha1

kind: Middleware

metadata:

name: https-redirect

namespace: default

spec:

redirectScheme:

scheme: https

permanent: true

apiVersion: traefik.io/v1alpha1

kind: Middleware

metadata:

name: legacy-redirect

namespace: default

spec:

redirectRegex:

regex: "^https://old.example.com/(.*)"

replacement: "https://new.example.com/${1}"

permanent: true

3. Rate Limit

Limit the number of requests per second or minute to protect the backend. average is the allowed average rate and burst is the instantaneous allowance.

apiVersion: traefik.io/v1alpha1

kind: Middleware

metadata:

name: api-ratelimit

namespace: default

spec:

rateLimit:

average: 100

burst: 50

period: 1s

sourceCriterion:

ipStrategy:

depth: 1

sourceCriterion sets the basis for identifying the client. If you sit behind a proxy, configure ipStrategy.depth so the real client IP is extracted from the X-Forwarded-For header.

4. StripPrefix

When the backend expects the root path (/) but external clients access it under a specific prefix, strip the leading part of the path.

apiVersion: traefik.io/v1alpha1

kind: Middleware

metadata:

name: strip-api-prefix

namespace: default

spec:

stripPrefix:

prefixes:

- /api

forceSlash: false

When this middleware is applied, an external /api/users request is delivered to the backend as /users.

Building the Chain and Ordering

When you list multiple middlewares as an array in an IngressRoute, they are applied in that order. Getting the order wrong can produce unexpected behavior, so be careful.

apiVersion: traefik.io/v1alpha1

kind: IngressRoute

metadata:

name: secure-api

namespace: default

spec:

entryPoints:

- websecure

routes:

- match: Host(`api.example.com`)

kind: Rule

middlewares:

- name: https-redirect

- name: api-auth

- name: api-ratelimit

- name: strip-api-prefix

services:

- name: api-service

port: 8080

tls:

certResolver: letsencrypt

The chain above operates in the following order.

request

-> https-redirect (redirect to HTTPS if HTTP)

-> api-auth (verify authentication)

-> api-ratelimit (throttle request rate)

-> strip-api-prefix (remove path prefix)

-> api-service (forward to backend)

As a principle, place cheap middlewares that are likely to reject (redirect, authentication, rate limit) toward the front so unnecessary processing is cut off early. Put transformations such as path rewriting toward the back.

Automatic TLS — Let's Encrypt ACME

One of Traefik's appealing features is automatic certificate issuance and renewal via Let's Encrypt. It embeds the ACME protocol, so it works without a separate cert-manager.

ACME Challenge Types

ACME supports three challenges that prove domain ownership.

| Challenge | How it works | Wildcard certs |

| --- | --- | --- |

| HTTP-01 | Responds with a validation token on port 80 | Not supported |

| TLS-ALPN-01 | TLS handshake on port 443 | Not supported |

| DNS-01 | Validation via a DNS TXT record | Supported |

static configuration — HTTP-01 challenge

certificatesResolvers:

letsencrypt:

acme:

email: ops@example.com

storage: /data/acme.json

httpChallenge:

entryPoint: web

If you need a wildcard certificate, you must use the DNS-01 challenge. Inject the API token of your DNS provider (for example, Cloudflare or Route53) as an environment variable.

certificatesResolvers:

letsencrypt-dns:

acme:

email: ops@example.com

storage: /data/acme.json

dnsChallenge:

provider: cloudflare

resolvers:

- "1.1.1.1:53"

Because the acme.json file stores issued certificates and private keys, restrict its permissions to 600 and store it on a persistent volume (PVC). When the pod scales to several replicas, concurrent writes to the same file can collide, so in multi-replica environments it is safer to use cert-manager separately or to limit certificate issuance to a single instance.

Dashboard

Traefik currently provides a web dashboard that visually shows the state of routers, services, and middlewares. It is handy for quickly checking the live routing configuration.

enable the dashboard and API in the static configuration

api:

dashboard: true

insecure: false

Setting insecure to true exposes it without authentication, so you must never use that in production. Instead, expose the dashboard via an IngressRoute and protect it with a BasicAuth middleware.

apiVersion: traefik.io/v1alpha1

kind: IngressRoute

metadata:

name: traefik-dashboard

namespace: traefik

spec:

entryPoints:

- websecure

routes:

- match: Host(`traefik.example.com`)

kind: Rule

middlewares:

- name: dashboard-auth

services:

- name: api@internal

kind: TraefikService

tls:

certResolver: letsencrypt

Note that the service points to an internal TraefikService called api@internal. This is a special reference to Traefik's internal API handler.

Gateway API Support

As of 2026 the most important trend is the Gateway API. As mentioned, the standard Ingress is frozen, and the next-generation standard for Kubernetes networking has been settled as the Gateway API. The Gateway API provides role separation (infrastructure operators own the Gateway, app developers own the HTTPRoute) and rich routing expressiveness through standard CRDs.

Traefik is a conformant Gateway API implementation and processes the standard resources through the kubernetesGateway provider. In other words, you can obtain IngressRoute-level expressiveness as a standard without vendor lock-in.

apiVersion: gateway.networking.k8s.io/v1

kind: GatewayClass

metadata:

name: traefik

spec:

controllerName: traefik.io/gateway-controller

apiVersion: gateway.networking.k8s.io/v1

kind: Gateway

metadata:

name: traefik-gateway

namespace: traefik

spec:

gatewayClassName: traefik

listeners:

- name: web

protocol: HTTP

port: 80

- name: websecure

protocol: HTTPS

port: 443

tls:

mode: Terminate

certificateRefs:

- name: example-tls

apiVersion: gateway.networking.k8s.io/v1

kind: HTTPRoute

metadata:

name: my-app-route

namespace: default

spec:

parentRefs:

- name: traefik-gateway

namespace: traefik

hostnames:

- "app.example.com"

rules:

- matches:

- path:

type: PathPrefix

value: /api

backendRefs:

- name: my-app-service

port: 80

The table below summarizes where the three approaches stand.

| Approach | Standard? | Expressiveness | Recommended for |

| --- | --- | --- | --- |

| Standard Ingress | k8s standard (frozen) | Low | Simple routing, legacy |

| IngressRoute | Traefik-only | High | When you need Traefik features |

| Gateway API | k8s standard (evolving) | High | Recommended for new projects |

For now the Gateway API's middleware expressiveness may not be as rich as IngressRoute, so a transitional setup that mixes both approaches is common. In the long run, converging on the Gateway API is recommended.

Deployment in Practice — Helm values

In production it is common to deploy Traefik with the official Helm chart. The following is a values example frequently used in the field.

add the repository and install

helm repo add traefik https://traefik.github.io/charts

helm repo update

helm install traefik traefik/traefik \

--namespace traefik --create-namespace \

--values values.yaml

values.yaml

deployment:

replicas: 2

ingressClass:

enabled: true

isDefaultClass: true

providers:

kubernetesCRD:

enabled: true

allowCrossNamespace: false

kubernetesIngress:

enabled: true

kubernetesGateway:

enabled: true

ports:

web:

redirectTo:

port: websecure

websecure:

tls:

enabled: true

certificatesResolvers:

letsencrypt:

acme:

email: ops@example.com

storage: /data/acme.json

httpChallenge:

entryPoint: web

persistence:

enabled: true

size: 128Mi

path: /data

dashboard:

enabled: true

resources:

requests:

cpu: 100m

memory: 128Mi

limits:

cpu: 500m

memory: 256Mi

logs:

general:

level: INFO

access:

enabled: true

After installation, check the state with the following commands.

kubectl get pods -n traefik

kubectl get svc -n traefik

kubectl logs -n traefik deploy/traefik --tail=100

Operations and Tuning

Access Logs and Metrics

In production, write access logs in JSON format and enable Prometheus metrics to secure observability.

metrics:

prometheus:

entryPoint: metrics

addEntryPointsLabels: true

addServicesLabels: true

accessLog:

format: json

filters:

statusCodes:

- "400-499"

- "500-599"

Using the statusCodes filter logs only 4xx and 5xx responses, reducing log volume.

Health Checks and Probes

Traefik's own readiness and liveness probes are configured through the ping EntryPoint.

ping:

entryPoint: web

Timeout Tuning

If you handle long-lived connections or large uploads, adjust the transport timeouts of the EntryPoint.

entryPoints:

websecure:

address: ":443"

transport:

respondingTimeouts:

readTimeout: 60s

writeTimeout: 60s

idleTimeout: 180s

Pitfalls and Troubleshooting

Here are the problems you will frequently run into in operations.

1. 404 or the Router Does Not Match

The most common cause is a missing EntryPoint specification. If you do not specify entryPoints on an IngressRoute, it may be exposed on every EntryPoint, or traffic may not arrive on the intended port. First check in the dashboard whether the router is registered and whether the rule is correct.

query router state via the API

kubectl port-forward -n traefik deploy/traefik 8080:8080

curl http://localhost:8080/api/http/routers

2. Middleware Not Found

To reference a middleware in another namespace, you must specify the namespace. In the annotation-based approach for an IngressRoute, you use the form name-namespace@kubernetescrd. Also, if allowCrossNamespace is false, cross-namespace references are blocked.

3. Certificate Is Not Issued

The HTTP-01 challenge requires port 80 to be reachable from the outside. Check your firewall or load balancer settings. If the acme.json file permissions are not 600, Traefik will reject it. Also, sharing the same acme.json across multiple replicas can tangle issuance.

4. Backend Breaks After StripPrefix

If the backend application references static resources by absolute path, links can break after the prefix is stripped. In that case configure a base path in the application, or handle the path more precisely with the replacePathRegex middleware.

5. The Real Client IP Is Not Visible

When you sit behind a cloud load balancer, only the LB's IP may appear in rate limits or logs. Configure forwardedHeaders.trustedIPs and adjust the rate limit middleware's ipStrategy.depth to match your environment.

entryPoints:

websecure:

address: ":443"

forwardedHeaders:

trustedIPs:

- "10.0.0.0/8"

- "172.16.0.0/12"

Closing

Traefik is a powerful tool that bundles dynamic configuration, middleware, and automatic TLS so you can operate Kubernetes ingress declaratively. The IngressRoute CRD frees you from the annotation hell of standard Ingress, but it comes at the cost of vendor lock-in.

As of 2026 the standard Ingress is frozen and the Gateway API has settled in as the next-generation standard. Because Traefik officially supports the Gateway API, for a new project it is realistic to consider the Gateway API first while still using IngressRoute where you need Traefik's middleware ecosystem. If you understand the core concepts accurately (EntryPoint, Router, Middleware, Service, Provider), you can operate confidently no matter which approach you choose.

References

- [Traefik Official Documentation](https://doc.traefik.io/traefik/)

- [Traefik Kubernetes IngressRoute Guide](https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/)

- [Traefik Helm Charts](https://github.com/traefik/traefik-helm-chart)

- [Kubernetes Ingress Concepts](https://kubernetes.io/docs/concepts/services-networking/ingress/)

- [Gateway API Official Documentation](https://gateway-api.sigs.k8s.io/)

- [Let's Encrypt Documentation](https://letsencrypt.org/docs/)

- [cert-manager Documentation](https://cert-manager.io/docs/)

- [Helm Official Documentation](https://helm.sh/docs/)

- [ingress-nginx Documentation](https://kubernetes.github.io/ingress-nginx/)

현재 단락 (1/441)

When you run a Kubernetes cluster, you inevitably need an ingress point that routes external traffic...

작성 글자: 0원문 글자: 17,603작성 단락: 0/441