Traefik 文档 Traefik 文档。内容保持上游原样。 Content What is Traefik? Traefik is an open-source Application Proxy and the core of the Traefik Hub Runtime Platform. If you start with Traefik for service discovery and routing, you can seamlessly add API management, API gateway, AI gateway, and API mocking capabilities as needed. For a detailed comparison of all Traefik products and their capabilities, see our Product Features Comparison. With 3.3 billion downloads and over 55k stars on GitHub, Traefik is used globally across hybrid cloud, multi-cloud, on prem, and bare metal environments running Kubernetes, Docker Swarm, AWS, the list goes on. Here’s how it works—Traefik receives requests on behalf of your system, identifies which components are responsible for handling them, and routes them securely. It automatically discovers the right configuration for your services by inspecting your infrastructure to identify relevant information and which service serves which request. Because everything happens automatically, in real time (no restarts, no connection interruptions), you can focus on developing and deploying new features to your system, instead of configuring and maintaining its working state. !!! quote "From the Traefik Maintainer Team" When developing Traefik, our main goal is to make it easy to use, and we're sure you'll enjoy it. Personas Traefik supports different needs depending on your background. We keep three user personas in mind as we build and organize these docs: Beginners: You are new to Traefik or new to reverse proxies. You want simple, guided steps to set things up without diving too deep into advanced topics. DevOps Engineers: You manage infrastructure or clusters (Docker, Kubernetes, or other orchestrators). You integrate Traefik into your environment and value reliability, performance, and streamlined deployments. Developers: You create and deploy applications or APIs. You focus on how to expose your services through Traefik, apply routing rules, and integrate it with your development workflow. Core Concepts Traefik’s main concepts help you understand how requests flow to your services: Entrypoints are the network entry points into Traefik. They define the port that will receive the packets and whether to listen for TCP or UDP. Routers are in charge of connecting incoming requests to the services that can handle them. In the process, routers may use pieces of middleware to update the request or act before forwarding the request to the service. Services are responsible for configuring how to reach the actual services that will eventually handle the incoming requests. Providers are infrastructure components, whether orchestrators, container engines, cloud providers, or key-value stores. The idea is that Traefik queries the provider APIs in order to find relevant information about routing, and when Traefik detects a change, it dynamically updates the routes. These concepts work together to manage your traffic from the moment a request arrives until it reaches your application. How to Use the Documentation Navigation: Each main section focuses on a specific stage of working with Traefik - installing, exposing services, observing, extending & migrating. Use the sidebar to navigate to the section that is most appropriate for your needs. Practical Examples: You will see code snippets and configuration examples for different environments (YAML/TOML, Labels, & Tags). Reference: When you need to look up technical details, our reference section provides a deep dive into configuration options and key terms. !!! info Have a question? Join our [Community Forum](https://community.traefik.io "Link to Traefik Community Forum") to discuss, learn, and connect with the Traefik community. Using Traefik OSS in production? Consider upgrading to our API gateway ([watch demo video](https://info.traefik.io/watch-traefik-api-gw-demo)) for better security, control, and 24/7 support. Just need support? Explore our [24/7/365 support for Traefik OSS](https://info.traefik.io/request-commercial-support?cta=doc). Advocating Spread the Love & Tell Us About It {: .subtitle } Traefik Proxy was started by the community and for the community. You can contribute to the Traefik community in three main ways: Spread the word! Guides, videos, blog posts, how-to articles, and showing off your network design all help spread the word about Traefik Proxy and teach others in the community how to best implement it. It always sparks joy when users share how Traefik Proxy helps them solve their problems. If you are talking about Traefik Proxy, let us know and we will promote your work and reward your enthusiasm! If you are giving a talk that includes or is about Traefik Proxy, let us know and we will send you swag and stickers for your time at the conference. If you have written about Traefik or shared useful information you would like to promote, feel free to add links to the dedicated wiki page on GitHub. Help community members! Everyone needs a place to share their cool innovations or get help with that pesky bug that only a different pair of eyes seems to be able to see. Join our Community Forum where you can ask questions, help out other users, and share your neat configuration examples or snippets. Top contributors will be asked to join the Ambassador program and get unique swag to celebrate! Build cool solutions! Traefik Proxy would be so much better if only it had… We love all the wonderful ideas that our users come up with, but we can only build so much. Luckily, as an open source community, our users can help by building awesome features, enhancements, or bug fixes. We are a big community, so we do need to prioritize a bit. That is why we use the tag contributor/wanted to let you know which pull requests will make it to the front of the queue for design support and review. Feel free to grab one of these and run with it. Top contributors get unique swag to celebrate. Building and Testing Compile and Test Your Own Traefik! {: .subtitle } You want to build your own Traefik binary from the sources? Let's see how. Building You need: - Docker - make - Go - misspell - shellcheck - Tailscale if you are using Docker Desktop !!! tip "Source Directory" It is recommended that you clone Traefik into the `~/go/src/github.com/traefik/traefik` directory. This is the official golang workspace hierarchy that will allow dependencies to be properly resolved. !!! note "Environment" Set your `GOPATH` and `PATH` variable to be set to `~/go` via: ```bash export GOPATH=~/go export PATH=$PATH:$GOPATH/bin ``` For convenience, add `GOPATH` and `PATH` to your `.bashrc` or `.bash_profile` Verify your environment is setup properly by running `$ go env`. Depending on your OS and environment, you should see an output similar to: ```bash GOARCH="amd64" GOBIN="" GOEXE="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOOS="linux" GOPATH="/home//go" GORACE="" ## ... and the list goes on ``` Build Traefik Once you've set up your go environment and cloned the source repository, you can build Traefik. $ make binary SHA: 8fddfe118288bb5280eb5e77fa952f52def360b4 cheddar 2024-01-11_03:14:57PM CGO_ENABLED=0 GOGC=off GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w \ -X github.com/traefik/traefik/v2/pkg/version.Version=8fddfe118288bb5280eb5e77fa952f52def360b4 \ -X github.com/traefik/traefik/v2/pkg/version.Codename=cheddar \ -X github.com/traefik/traefik/v2/pkg/version.BuildDate=2024-01-11_03:14:57PM" \ -installsuffix nocgo -o "./dist/darwin/arm64/traefik" ./cmd/traefik $ ls dist/ traefik* You will find the Traefik executable ( traefik) in the ./dist directory. Testing Run unit tests using the test-unit target. Run integration tests using the test-integration target. Run all tests (unit and integration) using the test target. $ make test-unit GOOS=darwin GOARCH=arm64 go test -cover "-coverprofile=cover.out" -v ./pkg/... ./cmd/... + go test -cover -coverprofile=cover.out . ok github.com/traefik/traefik 0.005s coverage: 4.1% of statements Test success For development purposes, you can specify which tests to run by using (only works the test-integration target): ??? note "Configuring Tailscale for Docker Desktop user" Create `tailscale.secret` file in `integration` directory. This file needs to contain a [Tailscale auth key](https://tailscale.com/kb/1085/auth-keys) (an ephemeral, but reusable, one is recommended). Add this section to your tailscale ACLs to auto-approve the routes for the containers in the docker subnet: ```json "autoApprovers": { // Allow myself to automatically // advertize routes for docker networks "routes": { "172.31.42.0/24": ["your_tailscale_identity"], }, }, ``` # Run every tests in the MyTest suite TESTFLAGS="-test.run TestAccessLogSuite" make test-integration # Run the test "MyTest" in the MyTest suite TESTFLAGS="-test.run TestAccessLogSuite -testify.m ^TestAccessLog\$\$" make test-integration Data Collection Understanding the data Traefik shares and how it is used {: .subtitle } Introduction Protecting user privacy is essential to Traefik Labs, and we design every data-sharing mechanism with transparency and minimalism in mind. This page describes the two types of data exchanged by Traefik and how to configure them. For more details on how your data is handled, please refer to our Privacy and Cookie Policy. Configuration Overview Traefik provides two independent mechanisms: checkNewVersion, enabled by default. You may disable it at any time. sendAnonymousUsage, which requires explicit opt‑in. Examples below show how to activate or deactivate both of them. global: checkNewVersion: true # set to false to disable sendAnonymousUsage: false # set to true to enable [global] checkNewVersion = true # set to false to disable sendAnonymousUsage = false # set to true to enable --global.checkNewVersion=true # set to false to disable --global.sendAnonymousUsage=false # set to true to enable A log message at startup clearly indicates whether each of those options are enabled or disabled. Version Check ( checkNewVersion) – Opt-out Traefik periodically contacts update.traefik.io to determine whether a newer version is available. When this request is made, Traefik shares the running version and the public IP of the instance. The IP is used to build global usage statistics and does not influence the version comparison. This mechanism helps you stay informed about updates and provides TraefikLabs with a broad view of which versions are deployed in the wild. The collected IP addresses are also used for marketing purposes, specifically to detect companies running Traefik and offer them adapted support contracts, enterprise features, and tailored services. If you want to explore the implementation, you can read the version check source code: version.go Anonymous Usage Data ( sendAnonymousUsage) – Opt‑in Traefik can also collect anonymous usage statistics once per day, starting 10 minutes after it starts running. These statistics include: the Traefik version, a hash of the configuration, an anonymized version of the static configuration (all sensitive fields removed: tokens, passwords, URLs, IP addresses, domains, emails, etc.). This feature comes from this public proposal. This information helps TraefikLabs understand how Traefik is used in general and prioritize features and provider support accordingly. Dynamic configuration (routers and services) is never collected. !!! example "Enabling Data Collection" ```yaml tab="File (YAML)" global: # Send anonymous usage data sendAnonymousUsage: true ``` ```toml tab="File (TOML)" [global] # Send anonymous usage data sendAnonymousUsage = true ``` ```bash tab="CLI" # Send anonymous usage data --global.sendAnonymousUsage ``` !!! info - We do not collect the dynamic configuration information (routers & services). - We do not collect this data to run advertising programs. - We do not sell this data to third-parties. Example of Collected Data entryPoints: web: address: ":80" api: {} providers: docker: endpoint: "tcp://10.10.10.10:2375" exposedByDefault: true tls: ca: dockerCA cert: dockerCert key: dockerKey insecureSkipVerify: true entryPoints: web: address: ":80" api: {} providers: docker: endpoint: "xxxx" exposedByDefault: true tls: ca: xxxx cert: xxxx key: xxxx insecureSkipVerify: true The Code for Anonymous Usage Collection If you want to explore the implementation, you can read the collector source code: collector.go Traefik anonymizes all configuration fields by default, except those explicitly marked with export=true. Documentation Style Guide This guide covers how to write and edit pages under docs/content/. It is written for contributors and for the AI assistants they use. Follow it for new pages and for any lines you change. Existing pages may not follow every rule. Don't copy a pattern from a neighboring page when it contradicts this guide, and don't fix unrelated lines in the same pull request. When following a rule would make the text less accurate or less clear, accuracy wins. Say why in the pull request. Write Clearly Voice Use active voice and simple present tense. Use the imperative in procedures: "Set address to :80", not "You should set address to :80". Address the reader as "you". Guides can use "we" when walking through a procedure together ("we'll create a cluster"). Make the reader the subject, not the page or the product. Describe what the reader can do or must do, and don't describe what the page does. Avoid: "This page allows you to attach a middleware to a router." Prefer: "You can attach a middleware to a router to change requests before they reach a service." Omit "please". Replace "should" with a direct statement. Write "click Save", not "click on Save". Use simple words. Use technical terms only when they are standard for the technology ( TLS, mTLS, CIDR) or appear in Traefik's configuration or reference docs. Explain any other shorthand on first use. Don't give human characteristics to software ("Traefik wants", "the router decides"). Don't include customer names or customer-specific details. Generalize the use case or leave it out. Don't state how a third-party service behaves (what it accepts, rejects, or requires) unless that service's documentation or the source says so. The source shows what Traefik sends, not how an external service responds. Link to the third party's documentation instead. When the source supports a vendor-specific behavior, write the general condition first and the vendor as the example: "If your identity provider returns no groups, as ExampleIdP does, ...". Numbers Spell out one through ten in prose. Use numerals for 11 and above. Always use numerals for values, versions, ports, and numbers with units: maxBodySize: 5, HTTP/2, port 80, 5 MB. Don't state how many items a list or table on the page contains ("the following three options"). The count goes stale when the list changes. Limits the product defines ("up to 100 routers") are fine. Words and Phrases to Avoid Swap for a plain word: Avoid Write leverage, utilize, harness use facilitate help, let, enable In order to To Furthermore, Moreover, Additionally Also Could potentially can, might Prior to this release Before v3.4 Delete, and keep the rest of the sentence. The sentence reads correctly without them: cutting-edge, innovative, In conclusion, To summarize, As mentioned above. Replace with the specific fact. These words describe nothing, so rewrite the sentence with the concrete detail: Avoid: "A robust, seamless integration with Consul." Prefer: "Traefik reads services from Consul Catalog and updates routes when services change." Avoid: "Powerful middleware lets you streamline authentication." Prefer: "The forwardAuth middleware sends each request to your authentication service before it reaches a backend." Avoid: "This empowers you to control traffic." Prefer: "You can limit requests per client with the rateLimit middleware." This applies to: streamline, robust, comprehensive, powerful, seamless, seamlessly, empower, delve into. Also avoid these constructions: Em dashes as connectors. Split into two sentences, or join with "so", "and", or "but". Don't swap the dash for a semicolon or colon. Rhetorical questions ("But what if you need X?"). Write a statement. Dramatic framing ("This changes everything"). State the fact. Contrast framing ("It's not just a proxy, it's a platform"). State the positive claim. A negation is fine when it names a wrong value the reader might choose: "Set the timeout in seconds, not milliseconds." Absolutes ("never X, even when Y"). State the rule and keep the condition the source gives. This doesn't apply to security warnings and !!! danger content, which keep their explicit form: "Never expose the dashboard without authentication." Clarity Rules Name the concrete noun. Replace "this", "it", "the same", "both", and "these" with the thing they point to when the noun isn't in the same sentence. Every table row must make sense on its own. Name the exact option when you mean the option. Write entryPoints when you refer to the option, and "entry point" when you explain the concept. Write "identifier", not "ID", in prose. Use id only for a literal field, and keep standard or UI names as they are ("Client ID", "Trace ID"). Give a concrete recommendation. Replace "use a smaller timeout" with "Set idleTimeout to a lower value, for example 3s." Use only options and values the source or reference docs show. Make every sentence in a procedure change what the reader does. Each sentence gives an action, a value to use, or the result of an action. This doesn't apply to option descriptions, warnings, concept and reference pages, introductions, and callouts. Don't claim a capability without the way to use it. "You can verify each entry" needs the steps or a link in the same section. Document each case separately when behavior differs by state, or by the value of another option. List the value for each sub-option by name. Document a trade-off option by its trade-off. Say what it does, when to use it, and the risk of leaving it on. Put a caveat directly after the option, step, or example it qualifies. Put a prerequisite before the action that needs it. Lead exceptions with the action. Write "Set x for y. Without it, ..." and then the explanation. Don't refer to position. Avoid "above", "below", and "as shown earlier". Name the section or option instead. Readers often land mid-page from a search result. Don't narrate code. Explain why a step matters, not what a readable block of code does. Use a worked example as an example. Say "using a payments API as the example", so readers don't take the scenario as the limit of the feature. Keep setup details out of a concept introduction. Option names and values belong in Prerequisites or the reference page. State version-specific behavior only for versions you verified. Omit "Starting in vX" when the whole page requires vX. A single option added in a later version keeps its note. This doesn't apply to migrate and deprecation pages or to security advisories, where the version is the content. Terminology Write install configuration and routing configuration. Don't write "static configuration" or "dynamic configuration" in new text. Older pages use both pairs of terms, so leave a term unchanged when it is part of a quoted option name or a URL. Write Traefik Proxy on first mention on a page and Traefik afterward. Use one name per concept across pages. Search neighboring pages and the pages you link to for an existing term before you introduce a name, and define it on first use on each page. Use each provider's own name (Docker, Consul Catalog, Kubernetes Gateway API, IngressRoute). Don't abbreviate them in prose. Page Types Put new content in the existing sections. Don't add a top-level section. Section Contains getting-started, setup First-run and installation walkthroughs expose How-to guides for exposing services on a platform secure, observe Task guides and overviews for a feature area reference One page per option group, middleware, router, service, or provider migrate, deprecation Version migration and deprecation notices security Security advisories Reference Pages Reference pages have no body H1. They start with the description sentence. Use these sections, in this order, when they apply: Configuration Examples. One example per supported format. Configuration Options. A table of options. Guide Pages Guides start with a body H1 that names the task. Use this order: A short introduction: what the reader accomplishes, and when to do it. Prerequisites. For a prerequisite whose absence causes a visible failure, state what the reader sees. One H2 per step or task, named with a verb ("Create the Cluster"). A closing paragraph that states the outcome, then links to related pages. Don't restate the steps. State the expected result at the end of each major step. When a step is backed by an example with its own identifier (a Kubernetes metadata.name), that identifier carries the step's number, and so does every later reference to that step. Titles and Headings Use Title Case for every heading and every page title, including a heading you add to a page whose other headings use another case. Capitalize the first and last word and every major word. Lowercase articles, conjunctions, and short prepositions (a, an, the, and, but, or, for, in, of, on, to, with) unless they are the first or last word. Keep code, option names, acronyms, and error messages exactly as written: entryPoints, HTTP, connection refused. Name a task with a verb: "Configure Sticky Sessions". Name a reference section after its topic using the product's own term: "Certificate Resolver". Don't phrase a heading as a question, or as the reader's discovery ("Find Out What Went Wrong"). Use "Troubleshoot Failed Requests". Title a troubleshooting entry with the symptom or the exact error message. Reference page titles in frontmatter follow the existing pattern: Traefik Documentation. Make each section understandable without the sections around it. Formatting Frontmatter Use title and description only. Write the description as one sentence that says what the page covers, for search results. Code Blocks and Tabs Show every format the feature supports for a configuration example, and make sure each format produces the same configuration. Label tabs with these names, in this order: Install configuration: File (YAML), File (TOML), CLI, Helm Chart Values. Routing configuration: Structured (YAML), Structured (TOML), Labels, Tags, Kubernetes. Include only the formats the provider supports. Use the tab syntax in the build guide: a tab="Label" attribute on the code fence. Put explanation in comments inside the example, once per example, in the formats that support comments. Don't narrate the example in the paragraph around it. Use yaml, toml, bash, or text as the fence language. Don't leave a fence without a language. Option Tables Use the columns Field, Description, Default, and Required. Use Value instead of Default and Required for a table that lists fixed values. Link each field name to its own anchor so readers can link to a single option. Describe each option with what it does, its expected format, and an example value. State what happens when the option is unset. Write "Traefik doesn't compress responses", not "the default configuration". When a field is conditional, state when it is required or applies. Sort a long table alphabetically. Don't use table headers that address the reader ("Tells you"). Use neutral labels ("Contains", "Effect"). When you extend a table, write out every row. Never abbreviate existing rows with "..." or "etc." Don't follow a table with a list that groups the same rows differently. Add a column instead. Avoid tables that need horizontal scrolling. Split them or use a list. Callouts Prose is the default. Add a callout only when the information would be lost in the body text. Use !!! note for extra details or alternatives, !!! warning for restrictions that cause errors if missed, !!! tip for shortcuts, and !!! info for background. Give each callout a title when the type alone doesn't say enough. If a callout explains why an instruction matters, merge it into the instruction. Never stack two callouts. Put body text between them, or fold one into prose. ??? example is a collapsible container for a long, optional example. It is not an attention callout, so the limits above don't apply to it. Links Name the destination in the link text. Never write "here" or "this link". Use relative paths to the .md file: [HTTP Routers](../routing/router.md). Link to a page only when it exists on the branch you target. If it doesn't exist yet, use plain text and note the missing link in your pull request. After you move or rename a page, add a redirect to mkdocs.yml. Screenshots and Media Use text to instruct. A screenshot supports the text and never replaces it. Write alt text and a supporting sentence for each screenshot. Use as few screenshots as you can. Name the control ("click Settings"). Don't describe its position ("the button on the left"). Diagrams Avoid adding diagrams. Add one only when a new feature is documented noticeably better with it. In that case: Save the image in docs/content/assets/img/ as PNG, or as SVG if your tool exports it cleanly. Say in the pull request where the editable source file is, so maintainers can update it. Reference it with a relative path and Markdown image syntax: ![Request Flow Through Entry Points, Routers, and Services](../assets/img/request-flow.png). Write alt text that states what the diagram shows. Don't write "diagram of". Introduce the diagram with one sentence that uses the same labels as the diagram. Put every fact the diagram carries in the text as well, because a reader using a screen reader or search can't read an image. Don't redraw a flow that another page already diagrams. Link to that page, or verify every arrow against the source. Generated Files Don't edit these files by hand. A build step overwrites them: reference/install-configuration/configuration-options.md reference/dynamic-configuration/traefik.io_*.yaml and kubernetes-crd-definition-v1.yml To change an option description in the generated reference, change the comment on the Go struct field and run make generate. The CI check fails if generation leaves uncommitted changes. Before You Open a Pull Request Verify every claim against the source code or the third party's documentation. Don't add an error message, default, or value you haven't confirmed, and don't publish behavior you haven't confirmed. Check that every link and anchor resolves. Run the docs build with mkdocs build --strict and the markdown lint, as described in the contributing guide. Target the right branch: master for new features, and the maintenance branch for the release for fixes. Don't backport your own change. Declare substantial AI assistance with an Assisted-by: trailer. Documentation Features Are Better When You Know How to Use Them {: .subtitle } You've found something unclear in the documentation and want to give a try at explaining it better? Let's see how. Building Documentation General This documentation is built with MkDocs. Method 1: Docker and make Please make sure you have the following requirements installed: Docker You can build the documentation and test it locally (with live reloading), using the docs-serve target: $ make docs-serve docker build -t traefik-docs -f docs.Dockerfile . # […] docker run --rm -v /home/user/go/github/traefik/traefik:/mkdocs -p 8000:8000 traefik-docs mkdocs serve # […] [I 170828 20:47:48 server:283] Serving on http://0.0.0.0:8000 [I 170828 20:47:48 handlers:60] Start watching changes [I 170828 20:47:48 handlers:62] Start detecting changes !!! tip "Default URL" Your local documentation server will run by default on . If you only want to build the documentation without serving it locally, you can use the following command: $ make docs-build ... Method 2: MkDocs Please make sure you have the following requirements installed: Python pip $ python --version Python 2.7.2 $ pip --version pip 1.5.2 Then, install MkDocs with pip. pip install --user -r requirements.txt To build the documentation locally and serve it locally, run mkdocs serve from the root directory. This will start a local server. $ mkdocs serve INFO - Building documentation... INFO - Cleaning site directory [I 160505 22:31:24 server:281] Serving on http://127.0.0.1:8000 [I 160505 22:31:24 handlers:59] Start watching changes [I 160505 22:31:24 handlers:61] Start detecting changes Check the Documentation To check that the documentation meets standard expectations (no dead links, html markup validity, ...), use the docs-verify target. $ make docs-verify docker build -t traefik-docs-verify ./script/docs-verify-docker-image ## Build Validator image ... docker run --rm -v /home/travis/build/traefik/traefik:/app traefik-docs-verify ## Check for dead links and w3c compliance === Checking HTML content... Running ["HtmlCheck", "ImageCheck", "ScriptCheck", "LinkCheck"] on /app/site/basics/index.html on *.html... !!! note "Clean & Verify" If you've made changes to the documentation, it's safer to clean it before verifying it. ```bash $ make docs ... ``` Will perform all necessary steps for you. !!! note "Disabling Documentation Verification" Verification can be disabled by setting the environment variable `DOCS_VERIFY_SKIP` to `true`: ```shell DOCS_VERIFY_SKIP=true make docs-verify ... DOCS_LINT_SKIP is true: no linting done. ``` Maintainer's Guidelines Welcome to the Traefik Community. We are strongly promoting a philosophy of openness and sharing, and firmly standing against the elitist closed approach. Being part of the core team should be accessible to anyone motivated and wants to be part of that journey! Becoming a Maintainer Before a contributor becomes a maintainer, they should meet the following requirements: The contributor enabled 2FA on their GitHub account The contributor showed a consistent pattern of helpful, non-threatening, and friendly behavior towards other community members in the past. The contributor has read and accepted the maintainer's guidelines. The contributor should also meet one or several of the following requirements: The contributor has opened and successfully run medium to large PR’s in the past 6 months. The contributor has participated in multiple code reviews of other PR’s, including those of other maintainers and contributors. The contributor is active on Traefik Community forums or other technical forums/boards, such as K8S Slack, Reddit, StackOverflow, and Hacker News. Any existing active maintainer can create an issue to discuss promoting a contributor to maintainer. Other maintainers can vote on the issue, and if the quorum is reached, the contributor is promoted to maintainer. If the quorum is not reached within one month after the issue is created, it is closed. Maintainer's Responsibilities and Privileges As a maintainer, you are granted a vote for the following: PR review. Design review. Proposals. Maintainers are also added to the maintainer's Discord server where happens the issue triage and appear on the Maintainers page. As a maintainer, you should: Prioritize PR reviews, design reviews, and issue triage above any other task. Making sure contributors and community members are listened to and have an impact on the project is essential to keeping the project active and develop a thriving community. Prioritize helping contributors reaching the expecting quality level over rewriting contributions. Any triage activity on issues and PRs (e.g. labels, marking messages as off-topic, refusing, marking duplicates) should result from a collective decision to ensure knowledge is shared among maintainers. Communicating All of our maintainers are added to the Traefik Maintainers Discord server that belongs to Traefik labs. Having the team in one place helps us to communicate effectively. Maintainers can discuss issues, pull requests, enhancements more efficiently and get the feedback almost immediately. Fewer blockers mean more fun and engaging work. Every decision made on the discord server among maintainers is documented so it's visible to the rest of the community. Maintainers express their opinions on issues and reviews. It is fine to have different point of views. We encourage active and open conversations which goals are to improve Traefik. When discussing issues and proposals, maintainers should share as much information as possible to help solve the issue. Maintainers Activity In order to keep the core team efficient and dynamic, maintainers' activity and involvement will be reviewed on a regular basis. Has the maintainer engaged with the team and the community by meeting two or more of these benchmarks in the past six months? Has the maintainer participated in at least two or three maintainer meetings? Substantial review of at least one or two PRs from either contributors or maintainers. Opened at least one or two bug fixes or feature request PRs that were eventually merged (or on a trajectory for merge). Substantial participation in the Help Wanted program (answered questions, helped identify issues, applied guidelines from the Help Wanted guide to open issues). Substantial participation with the community in general. Has the maintainer shown a consistent pattern of helpful, non-threatening, and friendly behavior towards other people on the maintainer team and with our community? Additional Comments for Maintainers (that should apply to any contributor) Be respectful with other maintainers and other community members. Be open minded when participating in conversations: try to put yourself in others’ shoes. Keep the communication public - if anyone tries to communicate with you directly, ask politely to move the conversation to a public communication channel. Stay away from defensive comments. Please try to express your thoughts clearly enough and note that some of us are not native English speakers. Try to rephrase your sentences, avoiding mental shortcuts; none of us is able to predict anyone's thoughts. Be proactive. Emoji are fine, but if you express yourself clearly enough they are not necessary. They will not replace good communication. Embrace mentorship: help others grow and match the quality level we strive for. Keep in mind that we all have the same goal: improve the project. Maintainers Active Maintainers Emile Vauge @emilevauge Manuel Zapf @SantoDE Julien Salleyron @juliens Nicolas Mengin @nmengin Michaël Matur @mmatur Gérald Croës @geraldcroes Romain Tribotté @rtribotte Kevin Pollet @kevinpollet Harold Ozouf @jspdown Tom Moulard @tommoulard Landry Benguigui @lbenguigui Simon Delicata @sdelicata Baptiste Mayelle @youkoulayley Jesper Noordsij @jnoordsij Gina Adzani @gndz07 Mathis Urien @LBF38 Kangmin Kim @amazon7737 Nándor Kollár @nandorKollar Past Maintainers People who have had an incredibly positive impact on the project, and are now focusing on other projects. Vincent Demeester @vdemeester Ed Robinson @errm Daniel Tomcej @dtomcej Timo Reimann @timoreimann Marco Jantke @mjantke Ludovic Fernandez @ldez Jean-Baptiste Doumenjou @jbdoumenjou Mathieu Lonjaret @mpl Maintainer's Guidelines Please read the maintainer's guidelines. Security Decisions Some classes of report reach us repeatedly. This page records the positions we have already settled, so that you can check a finding against them before submitting, and so that we can answer with a reference instead of a fresh analysis. It is organised by the surface a report touches. Each entry states our position, then where the line is: the neighbouring variant we do treat as a vulnerability, with the advisories that prove it. That line is the useful part. Almost every surface below has produced both closures and CVEs. This page applies the threat model, which defines the boundary itself. Start there if you want the short version. !!! note "Why only some cases are linked" We reference published advisories only. Reports closed as not-a-vulnerability stay private to the reporter and the security team, so declined classes are described as rules rather than linked. Where a class has produced a CVE, it is cited: that is the evidence the line is real rather than a way of declining work. Path Handling, Normalization and Encoding What is usually reported. A crafted path ( %2e%2e, %2f, double encoding, a literal ; or backslash, a fragment) traverses or escapes a prefix and reaches a route or backend that a middleware was expected to protect. Our position. This is our most productive surface and we treat it seriously. A normalization or encoding differential that reaches the backend with stock entrypoint defaults is a vulnerability, including when it only manifests as a desynchronisation between the decoded and raw forms of the path. Where the line is. We decline variants whose escape depends on the operator having widened handling, or on one backend's own re-interpretation of a character the standard permits: The escape works only with encoded-character handling left permissive. That default is a deliberate, documented compatibility decision, revisited only at a major version. The vector is a character RFC 3986 permits in a path segment, such as a literal ; or a backslash, and the escape exists only because a given backend re-interprets it. That re-interpretation varies by backend and is the backend's to define: path parameters introduced by ; are standard behaviour across the Java servlet family, not one implementation's quirk. We do not extend CVE treatment to every literal-byte sibling of a published encoded-separator issue. Confirm the bypass against a normalizing backend with stock entrypoint configuration before submitting. Decided in this class. GHSA-xf64-8mw2-4gr2 (CVE-2026-48020, StripPrefix route-level auth bypass), GHSA-6jwx-7vp4-9847 (CVE-2026-40912, StripPrefixRegex, Path/RawPath desync), GHSA-46wh-3698-f2cx (CVE-2026-33186, dot-segment bypass in strip-prefix middleware), GHSA-gm3x-23wp-hc2c (CVE-2025-66490, router plus middleware rules), GHSA-vrch-868g-9jx5 (CVE-2025-47952, traversal via URL encoding), GHSA-6p68-w45g-48j7 (CVE-2025-32431, path matchers), GHSA-fvhj-4qfh-q2hm (CVE-2023-47106, URL fragment), and GHSA-cxjq-mrr5-89rv (ReplacePathRegex). Forwarded Headers and Client Identity What is usually reported. A middleware passes through, or fails to strip, an X-Forwarded-* or Forwarded header, letting a client influence what a backend believes about its identity, protocol, port or address. Often framed as an incomplete fix for a published issue, because a sibling code path does not repeat a strip added elsewhere. Our position. The trust boundary for forwarded headers is entrypoint-level. forwardedHeaders.trustedIPs and forwardedHeaders.insecure decide once, at the entrypoint, before any middleware runs, whether a client's forwarding headers are trusted. We deliberately do not re-decide per middleware: re-deciding in each middleware is the design mistake we are avoiding, not an omission. A middleware passing through a header the entrypoint accepted is behaving as designed, and a sibling path that does not repeat a strip is not automatically an incomplete fix. Where the line is. In scope: A path that reintroduces or reconstructs a trusted value after entrypoint sanitisation, so the entrypoint's decision no longer holds. A middleware that makes a pre-authentication decision on a header the operator declared untrusted. "Not automatically an incomplete fix" is not "never": where a sibling genuinely reintroduces the same primitive, we have published it as one. Decided in this class. GHSA-6384-m2mw-rf54 (CVE-2026-35051, trustForwardHeader=false still honouring a spoofed prefix), GHSA-3q9r-p662-5j8m (CVE-2026-54764, ForwardAuth trusting a spoofed port), GHSA-92mv-8f8w-wq52 (CVE-2026-29054, case-sensitive Connection header), GHSA-62c8-mh53-4cqv (CVE-2024-45410, Connection header abused to strip X-Forwarded-*), GHSA-h924-8g65-j9wg (CVE-2024-52003, open redirect via prefix) and GHSA-6qq8-5wq3-86rp (CVE-2020-15129, prefix header not validated). Headers Traefik Sets for the Backend What is usually reported. A client pre-sets, or sets an alternative spelling of, a header that Traefik writes for the backend's benefit: the authenticated user an auth middleware puts in its configured headerField, client certificate information from PassTLSClientCert, X-Forwarded-Prefix from a prefix middleware, X-Replaced-Path, or a custom request header. The backend trusts the value because Traefik set it, so forging it is the attack. Our position. The same architecture as forwarded headers, for the same reason: request header sanitisation is an entrypoint concern, not a per-middleware one. A middleware removes the canonical spelling of the header it is about to set. Alternative spellings that a backend folds onto that same name are handled once, before routing, through the entrypoint's aliasHeadersStrategy. The underlying mismatch is worth stating, because it is what makes the class non-obvious: Go canonicalises header names on - only, while backends that derive variable names from header names (CGI, WSGI, PHP, nginx, Tomcat) fold other characters to _. Two spellings that Traefik sees as different headers can therefore arrive at the backend as one. That is a property of the whole request rather than of any one middleware, which is precisely why it is resolved at the entrypoint. Where the line is. A report showing that one middleware, taken in isolation, does not sanitise a header it sets is declined. The entrypoint owns that sanitisation, and re-deciding it inside each middleware is the design we are avoiding, not an omission. In scope: a spelling that survives the entrypoint sanitisation and still reaches the backend as the trusted name; a middleware that reconstructs or reintroduces the value after the entrypoint has sanitised it. Decided in this class. GHSA-qr99-7898-vr7c (CVE-2026-33433, identity spoofing through a non-canonical headerField), GHSA-x677-9fxg-v5c5 (CVE-2026-54763, an accepted incomplete fix: an aliased spelling survived the strip added for the case above) and GHSA-5m6w-wvh7-57vm (CVE-2026-39858, alias spoofing ahead of a pre-authentication decision). TLS and mTLS Enforcement What is usually reported. A client reaches a route, or avoids presenting a certificate, because Traefik selected the wrong TLS configuration for the connection. Our position. Enforcement that does not hold is in scope, and this surface has a specific recurring shape we now look for directly: the TLS configuration chosen for a connection must match the configuration the operator intended for that host, including wildcard mappings, mixed-case hosts, and every protocol version. A mismatch that drops client-certificate verification is a bypass even when each component behaves as written. Where the line is. Configuring a permissive TLSOption, or omitting client authentication, is the operator's choice and not a defect. In scope is Traefik not applying the stricter configuration that the operator did set, or applying it on one protocol but not another. Decided in this class. GHSA-9cr8-q42q-g8m7 (CVE-2026-53622, HTTP/3, exact SNI lookup for wildcard and mixed-case hosts), GHSA-5r4w-85f3-pw66 (CVE-2026-48491, SNICheck ignoring wildcard mappings, domain-fronted bypass), GHSA-wvvq-wgcr-9q48 (CVE-2026-32305, fragmented ClientHello, pre-SNI fallback to the default), GHSA-gv8r-9rw9-9697 (CVE-2025-68121, ClientAuth on HTTP/3), GHSA-gxrv-wf35-62w9 (CVE-2024-39321, IP allow-lists bypassed via QUIC 0-RTT early data), GHSA-468w-8x39-gj5v (CVE-2022-46153, routes exposed with an empty TLSOption) and GHSA-hrhx-6h34-j5hc (CVE-2022-23632, wrong TLS configuration selected). Kubernetes References Across Namespaces and Providers What is usually reported. A resource in one namespace, or under one provider, reaches a service, middleware or transport it should not, through a backendRef, an ExtensionRef, a ServersTransport, or a cross-provider reference. Our position. A reference that escapes a boundary the operator established, reaching a namespace or provider the configuration did not grant, is a vulnerability. This surface has produced a large share of our CVEs. Where the line is. Check whether the allow-list trust anchor is genuinely bypassable for the route in question. If the traversal is gated by an opt-in the operator enabled, such as crossProviderNamespaces or allowCrossNamespace, that is the documented contract of the option. If it works without that opt-in, or defeats it, it is in scope. Equally, a report requiring the ability to create or edit the Kubernetes objects involved is not a boundary crossing: that actor already controls routing in the namespace. Decided in this class. GHSA-62fc-8686-hfmq (CVE-2026-71325, allowCrossNamespace=false bypassed via @kubernetescrd), GHSA-3g6v-2r68-prfc (CVE-2026-54761, crossProviderNamespaces allow-list defeated), GHSA-42cj-m3vj-89wv (CVE-2026-65602, IngressRouteTCP ServersTransport), GHSA-qq9q-x9w4-chhj (CVE-2026-65601, ExtensionRef namespace confusion), GHSA-xhjw-95fp-8vgq (CVE-2026-41174, cross-namespace middleware binding), GHSA-96qj-4jj5-wcjc (CVE-2026-44774, rest@internal reachable as a backend), GHSA-67jx-r9pv-98rj (CVE-2026-32695, host restriction bypassed) and GHSA-8q2w-wr49-whqj (CVE-2026-29777, rule injection through unescaped values in Ingress and HTTPRoute). Generated Keys and Shared State What is usually reported. Two distinct objects collide in an internal key, or share a cache, connection pool or in-flight request, so one reaches the other's context. Our position. The distinction that decides these reports is who generates the colliding key. A collision the reporter must author themselves, by creating or editing objects whose names collide, is not a boundary crossing. The internal keyspace naming routers, services and middlewares is not a tenant isolation boundary on a shared instance. A key Traefik generates that collides for inputs the operator kept separate is a vulnerability. So is state shared through a cache, pool or de-duplication mechanism keyed too loosely. Where the line is. Severity follows the boundary the collision actually crosses, not the mechanism: a generated-key collision reaching across a namespace or tenant on a shared control plane is high, while one confined inside a single credential cache with no cross-tenant reach is low. Both are still vulnerabilities. Decided in this class. GHSA-fgjj-px3w-67xx (CVE-2026-71327, Gateway API route identity collision, cross-namespace backend hijacking, high), GHSA-6765-c87h-8mrf (CVE-2026-71326, BasicAuth singleflight key collision, low), GHSA-6p8f-p8j2-rqmv (CVE-2026-54765, backendRef filters leaking across routes sharing a Service:port) and GHSA-3ccp-42pg-hgv6 (CVE-2026-71324, cross-user response poisoning through the shared backend keep-alive pool). Ingress-NGINX Provider Compatibility What is usually reported. A default or annotation behaviour of the Kubernetes Ingress-NGINX provider is insecure, with a working reproduction. Our position. This provider's contract is annotation compatibility with ingress-nginx. Where it faithfully reproduces documented upstream semantics, we keep the compatible behaviour even when the upstream outcome is insecure, and we improve the documentation instead: changing it would silently break the migrations the provider exists to serve. Check the upstream behaviour first. If Traefik matches it, expect a documentation change rather than an advisory. Reports we have closed on these grounds include permissive CORS defaults, per-ingress auth-url precedence, and auth-url variable interpolation differences. Where the line is. Compatibility covers semantics the operator opted into. It does not cover authentication or mTLS enforcement silently not happening. Where the provider fails open, rather than faithfully reproducing an insecure upstream default, that is a vulnerability. Decided in this class. GHSA-4mr2-fg2p-w63c (CVE-2026-54762, fails open when auth-secret resolution fails), GHSA-7vww-mvcr-x6vj (CVE-2025-66491, inverted TLS verification logic, so client certificates were not verified) and GHSA-8rxv-jg7p-wvg3 ( rewrite-target path traversal defeating route-level authentication). Authentication Middleware Correctness What is usually reported. An authentication middleware leaks information, accepts an identity it should not, or forwards credentials somewhere unintended. Our position. In scope: credential or identity handling that leaks across requests or users, observable timing differences that disclose whether a principal exists, and credentials forwarded to a destination the operator did not authorise. Where the line is. Choosing a weak authentication mechanism, or configuring it permissively, is the operator's decision. The middleware failing to deliver what its documentation promises is ours. Decided in this class. GHSA-6x2q-h3cr-8j2h (CVE-2026-41263, BasicAuth timing side channel) and GHSA-g3hg-j4jv-cwfr (CVE-2026-32595, BasicAuth timing side channels, username enumeration), GHSA-p6hg-qh38-555r (CVE-2026-41181, Errors middleware forwarding Authorization and Cookie to a separate service) and GHSA-h2ph-vhm7-g4hp (CVE-2022-23469, Authorization in debug logs). Availability and Resource Consumption What is usually reported. A request pattern that exhausts memory, connections, file descriptors or CPU, or that stalls a connection indefinitely. Our position. Unbounded consumption, panics, and missing timeouts reachable from unauthenticated requests are in scope. Buffering and queuing that stays within documented, configurable limits is not. Where the line is. We require a reproduction rather than a reading of the code, and so should you. This class repeatedly turns on whether a per-stream limit actually bounds the per-connection aggregate, which code reading gets wrong in both directions. A resource claim with no reproduction against a capped environment cannot be assessed, and we will ask for one. Decided in this class. GHSA-4hjq-9h5c-252j (CVE-2026-27141, HTTP/2 frames panicking the server), GHSA-fw45-f5q2-2p4x (CVE-2026-26998, ForwardAuth unbounded response body), GHSA-xw98-5q62-jx94 (CVE-2026-26999, stalled TCP router connections) and GHSA-cwjm-3f7h-9hwq (CVE-2026-22045, handshake stalls without timeouts), GHSA-89p3-4642-cr2w (CVE-2026-25949, readTimeout bypassed via STARTTLS), GHSA-4vwx-54mw-vqfw (CVE-2024-28869, Content-Length handling), GHSA-7hj9-rv74-5g92 (CVE-2023-29013, header parsing), GHSA-c6hx-pjc3-7fqr (CVE-2022-39271, HTTP/2 connection management) and GHSA-8g85-whqh-cr2f (CVE-2023-47124, ACME challenge amplification). Configuration the Operator Controls What is usually reported. A behaviour reachable after enabling a documented option, or in a default deployment the documentation tells operators to harden. Dashboard and API reachability, snippet annotations, error request headers, and variable interpolation are the recurring examples. Our position. Configuration is trusted input, and so is every provider that supplies it. Anyone able to write configuration Traefik reads already controls routing. A report whose precondition is configuration-write access, or operator or cluster-admin privilege, is not a vulnerability. Where an option is explicitly opt-in, its documented effect is its contract. Where the line is. In scope: an unprivileged, untrusted client achieving the same effect without that configuration access, or a documented option that does not do what it says. Dependency and Standard Library Findings What is usually reported. A scanner flags a CVE in a Go module or in the standard library Traefik builds against. Our position. A dependency finding is an exposure only if Traefik reaches the vulnerable code path at runtime. Build-time-only and unreachable paths are not vulnerabilities in Traefik, and we confirm reachability with govulncheck before answering. Where the path is reachable we publish, which is why several standard library CVEs appear in our advisory history. Where the line is. If you can show a reachable call path from a Traefik entrypoint, say so explicitly: that is the part that determines the answer. Non-GA Code Vulnerabilities affecting only release candidates, betas, or development branches are fixed without a CVE, as stated in the CVE policy. Open a normal issue for these, not a security advisory. Once you have confirmed the defect is absent from every GA release, there is no released version to protect, so there is nothing to keep private, and an issue reaches the maintainers faster than the advisory queue. Reporting during a release candidate is also the most useful moment to reach us: the fix costs a single commit, rather than an advisory, a backport across every maintained branch, and exposure for everyone who already upgraded. If the same defect is also reachable in a GA release, it is not a non-GA finding, and it belongs in a security advisory. Check the released branches before concluding that a finding is release-candidate only, and tell us which ones you checked. Submitting Issues Help Us Help You! {: .subtitle } Issues are perfect for requesting a feature/enhancement or reporting a suspected bug. We use the GitHub issue tracker to keep track of issues in Traefik. The process of sorting and checking the issues is a daunting task, and requires a lot of work. To help maintainers (and other community members) quickly and effortlessly understand what you need, be sure to follow the guidelines below. !!! important "Getting Help Vs Reporting an Issue" The issue tracker is not a general support forum, but a place to report bugs and asks for new features. For end-user related support questions, try using the [Traefik Community Forum](https://community.traefik.io/) Issue Title The title must be short and descriptive. (~60 characters) Examples: Bug: Duplicate requests in access logs Feature: Support TCP Feature Request Traefik is an open source project and aims to be the best edge router possible. Remember when asking for new features that these must be useful to the majority (and not only useful in edge case scenarios, or hack-like setups). Follow the issue template as much as possible. Do your best to explain what you're looking for, and why it would improve Traefik for everyone. Be detailed and share the use-case(s) to allow us to see the value of your feature request as quickly as possible. Features with a lot of positive interaction (claps, +1s, conversation about how this would impact them) indicate higher community interest and help us to prioritize. If you are interested in creating a PR for your feature request, let us know in the issue, so we can work with you. It can take a lot of work to make sure a PR can integrate with our existing code and planning with the team ahead of time can make sure that your PR can be accepted and merged quickly. Issues or Possible Bug Reports Follow the issue template as much as possible. Explain the conditions in which you encountered the issue; what is your context? Share any logs you may have, and make sure to share the steps it takes to reproduce your issue or bug. Remain as clear and concise as possible. Take time to polish the format of your message, so we'll enjoy reading it and working on it. Help your readers focus on what matters and help them understand the structure of your message (see the GitHub Markdown Syntax). International English Every maintainer / Traefik user is not a native English speaker, so if you sometimes feel that some messages sound rude, remember that it probably is a language barrier problem from someone willing to help you. Before You Submit a Pull Request This guide is for contributors who already have a pull request to submit. If you are looking for information on setting up your developer environment and creating code to contribute to Traefik Proxy or related projects, see the development guide. Looking for a way to contribute to Traefik Proxy? Check out this list of Priority Issues, the Good First Issue list, or the list of confirmed bugs waiting to be remedied. How We Prioritize We wish we could review every pull request right away, but because it's a time-consuming operation, it's not always possible. The PRs we are able to handle the fastest are: Documentation updates. Bug fixes. Enhancements and Features with a contributor/wanted tag. PRs that take more time to address include: Enhancements or Features without the contributor/wanted tag. If you have an idea for an enhancement or feature that you would like to build, create an issue for it first and tell us you are interested in writing the PR. If an issue already exists, definitely comment on it to tell us you are interested in creating a PR. This will allow us to communicate directly and let you know if it is something we would accept. It also allows us to make sure you have all the information you need during the design phase so that it can be reviewed and merged quickly. Read more about the Triage process in the docs. The Pull Request Submit Process Merging a PR requires the following steps to be completed before it is merged automatically. Make sure your pull request adheres to our best practices. These include: Following project conventions; including using the PR Template. Make small pull requests. Solve only one problem at a time. Comment thoroughly. Do not open the PR from an organization repository. Keep "allows edit from maintainer" checked. Use semantic line breaks for documentation. Ensure your PR is not a draft. We do not review drafts, but do answer questions and confer with developers on them as needed. Ensure that the dependencies in the go.mod file reference a tag. If referencing a tag is not possible, add a comment explaining why. Pass the validation check. Pass all tests. Receive 2 approving reviews from maintainers. Pull Request Review Cycle Learn about our Triage Process, in short, it looks like this: We triage every new PR or comment before entering it into the review process. We ensure that all prerequisites for review have been met. We check to make sure the use case meets our needs. We assign reviewers. Design Review. This takes longer than other parts of the process. We review that there are no obvious conflicts with our codebase. Code Review. We review the code in-depth and run tests. We may ask for changes here. During code review, we ask that you be reasonably responsive, if a PR languishes in code review it is at risk of rejection, or we may take ownership of the PR and the contributor will become a co-author. Maintainers may add the ai/review label to trigger an automated AI review of the pull request. The review is based on repository-specific guidelines and posted as inline comments. Merge. Success! !!! note Occasionally, we may freeze our codebase when working towards a specific feature or goal that could impact other development. During this time, your pull request could remain unmerged while the release work is completed. Run Local Verifications You must run these local verifications before you submit your pull request to predict the pass or failure of continuous integration. Your PR will not be reviewed until these are green on the CI. make generate make generate-crd make test-gateway-api-conformance make test-gateway-api-conformance-merged make validate make pull-images make test The Testing and Merge Workflow Pull Requests are managed by the bot Myrmica Lobicornis. This bot is responsible for verifying GitHub Checks (CI, Tests, etc), mergability, and minimum reviews. In addition, it rebases or merges with the base PR branch if needed. It performs several other housekeeping items and you can read more about those on the README for Lobicornis. The maintainer giving the final LGTM must add the status/3-needs-merge label to trigger the merge bot. By default, a squash-rebase merge will be carried out. The status status/4-merge-in-progress is only used by the bot. If the bot is not able to perform the merge, the label bot/need-human-merge is added. In such a situation, solve the conflicts/CI/... and then remove the label bot/need-human-merge. To prevent the bot from automatically merging a PR, add the label bot/no-merge. The label bot/light-review decreases the number of required LGTM from 2 to 1. This label can be used when: Updating a dependency. Merging branches back into the next version branch. Submitting minor documentation changes. Submitting changelog PRs. Why Was My Pull Request Closed? Traefik Proxy is made by the community for the community, as such the goal is to engage the community to make Traefik the best reverse proxy available. Part of this goal is maintaining a lean codebase and ensuring code velocity. Unfortunately, this means that sometimes we will not be able to merge a pull request. Because we respect the work you did, you will always be told why we are closing your pull request. If you do not agree with our decision, do not worry; closed pull requests are effortless to recreate, and little work is lost by closing a pull request that subsequently needs to be reopened. Your pull request might be closed if: Your PR's design conflicts with our existing codebase in such a way that merging is not an option and the work needed to make your pull request usable is too high. To prevent this, make sure you created an issue first and think about including Traefik Proxy maintainers in your design phase to minimize conflicts. Your PR is for an enhancement or feature that we will not use. Please remember to create an issue for any pull request before you create a PR to ensure that your goal is something we can merge and that you have any design insight you might need from the team. Your PR has been waiting for feedback from the contributor for over 90 days. Why is My Pull Request Not Getting Reviewed A few factors affect how long your pull request might wait for review. We must prioritize which PRs we focus on. Our first priority is PRs we have identified as having high community engagement and broad applicability. We put our top priorities on our roadmap, and you can identify them by the contributor/wanted tag. These PRs will enter our review process the fastest. Our second priority is bug fixes. Especially for bugs that have already been tagged with bug/confirmed. These reviews enter the process quickly. If your PR does not meet the criteria above, it will take longer for us to review, as any PRs that do meet the criteria above will be prioritized. Additionally, during the last few weeks of a milestone, we stop reviewing PRs to reduce churn and stabilize. We will resume after the release. The second major reason that we deprioritize your PR is that you are not following best practices. The most common failures to follow best practices are: You did not create an issue for the PR you wish to make. If you do not create an issue before submitting your PR, we will not be able to answer any design questions and let you know how likely your PR is to be merged. You created pull requests that are too large to review. Break your pull requests up. If you can extract whole ideas from your pull request and send those as pull requests of their own, you should do that instead. It is better to have many pull requests addressing one thing than one pull request addressing many things. Traefik Proxy is a fast-moving codebase — lock in your changes ASAP with your small pull request, and make merges be someone else's problem. We want every pull request to be useful on its own, so use your best judgment on what should be a pull request vs. a commit. You did not comment well. Comment everything. Please remember that we are working internationally, cross-culturally, and with different use-cases. Your reviewer will not intuitively understand the problem the same way you do or solve it the same way you would. This is why every change you make must be explained, and your strategy for coding must also be explained. Your tests were inadequate or absent. If you do not know how to test your PR, please ask! We will be happy to help you or suggest appropriate test cases. If you have already followed the best practices and your PR still has not received a response, here are some things you can do to move the process along: If you have fixed all the issues from a review, remember to re-request a review (using the designated button) to let your reviewer know that you are ready. You can choose to comment with the changes you made. Kindly comment on the pull request. Doing so will automatically give your PR visibility during the triage process. For more information on best practices, try these links: How to Write a Git Commit Message - Chris Beams Distributed Git - Contributing to a Project (Commit Guidelines) What’s with the 50/72 rule? - Preslav Rachev A Note About Git Commit Messages - Tim Pope It's OK to Push Back Sometimes reviewers make mistakes. It is OK to push back on changes your reviewer requested. If you have a good reason for doing something a certain way, you are absolutely allowed to debate the merits of a requested change. Both the reviewer and reviewee should strive to discuss these issues in a polite and respectful manner. You might be overruled, but you might also prevail. We are pretty reasonable people. Another phenomenon of open-source projects (where anyone can comment on any issue) is the dog-pile - your pull request gets so many comments from so many people it becomes hard to follow. In this situation, you can ask the primary reviewer (assignee) whether they want you to fork a new pull request to clear out all the comments. You do not have to fix every issue raised by every person who feels like commenting, but you should answer reasonable comments with an explanation. AI-Assisted Code Review Maintainers may add the ai/review label to a pull request to trigger an automated AI code review. When the label is applied, an AI agent reads the diff and the full content of every changed file, then posts inline comments directly on the pull request. The review follows repository-specific guidelines covering security, correctness, breaking changes, performance, and Go conventions (error wrapping, context propagation, logging, test style, and more). What to expect: Comments are categorized by severity: CRITICAL, IMPORTANT, MINOR, or QUESTION. The agent checks call sites before flagging a change as unsafe — a finding that does not survive that check will not be posted. Generated files, //nolint: directives, and patterns already used consistently across the codebase are not flagged. How to respond: Treat AI review comments the same way you would a human reviewer's comments. If a finding is incorrect or does not apply to your change, explain why in a reply — maintainers read every thread before approving. Common Sense and Courtesy No document can take the place of common sense and good taste. Use your best judgment, while you put a bit of thought into how your work can be made easier to review. If you do these things, your pull requests will get merged with less friction. Security Security Advisories We publish our security announcements as GitHub security advisories. Check this page to stay aware of the latest announcements from our security team. Each advisory is published together with the releases that fix the vulnerability. To be notified when they are out, watch the Traefik repository on GitHub, and select Custom > Releases. CVE Reported vulnerabilities can be found on cve.mitre.org. CVEs are only created for vulnerabilities affecting Generally Available (GA) versions of Traefik. Vulnerabilities discovered in non-GA versions (release candidates, betas, early access, or development branches) will be fixed without creating a CVE. Threat Model Traefik is an edge router. Its security boundary sits between untrusted network clients and the services it routes to. A report is a vulnerability when an unprivileged, untrusted client crosses that boundary. Reports that start from the other side of it describe bugs, and we fix bugs. This threat model applies to reports submitted on or after 1 September 2026. It states positions we already apply; publishing them is meant to save you the work of rediscovering them. What Traefik Trusts The configuration, and every provider that supplies it: static and dynamic configuration, Kubernetes objects, container labels, files, and KV stores. Anyone able to write configuration that Traefik reads already controls routing, and can redirect traffic, terminate TLS, or remove a middleware, by design. Operators and cluster administrators. A report requiring operator, cluster-admin, or equivalent privilege does not cross the boundary. Trust the operator has declared. Where the configuration says a client, a namespace or a forwarding header is trusted, Traefik trusts it. Such decisions are taken once, at the entrypoint, before any middleware runs, and are not re-litigated per middleware. The internal configuration keyspace is not a tenant isolation boundary on a shared instance. Hardening it is defence in depth. What Crosses the Boundary With no configuration-write access and no operator privilege required: Routing or matching bypass: an untrusted request reaching a router, service or backend the configuration does not grant it. Authentication or authorization that fails open or is bypassable under a configuration a reasonable reading of the documentation would call correct. Loss of confidentiality or integrity of proxied traffic, including credential exposure and TLS or mTLS enforcement that does not hold. Remote crash or unbounded resource consumption reachable from unauthenticated requests. Escalation across a boundary the configuration explicitly established. Where the Line Falls in Practice A boundary stated this briefly does not resolve a concrete report on its own. The surfaces where we have already settled a position, each with the neighbouring variant we do treat as a vulnerability and the CVEs that prove it, are on the Security Decisions page. Check your finding there before submitting. Handled as a Bug, Without an Advisory Some reports describe real defects that we fix, often at high priority, but that do not receive an advisory or a CVE, because they do not cross the boundary above. We say so explicitly rather than leaving it implicit, and we will point at a specific entry in Security Decisions when we close a report on these grounds. Report a Vulnerability We want to keep Traefik safe for everyone. If you've discovered a security vulnerability in Traefik, we appreciate your help in disclosing it to us in a responsible manner, by creating a security advisory. Coordinated Disclosure A reported vulnerability stays under embargo until its security advisory is published. Until then, please keep the report, the proof of concept, and any exchange with the security team confidential, and do not share them outside the people already involved in the report. This confidentiality is a fundamental part of the security of Traefik users: until the fixed releases are out, a disclosed vulnerability can be exploited against every deployment that has no way to upgrade yet. We publish the security advisory together with the releases that fix the vulnerability, and we coordinate the publication date with the reporter. Once the advisory is published, the reporter is free to discuss the vulnerability publicly, and is credited in it unless the Code of Conduct below says otherwise. If you need to share the report with a third party before publication, for example another affected vendor, please ask us first on the security advisory. Code of Conduct for Vulnerability Submissions We are committed to handling every legitimate report responsibly, and we expect submitters to engage with our security team in a respectful and collaborative manner. The following behaviors are not acceptable and will not be tolerated: Threats to publicly disclose the vulnerability if it is not fixed within a timeframe you set unilaterally. Ultimatums or pressure tactics intended to force a faster response than our normal triage and remediation process allows. Demands for payment, bug bounties, or any form of compensation in exchange for not disclosing the issue (Traefik does not operate a paid bug bounty program). Aggressive, abusive, or disrespectful communication with our security team. Submitters who engage in any of the above may face the following consequences: The submitter will not be credited in the security advisory or any subsequent communication. The submitter's GitHub profile may be reported to GitHub for violation of platform terms of service. We may decline to engage further on the report, while still addressing the underlying issue if it is legitimate. We take security seriously and act on legitimate reports as quickly as our resources allow. Patience and constructive dialogue help us protect users effectively. Submission Quality Guidelines We have been receiving an increasing number of low-quality vulnerability reports that are not actual security issues. Many of these reports originate from AI/LLM tools and are submitted without any human validation or testing. This wastes the time of our security team and delays the handling of legitimate vulnerabilities. Before submitting a security advisory, you must: Carefully test and validate the vulnerability yourself before submitting. You must be able to demonstrate a working proof of concept with clear reproduction steps. Understand the impact of the vulnerability and explain how it can be exploited in a realistic scenario. Verify that the issue is not a false positive. Ensure the behavior you are reporting is actually a security concern and not expected behavior. Check it against the Threat Model above before submitting. Submit one finding per report. Bundling several unrelated issues into a single advisory makes each one slower to triage, and means a single closure decision has to cover claims that deserve different answers. Disclose your use of AI tooling. Using an AI assistant to find or write up an issue is acceptable, and saying so is required. State which tool you used and what you verified yourself. An undisclosed AI-generated report that turns out to be unvalidated is treated as a breach of these guidelines, not merely a low-quality report. Policy on AI-Generated Reports Security reports that are directly generated by AI/LLM tools without proper human validation will be closed immediately. Indicators of unvalidated AI-generated reports include (but are not limited to): No working proof of concept or reproduction steps. Generic or theoretical vulnerability descriptions with no evidence of actual testing. Misunderstanding of Traefik's architecture or threat model. Hallucinated code paths, configuration options, or behaviors that do not exist. Contributors who repeatedly submit low-quality or unvalidated reports may have their accounts blocked. We appreciate the work of security researchers who take the time to rigorously validate their findings. Quality over quantity helps keep Traefik safe for everyone. Thank You! You Made It {: .subtitle} Traefik Proxy truly is an open-source project, and wouldn't have become what it is today without the help of our many contributors, not accounting for people having helped with issues, tests, comments, articles, ... or just enjoy using Traefik Proxy and share with others. So once again, thank you for your invaluable help in making Traefik such a good product! !!! question "Where to Go Next?" If you want to: - Propose an idea, request a feature, or report a bug, then read [Submitting Issues](./submitting-issues.md). - Discover how to make an efficient contribution, then read [Submitting Pull Requests](./submitting-pull-requests.md). - Learn how to build and test Traefik, then the page [Building and Testing](./building-testing.md) is for you. - Contribute to the documentation, then read the page about [Documentation](./documentation.md). - Understand how do we learn about Traefik usage, read the [Data Collection](./data-collection.md) page. - Spread the love about Traefik, please check the [Advocating](./advocating.md) page. - Learn about who are the maintainers and how they work on the project, read the [Maintainers](./maintainers.md) and [Maintainer Guidelines](./maintainers-guidelines.md) pages. Feature Deprecation Notices This page is maintained and updated periodically to reflect our roadmap and any decisions around feature deprecation. Feature Deprecated End of Support Removal Kubernetes Ingress API Version networking.k8s.io/v1beta1 N/A N/A 3.0 CRD API Version apiextensions.k8s.io/v1beta1 N/A N/A 3.0 Entry point underscoreHeadersStrategy option 3.7.12 N/A N/A Impact Kubernetes Ingress API Version networking.k8s.io/v1beta1 The Kubernetes Ingress API Version networking.k8s.io/v1beta1 support is removed in v3. Please use the API Group networking.k8s.io/v1 instead. Traefik CRD Definitions API Version apiextensions.k8s.io/v1beta1 The Traefik CRD definitions API Version apiextensions.k8s.io/v1beta1 support is removed in v3. Please use the API Group apiextensions.k8s.io/v1 instead. Entry Point underscoreHeadersStrategy Option Starting on 3.7.12 the underscoreHeadersStrategy entry point option is deprecated, please use the aliasHeadersStrategy option instead. Underscores are only one of the characters making a header name alias another one, and aliasHeadersStrategy handles them all. An entry point cannot configure both options with different values. Releases Versions Below is a non-exhaustive list of versions and their maintenance status: Version Release Date Active Support Security Support 3.7 May 05, 2026 Yes Yes 3.6 Nov 07, 2025 Ended May 07, 2026 Ended Aug 16, 2026 3.5 Jul 23, 2025 Ended Nov 07, 2025 No 3.4 May 05, 2025 Ended Jul 23, 2025 No 3.3 Jan 06, 2025 Ended May 05, 2025 No 3.2 Oct 28, 2024 Ended Jan 06, 2025 No 3.1 Jul 15, 2024 Ended Oct 28, 2024 No 3.0 Apr 29, 2024 Ended Jul 15, 2024 No 2.11 Feb 12, 2024 Ended Apr 29, 2025 Ends Sept 07, 2026 ??? example "Active Support / Security Support" - **Active support**: Receives any bug fixes. - **Security support**: Receives only critical bug and security fixes. This page is maintained and updated periodically to reflect our roadmap and any decisions affecting the end of support for Traefik Proxy. Please refer to our migration guides for specific instructions on upgrading between versions, an example is the v2 to v3 migration guide. !!! important "All target dates for end of support or feature removal announcements may be subject to change." Versioning Scheme The Traefik Proxy project follows the semantic versioning scheme and maintains a separate branch for each minor version. The main branch always represents the next upcoming minor or major version. And these are our guiding rules for version support, as of Traefik v3.6: Every minor is supported for 6 months from its GA release date, which means several minor versions can be supported at the same time The last minor after releasing a new major is supported for 2 years following the major release (starting with v3) Previous rules are subject to change and in such cases an announcement will be made publicly, here is an example extending v1.x branch support. !!! note "Versions released before v3.6" These rules apply starting with Traefik v3.6. Before that, only the latest `minor` was on active support at any given time, and support for a `minor` ended as soon as the next one was released. Exposing Services with Traefik Proxy This section guides you through exposing services securely with Traefik Proxy. You'll learn how to route HTTP and HTTPS traffic to your services, add security features, and implement advanced load balancing. What You'll Accomplish Following these guides, you'll learn how to: Route HTTP traffic to your services with Gateway API and IngressRoute Configure routing rules to direct requests Enable HTTPS with TLS Add security middlewares Generate certificates automatically with Let's Encrypt Implement sticky sessions for session persistence Platform-Specific Guides For detailed steps tailored to your environment, follow the guide for your platform: Kubernetes Docker Docker Swarm Advanced Use Cases Exposing gRPC Services Traefik Proxy supports gRPC applications without requiring specific configuration. You can expose gRPC services using either HTTP (h2c) or HTTPS. ??? example "Using HTTP (h2c)" For unencrypted gRPC communication, configure your service to use the `h2c://` protocol scheme: ```yaml http: routers: grpc-router: service: grpc-service rule: Host(`grpc.example.com`) services: grpc-service: loadBalancer: servers: - url: h2c://backend:8080 ``` !!! note For providers with labels (Docker, Kubernetes), specify the scheme using: `traefik.http.services..loadbalancer.server.scheme=h2c` ??? example "Using HTTPS" For encrypted gRPC communication, use standard HTTPS URLs. Traefik will use HTTP/2 over TLS to communicate with your gRPC backend: ```yaml http: routers: grpc-router: service: grpc-service rule: Host(`grpc.example.com`) tls: {} services: grpc-service: loadBalancer: servers: - url: https://backend:8080 ``` Traefik handles the protocol negotiation automatically. Configure TLS certificates for your backends using [ServersTransport](../reference/routing-configuration/http/load-balancing/serverstransport.md) if needed. Exposing WebSocket Services Traefik Proxy supports WebSocket (WS) and WebSocket Secure (WSS) connections out of the box. No special configuration is required beyond standard HTTP routing. ??? example "Basic WebSocket" Configure a router and service pointing to your WebSocket server. Traefik automatically detects and handles the WebSocket upgrade: ```yaml http: routers: websocket-router: rule: Host(`ws.example.com`) service: websocket-service services: websocket-service: loadBalancer: servers: - url: http://websocket-backend:8000 ``` ??? example "WebSocket Secure (WSS)" For encrypted WebSocket connections, enable TLS on your router. Clients connect using `wss://` while you can choose whether backends use encrypted or unencrypted connections: ```yaml http: routers: websocket-secure-router: rule: Host(`wss.example.com`) service: websocket-service tls: {} services: websocket-service: loadBalancer: servers: - url: http://websocket-backend:8000 # SSL termination at Traefik # OR # - url: https://websocket-backend:8443 # End-to-end encryption ``` Traefik preserves WebSocket headers including `Origin`, `Sec-WebSocket-Key`, and `Sec-WebSocket-Version`. Use the [Headers middleware](../reference/routing-configuration/http/middlewares/headers.md) if you need to modify headers for origin checking or other requirements. Exposing Services with Traefik on Docker - Advanced This guide builds on the concepts and setup from the Basic Guide. Make sure you've completed the basic guide and have a working Traefik setup with Docker before proceeding. In this advanced guide, you'll learn how to enhance your Traefik deployment with: Middlewares for security headers and access control Let's Encrypt for automated certificate management Sticky sessions for stateful applications Multi-layer routing for hierarchical routing with a complex authentication based routing example Service middlewares for applying middleware at the service level Prerequisites Completed the Basic Guide Docker and Docker Compose installed Working Traefik setup from the basic guide Add Middlewares Middlewares allow you to modify requests or responses as they pass through Traefik. Let's add two useful middlewares: Headers for security and IP allowlisting for access control. Add the following labels to your whoami service in docker-compose.yml: labels: # Secure Headers Middleware - "traefik.http.middlewares.secure-headers.headers.frameDeny=true" - "traefik.http.middlewares.secure-headers.headers.sslRedirect=true" - "traefik.http.middlewares.secure-headers.headers.browserXssFilter=true" - "traefik.http.middlewares.secure-headers.headers.contentTypeNosniff=true" - "traefik.http.middlewares.secure-headers.headers.stsIncludeSubdomains=true" - "traefik.http.middlewares.secure-headers.headers.stsPreload=true" - "traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000" # IP Allowlist Middleware - "traefik.http.middlewares.ip-allowlist.ipallowlist.sourceRange=127.0.0.1/32,192.168.0.0/16,10.0.0.0/8" # Apply middlewares to whoami router - "traefik.http.routers.whoami.middlewares=secure-headers,ip-allowlist" Add the same middleware to your whoami-api service: labels: - "traefik.http.routers.whoami-api.middlewares=secure-headers,ip-allowlist" Apply the changes: docker compose up -d Test the Middlewares Now let's verify that our middlewares are working correctly: Test the Secure Headers middleware: curl -k -I -H "Host: whoami.docker.localhost" https://localhost/ In the response headers, you should see security headers set by the middleware: X-Frame-Options: DENY X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Strict-Transport-Security with the appropriate settings Test the IP Allowlist middleware: If your request comes from an IP that's in the allow list (e.g., 127.0.0.1), it should succeed: curl -k -I -H "Host: whoami.docker.localhost" https://localhost/ If you try to access from an IP not in the allow list, the request will be rejected with a 403 Forbidden response. To simulate this in a local environment, you can modify the middleware configuration temporarily to exclude your IP address, then test again. Generate Certificates with Let's Encrypt Let's Encrypt provides free, automated TLS certificates. Let's configure Traefik to automatically obtain and renew certificates for our services. Instead of using self-signed certificates, update your existing docker-compose.yml file with the following changes: Add the Let's Encrypt certificate resolver to the Traefik service command section: command: - "--api.insecure=false" - "--api.dashboard=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=proxy" - "--entryPoints.web.address=:80" - "--entryPoints.websecure.address=:443" - "--entryPoints.websecure.http.tls=true" - "--entryPoints.web.http.redirections.entryPoint.to=websecure" - "--entryPoints.web.http.redirections.entryPoint.scheme=https" # Let's Encrypt configuration - "--certificatesresolvers.le.acme.email=your-email@example.com" # replace with your actual email - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json" - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web" Add a volume for Let's Encrypt certificates: volumes: # ...Existing volumes... - "./letsencrypt:/letsencrypt" Update your service labels to use the certificate resolver: labels: - "traefik.http.routers.whoami.tls.certresolver=le" Do the same for any other services you want to secure: labels: - "traefik.http.routers.whoami-api.tls.certresolver=le" Create a directory for storing Let's Encrypt certificates: mkdir -p letsencrypt Apply the changes: docker compose up -d !!! important "Public DNS Required" Let's Encrypt may require a publicly accessible domain to validate domain ownership. For testing with local domains like whoami.docker.localhost, the certificate will remain self-signed. In production, replace it with a real domain that has a publicly accessible DNS record pointing to your Traefik instance. Once the certificate is issued, you can verify it: # Verify the certificate chain curl -v https://whoami.docker.localhost/ 2>&1 | grep -i "server certificate" You should see that your certificate is issued by Let's Encrypt. Configure Sticky Sessions Sticky sessions ensure that a user's requests always go to the same backend server, which is essential for applications that maintain session state. Let's implement sticky sessions for our whoami service. First, Add Sticky Session Labels Add the following labels to your whoami service in the docker-compose.yml file: labels: - "traefik.http.services.whoami.loadbalancer.sticky.cookie=true" - "traefik.http.services.whoami.loadbalancer.sticky.cookie.name=sticky_cookie" - "traefik.http.services.whoami.loadbalancer.sticky.cookie.secure=true" - "traefik.http.services.whoami.loadbalancer.sticky.cookie.httpOnly=true" Apply the changes: docker compose up -d Then, Scale Up the Service To demonstrate sticky sessions with Docker, use Docker Compose's scale feature: docker compose up -d --scale whoami=3 This creates multiple instances of the whoami service. !!! important "Scaling After Configuration Changes" If you run docker compose up -d after scaling, it will reset the number of whoami instances back to 1. Always scale after applying configuration changes and starting the services. Test Sticky Sessions You can test the sticky sessions by making multiple requests and observing that they all go to the same backend container: # First request - save cookies to a file curl -k -c cookies.txt -H "Host: whoami.docker.localhost" https://localhost/ # Subsequent requests - use the cookies curl -k -b cookies.txt -H "Host: whoami.docker.localhost" https://localhost/ curl -k -b cookies.txt -H "Host: whoami.docker.localhost" https://localhost/ Pay attention to the Hostname field in each response - it should remain the same across all requests when using the cookie file, confirming that sticky sessions are working. For comparison, try making requests without the cookie: # Requests without cookies should be load-balanced across different containers curl -k -H "Host: whoami.docker.localhost" https://localhost/ curl -k -H "Host: whoami.docker.localhost" https://localhost/ You should see different Hostname values in these responses, as each request is load-balanced to a different container. !!! important "Browser Testing" When testing in browsers, you need to use the same browser session to maintain the cookie. The cookie is set with httpOnly and secure flags for security, so it will only be sent over HTTPS connections and won't be accessible via JavaScript. For more advanced configuration options, see the reference documentation. Multi-Layer Routing Multi-layer routing enables hierarchical relationships between routers, where parent routers can process requests through middleware before child routers make final routing decisions. This is particularly useful for authentication-based routing or staged middleware application. !!! info "Provider Requirement" Multi-layer routing requires the File provider, as Docker labels do not support the parentRefs field. However, you can use both Docker and File providers together - Docker labels for service discovery and File configuration for multi-layer routing. Setup Multi-Layer Routing with Docker To use multi-layer routing with Docker, you need to enable the File provider alongside the Docker provider. Update your Traefik service in docker-compose.yml: services: traefik: image: "traefik:latest" container_name: "traefik" restart: unless-stopped security_opt: - no-new-privileges:true networks: - proxy command: - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=proxy" - "--providers.file.directory=/etc/traefik/dynamic" # Enable File provider - "--entryPoints.web.address=:80" - "--entryPoints.websecure.address=:443" - "--entryPoints.websecure.http.tls=true" ports: - "80:80" - "443:443" - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./dynamic:/etc/traefik/dynamic:ro" # Mount directory for dynamic config Authentication-Based Routing Example Let's create a multi-layer routing setup where a parent router authenticates requests, and child routers direct traffic based on user roles. First, keep your Docker services defined with labels as usual: # In docker-compose.yml services: # ... traefik service from above ... # Mock authentication service that adds X-User-Role header auth-service: image: "traefik/whoami" networks: - proxy environment: - WHOAMI_NAME=Auth Service labels: - "traefik.enable=true" - "traefik.http.services.auth-service.loadbalancer.server.port=80" # Admin backend service admin-backend: image: "traefik/whoami" networks: - proxy environment: - WHOAMI_NAME=Admin Backend labels: - "traefik.enable=true" - "traefik.http.services.admin-backend.loadbalancer.server.port=80" # User backend service user-backend: image: "traefik/whoami" networks: - proxy environment: - WHOAMI_NAME=User Backend labels: - "traefik.enable=true" - "traefik.http.services.user-backend.loadbalancer.server.port=80" Now create the multi-layer routing configuration in a file. Create dynamic/mlr.yml: http: routers: # Parent router with authentication middleware api-parent: rule: "Host(`api.docker.localhost`) && PathPrefix(`/api`)" middlewares: - auth-middleware entryPoints: - websecure # Note: No service and no TLS config - this is a parent router # Child router for admin users api-admin: rule: "HeadersRegexp(`X-Auth-User`, `admin`)" service: admin-backend@docker # Reference Docker service parentRefs: - api-parent@file # Explicit reference to parent in file provider # Child router for regular users api-user: rule: "HeadersRegexp(`X-Auth-User`, `user`)" service: user-backend@docker # Reference Docker service parentRefs: - api-parent@file # Explicit reference to parent in file provider middlewares: auth-middleware: basicAuth: users: - "admin:$apr1$DmXR3Add$wfdbGw6RWIhFb0ffXMM4d0" - "user:$apr1$GJtcIY1o$mSLdsWYeXpPHVsxGDqadI." headerField: X-Auth-User !!! note "Generating Password Hashes" The password hashes above are generated using htpasswd. To create your own user credentials: ```bash # Using htpasswd (Apache utils) htpasswd -nb admin yourpassword ``` !!! important "Cross-Provider References" Notice the @docker suffix on service names and the @file suffix in parentRefs. When using the File provider to orchestrate multi-layer routing with Docker services: - Use `service-name@docker` to reference Docker services - Use `parent-name@file` in `parentRefs` to reference the parent router in the File provider The `@provider` suffix tells Traefik which provider namespace to look in for the resource. Apply the changes: docker compose up -d Test Multi-Layer Routing Test the routing behavior: # Request goes through parent router → auth middleware → admin child router curl -k -u admin:test -H "Host: api.docker.localhost" https://localhost/api You should see the response from the admin-backend service when authenticating as admin. Try with user:test credentials to reach the user-backend service instead. How It Works Request arrives at api.docker.localhost/api Parent router ( api-parent) matches based on host and path BasicAuth middleware authenticates the user and sets the X-Auth-User header with the username Child router ( api-admin or api-user) matches based on the header value Request forwarded to the appropriate Docker service For more details about multi-layer routing, see the Multi-Layer Routing documentation. Service Middlewares Service middlewares allow you to apply middleware to a service rather than to individual routers. This means the middleware takes effect for all requests handled by the service, regardless of which router forwards the request. This is useful when you want to apply the same middleware (like headers, rate limiting, or authentication) to all traffic reaching a service without having to configure it on each router. When to Use Service Middlewares Use service middlewares when: Multiple routers forward traffic to the same service, and all should have the same middleware applied You want to ensure a middleware is always applied to a service regardless of how traffic reaches it You're centralizing middleware configuration at the service level for easier management Add Service Middleware Labels Add the following labels to your whoami service in docker-compose.yml: services: whoami: image: traefik/whoami networks: - proxy labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)" - "traefik.http.routers.whoami.entrypoints=websecure" - "traefik.http.routers.whoami.tls=true" # Define the middleware - "traefik.http.middlewares.service-headers.headers.customRequestHeaders.X-Service-Middleware=applied" # Attach middleware at the SERVICE level (not the router level) - "traefik.http.services.whoami.middlewares=service-headers" - "traefik.http.services.whoami.loadbalancer.server.port=80" !!! info "Service-Level vs Router-Level Middlewares" - **Router-level middleware** (`traefik.http.routers..middlewares`): Applied only when traffic matches that specific router's rule - **Service-level middleware** (`traefik.http.services..middlewares`): Applied to all traffic reaching the service, regardless of which router forwarded it When both are configured, router middlewares execute first, followed by service middlewares. Apply the changes: docker compose up -d Test Service Middleware Verify the service middleware is working: curl -k -H "Host: whoami.docker.localhost" https://localhost/ In the response from whoami, you should see the custom header that was added by the service middleware: X-Service-Middleware: applied For more details on service middlewares, see the reference documentation. Conclusion In this advanced guide, you've learned how to: Add security with middlewares like secure headers and IP allow listing Automate certificate management with Let's Encrypt Implement sticky sessions for stateful applications Setup multi-layer routing for authentication-based routing Apply middlewares at the service level for centralized middleware management These advanced capabilities allow you to build production-ready Traefik deployments with Docker. Each of these can be further customized to meet your specific requirements. Next Steps Now that you've mastered both basic and advanced Traefik features with Docker, you might want to explore: Advanced routing options like query parameter matching, header-based routing, and more Additional middlewares for authentication, rate limiting, and request modifications Observability features for monitoring and debugging your Traefik deployment TCP services for exposing TCP services UDP services for exposing UDP services Docker provider documentation for more details about the Docker integration Exposing Services with Traefik on Docker - Basic This guide will help you get started with exposing your services through Traefik Proxy using Docker. You'll learn the fundamentals of routing HTTP traffic, setting up path-based routing, and securing your services with TLS. Prerequisites Docker and Docker Compose installed Basic understanding of Docker concepts Traefik deployed using the Traefik Docker Setup guide Expose Your First HTTP Service Let's expose a simple HTTP service using the whoami application. This will demonstrate basic routing to a backend service. First, create a docker-compose.yml file: services: traefik: image: "traefik:v3.8" container_name: "traefik" restart: unless-stopped security_opt: - no-new-privileges:true networks: - proxy command: - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=proxy" - "--entryPoints.web.address=:80" ports: - "80:80" - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" whoami: image: "traefik/whoami" restart: unless-stopped networks: - proxy labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)" - "traefik.http.routers.whoami.entrypoints=web" networks: proxy: name: proxy Save this as docker-compose.yml and start the services: docker compose up -d Verify Your Service Your service is now available at http://whoami.docker.localhost/. Test that it works: curl -H "Host: whoami.docker.localhost" http://localhost/ You should see output similar to: Hostname: whoami IP: 127.0.0.1 IP: ::1 IP: 172.18.0.3 IP: fe80::215:5dff:fe00:c9e RemoteAddr: 172.18.0.2:55108 GET / HTTP/1.1 Host: whoami.docker.localhost User-Agent: curl/7.68.0 Accept: */* Accept-Encoding: gzip X-Forwarded-For: 172.18.0.1 X-Forwarded-Host: whoami.docker.localhost X-Forwarded-Port: 80 X-Forwarded-Proto: http X-Forwarded-Server: 5789f594e7d5 X-Real-Ip: 172.18.0.1 This confirms that Traefik is successfully routing requests to your whoami application. Add Routing Rules Now we'll enhance our routing by directing traffic to different services based on URL paths. This is useful for API versioning, frontend/backend separation, or organizing microservices. Update your docker-compose.yml to add another service: # ... # New service whoami-api: image: "traefik/whoami" networks: - proxy container_name: "whoami-api" environment: - WHOAMI_NAME=API Service labels: - "traefik.enable=true" # Path-based routing - "traefik.http.routers.whoami-api.rule=Host(`whoami.docker.localhost`) && PathPrefix(`/api`)" - "traefik.http.routers.whoami-api.entrypoints=web" Apply the changes: docker compose up -d Test the Path-Based Routing Verify that different paths route to different services: # Root path should go to the main whoami service curl -H "Host: whoami.docker.localhost" http://localhost/ # /api path should go to the whoami-api service curl -H "Host: whoami.docker.localhost" http://localhost/api For the /api requests, you should see the response showing "API Service" in the environment variables section, confirming that your path-based routing is working correctly. Enable TLS Let's secure our service with HTTPS by adding TLS. We'll start with a self-signed certificate for local development. Create a Self-Signed Certificate Generate a self-signed certificate: mkdir -p certs openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout certs/local.key -out certs/local.crt \ -subj "/CN=*.docker.localhost" Create a directory for dynamic configuration and add a TLS configuration file: mkdir -p dynamic cat > dynamic/tls.yml << EOF tls: certificates: - certFile: /certs/local.crt keyFile: /certs/local.key EOF Update your docker-compose.yml file with the following changes: services: traefik: image: "traefik:v3.8" container_name: "traefik" restart: unless-stopped security_opt: - no-new-privileges:true networks: - proxy command: - "--api.insecure=false" - "--api.dashboard=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=proxy" - "--providers.file.directory=/etc/traefik/dynamic" - "--entryPoints.web.address=:80" - "--entryPoints.websecure.address=:443" - "--entryPoints.websecure.http.tls=true" ports: - "80:80" - "443:443" - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" # Add the following volumes - "./certs:/certs:ro" - "./dynamic:/etc/traefik/dynamic:ro" labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`dashboard.docker.localhost`)" - "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.routers.dashboard.service=api@internal" # Add the following label - "traefik.http.routers.dashboard.tls=true" whoami: image: "traefik/whoami" restart: unless-stopped networks: - proxy labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)" - "traefik.http.routers.whoami.entrypoints=websecure" # Add the following label - "traefik.http.routers.whoami.tls=true" whoami-api: image: "traefik/whoami" container_name: "whoami-api" restart: unless-stopped networks: - proxy environment: - WHOAMI_NAME=API Service labels: - "traefik.enable=true" - "traefik.http.routers.whoami-api.rule=Host(`whoami.docker.localhost`) && PathPrefix(`/api`)" - "traefik.http.routers.whoami-api.entrypoints=websecure" # Add the following label - "traefik.http.routers.whoami-api.tls=true" networks: proxy: name: proxy Apply the changes: docker compose up -d Your browser can access https://whoami.docker.localhost/ for the service. You'll need to accept the security warning for the self-signed certificate. Next Steps Now that you've mastered the basics of exposing services with Traefik on Docker, you're ready to explore more advanced features like middlewares, Let's Encrypt certificates, sticky sessions, and multi-layer routing. Continue to the Advanced Guide to learn about: Adding middlewares for security and access control Generating certificates with Let's Encrypt Configuring sticky sessions for stateful applications Setting up multi-layer routing for authentication-based routing Exposing Services with Traefik on Kubernetes - Advanced This guide builds on the concepts and setup from the Basic Guide. Make sure you've completed the basic guide and have a working Traefik setup with Kubernetes before proceeding. In this advanced guide, you'll learn how to enhance your Traefik deployment with: Middlewares for security headers and access control Let's Encrypt for automated certificate management (IngressRoute) cert-manager for automated certificate management (Gateway API) Sticky sessions for stateful applications Multi-layer routing for hierarchical routing with complex authentication scenarios (IngressRoute only) Service middlewares for applying middleware at the service level Prerequisites Completed the Basic Guide A Kubernetes cluster with Traefik Proxy installed kubectl configured to interact with your cluster Working Traefik setup from the basic guide Add Middlewares Middlewares allow you to modify requests or responses as they pass through Traefik. Let's add two useful middlewares: Headers for security and IP allowlisting for access control. Create Middlewares apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: secure-headers namespace: default spec: headers: frameDeny: true sslRedirect: true browserXssFilter: true contentTypeNosniff: true stsIncludeSubdomains: true stsPreload: true stsSeconds: 31536000 --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: ip-allowlist namespace: default spec: ipAllowList: sourceRange: - 127.0.0.1/32 - 10.0.0.0/8 # Typical cluster network range - 192.168.0.0/16 # Common local network range Save this as middlewares.yaml and apply it: kubectl apply -f middlewares.yaml Apply Middlewares with Gateway API In Gateway API, you can apply middlewares using the ExtensionRef filter type. This is the preferred and standard way to use Traefik middlewares with Gateway API, as it integrates directly with the HTTPRoute specification. Now, update your HTTPRoute to reference these middlewares using the ExtensionRef filter: apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami namespace: default spec: parentRefs: - name: traefik-gateway sectionName: websecure hostnames: - "whoami.docker.localhost" rules: - matches: - path: type: PathPrefix value: /api filters: - type: ExtensionRef extensionRef: # Headers Middleware Definition group: traefik.io kind: Middleware name: secure-headers - type: ExtensionRef extensionRef: # IP AllowList Middleware Definition group: traefik.io kind: Middleware name: ip-allowlist backendRefs: - name: whoami-api port: 80 - matches: - path: type: PathPrefix value: / filters: - type: ExtensionRef extensionRef: # Headers Middleware Definition group: traefik.io kind: Middleware name: secure-headers - type: ExtensionRef extensionRef: # IP AllowList Middleware Definition group: traefik.io kind: Middleware name: ip-allowlist backendRefs: - name: whoami port: 80 Update the file whoami-route.yaml and apply it: kubectl apply -f whoami-route.yaml This approach uses the Gateway API's native filter mechanism rather than annotations. The ExtensionRef filter type allows you to reference Traefik middlewares directly within the HTTPRoute specification, which is more consistent with the Gateway API design principles. Apply Middlewares with IngressRoute Update your existing IngressRoute to include middlewares: apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: whoami namespace: default spec: entryPoints: - websecure routes: - match: Host(`whoami.docker.localhost`) && Path(`/api`) kind: Rule middlewares: # Middleware Definition - name: secure-headers - name: ip-allowlist services: - name: whoami-api port: 80 - match: Host(`whoami.docker.localhost`) kind: Rule middlewares: # Middleware Definition - name: secure-headers - name: ip-allowlist services: - name: whoami port: 80 tls: certResolver: le Update the file whoami-ingressroute.yaml and apply it: kubectl apply -f whoami-ingressroute.yaml Verify Middleware Effects Check that the security headers are being applied: curl -k -I -H "Host: whoami.docker.localhost" https://localhost/ You should see security headers in the response, such as: HTTP/2 200 x-content-type-options: nosniff x-frame-options: DENY x-xss-protection: 1; mode=block strict-transport-security: max-age=31536000; includeSubDomains; preload content-type: text/plain; charset=utf-8 content-length: 403 To test the IP allowlist, you can modify the sourceRange in the middleware to exclude your IP and verify that access is blocked. Generate Certificates with Let's Encrypt !!! info Traefik's built-in Let's Encrypt integration works with IngressRoute but does not automatically issue certificates for Gateway API listeners. For Gateway API, you should use cert-manager or another certificate controller. Using IngressRoute with Let's Encrypt Configure a certificate resolver in your Traefik values.yaml: additionalArguments: - "--certificatesresolvers.le.acme.email=your-email@example.com" #replace with your email - "--certificatesresolvers.le.acme.storage=/data/acme.json" - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web" !!! important "Public DNS Required" Let's Encrypt may require a publicly accessible domain to validate domain ownership. For testing with local domains like whoami.docker.localhost, the certificate will remain self-signed. In production, replace it with a real domain that has a publicly accessible DNS record pointing to your Traefik instance. Update your Traefik installation with this configuration: helm upgrade traefik traefik/traefik -n traefik --reuse-values -f values.yaml Update your IngressRoute with the Let's Encrypt certificate: apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: whoami namespace: default spec: entryPoints: - websecure routes: - match: Host(`whoami.docker.localhost`) && Path(`/api`) kind: Rule middlewares: - name: secure-headers - name: ip-allowlist services: - name: whoami-api port: 80 - match: Host(`whoami.docker.localhost`) kind: Rule middlewares: - name: secure-headers - name: ip-allowlist services: - name: whoami port: 80 tls: certResolver: le Apply it: kubectl apply -f whoami-ingressroute.yaml Using Gateway API with cert-manager For Gateway API, install cert-manager: kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.0/cert-manager.yaml Create an Issuer & Certificate: apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: letsencrypt spec: acme: email: your-email@example.com # replace with your email server: https://acme-v02-staging.api.letsencrypt.org/directory # Replace with the production server in production privateKeySecretRef: name: letsencrypt-account-key solvers: - http01: gatewayHTTPRoute: parentRefs: - name: traefik namespace: default kind: Gateway --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: whoami namespace: default spec: secretName: whoami-tls-le # Name of secret where the generated certificate will be stored. dnsNames: - "whoami.docker.localhost" # Replace a real domain issuerRef: name: letsencrypt kind: Issuer !!! important "Public DNS Required" Let's Encrypt requires a publicly accessible domain to verify ownership. When using a local domain like whoami.docker.localhost, cert-manager will attempt the challenge but it will fail, and the certificate will remain self-signed. For production use, replace the domain with one that has a public DNS record pointing to your cluster's ingress point. Save the YAML file and apply: kubectl apply -f letsencrypt-issuer-andwhoami-certificate.yaml Now, update your Gateway to use the generated certificate: apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: traefik-gateway namespace: default spec: gatewayClassName: traefik listeners: - name: web port: 80 protocol: HTTP allowedRoutes: namespaces: from: All - name: websecure port: 443 protocol: HTTPS allowedRoutes: namespaces: from: All tls: certificateRefs: - name: whoami-tls-le # References the secret created by cert-manager Apply the updated Gateway: kubectl apply -f gateway.yaml Your existing HTTPRoute will now use this certificate when connecting to the secured gateway listener. Verify the Let's Encrypt Certificate Once the certificate is issued, you can verify it: # Check certificate status kubectl get certificate -n default # Verify the certificate chain curl -v https://whoami.docker.localhost/ 2>&1 | grep -i "server certificate" You should see that your certificate is issued by Let's Encrypt. Configure Sticky Sessions Sticky sessions ensure that a user's requests always go to the same backend server, which is essential for applications that maintain session state. Let's implement sticky sessions for our whoami service. First, Scale Up the Deployment To demonstrate sticky sessions, first scale up the deployment to 3 replicas: kubectl scale deployment whoami --replicas=3 Using Gateway API with TraefikService First, create the TraefikService for sticky sessions: apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: whoami-sticky namespace: default spec: weighted: services: - name: whoami port: 80 weight: 1 sticky: cookie: name: sticky_cookie secure: true httpOnly: true Save this as whoami-sticky-service.yaml and apply it: kubectl apply -f whoami-sticky-service.yaml Now update your HTTPRoute with an annotation referencing the TraefikService: apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami namespace: default spec: parentRefs: - name: traefik-gateway sectionName: websecure hostnames: - "whoami.docker.localhost" rules: - matches: - path: type: PathPrefix value: /api filters: - type: ExtensionRef extensionRef: # Headers Middleware Definition group: traefik.io kind: Middleware name: secure-headers - type: ExtensionRef extensionRef: # IP AllowList Middleware Definition group: traefik.io kind: Middleware name: ip-allowlist backendRefs: - name: whoami-api port: 80 - matches: - path: type: PathPrefix value: / backendRefs: - group: traefik.io # <── tell Gateway this is a TraefikService kind: TraefikService name: whoami-sticky filters: - type: ExtensionRef extensionRef: # Headers Middleware Definition group: traefik.io kind: Middleware name: secure-headers - type: ExtensionRef extensionRef: # IP AllowList Middleware Definition group: traefik.io kind: Middleware name: ip-allowlist backendRefs: - name: whoami port: 80 Update the file whoami-route.yaml and apply it: kubectl apply -f whoami-route.yaml Using IngressRoute with TraefikService First, create the TraefikService for sticky sessions: apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: whoami-sticky namespace: default spec: weighted: services: - name: whoami port: 80 sticky: cookie: name: sticky_cookie secure: true httpOnly: true Save this as whoami-sticky-service.yaml and apply it: kubectl apply -f whoami-sticky-service.yaml Now update your IngressRoute to use this TraefikService: apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: whoami namespace: default spec: entryPoints: - websecure routes: - match: Host(`whoami.docker.localhost`) && Path(`/api`) kind: Rule middlewares: # Middleware Definition - name: secure-headers - name: ip-allowlist services: - name: whoami-api port: 80 - match: Host(`whoami.docker.localhost`) kind: Rule middlewares: # Middleware Definition - name: secure-headers - name: ip-allowlist services: - name: whoami-sticky # Changed from whoami to whoami-sticky kind: TraefikService # Added kind: TraefikService tls: certResolver: le Update the file whoami-ingressroute.yaml and apply it: kubectl apply -f whoami-ingressroute.yaml Test Sticky Sessions You can test the sticky sessions by making multiple requests and observing that they all go to the same backend pod: # First request - save cookies to a file curl -k -c cookies.txt -H "Host: whoami.docker.localhost" https://localhost/ # Subsequent requests - use the cookies curl -k -b cookies.txt -H "Host: whoami.docker.localhost" https://localhost/ curl -k -b cookies.txt -H "Host: whoami.docker.localhost" https://localhost/ Pay attention to the Hostname field in each response - it should remain the same across all requests when using the cookie file, confirming that sticky sessions are working. For comparison, try making requests without the cookie: # Requests without cookies should be load-balanced across different pods curl -k -H "Host: whoami.docker.localhost" https://localhost/ curl -k -H "Host: whoami.docker.localhost" https://localhost/ You should see different Hostname values in these responses, as each request is load-balanced to a different pod. !!! important "Browser Testing" When testing in browsers, you need to use the same browser session to maintain the cookie. The cookie is set with httpOnly and secure flags for security, so it will only be sent over HTTPS connections and won't be accessible via JavaScript. For more advanced configuration options, see the reference documentation. Setup Multi-Layer Routing Multi-layer routing enables hierarchical relationships between routers, where parent routers can process requests through middleware before child routers make final routing decisions. This is particularly useful for authentication-based routing or staged middleware application. !!! info "IngressRoute Support" Multi-layer routing is natively supported by Kubernetes IngressRoute (CRD) using the spec.parentRefs field. This feature is not available when using standard Kubernetes Ingress or Gateway API resources. Authentication-Based Routing Example Let's create a multi-layer routing setup where a parent IngressRoute authenticates requests, and child IngressRoutes direct traffic based on user roles. !!! important "Parent Router Requirements" Parent routers in multi-layer routing must not have a service defined. The child routers will handle the service selection based on their matching rules. Make sure all child IngressRoutes reference the parent correctly using parentRefs. First, deploy your backend services: # whoami-backends.yaml apiVersion: apps/v1 kind: Deployment metadata: name: admin-backend namespace: default spec: replicas: 2 selector: matchLabels: app: admin-backend template: metadata: labels: app: admin-backend spec: containers: - name: whoami image: traefik/whoami env: - name: WHOAMI_NAME value: "Admin Backend" ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: admin-backend namespace: default spec: selector: app: admin-backend ports: - port: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: user-backend namespace: default spec: replicas: 2 selector: matchLabels: app: user-backend template: metadata: labels: app: user-backend spec: containers: - name: whoami image: traefik/whoami env: - name: WHOAMI_NAME value: "User Backend" ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: user-backend namespace: default spec: selector: app: user-backend ports: - port: 80 Apply the backend services: kubectl apply -f whoami-backends.yaml Now create the middleware and IngressRoutes for multi-layer routing: # mlr-ingressroute.yaml apiVersion: v1 kind: Secret metadata: name: auth-secret namespace: default type: Opaque stringData: users: | admin:$apr1$DmXR3Add$wfdbGw6RWIhFb0ffXMM4d0 user:$apr1$GJtcIY1o$mSLdsWYeXpPHVsxGDqadI. --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: auth-middleware namespace: default spec: basicAuth: secret: auth-secret headerField: X-Auth-User --- apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: api-parent namespace: default spec: entryPoints: - websecure routes: - match: Host(`api.docker.localhost`) && PathPrefix(`/api`) kind: Rule middlewares: - name: auth-middleware # Note: No services and no TLS config - this is a parent IngressRoute --- apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: api-admin namespace: default spec: parentRefs: - name: api-parent namespace: default # Optional, defaults to same namespace routes: - match: HeadersRegexp(`X-Auth-User`, `admin`) kind: Rule services: - name: admin-backend port: 80 --- apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: api-user namespace: default spec: parentRefs: - name: api-parent namespace: default # Optional, defaults to same namespace routes: - match: HeadersRegexp(`X-Auth-User`, `user`) kind: Rule services: - name: user-backend port: 80 !!! note "Generating Password Hashes" The password hashes above are generated using htpasswd. To create your own user credentials: ```bash # Using htpasswd (Apache utils) htpasswd -nb admin yourpassword ``` Apply the multi-layer routing configuration: kubectl apply -f mlr-ingressroute.yaml Test Multi-Layer Routing Test the routing behavior: # Request goes through parent router → auth middleware → admin child router curl -k -u admin:test -H "Host: api.docker.localhost" https://localhost/api You should see the response from the admin-backend service when authenticating as admin. Try with user:test credentials to reach the user-backend service instead. How It Works Request arrives at api.docker.localhost/api Parent IngressRoute ( api-parent) matches based on host and path BasicAuth middleware authenticates the user and sets the X-Auth-User header with the username Child IngressRoute ( api-admin or api-user) matches based on the header value Request forwarded to the appropriate Kubernetes service Cross-Namespace Parent References You can reference parent IngressRoutes in different namespaces by specifying the namespace field: apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: api-child namespace: app-namespace spec: parentRefs: - name: api-parent namespace: shared-namespace # Parent in different namespace routes: - match: Path(`/child`) kind: Rule services: - name: child-service port: 80 !!! important "Cross-Namespace Requirement" To use cross-namespace parent references, you must enable the allowCrossNamespace option in your Traefik Helm values: ```yaml providers: kubernetesCRD: allowCrossNamespace: true ``` Multiple Parent References Child IngressRoutes can reference multiple parent IngressRoutes: apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: api-child namespace: default spec: parentRefs: - name: parent-one - name: parent-two routes: - match: Path(`/api`) kind: Rule services: - name: child-service port: 80 For more details about multi-layer routing, see the Multi-Layer Routing documentation. Service Middlewares Service middlewares allow you to apply middleware to a service rather than to individual routers. This means the middleware takes effect for all requests handled by the service, regardless of which router forwards the request. This is useful when you want to apply the same middleware (like headers, rate limiting, or authentication) to all traffic reaching a service without having to configure it on each router. When to Use Service Middlewares Use service middlewares when: Multiple routers forward traffic to the same service, and all should have the same middleware applied You want to ensure a middleware is always applied to a service regardless of how traffic reaches it You're centralizing middleware configuration at the service level for easier management !!! info "Service-Level vs Router-Level Middlewares" - **Router-level middleware**: Applied only when traffic matches that specific router's rule - **Service-level middleware**: Applied to all traffic reaching the service, regardless of which router forwarded it When both are configured, router middlewares execute first, followed by service middlewares. Using IngressRoute with Service Middlewares With IngressRoute, you can attach middlewares directly to a service reference within a route: apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: service-headers namespace: default spec: headers: customRequestHeaders: X-Service-Middleware: "applied" --- apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: whoami namespace: default spec: entryPoints: - websecure routes: - match: Host(`whoami.docker.localhost`) kind: Rule services: - name: whoami port: 80 middlewares: - name: service-headers tls: {} Save this as service-middleware-ingressroute.yaml and apply it: kubectl apply -f service-middleware-ingressroute.yaml Using Gateway API with Backend Filters Gateway API supports applying filters directly to individual backends through the backendRefs[].filters field. This enables backend-level request modifications. apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: service-headers namespace: default spec: headers: customRequestHeaders: X-Service-Middleware: "applied" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami namespace: default spec: parentRefs: - name: traefik-gateway sectionName: websecure hostnames: - "whoami.docker.localhost" rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: whoami port: 80 filters: - type: ExtensionRef extensionRef: group: traefik.io kind: Middleware name: service-headers Gateway API also supports the native RequestHeaderModifier filter type for simpler header modifications: apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami namespace: default spec: parentRefs: - name: traefik-gateway sectionName: websecure hostnames: - "whoami.docker.localhost" rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: whoami port: 80 filters: - type: RequestHeaderModifier requestHeaderModifier: add: - name: X-Backend-Header value: "gateway-api-filter" Save and apply: kubectl apply -f service-middleware-gateway.yaml Using Kubernetes Ingress with Service Annotation For standard Kubernetes Ingress, you can apply middlewares to a service using annotations: apiVersion: v1 kind: Service metadata: name: whoami namespace: default annotations: traefik.ingress.kubernetes.io/service.middlewares: default-service-headers@kubernetescrd spec: selector: app: whoami ports: - port: 80 The annotation value follows the format -@kubernetescrd. When safeNaming is enabled, the value becomes _@kubernetescrd, using the same _ separator as the other names generated by the provider. Test Service Middleware Verify the service middleware is working: curl -k -H "Host: whoami.docker.localhost" https://localhost/ In the response from whoami, you should see the custom header that was added by the service middleware: X-Service-Middleware: applied For more details on service middlewares, see the reference documentation. Conclusion In this advanced guide, you've learned how to: Add security with middlewares like secure headers and IP allow listing Automate certificate management with Let's Encrypt (IngressRoute) and cert-manager (Gateway API) Implement sticky sessions for stateful applications Setup multi-layer routing for authentication-based routing (IngressRoute only) Apply middlewares at the service level for centralized middleware management These advanced capabilities allow you to build production-ready Traefik deployments with Kubernetes. Each of these can be further customized to meet your specific requirements. Next Steps Now that you've mastered both basic and advanced Traefik features with Kubernetes, you might want to explore: Advanced routing options like query parameter matching, header-based routing, and more Additional middlewares for authentication, rate limiting, and request modifications Observability features for monitoring and debugging your Traefik deployment TCP services for exposing TCP services UDP services for exposing UDP services Kubernetes Provider documentation for more details about the Kubernetes integration Gateway API provider documentation for more details about the Gateway API integration Exposing Services with Traefik on Kubernetes - Basic This guide will help you get started with exposing your services through Traefik Proxy on Kubernetes. You'll learn the fundamentals of routing HTTP traffic, setting up path-based routing, and securing your services with TLS. For routing, this guide gives you two options: Gateway API IngressRoute Feel free to choose the one that fits your needs best. Prerequisites A Kubernetes cluster with Traefik Proxy installed kubectl configured to interact with your cluster Traefik deployed using the Traefik Kubernetes Setup guide Expose Your First HTTP Service Let's expose a simple HTTP service using the whoami application. This will demonstrate basic routing to a backend service. First, create the deployment and service: apiVersion: apps/v1 kind: Deployment metadata: name: whoami namespace: default spec: replicas: 2 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: whoami namespace: default spec: selector: app: whoami ports: - port: 80 Save this as whoami.yaml and apply it: kubectl apply -f whoami.yaml Now, let's create routes using either Gateway API or IngressRoute. Using Gateway API apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami namespace: default spec: parentRefs: - name: traefik-gateway # This Gateway is automatically created by Traefik hostnames: - "whoami.docker.localhost" rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: whoami port: 80 Save this as whoami-route.yaml and apply it: kubectl apply -f whoami-route.yaml Using IngressRoute apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: whoami namespace: default spec: entryPoints: - web routes: - match: Host(`whoami.docker.localhost`) kind: Rule services: - name: whoami port: 80 Save this as whoami-ingressroute.yaml and apply it: kubectl apply -f whoami-ingressroute.yaml Verify Your Service Your service is now available at http://whoami.docker.localhost/. Test that it works: curl -H "Host: whoami.docker.localhost" http://localhost/ !!! info Make sure to remove the ports.web.http.redirections block from the values.yaml file if you followed the Kubernetes Setup Guide to install Traefik otherwise you will be redirected to the HTTPS entrypoint: ```yaml redirections: entryPoint: to: websecure ``` You should see output similar to: Hostname: whoami-6d5d964cb-8pv4k IP: 127.0.0.1 IP: ::1 IP: 10.42.0.18 IP: fe80::d4c0:3bff:fe20:b0a3 RemoteAddr: 10.42.0.17:39872 GET / HTTP/1.1 Host: whoami.docker.localhost User-Agent: curl/7.68.0 Accept: */* Accept-Encoding: gzip X-Forwarded-For: 10.42.0.1 X-Forwarded-Host: whoami.docker.localhost X-Forwarded-Port: 80 X-Forwarded-Proto: http X-Forwarded-Server: traefik-76cbd5b89c-rx5xn X-Real-Ip: 10.42.0.1 This confirms that Traefik is successfully routing requests to your whoami application. Add Routing Rules Now we'll enhance our routing by directing traffic to different services based on URL paths. This is useful for API versioning, frontend/backend separation, or organizing microservices. First, deploy a second service to represent an API: apiVersion: apps/v1 kind: Deployment metadata: name: whoami-api namespace: default spec: replicas: 1 selector: matchLabels: app: whoami-api template: metadata: labels: app: whoami-api spec: containers: - name: whoami image: traefik/whoami env: - name: WHOAMI_NAME value: "API Service" ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: whoami-api namespace: default spec: selector: app: whoami-api ports: - port: 80 Save this as whoami-api.yaml and apply it: kubectl apply -f whoami-api.yaml Now set up path-based routing: Gateway API with Path Rules Update your existing HTTPRoute to include path-based routing: apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami namespace: default spec: parentRefs: - name: traefik-gateway hostnames: - "whoami.docker.localhost" rules: - matches: - path: type: PathPrefix value: /api backendRefs: - name: whoami-api port: 80 - matches: - path: type: PathPrefix value: / backendRefs: - name: whoami port: 80 Update the file whoami-route.yaml and apply it: kubectl apply -f whoami-route.yaml IngressRoute with Path Rules Update your existing IngressRoute to include path-based routing: apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: whoami namespace: default spec: entryPoints: - web routes: - match: Host(`whoami.docker.localhost`) && Path(`/api`) kind: Rule services: - name: whoami-api port: 80 - match: Host(`whoami.docker.localhost`) kind: Rule services: - name: whoami port: 80 Save this as whoami-ingressroute.yaml and apply it: kubectl apply -f whoami-ingressroute.yaml Test the Path-Based Routing Verify that different paths route to different services: # Root path should go to the main whoami service curl -H "Host: whoami.docker.localhost" http://localhost/ # /api path should go to the whoami-api service curl -H "Host: whoami.docker.localhost" http://localhost/api For the /api requests, you should see the response showing "API Service" in the environment variables section, confirming that your path-based routing is working correctly: {"hostname":"whoami-api-67d97b4868-dvvll","ip":["127.0.0.1","::1","10.42.0.9","fe80::10aa:37ff:fe74:31f2"],"headers":{"Accept":["*/*"],"Accept-Encoding":["gzip"],"User-Agent":["curl/8.7.1"],"X-Forwarded-For":["10.42.0.1"],"X-Forwarded-Host":["whoami.docker.localhost"],"X-Forwarded-Port":["80"],"X-Forwarded-Proto":["http"],"X-Forwarded-Server":["traefik-669c479df8-vkj22"],"X-Real-Ip":["10.42.0.1"]},"url":"/api","host":"whoami.docker.localhost","method":"GET","name":"API Service","remoteAddr":"10.42.0.13:36592"} Enable TLS Let's secure our service with HTTPS by adding TLS. We'll start with a self-signed certificate for local development. Create a Self-Signed Certificate Generate a self-signed certificate: openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout tls.key -out tls.crt \ -subj "/CN=whoami.docker.localhost" Create a TLS secret in Kubernetes: kubectl create secret tls whoami-tls --cert=tls.crt --key=tls.key !!! important "Prerequisite for Gateway API with TLS" Before using the Gateway API with TLS, you must define the websecure listener in your Traefik installation. This is typically done in your Helm values. Example configuration in `values.yaml`: ```yaml ports: web: port: 80 websecure: port: 443 gateway: listeners: web: port: 80 protocol: HTTP namespacePolicy: from: All websecure: port: 443 protocol: HTTPS namespacePolicy: from: All mode: Terminate certificateRefs: - kind: Secret name: whoami-tls group: "" ``` See the Traefik Kubernetes Setup Guide for complete installation details. Gateway API with TLS Update your existing HTTPRoute to use the secured gateway listener: apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami namespace: default spec: parentRefs: - name: traefik-gateway sectionName: websecure # The HTTPS listener hostnames: - "whoami.docker.localhost" rules: - matches: - path: type: PathPrefix value: /api backendRefs: - name: whoami-api port: 80 - matches: - path: type: PathPrefix value: / backendRefs: - name: whoami port: 80 Update the file whoami-route.yaml and apply it: kubectl apply -f whoami-route.yaml IngressRoute with TLS Update your existing IngressRoute to use TLS: apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: whoami namespace: default spec: entryPoints: - websecure # Changed from 'web' to 'websecure' routes: - match: Host(`whoami.docker.localhost`) && Path(`/api`) kind: Rule services: - name: whoami-api port: 80 - match: Host(`whoami.docker.localhost`) kind: Rule services: - name: whoami port: 80 tls: secretName: whoami-tls # Added TLS configuration Update the file whoami-ingressroute.yaml and apply it: kubectl apply -f whoami-ingressroute.yaml Verify HTTPS Access Now you can access your service securely. Since we're using a self-signed certificate, you'll need to skip certificate verification: curl -k -H "Host: whoami.docker.localhost" https://localhost/ Your browser can also access https://whoami.docker.localhost/ (you'll need to accept the security warning for the self-signed certificate). Next Steps Now that you've mastered the basics of exposing services with Traefik on Kubernetes, you're ready to explore more advanced features like middlewares, Let's Encrypt certificates, sticky sessions, and multi-layer routing. Continue to the Advanced Guide to learn about: Adding middlewares for security and access control Generating certificates with Let's Encrypt (IngressRoute) or cert-manager (Gateway API) Configuring sticky sessions for stateful applications Setting up multi-layer routing for authentication-based routing with IngressRoute Exposing Services with Traefik on Docker Swarm - Advanced This guide builds on the concepts and setup from the Basic Guide. Make sure you've completed the basic guide and have a working Traefik setup with Docker Swarm before proceeding. In this advanced guide, you'll learn how to enhance your Traefik deployment with: Middlewares for security headers and access control Let's Encrypt for automated certificate management Sticky sessions for stateful applications Multi-layer routing for complex authentication scenarios Service middlewares for applying middleware at the service level Prerequisites Completed the Basic Guide Docker Swarm cluster initialized Working Traefik setup from the basic guide Add Middlewares Middlewares allow you to modify requests or responses as they pass through Traefik. Let's add two useful middlewares: Headers for security and IP allowlisting for access control. Add the following labels to your whoami service deployment section in docker-compose.yml: deploy: # ... existing configuration ... labels: # ... existing labels ... # Secure Headers Middleware - "traefik.http.middlewares.secure-headers.headers.frameDeny=true" - "traefik.http.middlewares.secure-headers.headers.sslRedirect=true" - "traefik.http.middlewares.secure-headers.headers.browserXssFilter=true" - "traefik.http.middlewares.secure-headers.headers.contentTypeNosniff=true" - "traefik.http.middlewares.secure-headers.headers.stsIncludeSubdomains=true" - "traefik.http.middlewares.secure-headers.headers.stsPreload=true" - "traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000" # IP Allowlist Middleware - "traefik.http.middlewares.ip-allowlist.ipallowlist.sourceRange=127.0.0.1/32,192.168.0.0/16,10.0.0.0/8" # Apply the middlewares - "traefik.http.routers.whoami.middlewares=secure-headers,ip-allowlist" Add the same middleware to your whoami-api service: deploy: # ... existing configuration ... labels: # ... existing labels ... - "traefik.http.routers.whoami-api.middlewares=secure-headers,ip-allowlist" Apply the changes: docker stack deploy -c docker-compose.yml traefik Test the Middlewares Now let's verify that our middlewares are working correctly: Test the Secure Headers middleware: curl -k -I -H "Host: whoami.swarm.localhost" https://localhost/ In the response headers, you should see security headers set by the middleware: X-Frame-Options: DENY X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Strict-Transport-Security with the appropriate settings Test the IP Allowlist middleware: If your request comes from an IP that's in the allow list (e.g., 127.0.0.1), it should succeed: curl -k -I -H "Host: whoami.swarm.localhost" https://localhost/ If you try to access from an IP not in the allow list, the request will be rejected with a 403 Forbidden response. To simulate this in a local environment, you can modify the middleware configuration temporarily to exclude your IP address, then test again. Generate Certificates with Let's Encrypt Let's Encrypt provides free, automated TLS certificates. Let's configure Traefik to automatically obtain and renew certificates for our services. Instead of using self-signed certificates, update your existing docker-compose.yml file with the following changes: Add the Let's Encrypt certificate resolver to the Traefik service command section: command: # ... existing commands ... # Let's Encrypt configuration - "--certificatesresolvers.le.acme.email=your-email@example.com" # replace with your actual email - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json" - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web" Add a volume for Let's Encrypt certificates: volumes: # ...Existing volumes... - letsencrypt:/letsencrypt Update your service labels to use the certificate resolver: labels: # ... existing labels ... - "traefik.http.routers.whoami.tls.certresolver=le" Do the same for any other services you want to secure: labels: # ... existing labels ... - "traefik.http.routers.whoami-api.tls.certresolver=le" Create a named volume for storing Let's Encrypt certificates by adding to the volumes section: volumes: # ... existing volumes ... letsencrypt: driver: local Apply the changes: docker stack deploy -c docker-compose.yml traefik !!! important "Public DNS Required" Let's Encrypt may require a publicly accessible domain to validate domain ownership. For testing with local domains like whoami.swarm.localhost, the certificate will remain self-signed. In production, replace it with a real domain that has a publicly accessible DNS record pointing to your Traefik instance. Once the certificate is issued, you can verify it: # Verify the certificate chain curl -v https://whoami.swarm.localhost/ 2>&1 | grep -i "server certificate" You should see that your certificate is issued by Let's Encrypt. Configure Sticky Sessions Sticky sessions ensure that a user's requests always go to the same backend server, which is essential for applications that maintain session state. Let's implement sticky sessions for our whoami service. Docker Swarm already has multiple replicas running; we'll now add sticky session configuration. Update your whoami service in the docker-compose.yml file: Add Sticky Session Configuration Add the following labels to your whoami service in the docker-compose.yml file: deploy: # ... existing configuration ... labels: # ... existing labels ... # Sticky Sessions Configuration - "traefik.http.services.whoami.loadbalancer.sticky.cookie=true" - "traefik.http.services.whoami.loadbalancer.sticky.cookie.name=sticky_cookie" - "traefik.http.services.whoami.loadbalancer.sticky.cookie.secure=true" - "traefik.http.services.whoami.loadbalancer.sticky.cookie.httpOnly=true" Apply the changes: docker stack deploy -c docker-compose.yml traefik Test Sticky Sessions You can test the sticky sessions by making multiple requests and observing that they all go to the same backend container: # First request - save cookies to a file curl -k -c cookies.txt -H "Host: whoami.swarm.localhost" https://localhost/ # Subsequent requests - use the cookies curl -k -b cookies.txt -H "Host: whoami.swarm.localhost" https://localhost/ curl -k -b cookies.txt -H "Host: whoami.swarm.localhost" https://localhost/ Pay attention to the Hostname field in each response - it should remain the same across all requests when using the cookie file, confirming that sticky sessions are working. For comparison, try making requests without the cookie: # Requests without cookies should be load-balanced across different containers curl -k -H "Host: whoami.swarm.localhost" https://localhost/ curl -k -H "Host: whoami.swarm.localhost" https://localhost/ You should see different Hostname values in these responses, as each request is load-balanced to a different container. !!! important "Browser Testing" When testing in browsers, you need to use the same browser session to maintain the cookie. The cookie is set with httpOnly and secure flags for security, so it will only be sent over HTTPS connections and won't be accessible via JavaScript. For more advanced configuration options, see the reference documentation. Multi-Layer Routing Multi-layer routing enables hierarchical relationships between routers, where parent routers can process requests through middleware before child routers make final routing decisions. This is particularly useful for authentication-based routing or staged middleware application. !!! info "Provider Requirement" Multi-layer routing requires the File provider, as Docker Swarm labels do not support the parentRefs field. However, you can use both Docker Swarm and File providers together - Swarm labels for service discovery and File configuration for multi-layer routing. Setup Multi-Layer Routing with Docker Swarm To use multi-layer routing with Docker Swarm, you need to enable the File provider alongside the Docker provider. Update your Traefik service in docker-compose.yml: services: traefik: image: traefik:v3.4 command: - "--api.dashboard=true" - "--providers.docker.swarmMode=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=traefik_proxy" - "--providers.file.directory=/etc/traefik/dynamic" # Enable File provider - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--entrypoints.websecure.http.tls=true" ports: - "80:80" - "443:443" - "8080:8080" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro configs: - source: mlr-config target: /etc/traefik/dynamic/mlr.yml networks: - traefik_proxy deploy: placement: constraints: - node.role == manager configs: mlr-config: file: ./dynamic/mlr.yml networks: traefik_proxy: external: true Authentication-Based Routing Example Let's create a multi-layer routing setup where a parent router authenticates requests, and child routers direct traffic based on user roles. First, keep your Docker Swarm services defined with labels as usual: # In docker-compose.yml services: # ... traefik service from above ... # Admin backend service admin-backend: image: traefik/whoami networks: - traefik_proxy environment: - WHOAMI_NAME=Admin Backend deploy: replicas: 2 labels: - "traefik.enable=true" - "traefik.http.services.admin-backend.loadbalancer.server.port=80" # User backend service user-backend: image: traefik/whoami networks: - traefik_proxy environment: - WHOAMI_NAME=User Backend deploy: replicas: 2 labels: - "traefik.enable=true" - "traefik.http.services.user-backend.loadbalancer.server.port=80" Now create the multi-layer routing configuration in a file. Create dynamic/mlr.yml: http: routers: # Parent router with authentication middleware api-parent: rule: "Host(`api.swarm.localhost`) && PathPrefix(`/api`)" middlewares: - auth-middleware entryPoints: - websecure # Note: No service and no TLS config - this is a parent router # Child router for admin users api-admin: rule: "HeadersRegexp(`X-Auth-User`, `admin`)" service: admin-backend@swarm # Reference Swarm service parentRefs: - api-parent@file # Explicit reference to parent in file provider # Child router for regular users api-user: rule: "HeadersRegexp(`X-Auth-User`, `user`)" service: user-backend@swarm # Reference Swarm service parentRefs: - api-parent@file # Explicit reference to parent in file provider middlewares: auth-middleware: basicAuth: users: - "admin:$apr1$DmXR3Add$wfdbGw6RWIhFb0ffXMM4d0" - "user:$apr1$GJtcIY1o$mSLdsWYeXpPHVsxGDqadI." headerField: X-Auth-User !!! note "Generating Password Hashes" The password hashes above are generated using htpasswd. To create your own user credentials: ```bash # Using htpasswd (Apache utils) htpasswd -nb admin yourpassword ``` !!! important "Cross-Provider References" Notice the @swarm suffix on service names and the @file suffix in parentRefs. When using the File provider to orchestrate multi-layer routing with Swarm services: - Use `service-name@swarm` to reference Swarm services - Use `parent-name@file` in `parentRefs` to reference the parent router in the File provider The `@provider` suffix tells Traefik which provider namespace to look in for the resource. Deploy the stack: docker stack deploy -c docker-compose.yml traefik Test Multi-Layer Routing Test the routing behavior: # Request goes through parent router → auth middleware → admin child router curl -k -u admin:test -H "Host: api.swarm.localhost" https://localhost/api You should see the response from the admin-backend service when authenticating as admin. Try with user:test credentials to reach the user-backend service instead. How It Works Request arrives at api.swarm.localhost/api Parent router ( api-parent) matches based on host and path BasicAuth middleware authenticates the user and sets the X-Auth-User header with the username Child router ( api-admin or api-user) matches based on the header value Request forwarded to the appropriate Swarm service For more details about multi-layer routing, see the Multi-Layer Routing documentation. Service Middlewares Service middlewares allow you to apply middleware to a service rather than to individual routers. This means the middleware takes effect for all requests handled by the service, regardless of which router forwards the request. This is useful when you want to apply the same middleware (like headers, rate limiting, or authentication) to all traffic reaching a service without having to configure it on each router. When to Use Service Middlewares Use service middlewares when: Multiple routers forward traffic to the same service, and all should have the same middleware applied You want to ensure a middleware is always applied to a service regardless of how traffic reaches it You're centralizing middleware configuration at the service level for easier management Add Service Middleware Labels Add the following labels to your whoami service deployment section in docker-compose.yml: services: whoami: image: traefik/whoami networks: - traefik_proxy deploy: replicas: 2 labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.swarm.localhost`)" - "traefik.http.routers.whoami.entrypoints=websecure" - "traefik.http.routers.whoami.tls=true" # Define the middleware - "traefik.http.middlewares.service-headers.headers.customRequestHeaders.X-Service-Middleware=applied" # Attach middleware at the SERVICE level (not the router level) - "traefik.http.services.whoami.middlewares=service-headers" - "traefik.http.services.whoami.loadbalancer.server.port=80" !!! info "Service-Level vs Router-Level Middlewares" - **Router-level middleware** (`traefik.http.routers..middlewares`): Applied only when traffic matches that specific router's rule - **Service-level middleware** (`traefik.http.services..middlewares`): Applied to all traffic reaching the service, regardless of which router forwarded it When both are configured, router middlewares execute first, followed by service middlewares. Deploy the stack: docker stack deploy -c docker-compose.yml traefik Test Service Middleware Verify the service middleware is working: curl -k -H "Host: whoami.swarm.localhost" https://localhost/ In the response from whoami, you should see the custom header that was added by the service middleware: X-Service-Middleware: applied For more details on service middlewares, see the reference documentation. Conclusion In this advanced guide, you've learned how to: Add security with middlewares like secure headers and IP allow listing Automate certificate management with Let's Encrypt Implement sticky sessions for stateful applications Setup multi-layer routing for authentication-based routing Apply middlewares at the service level for centralized middleware management These advanced capabilities allow you to build production-ready Traefik deployments with Docker Swarm. Each of these can be further customized to meet your specific requirements. Next Steps Now that you've mastered both basic and advanced Traefik features with Docker Swarm, you might want to explore: Advanced routing options like query parameter matching, header-based routing, and more Additional middlewares for authentication, rate limiting, and request modifications Observability features for monitoring and debugging your Traefik deployment TCP services for exposing TCP services UDP services for exposing UDP services Docker Swarm provider documentation for more details about the Docker Swarm integration Exposing Services with Traefik on Docker Swarm - Basic This guide will help you get started with exposing your services through Traefik Proxy using Docker Swarm. You'll learn the fundamentals of routing HTTP traffic, setting up path-based routing, and securing your services with TLS. Prerequisites Docker Swarm cluster initialized Basic understanding of Docker Swarm concepts Traefik deployed using the Traefik Docker Swarm Setup guide Expose Your First HTTP Service Let's expose a simple HTTP service using the whoami application. This will demonstrate basic routing to a backend service. First, update your existing docker-compose.yml file if you haven't already: services: whoami: image: traefik/whoami networks: - traefik_proxy deploy: replicas: 3 labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.swarm.localhost`)" - "traefik.http.routers.whoami.entrypoints=web,websecure" Save this as docker-compose.yml and deploy the stack: docker stack deploy -c docker-compose.yml traefik Verify Your Service Your service is now available at http://whoami.swarm.localhost/. Test that it works: curl -H "Host: whoami.swarm.localhost" http://localhost/ You should see output similar to: Hostname: whoami.1.7c8f7tr56q3p949rscxrkp80e IP: 127.0.0.1 IP: ::1 IP: 10.0.1.8 IP: fe80::215:5dff:fe00:c9e RemoteAddr: 10.0.1.2:45098 GET / HTTP/1.1 Host: whoami.swarm.localhost User-Agent: curl/7.68.0 Accept: */* Accept-Encoding: gzip X-Forwarded-For: 10.0.1.1 X-Forwarded-Host: whoami.swarm.localhost X-Forwarded-Port: 80 X-Forwarded-Proto: http X-Forwarded-Server: 5789f594e7d5 X-Real-Ip: 10.0.1.1 This confirms that Traefik is successfully routing requests to your whoami application. Add Routing Rules Now we'll enhance our routing by directing traffic to different services based on URL paths. This is useful for API versioning, frontend/backend separation, or organizing microservices. Update your docker-compose.yml to add another service: # ... # New service whoami-api: image: traefik/whoami networks: - traefik_proxy environment: - WHOAMI_NAME=API Service deploy: replicas: 2 labels: - "traefik.enable=true" # Path-based routing - "traefik.http.routers.whoami-api.rule=Host(`whoami.swarm.localhost`) && PathPrefix(`/api`)" - "traefik.http.routers.whoami-api.entrypoints=web,websecure" - "traefik.http.routers.whoami-api.service=whoami-api-svc" - "traefik.http.services.whoami-api-svc.loadbalancer.server.port=80" # ... Apply the changes: docker stack deploy -c docker-compose.yml traefik Test the Path-Based Routing Verify that different paths route to different services: # Root path should go to the main whoami service curl -H "Host: whoami.swarm.localhost" http://localhost/ # /api path should go to the whoami-api service curl -H "Host: whoami.swarm.localhost" http://localhost/api For the /api requests, you should see the response showing "API Service" in the environment variables section, confirming that your path-based routing is working correctly. Enable TLS Let's secure our service with HTTPS by adding TLS. We'll start with a self-signed certificate for local development. Create a Self-Signed Certificate Generate a self-signed certificate and dynamic config file to tell Traefik where the cert lives: mkdir -p certs # key + cert (valid for one year) openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout certs/local.key -out certs/local.crt \ -subj "/CN=*.swarm.localhost" # dynamic config that tells Traefik where the cert lives cat > certs/tls.yml <<'EOF' tls: certificates: - certFile: /certificates/local.crt keyFile: /certificates/local.key EOF Create a Docker config for the certificate files: docker config create swarm-cert.crt certs/local.crt docker config create swarm-cert.key certs/local.key docker config create swarm-tls.yml certs/tls.yml Update your docker-compose.yml file with the following changes: # Add to the Traefik command section: command: # ... existing commands ... - "--entryPoints.websecure.address=:443" - "--entryPoints.websecure.http.tls=true" - "--providers.file.directory=/etc/traefik/dynamic" # Add to the root of your docker-compose.yml file: configs: swarm-cert.crt: file: ./certs/local.crt swarm-cert.key: file: ./certs/local.key swarm-tls.yml: file: ./certs/tls.yml Deploy the stack: docker stack deploy -c docker-compose.yml traefik Your browser can access https://whoami.swarm.localhost/ for the service. You'll need to accept the security warning for the self-signed certificate. Next Steps Now that you've mastered the basics of exposing services with Traefik on Docker Swarm, you're ready to explore more advanced features like middlewares, Let's Encrypt certificates, sticky sessions, and multi-layer routing. Continue to the Advanced Guide to learn about: Adding middlewares for security and access control Generating certificates with Let's Encrypt Configuring sticky sessions for stateful applications Setting up multi-layer routing for authentication-based routing Extend Traefik Plugins are a powerful feature for extending Traefik with custom features and behaviors. The Plugin Catalog is a software-as-a-service (SaaS) platform that provides an exhaustive list of the existing plugins. ??? note "Plugin Catalog Access" You can reach the Plugin Catalog from the Traefik Dashboard using the Plugins menu entry. Add a new plugin to a Traefik instance To add a new plugin to a Traefik instance, you must change that instance's install (static) configuration. Each plugin's Install section provides an install (static) configuration example. Many plugins have their own section in the Traefik routing (dynamic) configuration. !!! danger "Experimental Features" Plugins can change the behavior of Traefik in unforeseen ways. Exercise caution when adding new plugins to production Traefik instances. To learn more about how to add a new plugin to a Traefik instance, please refer to the developer documentation. Plugin Systems Traefik supports two different plugin systems, each designed for different use cases and developer preferences. Yaegi Plugin System Traefik Yaegi plugins are developed using the Go language. It is essentially a Go package. Unlike pre-compiled plugins, Yaegi plugins are executed on the fly by Yaegi, a Go interpreter embedded in Traefik. This approach eliminates the need for compilation and a complex toolchain, making plugin development as straightforward as creating web browser extensions. Yaegi plugins support both middleware and provider functionality. Key characteristics Written in Go language No compilation required Executed by embedded interpreter Supports full Go feature set Hot-reloadable during development WebAssembly (WASM) Plugin System Traefik WASM plugins can be developed using any language that compiles to WebAssembly (WASM). This method is based on http-wasm. WASM plugins compile to portable binary modules that execute with near-native performance while maintaining security isolation. Key characteristics Multi-language support (Go, Rust, C++, etc.) Compiled to WebAssembly binary Near-native performance Strong security isolation Currently supports middleware only Build Your Own Plugins Traefik users can create their own plugins and share them with the community using the Plugin Catalog. To learn more about Traefik plugin creation, please refer to the developer documentation. Traefik Product Features Comparison The Traefik ecosystem offers multiple products designed to meet different requirements, from basic reverse proxy functionality to comprehensive API management and AI gateway capabilities. This comparison matrix helps you understand the features available in each product and choose the right solution for your use case. Product Overview Traefik Proxy is the open-source application proxy that serves as the foundation for all Traefik products. It provides essential reverse proxy, load balancing, and service discovery capabilities. Traefik Hub API Gateway builds on Traefik Proxy with enterprise-grade security, distributed features, and advanced access control for cloud-native API gateway scenarios. It includes AI Gateway capabilities that transform any AI endpoint into a managed API. Traefik Hub API Management adds comprehensive API lifecycle management, developer portals, and organizational features for teams managing multiple APIs across environments. Traefik AI Gateway transforms any AI endpoint into a managed API with unified access to multiple LLMs, centralized credential management, semantic caching, local inferencing, and comprehensive AI governance features. Traefik MCP Gateway provides secure, governed access to Model Context Protocol (MCP) servers for AI agents with task-based access control (TBAC), session-smart routing, and comprehensive audit capabilities for enterprise AI workflows. Features Matrix Feature Traefik Proxy Traefik Hub API Gateway Traefik Hub API Management Core Networking Services Auto-Discovery ✓ ✓ ✓ Graceful Configuration Reload ✓ ✓ ✓ Websockets, HTTP/2, HTTP/3, TCP, UDP, GRPC ✓ ✓ ✓ Real-time Logs, Access Logs, Metrics & Distributed Tracing ✓ ✓ ✓ Canary Deployments ✓ ✓ ✓ Let's Encrypt ✓ ✓ ✓ Plugin Ecosystem Plugin Support (Go, WASM) ✓ ✓ ✓ Deployment & Operations Hybrid cloud, multi-cloud & on-prem compatible ✓ ✓ ✓ Per-cluster dashboard ✓ ✓ ✓ GitOps-native declarative configuration ✓ ✓ ✓ Authentication & Authorization JWT Authentication ✗ ✓ ✓ OAuth 2.0 Token Introspection Authentication ✗ ✓ ✓ OAuth 2.0 Client Credentials Authentication ✗ ✓ ✓ OpenID Connect Authentication ✗ ✓ ✓ Lightweight Directory Access Protocol (LDAP) ✗ ✓ ✓ API Key Authentication ✗ ✓ ✓ Security & Policy Open Policy Agent ✗ ✓ ✓ Native Coraza Web Application Firewall (WAF) ✗ ✓ ✓ HashiCorp Vault Integration ✗ ✓ ✓ Distributed Features Distributed Let's Encrypt ✗ ✓ ✓ Distributed Rate Limit ✗ ✓ ✓ HTTP Caching ✗ ✓ ✓ Compliance FIPS 140-2 Compliance (Linux & Windows) ✗ ✓ ✓ AI Gateway Capabilities Unified Multi-LLM API Access ✗ ✓ ✓ Centralized AI Credential Management ✗ ✓ ✓ AI Provider Flexibility (OpenAI, Anthropic, Azure OpenAI, AWS Bedrock, etc.) ✗ ✓ ✓ Semantic Caching for AI Responses ✗ ✓ ✓ Content Guard & PII Protection ✗ ✓ ✓ AI-specific Observability & OpenTelemetry Integration ✗ ✓ ✓ Support for Local/Self-hosted LLMs & Inference (Ollama, Mistral, etc.) ✗ ✓ ✓ MCP Gateway Capabilities Task-Based Access Control (TBAC) for AI Agents ✗ ✓ ✓ MCP Servers Governance ✗ ✓ ✓ Session-Smart Load Balancing for Agent Workflows ✗ ✓ ✓ OAuth 2.1 / 2.0 Resource Server for MCP ✗ ✓ ✓ Fine-grained Policy Enforcement for AI Tools ✗ ✓ ✓ Audit-ready Observability for Agent Interactions ✗ ✓ ✓ API Management Flexible API grouping and versioning ✗ ✗ ✓ API Developer Portal ✗ ✗ ✓ OpenAPI Specifications Support ✗ ✗ ✓ Multi-cluster dashboard ✗ ✗ ✓ Built-in identity provider (or use your own) ✗ ✗ ✓ Configuration linter & change impact analysis ✗ ✗ ✓ Pre-built Grafana dashboards ✗ ✗ ✓ Event correlation for quick incident mitigation ✗ ✗ ✓ Traffic debugger ✗ ✓ ✓ Support Built-In Commercial Support Add-on ✓ ✓ Choosing the Right Product Start with Traefik Proxy Traefik Proxy is the ideal starting point for organizations looking for a reliable, open-source application proxy with essential networking capabilities. Deploy it as your default ingress tier if you need: Basic reverse proxy and load balancing Service discovery for containerized applications Simple TLS termination and Let's Encrypt integration Cost-effective solution with community support (can upgrade to Traefik Hub for more features) Upgrade to Traefik Hub API Gateway Traefik Hub API Gateway layers enterprise security, distributed coordination, and AI Gateway capabilities on top of Traefik Proxy. Upgrade to it when you need: Enterprise security requirements (JWT, OIDC, LDAP) Distributed deployments across multiple clusters Advanced rate limiting and caching WAF and policy enforcement AI Gateway capabilities Commercial support Consider Traefik AI Gateway Traefik AI Gateway unifies hosted and self-hosted LLM access under centralized control and observability. Consider it if you have: Multi-LLM applications requiring unified API access Organizations using multiple AI providers (OpenAI, Anthropic, Azure OpenAI, AWS Bedrock, etc.) Local/self-hosted LLM deployments (Ollama, Mistral) Centralized AI credential and security management Cost optimization through semantic caching PII protection and content filtering for AI interactions Comprehensive AI observability and compliance requirements Choose Traefik MCP Gateway Traefik MCP Gateway governs how AI agents interact with Model Context Protocol servers through task-aware policies and session-smart routing. Choose it if you need: AI agent deployments requiring secure access to MCP servers Task-based access control (TBAC) for AI workflows Governance of Model Context Protocol interactions Session-smart routing for long-running agent conversations OAuth 2.1 / 2.0 compliant MCP server protection Audit-ready observability for AI agent activities Fine-grained policy enforcement for AI tools and resources Choose Traefik Hub API Management Traefik Hub API Management extends the gateway foundation with API lifecycle tooling, developer experience features, and governance workflows. Choose it when you have: Multiple APIs requiring centralized management Developer teams needing self-service portals Complex API versioning and lifecycle requirements Multi-cluster environments requiring unified dashboards Compliance and governance needs Migration Path The Traefik ecosystem is designed for seamless upgrades. You can start with Traefik Proxy and add capabilities as your requirements grow: Traefik Proxy → Hub API Gateway: Add enterprise security, distributed features, and AI Gateway capabilities Hub API Gateway → Hub API Management: Add comprehensive API management and governance features MCP Gateway: Specialized solution for AI agent governance and Model Context Protocol management All products share the same core configuration concepts, making migration straightforward while preserving your existing configurations and operational knowledge. Configuration Introduction How the Magic Happens {: .subtitle } Configuration in Traefik can refer to two different things: The install (startup) configuration (formerly known as the static configuration) The routing configuration (formerly known as the dynamic configuration) Elements in the install configuration set up connections to providers and define the entrypoints Traefik will listen to (these elements don't change often). The routing configuration contains everything that defines how the requests are handled by your system. This configuration can change and is seamlessly hot-reloaded, without any request interruption or connection loss. !!! warning "Incompatible Configuration" Please be aware that the old configurations for Traefik v1.x are NOT compatible with the v2.x config as of now. If you are running v2, please ensure you are using a v2 configuration. The Routing Configuration Traefik gets its routing configuration from providers: whether an orchestrator, a service registry, or a plain old configuration file. Since this configuration is specific to your infrastructure choices, we invite you to refer to the dedicated section of this documentation. !!! info "" In the [Quick Start example](./docker.md), the whoami application routing configuration comes from docker in the form of a label attached to the whoami container. !!! info "HTTPS Certificates also belong to the routing configuration." You can add / update / remove them without restarting your Traefik instance. The Install Configuration There are three different, mutually exclusive (i.e. you can use only one at the same time), ways to define install configuration options in Traefik: In a configuration file In the command-line arguments As environment variables These ways are evaluated in the order listed above. If no value was provided for a given option, a default value applies. Moreover, if an option has sub-options, and any of these sub-options is not specified, a default value will apply as well. For example, the --providers.docker option is enough by itself to enable the docker provider, even though sub-options like --providers.docker.endpoint exist. Once positioned, this option sets (and resets) all the default values of the sub-options of --providers.docker. Configuration File At startup, Traefik searches for install configuration in a file named traefik.yml (or traefik.yaml or traefik.toml) in: /etc/traefik/ $XDG_CONFIG_HOME/ $HOME/.config/ . (the working directory). You can override this using the configFile argument. traefik --configFile=foo/bar/myconfigfile.yml Arguments To get the list of all available arguments: traefik --help # or docker run traefik[:version] --help # ex: docker run traefik:v3.8 --help Check the CLI reference for an overview about all available arguments. Environment Variables All available environment variables can be found in the install configuration environment overview. Available Configuration Options All the configuration options are documented in their related section. You can browse the available features in the menu, the providers, or the routing section to see them in action. {% include-markdown "includes/traefik-for-business-applications.md" %} Getting Started with Docker and Traefik Docker is a first-class citizen in Traefik, offering native support for Docker containers and services. Whether you're using Docker Compose or running containers directly, Traefik provides a seamless experience for managing your Docker traffic. This guide shows you how to: Install Traefik using Docker Expose the Traefik dashboard Deploy a sample application Configure basic routing Prerequisites Docker Docker Compose (optional) Install Traefik Using Docker Compose Create a Docker Compose file. This configuration: Exposes ports 80 and 8080. Enables the Docker provider Configures the dashboard with basic settings. Port 8080 serves the dashboard because we enabled --api.insecure=true (development use only) Mounts the Docker socket for container discovery # docker-compose.yml services: traefik: image: traefik:v3.8 command: - "--api.insecure=true" - "--providers.docker=true" - "--entrypoints.web.address=:80" ports: - "80:80" - "8080:8080" volumes: - /var/run/docker.sock:/var/run/docker.sock Start Traefik: docker-compose up -d Using Docker CLI Alternatively, you can run Traefik directly with Docker. This command: Exposes ports 80 and 8080 for web traffic and dashboard access Mounts the configuration file and Docker socket Uses the same configuration as the Docker Compose example Create a configuration file: # traefik.yml api: insecure: true entryPoints: web: address: ":80" providers: docker: {} Start Traefik: docker run -d \ -p 80:80 \ -p 8080:8080 \ -v $PWD/traefik.yml:/etc/traefik/traefik.yml \ -v /var/run/docker.sock:/var/run/docker.sock \ traefik:v3.8 Expose the Dashboard Because we explicitly enabled insecure mode, the dashboard is reachable on port 8080 without authentication. Do not enable this flag in production. You can access the dashboard at: http://localhost:8080/dashboard/ Deploy a Sample Application Create a whoami service: # whoami.yml services: whoami: image: traefik/whoami labels: - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)" Apply the configuration: docker-compose -f whoami.yml up -d Test Your Setup You can use the following curl command to verify that the application is correctly exposed: curl http://whoami.localhost Hostname: 068c0a29a8b7 IP: 127.0.0.1 IP: ::1 IP: 192.168.147.3 RemoteAddr: 192.168.147.2:56006 GET / HTTP/1.1 Host: whoami.localhost User-Agent: curl/8.7.1 Accept: */* Accept-Encoding: gzip X-Forwarded-For: 192.168.147.1 X-Forwarded-Host: whoami.localhost X-Forwarded-Port: 80 X-Forwarded-Proto: http X-Forwarded-Server: 9232cdd4fd6c X-Real-Ip: 192.168.147.1 You can also open http://whoami.localhost in a browser to test the application: If you navigate to the HTTP Routers section of the Traefik dashboard, you can see that the whoami.localhost route is managed by the Traefik Docker provider: That's it! You've successfully deployed Traefik and configured routing in Docker. Next Steps Configure TLS Set up Middlewares Enable Metrics Learn more about Docker provider {% include-markdown "includes/traefik-for-business-applications.md" %} FAQ Why is Traefik Answering XXX HTTP Response Status Code? Traefik is a dynamic reverse proxy, and while the documentation often demonstrates configuration options through file examples, the core feature of Traefik is its dynamic configurability, directly reacting to changes from providers over time. Notably, the install configuration is static, and can be provided by a file on startup, whereas various providers, such as the file provider, contribute dynamically all along the traefik instance lifetime to its routing configuration changes. In addition, the configuration englobes concepts such as the EntryPoint which can be seen as a listener on the Transport Layer (TCP), as apposed to the Router which is more about the Presentation (TLS) and Application layers (HTTP). And there can be as many routers as one wishes for a given EntryPoint. In other words, for a given Entrypoint, at any given time the traffic seen is not bound to be just about one protocol. It could be HTTP, or otherwise. Over TLS, or not. Not to mention that dynamic configuration changes potentially make that kind of traffic vary over time. Therefore, in this dynamic context, the static configuration of an entryPoint does not give any hint whatsoever about how the traffic going through that entryPoint is going to be routed. Or whether it's even going to be routed at all, that is whether there is a Router matching the kind of traffic going through it. 404 Not found Traefik returns a 404 response code in the following situations: A request reaching an EntryPoint that has no Routers An HTTP request reaching an EntryPoint that has no HTTP Router An HTTPS request reaching an EntryPoint that has no HTTPS Router A request reaching an EntryPoint that has HTTP/HTTPS Routers that cannot be matched From Traefik's point of view, every time a request cannot be matched with a router the correct response code is a 404 Not found. In this situation, the response code is not a 503 Service Unavailable because Traefik is not able to confirm that the lack of a matching router for a request is only temporary. Traefik's routing configuration is dynamic and aggregated from different providers, hence it's not possible to assume at any moment that a specific route should be handled or not. ??? info "This behavior is consistent with rfc7231" ```txt The server is currently unable to handle the request due to a temporary overloading or maintenance of the server. The implication is that this is a temporary condition which will be alleviated after some delay. If known, the length of the delay MAY be indicated in a Retry-After header. If no Retry-After is given, the client SHOULD handle the response as it would for a 500 response. Note: The existence of the 503 status code does not imply that a server must use it when becoming overloaded. Some servers may wish to simply refuse the connection. ``` Extract from [rfc7231#section-6.6.4](https://datatracker.ietf.org/doc/html/rfc7231#section-6.6.4). 502 Bad Gateway Traefik returns a 502 response code when an error happens while contacting the upstream service. 503 Service Unavailable Traefik returns a 503 response code when a Router has been matched, but there are no servers ready to handle the request. This situation is encountered when a service has been explicitly configured without servers, or when a service has healthcheck enabled and all servers are unhealthy. XXX Instead of 404 Sometimes, the 404 response code doesn't play well with other parties or services (such as CDNs). In these situations, you may want Traefik to always reply with a 503 response code, instead of a 404 response code. To achieve this behavior, a catchall router, with the lowest possible priority and routing to a service without servers, can handle all the requests when no other router has been matched. The example below is a file provider only version ( yaml) of what this configuration could look like: # traefik.yml entryPoints: web: address: :80 providers: file: filename: dynamic.yaml # dynamic.yaml http: routers: catchall: # attached only to web entryPoint entryPoints: - "web" # catchall rule rule: "PathPrefix(`/`)" service: unavailable # lowest possible priority # evaluated when no other router is matched priority: 1 services: # Service that will always answer a 503 Service Unavailable response unavailable: loadBalancer: servers: {} !!! info "Dedicated service" If there is a need for a response code other than a 503 and/or a custom message, the principle of the above example above (a catchall router) still stands, but the unavailable service should be adapted to fit such a need. Why Is My TLS Certificate Not Reloaded When Its Contents Change? With the file provider, a configuration update is only triggered when one of the watched configuration files is modified. Which is why, when a certificate is defined by path, and the actual contents of this certificate change, a configuration update is not triggered. To take into account the new certificate contents, the update of the dynamic configuration must be forced. One way to achieve that, is to trigger a file notification, for example, by using the touch command on the configuration file. What Are the Forwarded Headers When Proxying HTTP Requests? By default, the following headers are automatically added when proxying requests: Property HTTP Header Client's IP X-Forwarded-For, X-Real-Ip Host X-Forwarded-Host Port X-Forwarded-Port Protocol X-Forwarded-Proto Proxy Server's Hostname X-Forwarded-Server For more details, please check out the forwarded header documentation. How Traefik is Storing and Serving TLS Certificates? Storing TLS Certificates TLS certificates are either provided directly by the routing configuration, or by Certificate resolvers. For each TLS certificate, Traefik produces an identifier used as a key to store it. This identifier is constructed as the alphabetically ordered concatenation of the SANs DNSNames and IPAddresses of the TLScertificate. Examples: X509v3 Subject Alternative Name TLS Certificate Identifier DNS:example.com, IP Address:127.0.0.1 127.0.0.1,example.com DNS:example.com, DNS:*.example.com *.example.com,example.com The identifier is used to store TLS certificates in order to be later used to handle TLS connections. This operation happens each time there are configuration changes. If multiple TLS certificates are provided with the same SANs definition (same identifier), only the one processed first is kept. Because the dynamic configuration is aggregated from all providers, when processing it to gather TLS certificates, there is no guarantee of the order in which they would be processed. This means that along with configurations applied, it is possible that the TLS certificate retained for a given identifier differs. Serving TLS Certificates For each incoming connection, Traefik is serving the "best" matching TLS certificate for the provided server name. The TLS certificate selection process narrows down the list of TLS certificates matching the server name, and then selects the last TLS certificate in this list after having ordered it by the identifier alphabetically. Examples: Selected TLS Certificates Identifiers Sorted TLS Certificates Identifiers Served Certificate Identifier 127.0.0.1,example.com, *.example.com,example.com *.example.com,example.com, 127.0.0.1,example.com 127.0.0.1,example.com *.example.com,example.com, example.com *.example.com,example.com, example.com example.com Caching TLS Certificates While Traefik is serving the best matching TLS certificate for each incoming connection, the selection process cost for each incoming connection is avoided thanks to a cache mechanism. Once a TLS certificate has been selected as the "best" TLS certificate for a server name, it is cached for an hour, avoiding the selection process for further connections. Nonetheless, when a new configuration is applied, the cache is reset. What does the "field not found" error mean? error: field not found, node: -badField- The "field not found" error occurs, when an unknown property is encountered in the dynamic or static configuration. One way to check whether a configuration file is well-formed, is to validate it with: JSON Schema of the static configuration JSON Schema of the dynamic configuration Why are some resources (routers, middlewares, services...) not created/applied? As a common tip, if a resource is dropped/not created by Traefik after the dynamic configuration was evaluated, one should look for an error in the logs. If found, the error confirms that something went wrong while creating the resource, and the message should help in figuring out the mistake(s) in the configuration, and how to fix it. When using the file provider, one way to check if the dynamic configuration is well-formed is to validate it with the JSON Schema of the dynamic configuration. Why does Let's Encrypt wildcard certificate renewal/generation with DNS challenge fail? If you're trying to renew wildcard certificates, with DNS challenge, and you're getting errors such as: msg="Error renewing certificate from LE: {example.com [*.example.com]}" providerName=letsencrypt.acme error="error: one or more domains had a problem: [example.com] acme: error presenting token: gandiv5: unexpected authZone example.com. for fqdn example.com." then it could be due to CNAME support. In which case, you should make sure your infrastructure is properly set up for a DNS challenge that does not rely on CNAME, and you should try disabling CNAME support with: LEGO_DISABLE_CNAME_SUPPORT=true {% include-markdown "includes/traefik-for-business-applications.md" %} Getting Started with Traefik Traefik can be deployed in various environments. Choose your preferred deployment method: Kubernetes Quick Start - Deploy Traefik using Helm Docker Quick Start - Deploy Traefik using Docker Each guide will help you: Install Traefik Expose the dashboard Deploy a sample application Configure basic routing Before You Begin Make sure you have the necessary prerequisites for your chosen environment: Kubernetes: A running Kubernetes cluster, Helm 3, and kubectl Docker: Docker and optionally Docker Compose Getting Started with Kubernetes and Traefik Kubernetes is a first-class citizen in Traefik, offering native support for Kubernetes resources and the latest Kubernetes standards. Whether you're using Traefik's IngressRoute CRD, Ingress or the Kubernetes Gateway API, Traefik provides a seamless experience for managing your Kubernetes traffic. This guide shows you how to: Create a Kubernetes cluster using k3d Install Traefik using Helm Expose the Traefik dashboard Deploy a sample application Configure basic routing with IngressRoute and Gateway API Prerequisites Kubernetes Helm 3 kubectl k3d (for local cluster creation) Create a Kubernetes Cluster Using k3d Create a cluster with the following command. This command: Creates a k3d cluster named "traefik" Maps ports 80, 443, and 8000 to the loadbalancer for accessing services Disables the built-in Traefik ingress controller to avoid conflicts k3d cluster create traefik \ --port 80:80@loadbalancer \ --port 443:443@loadbalancer \ --port 8000:8000@loadbalancer \ --k3s-arg "--disable=traefik@server:0" Configure kubectl: kubectl cluster-info --context k3d-traefik Install Traefik Using Helm Values File Add the Traefik Helm repository: helm repo add traefik https://traefik.github.io/charts helm repo update Create a values file. This configuration: Maps ports 80 and 443 to the web and websecure entrypoints Enables the dashboard with a specific hostname rule Enables the Kubernetes Gateway API provider Allows the Gateway to expose HTTPRoutes from all namespaces # values.yaml ingressRoute: dashboard: enabled: true matchRule: Host(`dashboard.localhost`) entryPoints: - web providers: kubernetesGateway: enabled: true gateway: listeners: web: namespacePolicy: from: All !!! info The KubernetesCRD provider is enabled by default when using the Helm chart so we don't need to set it in the values file. Install Traefik: helm install traefik traefik/traefik -f values.yaml --wait Using Helm CLI Arguments Alternatively, you can install Traefik using CLI arguments. This command: Maps ports 30000 and 30001 to the web and websecure entrypoints Enables the dashboard with a specific hostname rule Enables the Kubernetes Gateway API provider Allows the Gateway to expose HTTPRoutes from all namespaces helm install traefik traefik/traefik --wait \ --set ingressRoute.dashboard.enabled=true \ --set ingressRoute.dashboard.matchRule='Host(`dashboard.localhost`)' \ --set ingressRoute.dashboard.entryPoints={web} \ --set providers.kubernetesGateway.enabled=true \ --set gateway.listeners.web.namespacePolicy.from=All !!! info The KubernetesCRD provider is enabled by default when using the Helm chart so we don't need to set it in the CLI arguments. When Traefik is installed with the Gateway API provider enabled, it automatically creates a default GatewayClass named traefik: kubectl describe GatewayClass traefik Expose the Dashboard The dashboard is exposed with an IngressRoute provided by the Chart, as we defined in the helm values during installation. Access it at: http://dashboard.localhost/dashboard/ Deploy a Sample Application Create a deployment: # whoami.yaml apiVersion: apps/v1 kind: Deployment metadata: name: whoami spec: replicas: 2 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami ports: - containerPort: 80 Create a service: # whoami-service.yaml apiVersion: v1 kind: Service metadata: name: whoami spec: ports: - port: 80 selector: app: whoami Apply the manifests: kubectl apply -f whoami.yaml kubectl apply -f whoami-service.yaml Exposing the Application Using an IngressRoute (CRD) Create an IngressRoute: # whoami-ingressroute.yaml apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: whoami spec: entryPoints: - web routes: - match: Host(`whoami.localhost`) kind: Rule services: - name: whoami port: 80 Apply the manifest: kubectl apply -f whoami-ingressroute.yaml Test Your Setup You can use the following curl command to verify that the application is correctly exposed: curl http://whoami.localhost Hostname: whoami-76c9859cfc-6v8hh IP: 127.0.0.1 IP: ::1 IP: 10.42.0.11 IP: fe80::20ad:eeff:fe44:a63 RemoteAddr: 10.42.0.9:38280 GET / HTTP/1.1 Host: whoami.localhost User-Agent: curl/8.7.1 Accept: */* Accept-Encoding: gzip X-Forwarded-For: 127.0.0.1 X-Forwarded-Host: whoami.localhost X-Forwarded-Port: 80 X-Forwarded-Proto: http X-Forwarded-Server: traefik-598946cd7-zds59 X-Real-Ip: 127.0.0.1 You can also visit http://whoami.localhost in a browser to verify that the application is exposed correctly: Exposing the Application Using the Gateway API Traefik supports the Kubernetes Gateway API specification, which provides a more standardized way to configure ingress in Kubernetes. When we installed Traefik earlier, we enabled the Gateway API provider. You can verify this in the providers section of the Traefik dashboard. To use the Gateway API: Install the Gateway API CRDs in your cluster: kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.3/standard-install.yaml Create an HTTPRoute. This configuration: Creates an HTTPRoute named "whoami" Attaches it to the default Gateway that Traefik created during installation Configures routing for the hostname "whoami-gatewayapi.localhost" Routes all traffic to the whoami service on port 80 # httproute.yaml apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami spec: parentRefs: - name: traefik-gateway hostnames: - "whoami-gatewayapi.localhost" rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: whoami port: 80 Apply the manifest: kubectl apply -f httproute.yaml Test Your Setup You can use the following curl command to verify that the application is correctly exposed: curl http://whoami-gatewayapi.localhost Hostname: whoami-76c9859cfc-6v8hh IP: 127.0.0.1 IP: ::1 IP: 10.42.0.11 IP: fe80::20ad:eeff:fe44:a63 RemoteAddr: 10.42.0.9:38280 GET / HTTP/1.1 Host: whoami.localhost User-Agent: curl/8.7.1 Accept: */* Accept-Encoding: gzip X-Forwarded-For: 127.0.0.1 X-Forwarded-Host: whoami.localhost X-Forwarded-Port: 80 X-Forwarded-Proto: http X-Forwarded-Server: traefik-598946cd7-zds59 X-Real-Ip: 127.0.0.1 You can now visit http://whoami.localhost in your browser to verify that the application is exposed correctly: If you navigate to the HTTP Routes section of the traefik dashboard, you can see that the whoami.localhost route is managed by the Traefik Kubernetes Gateway API provider: That's it! You've successfully deployed Traefik and configured routing in a Kubernetes cluster. Next Steps Configure TLS Set up Middlewares Enable Metrics Learn more about Kubernetes CRD provider Learn more about Kubernetes Gateway API provider {% include-markdown "includes/traefik-for-business-applications.md" %} Govern Your APIs with Traefik Hub Traefik Hub transforms your API infrastructure by providing enterprise-grade API Gateway and comprehensive API Management capabilities. Built on the foundation of Traefik Proxy, Hub enables organizations to govern, secure, and manage APIs at scale across cloud-native environments. API Gateway and API Management Capabilities Traefik Hub offers two complementary approaches to API governance: Traefik Hub API Gateway: Enterprise-grade security, distributed features, and advanced access control for cloud-native API gateway scenarios. It includes AI Gateway capabilities for modern machine learning workloads. Traefik Hub API Management: Comprehensive API lifecycle management, developer portals, and organizational features for teams managing multiple APIs across environments. API Management Features Traefik Hub API Management provides a complete suite of features designed to streamline API governance and accelerate developer productivity: Comprehensive API Lifecycle Management Centralized API Catalog: Comprehensive API inventory providing real-time visibility and control Advanced Versioning: Utilize the most flexible API versioning and Kubernetes-native labels to logically organize APIs, track their evolution over time, and avoid breaking changes for client applications Quality Control: Perform error checks and change impact analysis with Traefik Hub's static analyzer to ensure compliance and prevent misconfiguration by catching errors early Resource Management: Centralize rate limits, quotas, and policy enforcement across groups of APIs through Plans & Bundles, ensuring consistent and efficient resource management Subscription Management: Create managed and self-serve subscriptions for enhanced ease-of-use, security, and auditability Standards Compliance: Import, validate, and manage APIs using industry-standard OpenAPI specifications Developer Experience & Self-Service Customizable Portals: Easily create one or more dedicated API Portals for developers to discover, understand, and interact with your APIs Interactive API Testing: Allow developers to test APIs directly within the portal for immediate feedback Branded Experience: Customize the API portal to house API documentation, clear integration instructions, and personalized content to foster adoption and streamline development Credential Management: Generate API access credentials, such as API keys, directly from the portal for simplified access and secure integration Auto-generated Documentation: Automatically generated, interactive API documentation from OpenAPI specifications in the portal Enterprise-Grade Security Access Control: Implement fine-grained permissions through detailed API policies and JWT inspection to secure access to API resources Identity Integration: Leverage existing identity and access management (IAM) solutions, such as Keycloak, Okta, Auth0, etc. through industry-standard authentication protocols, including native OIDC support Data Protection: Advanced TLS management, supporting Let's Encrypt (ACME) and SPIFFE for robust data protection Threat Prevention: Native Web Application Firewall (WAF) powered by OWASP Coraza to defend against known vulnerabilities Observability Open Standards Monitoring: Gain deep insights into API health and performance with OpenTelemetry integration to provide metrics and tracing capabilities without vendor lock-in Third-party Integrations: Turnkey integration with Treblle directly on the Traefik Hub Dashboard for real-time, out-of-the-box observability without maintaining a complex monitoring infrastructure Pre-built Grafana Dashboards: Ready-to-use monitoring dashboards with key API metrics and performance indicators Getting Started with API Governance Transform your API infrastructure with Traefik Hub's governance capabilities: Start with API Gateway: Implement enterprise security, authentication, distributed features, and AI Gateway capabilities Scale with API Management: Add comprehensive lifecycle management, developer portals, and governance features Ready to govern your APIs at scale? Explore Traefik Hub API Management and discover how it can transform your API strategy. include-acme-multiple-domains-example ## Dynamic configuration labels: - traefik.http.routers.blog.rule=Host(`example.com`) && Path(`/blog`) - traefik.http.routers.blog.tls=true - traefik.http.routers.blog.tls.certresolver=myresolver - traefik.http.routers.blog.tls.domains[0].main=example.com - traefik.http.routers.blog.tls.domains[0].sans=*.example.org apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: blogtls spec: entryPoints: - websecure routes: - match: Host(`example.com`) && Path(`/blog`) kind: Rule services: - name: blog port: 8080 tls: certResolver: myresolver domains: - main: example.com sans: - '*.example.org' ## Dynamic configuration http: routers: blog: rule: "Host(`example.com`) && Path(`/blog`)" tls: certResolver: myresolver domains: - main: "example.com" sans: - "*.example.org" ## Dynamic configuration [http.routers] [http.routers.blog] rule = "Host(`example.com`) && Path(`/blog`)" [http.routers.blog.tls] certResolver = "myresolver" # From static configuration [[http.routers.blog.tls.domains]] main = "example.com" sans = ["*.example.org"] include-acme-multiple-domains-from-rule-example ## Dynamic configuration labels: - traefik.http.routers.blog.rule=(Host(`example.com`) && Path(`/blog`)) || Host(`blog.example.org`) - traefik.http.routers.blog.tls=true - traefik.http.routers.blog.tls.certresolver=myresolver ## Dynamic configuration deploy: labels: - traefik.http.routers.blog.rule=(Host(`example.com`) && Path(`/blog`)) || Host(`blog.example.org`) - traefik.http.routers.blog.tls=true - traefik.http.routers.blog.tls.certresolver=myresolver - traefik.http.services.blog-svc.loadbalancer.server.port=8080" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: blogtls spec: entryPoints: - websecure routes: - match: (Host(`example.com`) && Path(`/blog`)) || Host(`blog.example.org`) kind: Rule services: - name: blog port: 8080 tls: certResolver: myresolver ## Dynamic configuration http: routers: blog: rule: "(Host(`example.com`) && Path(`/blog`)) || Host(`blog.example.org`)" tls: certResolver: myresolver ## Dynamic configuration [http.routers] [http.routers.blog] rule = "(Host(`example.com`) && Path(`/blog`)) || Host(`blog.example.org`)" [http.routers.blog.tls] certResolver = "myresolver" include-acme-single-domain-example ## Dynamic configuration labels: - traefik.http.routers.blog.rule=Host(`example.com`) && Path(`/blog`) - traefik.http.routers.blog.tls=true - traefik.http.routers.blog.tls.certresolver=myresolver ## Dynamic configuration deploy: labels: - traefik.http.routers.blog.rule=Host(`example.com`) && Path(`/blog`) - traefik.http.routers.blog.tls=true - traefik.http.routers.blog.tls.certresolver=myresolver - traefik.http.services.blog-svc.loadbalancer.server.port=8080" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: blogtls spec: entryPoints: - websecure routes: - match: Host(`example.com`) && Path(`/blog`) kind: Rule services: - name: blog port: 8080 tls: certResolver: myresolver ## Dynamic configuration http: routers: blog: rule: "Host(`example.com`) && Path(`/blog`)" tls: certResolver: myresolver ## Dynamic configuration [http.routers] [http.routers.blog] rule = "Host(`example.com`) && Path(`/blog`)" [http.routers.blog.tls] certResolver = "myresolver" kubernetes-requirements Traefik follows the Kubernetes support policy, and supports at least the latest three minor versions of Kubernetes. General functionality cannot be guaranteed for older versions. service-by-label In general when configuring a Traefik provider, a service assigned to one (or several) router(s) must be defined as well for the routing to be functional. There are, however, exceptions when using label-based configurations: If a label defines a router (e.g. through a router Rule) and a label defines a service (e.g. implicitly through a loadbalancer server port value), but the router does not specify any service, then that service is automatically assigned to the router. If a label defines a router (e.g. through a router Rule) but no service is defined, then a service is automatically created and assigned to the router. !!! info "" As one would expect, in either of these cases, if in addition a service is specified for the router, then that service is the one assigned, regardless of whether it actually is defined or whatever else other services are defined. traefik-for-business-applications !!! question "Using Traefik OSS in Production?" If you are using Traefik at work, consider adding enterprise-grade API gateway capabilities or commercial support for Traefik OSS. - [Watch our API Gateway Demo Video](https://info.traefik.io/watch-traefik-api-gw-demo?cta=doc) - [Request 24/7/365 OSS Support](https://info.traefik.io/request-commercial-support?cta=doc) Adding API Gateway capabilities to Traefik OSS is fast and seamless. There's no rip and replace and all configurations remain intact. See it in action via [this short video](https://info.traefik.io/watch-traefik-api-gw-demo?cta=doc). Migrate from Ingress NGINX Controller to Traefik How to migrate from Ingress NGINX Controller to Traefik with zero downtime. {: .subtitle } !!! danger "Ingress NGINX Controller Retirement" The Kubernetes Ingress NGINX Controller project has announced its retirement in **March 2026**. After this date: - No new releases or updates - No security patches - No bug fixes For more information, see the [official Kubernetes blog announcement](https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement). What You Will Achieve By completing this migration, your existing Ingress resources will work with Traefik without any modifications. The Traefik Kubernetes Ingress NGINX Provider automatically translates NGINX annotations into Traefik configuration: apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp annotations: # These NGINX annotations are automatically translated by Traefik nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/force-ssl-redirect: "true" nginx.ingress.kubernetes.io/enable-cors: "true" nginx.ingress.kubernetes.io/cors-allow-origin: "https://example.com" nginx.ingress.kubernetes.io/affinity: "cookie" nginx.ingress.kubernetes.io/session-cookie-name: "route" spec: ingressClassName: nginx # ← Traefik will watch this class rules: - host: myapp.example.com http: paths: - path: / pathType: Prefix backend: service: name: whoami port: number: 80 apiVersion: apps/v1 kind: Deployment metadata: name: whoami spec: replicas: 2 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: whoami spec: selector: app: whoami ports: - protocol: TCP port: 80 targetPort: 80 For a complete list of supported annotations and behavioral differences, see the Ingress NGINX Routing Configuration documentation. !!! info "Traefik Version Requirement" The Kubernetes Ingress NGINX provider requires **Traefik v3.6.2 or later**. !!! info "Legacy Scheme Headers" If your applications still depend on ingress-nginx's legacy `X-Forwarded-Scheme` or `X-Scheme` headers, enable `entryPoints..forwardedHeaders.addXForwardedSchemeHeaders=true` on the entrypoints that receive this traffic. This keeps `X-Forwarded-Proto` unchanged and restores the compatibility headers at the entrypoint level for every provider. Prerequisites Before starting the migration, ensure you have: Existing Ingress NGINX Controller running in your Kubernetes cluster Kubernetes cluster access with kubectl configured Cluster support for running multiple LoadBalancer services on ports 80/443 simultaneously Helm Cluster admin permissions to create RBAC resources Backup of critical configurations (Ingress resources, ConfigMaps, Secrets) !!! tip "Backup Recommendations" ```bash # Export all Ingress resources kubectl get ingress --all-namespaces -o yaml > ingress-backup.yaml # Export NGINX ConfigMaps kubectl get configmap --all-namespaces -l app.kubernetes.io/name=ingress-nginx -o yaml > nginx-configmaps.yaml ``` Migration Strategy Overview This migration achieves zero downtime by running Traefik alongside NGINX. Both controllers serve the same Ingress resources simultaneously, allowing you to progressively shift traffic before removing NGINX. Current: DNS → LoadBalancer → NGINX → Your Services Migration: DNS → LoadBalancer → NGINX → Your Services → LoadBalancer → Traefik → Your Services Final: DNS → LoadBalancer → Traefik → Your Services Migration Flow: Step 0 - Review your ingress-nginx ConfigMap and translate cluster-wide defaults to Traefik Step 1 - Install Traefik alongside NGINX Step 2 - Verify Traefik is handling traffic Step 3 - Progressively shift traffic from NGINX to Traefik Step 4 - Remove NGINX from DNS, preserve the IngressClass, and uninstall Step 0: Migrate Your Global ConfigMap Settings Before you install Traefik, review the global defaults currently set in the ingress-nginx ConfigMap. In ingress-nginx, the controller ConfigMap acts as a cluster-wide configuration layer. In Traefik, the same behavior is split across: the providers.kubernetesIngressNGINX static configuration for ingress-nginx compatibility defaults entryPoints for listener behavior such as HTTP-to-HTTPS redirection and PROXY protocol dynamic tls.options and HTTP middlewares for TLS policy, HSTS, and other header behavior Traefik access log configuration for request logging Start by exporting the ConfigMap you use today and reviewing the keys you have customized: kubectl get configmap --all-namespaces -l app.kubernetes.io/name=ingress-nginx,app.kubernetes.io/component=controller -o yaml This label selector locates the controller ConfigMap regardless of the namespace or release name you used when installing ingress-nginx. !!! tip "Convert NGINX units before copying values" Several ingress-nginx ConfigMap keys use NGINX-style values such as `16k`, `1m`, or `30s`. In Traefik, the matching `providers.kubernetesIngressNGINX` options below expect: - raw byte values for body-size and buffer settings - integer seconds for `proxyConnectTimeout` and `proxyNextUpstreamTimeout` - booleans for `proxyRequestBuffering` and `proxyBuffering` ConfigMap to Traefik Mapping ingress-nginx ConfigMap key Traefik equivalent (provider options) Notes proxy-connect-timeout proxyConnectTimeout Use integer seconds. proxy-request-buffering proxyRequestBuffering Translate on / off to true / false. ingress-nginx enables request buffering by default, while Traefik defaults to false. client-body-buffer-size clientBodyBufferSize Convert values such as 16k to bytes. proxy-buffering proxyBuffering Translate on / off to true / false. proxy-body-size proxyBodySize Convert values such as 1m to bytes. proxy-buffer-size proxyBufferSize Convert values such as 8k to bytes. proxy-buffers-number proxyBuffersNumber Keep the integer value. proxy-next-upstream proxyNextUpstream Use a space-separated list of retry conditions such as error timeout http_502. proxy-next-upstream-timeout proxyNextUpstreamTimeout Use integer seconds. proxy-next-upstream-tries proxyNextUpstreamTries Keep the integer value. custom-http-errors customHTTPErrors Also configure providers.kubernetesIngressNGINX.defaultBackendService if you want a global error page service. global-allowed-response-headers globalAllowedResponseHeaders Required for nginx.ingress.kubernetes.io/custom-headers annotations to take effect. allow-cross-namespace-resources allowCrossNamespaceResources Use when migrated ingresses must reference supported resources in other namespaces. strict-validate-path-type strictValidatePathType Traefik v3.7 defaults this option to true. ssl-redirect / force-ssl-redirect nginx.ingress.kubernetes.io/ssl-redirect and nginx.ingress.kubernetes.io/force-ssl-redirect annotations, or cluster-wide entryPoint redirection Traefik translates the annotations when they are present. For a global default, configure HTTP-to-HTTPS redirection on the web entryPoint and set providers.kubernetesIngressNGINX.httpEntryPoint / httpsEntryPoint if you need explicit entryPoint selection. To serve Ingresses on HTTPS only (no non-TLS routers), set providers.kubernetesIngressNGINX.disableNonTLSRouters: true. This stops this provider from creating non-TLS routers for its Ingresses — the HTTP entryPoint itself is unaffected. Remove the entryPoint from your install configuration if you want the port closed entirely. ssl-protocols / ssl-ciphers TLS options Apply them globally through an entryPoint TLS option, or per Ingress via traefik.ingress.kubernetes.io/router.tls.options. hsts, hsts-max-age, hsts-include-subdomains, hsts-preload Headers middleware Use stsSeconds, stsIncludeSubdomains, stsPreload, and forceSTSHeader. Attach the middleware on an entryPoint for a cluster-wide default. use-proxy-protocol EntryPoint proxyProtocol configuration Configure it on every entryPoint that sits behind a load balancer speaking PROXY protocol. access-log-path accessLog.filePath Static configuration. log-format-upstream accessLog.format Use Traefik's built-in common, genericCLF, or json formats. Custom NGINX log format strings do not have a 1:1 equivalent. ConfigMap Keys Without a Direct Equivalent Some ingress-nginx ConfigMap keys are NGINX-specific and can be dropped during migration because Traefik does not expose raw NGINX internals. Common examples include: worker tuning such as worker-processes, worker-cpu-affinity, and Lua shared dict settings snippet-style keys such as main-snippet, http-snippet, server-snippet, location-snippet, and stream-snippet custom NGINX log format templates beyond Traefik's built-in access log formats When you find one of these keys, translate the underlying intent rather than trying to copy the directive verbatim. Reference Pages Kubernetes Ingress NGINX provider configuration Traefik TLS Options Traefik Headers Middleware Traefik EntryPoints configuration ingress-nginx ConfigMap reference Step 1: Install Traefik Alongside NGINX ??? info "Install Ingress NGINX Controller" If you have not installed Ingress NGINX Controller yet, you can set up a fresh Ingress NGINX Controller installation following the instructions below: ### Install Ingress NGINX Controller ```bash helm upgrade --install ingress-nginx ingress-nginx \ --repo https://kubernetes.github.io/ingress-nginx \ --namespace ingress-nginx --create-namespace ``` Install Traefik with the Kubernetes Ingress NGINX provider enabled. Both controllers will serve the same Ingress resources simultaneously. !!! warning "Read the status race condition note first" Running both controllers against the same Ingresses creates contention on the `status.loadBalancer.ingress[]` field. Before installing, review the [Ingress Status Race Condition](#status-race) section in Step 3 and decide which mitigation to apply (disable `publishService` on Traefik, or use a transitional IngressClass). Add Traefik Helm Repository helm repo add traefik https://traefik.github.io/charts helm repo update Install Traefik helm upgrade --install traefik traefik/traefik \ --namespace traefik --create-namespace \ --set providers.kubernetesIngressNGINX.enabled=true Or using a values file for more configuration: ... providers: kubernetesIngressNGINX: enabled: true ... helm upgrade --install traefik traefik/traefik \ --namespace traefik --create-namespace \ --values traefik-values.yaml Verify Both Controllers Are Running # Check NGINX pods kubectl get pods -n ingress-nginx # Check Traefik pods kubectl get pods -n traefik # Check both services have LoadBalancer IPs kubectl get svc -n ingress-nginx ingress-nginx-controller kubectl get svc -n traefik traefik At this point, both NGINX and Traefik are running and can serve the same Ingress resources. Traffic is still flowing only through NGINX since DNS points to the NGINX LoadBalancer. Step 2: Verify Traefik Is Handling Traffic Before adding Traefik to DNS, verify it correctly serves your Ingress resources. Test via Traefik's LoadBalancer IP Get Traefik's LoadBalancer IP and use --resolve to test without changing DNS: # Get LoadBalancer IPs NGINX_IP=$(kubectl get svc -n ingress-nginx ingress-nginx-controller -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}') TRAEFIK_IP=$(kubectl get svc -n traefik traefik -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}') echo -e "Nginx IP: $NGINX_IP\nTraefik IP: $TRAEFIK_IP" # Test HTTP for both FQDN=myapp.example.com # Observe HTTPS redirections: curl --connect-to "${FQDN}:80:${NGINX_IP}:80" "http://${FQDN}" -D - curl --connect-to "${FQDN}:80:${TRAEFIK_IP}:80" "http://${FQDN}" -D - # note X-Forwarded-Server which should be traefik # Test HTTPS curl --connect-to "${FQDN}:443:${NGINX_IP}:443" "https://${FQDN}" curl --connect-to "${FQDN}:443:${TRAEFIK_IP}:443" "https://${FQDN}" !!! warning "TLS Certificates During Migration" Both NGINX and Traefik must serve valid TLS certificates for HTTPS tests to succeed. Since Traefik is not publicly exposed during this verification phase, **Let's Encrypt HTTP challenge will not work**. Your options for TLS certificates during migration: - **Existing certificates via `tls.secretName`** - If you use cert-manager or another external tool, your existing TLS secrets referenced in `spec.tls` will work with both controllers - **Let's Encrypt DNS challenge** - Configure Traefik's [ACME DNS challenge](../reference/install-configuration/tls/certificate-resolvers/acme.md#dnschallenge) to obtain certificates without public exposure Avoid using `curl -k` (skip certificate verification) as this masks TLS configuration issues that could cause problems after migration. Verify Ingress Discovery Check Traefik logs to confirm it discovered your Ingress resources: kubectl logs -n traefik deployment/traefik | grep -i "ingress" Step 3: Shift Traffic to Traefik With both controllers running and verified, progressively shift traffic from NGINX to Traefik. Option A: DNS-Based Migration Add the Traefik LoadBalancer IP to your DNS records alongside NGINX. This allows both controllers to receive traffic. Get LoadBalancer addresses: # NGINX LoadBalancer echo $(kubectl get svc -n ingress-nginx ingress-nginx-controller -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}') # Traefik LoadBalancer echo $(kubectl get svc -n traefik traefik -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}') Progressive DNS migration: Add Traefik to DNS - Add the Traefik LoadBalancer IP to your DNS records (both IPs now receive traffic via round-robin) Monitor - Observe traffic patterns on both controllers Remove NGINX from DNS - Once confident, remove the NGINX LoadBalancer IP from DNS Wait for DNS propagation - Allow time for DNS caches to expire Uninstall NGINX - Proceed to Step 4 !!! warning "DNS TTL May Not Be Respected" Some ISPs ignore DNS TTL values to reduce traffic costs, caching records longer than specified. After removing NGINX from DNS, keep NGINX running for at least 24-48 hours before uninstalling to avoid dropping traffic from users whose ISPs have stale DNS caches. !!! warning "Ingress Status Race Condition During Coexistence" While both controllers manage the same Ingress resources (same `ingressClassName: nginx`), they will both attempt to write the LoadBalancer address into `status.loadBalancer.ingress[]` on every Ingress they own. Each controller overwrites the other in a tight reconciliation loop, with no error reported in the logs (just repeated `Updated ingress status` info lines on both sides). Routing itself is not affected: both controllers correctly serve traffic during the coexistence window. The flapping status field affects anything that watches it: - [ExternalDNS](https://github.com/kubernetes-sigs/external-dns), which may shift DNS records back and forth between the two LoadBalancer IPs. - kube-state-metrics, monitoring dashboards, and alerting rules that observe Ingress status. - GitOps tools such as ArgoCD or Flux, which will report a permanent drift on every affected Ingress. - Custom operators reconciling on the Ingress status field. **Recommended mitigation (option 1): disable status publishing on Traefik during coexistence** 1. **[Install Traefik](#step-1-install-traefik-alongside-nginx) with `publishService` disabled**: ```yaml # traefik-values.yaml providers: kubernetesIngressNginx: enabled: true publishService: enabled: false # Disable to prevent status updates ``` Traefik keeps serving the Ingresses normally. It only stops writing the status field, leaving NGINX as the sole writer. 2. **Test Traefik** using [port-forward](#step-2-verify-traefik-is-handling-traffic) or a separate test hostname. 3. **Switch DNS via NGINX** (ExternalDNS users only). Configure NGINX to publish Traefik's service address so ExternalDNS points traffic to Traefik: ```yaml # nginx-values.yaml controller: publishService: pathOverride: "traefik/traefik" # Points to Traefik's service ``` 4. **Verify traffic flows through Traefik**. At this point, you can still roll back by removing the `pathOverride`. 5. **[Enable `publishService` on Traefik](#step-1-install-traefik-alongside-nginx)** and [uninstall NGINX](#step-4-uninstall-ingress-nginx-controller). **Alternative mitigation (option 2): use a transitional IngressClass** Give the migrating NGINX a distinct IngressClass (for example `nginx-migration`) so the two controllers never own the same Ingress at the same time. This is the approach SUSE documents for RKE2 migrations: see [SUSE: Migrate from Ingress NGINX to Traefik](https://documentation.suse.com/cloudnative/rke2/latest/en/reference/ingress_migration.html). This avoids any contention on `status.loadBalancer.ingress[]` entirely, at the cost of a short traffic-cutover step instead of a progressive DNS shift. Option B: External Load Balancer with Weighted Traffic For more control over traffic distribution, use an external load balancer (like Traefik, Cloudflare, AWS ALB, or a dedicated load balancer) in front of both Kubernetes LoadBalancers. !!! note "Infrastructure Prerequisite" This option assumes you already have an external load balancer in your infrastructure, or are willing to set one up **before** starting the migration. Adding an external load balancer is a significant infrastructure change that should be planned and tested separately from the ingress controller migration. Setup: Create an external load balancer pointing to the NGINX Kubernetes LoadBalancer Update DNS to point to the external load balancer Add the Traefik Kubernetes LoadBalancer to the external load balancer with a low weight (e.g., 10%) Gradually increase Traefik's weight while decreasing NGINX's weight Once NGINX receives no traffic, uninstall it Example weight progression: Phase NGINX Weight Traefik Weight Duration Initial 100% 0% - Start 90% 10% 1 hour Increase 50% 50% 2 hour Near-complete 10% 90% 4 hour Final 0% 100% - !!! tip "External Load Balancer Options" - **Cloudflare Load Balancing** - Traffic steering with health checks - **AWS Global Accelerator** - Weighted routing across endpoints - **Google Cloud Load Balancing** - Traffic splitting - **Traefik / HAProxy / NGINX (external)** - Self-hosted option with weighted backends - ... LoadBalancer IP Retention If you want Traefik to eventually use the same LoadBalancer IP as NGINX (to simplify DNS management), you can transfer the IP after the migration. Since Traefik is already running with its own LoadBalancer, this can be done with zero downtime. Zero-downtime IP transfer process: Traefik is already running with its own LoadBalancer IP (from Step 1) Add Traefik's LoadBalancer IP to DNS (traffic now goes to both NGINX and Traefik) Remove NGINX's IP from DNS and wait for propagation Delete NGINX's LoadBalancer service to release the IP Upgrade Traefik to claim the released IP (Optional) Remove Traefik's old IP from DNS once the new IP is active This way, traffic is always flowing to Traefik during the IP transfer. Get your current NGINX LoadBalancer IP: kubectl get svc -n ingress-nginx ingress-nginx-controller -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}' ??? note "AWS (Network Load Balancer with Elastic IPs)" AWS does not support static IPs for Classic Load Balancers. Use Network Load Balancers (NLB) with Elastic IPs instead. This requires the [AWS Load Balancer Controller](https://kubernetes-sigs.github.io/aws-load-balancer-controller/) to be installed in your cluster. **Pre-allocate Elastic IPs (one per availability zone):** ```bash aws ec2 allocate-address --domain vpc --region # Note the AllocationId (eipalloc-xxx) for each EIP ``` **Update `traefik-values.yaml`:** ```yaml service: type: LoadBalancer loadBalancerClass: service.k8s.aws/nlb # Requires AWS Load Balancer Controller annotations: service.beta.kubernetes.io/aws-load-balancer-type: "external" service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip" service.beta.kubernetes.io/aws-load-balancer-eip-allocations: "eipalloc-xxx,eipalloc-yyy" ``` For more details, see the [AWS Load Balancer Controller annotations documentation](https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/guide/service/annotations/). ??? note "Azure" Azure supports static public IPs for Load Balancers. **Identify existing public IP:** ```bash az network public-ip list --resource-group \ --query "[?ipAddress==''].name" -o tsv ``` **Update `traefik-values.yaml`:** ```yaml service: type: LoadBalancer annotations: # Only needed if the public IP is in a different resource group than the AKS cluster service.beta.kubernetes.io/azure-load-balancer-resource-group: "" spec: loadBalancerIP: "" ``` For more details, see the [Azure AKS static IP documentation](https://learn.microsoft.com/en-us/azure/aks/static-ip). ??? note "GCP" GCP supports static IPs through reserved regional IP addresses. **Reserve or identify existing IP:** ```bash # List existing static IPs gcloud compute addresses list # Or reserve a new regional static IP (must be in the same region as your GKE cluster) gcloud compute addresses create traefik-ip --region ``` **Update `traefik-values.yaml`:** ```yaml service: type: LoadBalancer spec: loadBalancerIP: "" ``` For more details, see the [GKE LoadBalancer Service parameters documentation](https://cloud.google.com/kubernetes-engine/docs/concepts/service-load-balancer-parameters). ??? note "OVHcloud" OVHcloud supports static IP on OVHcloud Public Load Balancer, it is based on Openstack Octavia which allocates floating IPs to LoadBalancer services. This requires the [Openstack Cloud Controller Manager](https://github.com/kubernetes/cloud-provider-openstack/blob/master/docs/openstack-cloud-controller-manager/using-openstack-cloud-controller-manager.md) to be installed in your cluster. If you are using OVHcloud Managed Kubernetes Service (MKS), the Openstack Cloud Controller Manager is already installed and managed for you. To retain your existing floating IP when migrating from NGINX to Traefik: **Identify the existing public IP:** ```bash NGINX_IP=$(kubectl get svc -n ingress-nginx ingress-nginx-controller \ -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}') echo "NGINX IP: $NGINX_IP" ``` **Edit your existing NGINX LoadBalancer service to ensure that the floating IP is not released when the loadbalancer service is deleted:** ```bash kubectl annotate svc my-lb-svc loadbalancer.openstack.org/keep-floatingip=true ``` The `keep-floatingip` annotation prevents the floating IP from being released when the service is deleted or modified. **Delete the NGINX LoadBalancer service to release the floating IP** **Update `traefik-values.yaml`:** ```yaml service: type: LoadBalancer spec: loadBalancerIP: "" ``` To learn more, see the [OVHcloud MKS Public Load Balancer annotations documentation](https://help.ovhcloud.com/csm/en-public-cloud-kubernetes-expose-applications-using-load-balancer?id=kb_article_view&sysparm_article=KB0062878#supported-annotations-features). ??? note "Other Cloud Providers" - **DigitalOcean:** Supports `loadBalancerIP` with floating IPs - **Linode:** Supports `loadBalancerIP` specification - **Bare Metal (MetalLB):** Use IP address pools Transfer the IP: Once DNS is pointing to Traefik and your values are configured with the target IP: # Ensure Traefik is already receiving traffic via its current LoadBalancer kubectl get svc -n traefik traefik # Delete NGINX LoadBalancer service to release the IP kubectl delete svc -n ingress-nginx ingress-nginx-controller # Upgrade Traefik to claim the released IP helm upgrade traefik traefik/traefik \ --namespace traefik \ --values traefik-values.yaml # Verify Traefik now has the old NGINX IP kubectl get svc -n traefik traefik !!! tip "Zero Downtime During Helm Upgrade" The Helm upgrade only restarts the Traefik pod, not the LoadBalancer service. Traefik uses a `RollingUpdate` deployment strategy by default, so the new pod starts before the old one terminates. For additional safety, configure high availability: ```yaml # In traefik-values.yaml deployment: replicas: 2 # Spread pods across nodes to survive node failures affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app.kubernetes.io/name: traefik app.kubernetes.io/instance: traefik topologyKey: kubernetes.io/hostname # Ensure at least one pod is always available during disruptions podDisruptionBudget: enabled: true minAvailable: 1 ``` With multiple replicas spread across nodes and a PodDisruptionBudget, at least one pod is always running during upgrades and node maintenance. Step 4: Uninstall Ingress NGINX Controller Once NGINX is no longer receiving traffic, remove it from your cluster. Before uninstalling, you must ensure the nginx IngressClass is preserved. Traefik needs it to continue discovering your Ingresses. Preserve the IngressClass ??? note "If NGINX Was Installed via Helm" Add the `helm.sh/resource-policy: keep` annotation to tell Helm to preserve the IngressClass: ```bash # Add the required annotation helm upgrade ingress-nginx ingress-nginx \ --repo https://kubernetes.github.io/ingress-nginx \ --namespace ingress-nginx \ --reuse-values \ --set-json 'controller.ingressClassResource.annotations={"helm.sh/resource-policy": "keep"}' # Check that the annotation is really here kubectl describe ingressclass nginx ``` The `--reuse-values` flag is critical - it preserves all your existing NGINX configuration. Without it, Helm would reset everything to defaults, potentially breaking your setup. !!! info "kubectl annotate/patch/edit does not work" Adding the annotation via `kubectl annotate`, `kubectl patch`, or `kubectl edit` will not preserve the IngressClass. Helm stores its release state internally and checks annotations from its internal manifest, not the live cluster state. Only `helm upgrade` updates Helm's internal state. ??? note "If NGINX Was Installed via GitOps (ArgoCD, Flux)" Ensure the `nginx` IngressClass is defined as a standalone resource in your Git repository, separate from the NGINX Helm release: ```yaml # ingressclass.yaml apiVersion: networking.k8s.io/v1 kind: IngressClass metadata: name: nginx spec: controller: k8s.io/ingress-nginx ``` ??? note "If NGINX Was Installed Manually" Create the IngressClass as a standalone resource: ```bash kubectl apply -f - < -o yaml | grep ingressClassName ``` ??? note "Annotation Not Working as Expected" Some NGINX annotations have behavioral differences in Traefik. Check the [limitations documentation](../reference/routing-configuration/kubernetes/ingress-nginx.md#limitations) for details. ??? note "TLS Certificates Not Working" Existing TLS configurations continue to work with Traefik: - Keep `spec.tls` entries exactly as-is; Traefik terminates TLS using the referenced secrets - TLS secrets must stay in the same namespace as the Ingress - NGINX `ssl-redirect` / `force-ssl-redirect` annotations are honored ```bash # Verify TLS secret exists in the same namespace as Ingress kubectl get secrets -n # Check secret format kubectl get secret -n -o yaml ``` ??? note "LoadBalancer IP Not Assigned" ```bash # Check service status kubectl describe svc -n traefik traefik # Check for events kubectl get events -n traefik --sort-by='.lastTimestamp' ``` Next Steps Learn More About Traefik: Kubernetes Ingress NGINX Install Configuration - Detailed provider configuration Kubernetes Ingress NGINX Routing Configuration - Routing rules and annotation support HTTP Middlewares - Extend functionality beyond NGINX annotations TLS Configuration - Advanced TLS and certificate management Enhance Your Setup: Enable metrics and tracing Configure access logs for observability Explore Traefik Middlewares for advanced traffic management Migrate from Nginx-based config to Traefik IngressRoute or Kubernetes Gateway API Consider Traefik Hub for enterprise features like AI & API Gateway, API Management, and advanced security Feedback and Support If you encounter issues during migration or have suggestions for improving this guide: Report Issues: GitHub Issues Community Support: Traefik Community Forum Enterprise Support: Traefik Labs Commercial Support We welcome contributions to improve this migration guide. See our contribution guidelines to get started. Migration Guide: From v1 to v2 How to Migrate from Traefik v1 to Traefik v2. {: .subtitle } The version 2 of Traefik introduced a number of breaking changes, which require one to update their configuration when they migrate from v1 to v2. For more information about the changes in Traefik v2, please refer to the v2 documentation. !!! info "Migration Helper" We created a tool to help during the migration: [traefik-migration-tool](https://github.com/traefik/traefik-migration-tool) This tool lets you: - convert `Ingress` to Traefik `IngressRoute` resources. - convert `acme.json` file from v1 to v2 format. - migrate the static configuration contained in the file `traefik.toml` to a Traefik v2 file. Configuration Details for Migrating from Traefik v2 to v3 Install Configuration Changes SwarmMode In v3, the provider Docker has been split into 2 providers: Docker provider (without Swarm support) Swarm provider (Swarm support only) ??? example "An example usage of v2 Docker provider with Swarm" ```yaml tab="File (YAML)" providers: docker: swarmMode: true ``` ```toml tab="File (TOML)" [providers.docker] swarmMode=true ``` ```bash tab="CLI" --providers.docker.swarmMode=true ``` This configuration is now unsupported and would prevent Traefik to start. Remediation In v3, the swarmMode should not be used with the Docker provider, and, to use Swarm, the Swarm provider should be used instead. ??? example "An example usage of the Swarm provider" ```yaml tab="File (YAML)" providers: swarm: endpoint: "tcp://127.0.0.1:2377" ``` ```toml tab="File (TOML)" [providers.swarm] endpoint="tcp://127.0.0.1:2377" ``` ```bash tab="CLI" --providers.swarm.endpoint=tcp://127.0.0.1:2377 ``` TLS.CAOptional Docker provider tls.CAOptional option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType). ??? example "An example usage of the TLS.CAOptional option" ```yaml tab="File (YAML)" providers: docker: tls: caOptional: true ``` ```toml tab="File (TOML)" [providers.docker.tls] caOptional=true ``` ```bash tab="CLI" --providers.docker.tls.caOptional=true ``` Remediation The tls.caOptional option should be removed from the Docker provider install configuration. Kubernetes Gateway API Experimental Channel Resources (TLSRoute and TCPRoute) In v3, the Kubernetes Gateway API provider does not enable support for the experimental channel API resources by default. Remediation The experimentalChannel option should be used to enable the support for the experimental channel API resources. ??? example "An example usage of the Kubernetes Gateway API provider with experimental channel support enabled" ```yaml tab="File (YAML)" providers: kubernetesGateway: experimentalChannel: true ``` ```toml tab="File (TOML)" [providers.kubernetesGateway] experimentalChannel = true # ... ``` ```bash tab="CLI" --providers.kubernetesgateway.experimentalchannel=true ``` Experimental Configuration HTTP3 In v3, HTTP/3 is no longer an experimental feature. It can be enabled on entry points without the associated experimental.http3 option, which is now removed. It is now unsupported and would prevent Traefik to start. ??? example "An example usage of v2 Experimental http3 option" ```yaml tab="File (YAML)" experimental: http3: true ``` ```toml tab="File (TOML)" [experimental] http3=true ``` ```bash tab="CLI" --experimental.http3=true ``` Remediation The http3 option should be removed from the install configuration experimental section. To configure http3, please checkout the entrypoint configuration documentation. Consul provider namespace The Consul provider namespace option was deprecated in v2 and is now removed in v3. It is now unsupported and would prevent Traefik to start. ??? example "An example usage of v2 Consul namespace option" ```yaml tab="File (YAML)" consul: namespace: foobar ``` ```toml tab="File (TOML)" [consul] namespace=foobar ``` ```bash tab="CLI" --consul.namespace=foobar ``` Remediation In v3, the namespaces option should be used instead of the namespace option. ??? example "An example usage of Consul namespaces option" ```yaml tab="File (YAML)" consul: namespaces: - foobar ``` ```toml tab="File (TOML)" [consul] namespaces=["foobar"] ``` ```bash tab="CLI" --consul.namespaces=foobar ``` TLS.CAOptional Consul provider tls.CAOptional option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType). ??? example "An example usage of the TLS.CAOptional option" ```yaml tab="File (YAML)" providers: consul: tls: caOptional: true ``` ```toml tab="File (TOML)" [providers.consul.tls] caOptional=true ``` ```bash tab="CLI" --providers.consul.tls.caOptional=true ``` Remediation The tls.caOptional option should be removed from the Consul provider install configuration. ConsulCatalog provider namespace The ConsulCatalog provider namespace option was deprecated in v2 and is now removed in v3. It is now unsupported and would prevent Traefik to start. ??? example "An example usage of v2 ConsulCatalog namespace option" ```yaml tab="File (YAML)" consulCatalog: namespace: foobar ``` ```toml tab="File (TOML)" [consulCatalog] namespace=foobar ``` ```bash tab="CLI" --consulCatalog.namespace=foobar ``` Remediation In v3, the namespaces option should be used instead of the namespace option. ??? example "An example usage of ConsulCatalog namespaces option" ```yaml tab="File (YAML)" consulCatalog: namespaces: - foobar ``` ```toml tab="File (TOML)" [consulCatalog] namespaces=["foobar"] ``` ```bash tab="CLI" --consulCatalog.namespaces=foobar ``` Endpoint.TLS.CAOptional ConsulCatalog provider endpoint.tls.CAOptional option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType). ??? example "An example usage of the Endpoint.TLS.CAOptional option" ```yaml tab="File (YAML)" providers: consulCatalog: endpoint: tls: caOptional: true ``` ```toml tab="File (TOML)" [providers.consulCatalog.endpoint.tls] caOptional=true ``` ```bash tab="CLI" --providers.consulCatalog.endpoint.tls.caOptional=true ``` Remediation The endpoint.tls.caOptional option should be removed from the ConsulCatalog provider install configuration. Nomad provider namespace The Nomad provider namespace option was deprecated in v2 and is now removed in v3. It is now unsupported and would prevent Traefik to start. ??? example "An example usage of v2 Nomad namespace option" ```yaml tab="File (YAML)" nomad: namespace: foobar ``` ```toml tab="File (TOML)" [nomad] namespace=foobar ``` ```bash tab="CLI" --nomad.namespace=foobar ``` Remediation In v3, the namespaces option should be used instead of the namespace option. ??? example "An example usage of Nomad namespaces option" ```yaml tab="File (YAML)" nomad: namespaces: - foobar ``` ```toml tab="File (TOML)" [nomad] namespaces=["foobar"] ``` ```bash tab="CLI" --nomad.namespaces=foobar ``` Endpoint.TLS.CAOptional Nomad provider endpoint.tls.CAOptional option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType). ??? example "An example usage of the Endpoint.TLS.CAOptional option" ```yaml tab="File (YAML)" providers: nomad: endpoint: tls: caOptional: true ``` ```toml tab="File (TOML)" [providers.nomad.endpoint.tls] caOptional=true ``` ```bash tab="CLI" --providers.nomad.endpoint.tls.caOptional=true ``` Remediation The endpoint.tls.caOptional option should be removed from the Nomad provider install configuration. Rancher v1 Provider In v3, the Rancher v1 provider has been removed because Rancher v1 is no longer actively maintained, and Rancher v2 is supported as a standard Kubernetes provider. ??? example "An example of Traefik v2 Rancher v1 configuration" ```yaml tab="File (YAML)" providers: rancher: {} ``` ```toml tab="File (TOML)" [providers.rancher] ``` ```bash tab="CLI" --providers.rancher=true ``` This configuration is now unsupported and would prevent Traefik to start. Remediation Rancher 2.x requires Kubernetes and does not have a metadata endpoint of its own for Traefik to query. As such, Rancher 2.x users should utilize the Kubernetes CRD provider directly. Also, all Rancher provider related configuration should be removed from the install configuration. Marathon provider Marathon maintenance ended on October 31, 2021. In v3, the Marathon provider has been removed. ??? example "An example of v2 Marathon provider configuration" ```yaml tab="File (YAML)" providers: marathon: {} ``` ```toml tab="File (TOML)" [providers.marathon] ``` ```bash tab="CLI" --providers.marathon=true ``` This configuration is now unsupported and would prevent Traefik to start. Remediation All Marathon provider related configuration should be removed from the install configuration. HTTP Provider TLS.CAOptional HTTP provider tls.CAOptional option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType). ??? example "An example usage of the TLS.CAOptional option" ```yaml tab="File (YAML)" providers: http: tls: caOptional: true ``` ```toml tab="File (TOML)" [providers.http.tls] caOptional=true ``` ```bash tab="CLI" --providers.http.tls.caOptional=true ``` Remediation The tls.caOptional option should be removed from the HTTP provider install configuration. ETCD Provider TLS.CAOptional ETCD provider tls.CAOptional option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType). ??? example "An example usage of the TLS.CAOptional option" ```yaml tab="File (YAML)" providers: etcd: tls: caOptional: true ``` ```toml tab="File (TOML)" [providers.etcd.tls] caOptional=true ``` ```bash tab="CLI" --providers.etcd.tls.caOptional=true ``` Remediation The tls.caOptional option should be removed from the ETCD provider install configuration. Redis Provider TLS.CAOptional Redis provider tls.CAOptional option has been removed in v3, as TLS client authentication is a server side option (see https://pkg.go.dev/crypto/tls#ClientAuthType). ??? example "An example usage of the TLS.CAOptional option" ```yaml tab="File (YAML)" providers: redis: tls: caOptional: true ``` ```toml tab="File (TOML)" [providers.redis.tls] caOptional=true ``` ```bash tab="CLI" --providers.redis.tls.caOptional=true ``` Remediation The tls.caOptional option should be removed from the Redis provider install configuration. InfluxDB v1 InfluxDB v1.x maintenance ended in 2021. In v3, the InfluxDB v1 metrics provider has been removed. ??? example "An example of Traefik v2 InfluxDB v1 metrics configuration" ```yaml tab="File (YAML)" metrics: influxDB: {} ``` ```toml tab="File (TOML)" [metrics.influxDB] ``` ```bash tab="CLI" --metrics.influxDB=true ``` This configuration is now unsupported and would prevent Traefik to start. Remediation All InfluxDB v1 metrics provider related configuration should be removed from the install configuration. Pilot Traefik Pilot is no longer available since October 4th, 2022. ??? example "An example of v2 Pilot configuration" ```yaml tab="File (YAML)" pilot: token: foobar ``` ```toml tab="File (TOML)" [pilot] token=foobar ``` ```bash tab="CLI" --pilot.token=foobar ``` In v2, Pilot configuration was deprecated and ineffective, it is now unsupported and would prevent Traefik to start. Remediation All Pilot related configuration should be removed from the install configuration. Kubernetes Ingress Path Matching In v3, the Kubernetes Ingress default path matching does not support regexes anymore. Remediation Two levels of remediation are possible: Interpret the default path matcher PathPrefix with v2 syntax. This can done globally for all routers with the install configuration or on a per-router basis by using the traefik.ingress.kubernetes.io/router.rulesyntax annotation. Adapt the path regex to be compatible with the Go regex syntax and change the default path matcher to use the PathRegexp matcher with the traefik.ingress.kubernetes.io/router.pathmatcher annotation. Operations Changes Traefik RBAC Update In v3, the support of TCPServersTransport has been introduced. When using the KubernetesCRD provider, it is therefore necessary to update RBAC and CRDs (See requirements). Content-Type Auto-Detection In v3, the Content-Type header is not auto-detected anymore when it is not set by the backend. One should use the ContentType middleware to enable the Content-Type header value auto-detection. Observability Open Connections Metric In v3, the open connections metric has been replaced with a global one because it was erroneously at the HTTP level, and providing misleading information. While previously produced at the entryPoint, router, and service levels, it is now replaced with a global metric. The equivalent to traefik_entrypoint_open_connections, traefik_router_open_connections and traefik_service_open_connections is now traefik_open_connections. Configuration Reload Failures Metrics In v3, the traefik_config_reloads_failure_total and traefik_config_last_reload_failure metrics have been suppressed since they could not be implemented. gRPC Metrics In v3, the reported status code for gRPC requests is now the value of the Grpc-Status header. Tracing In v3, the tracing feature has been revamped and is now powered exclusively by OpenTelemetry (OTel). !!! warning "Important" Traefik v3 no longer supports direct output formats for specific vendors such as Instana, Jaeger, Zipkin, Haystack, Datadog, and Elastic. Instead, it focuses on pure OpenTelemetry implementation, providing a unified and standardized approach for observability. Here are two possible transition strategies: OTLP Ingestion Endpoints: Most vendors now offer OpenTelemetry Protocol (OTLP) ingestion endpoints. You can seamlessly integrate Traefik v3 with these endpoints to continue leveraging tracing capabilities. Legacy Stack Compatibility: For legacy stacks that cannot immediately upgrade to the latest vendor agents supporting OTLP ingestion, using OpenTelemetry (OTel) collectors with appropriate exporters configuration is a viable solution. This allows continued compatibility with the existing infrastructure. Please check the OpenTelemetry Tracing provider documentation for more information. Internal Resources Observability In v3, observability for internal routers or services (e.g.: ping@internal) is disabled by default. To enable it one should use the new addInternals option for AccessLogs, Metrics or Tracing. Please take a look at the observability documentation for more information: AccessLogs Metrics Tracing Access logs In v3, the ServiceURL field is not an object anymore but a string representation. An update may be required if you index access logs. Routing Configuration Changes Router Rule Matchers In v3, a new rule matchers syntax has been introduced for HTTP and TCP routers. The default rule matchers syntax is now the v3 one, but for backward compatibility this can be configured. The v2 rule matchers syntax is deprecated and its support will be removed in the next major version. For this reason, we encourage migrating to the new syntax. By default, the defaultRuleSyntax install option is automatically set to v3, meaning that the default rule is the new one. New V3 Syntax Notable Changes The Headers and HeadersRegexp matchers have been renamed to Header and HeaderRegexp respectively. PathPrefix no longer uses regular expressions to match path prefixes. Path and PathPrefix no longer support path parameter placeholders (e.g., {id}, {name}). Routes using placeholders like Path(`/route/{id}`) will not match in v3 syntax. Use PathRegexp instead for dynamic path segments. QueryRegexp has been introduced to match query values using a regular expression. HeaderRegexp, HostRegexp, PathRegexp, QueryRegexp, and HostSNIRegexp matchers now uses the Go regexp syntax. All matchers now take a single value (except Header, HeaderRegexp, Query, and QueryRegexp which take two) and should be explicitly combined using logical operators to mimic previous behavior. Query can take a single value to match is the query value that has no value (e.g. /search?mobile). HostHeader has been removed, use Host instead. Remediation Configure the Default Syntax In Install Configuration The default rule matchers syntax is the expected syntax for any router that is not self opt-out from this default value. It can be configured in the install configuration. ??? example "An example configuration for the default rule matchers syntax" ```yaml tab="File (YAML)" # install configuration core: defaultRuleSyntax: v2 ``` ```toml tab="File (TOML)" # install configuration [core] defaultRuleSyntax="v2" ``` ```bash tab="CLI" # install configuration --core.defaultRuleSyntax=v2 ``` Configure the Syntax Per Router The rule syntax can also be configured on a per-router basis. This allows you to have heterogeneous router configurations and ease migration. ??? example "An example router with syntax configuration" labels: - "traefik.http.routers.test.ruleSyntax=v2" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test.route namespace: default spec: routes: - match: PathPrefix(`/foo`, `/bar`) syntax: v2 kind: Rule - "traefik.http.routers.test.ruleSyntax=v2" http: routers: test: ruleSyntax: v2 [http.routers] [http.routers.test] ruleSyntax = "v2" Migrate Path Placeholders to PathRegexp In v2, Path and PathPrefix supported path parameter placeholders like {id} for matching dynamic path segments. In v3, this is no longer supported and PathRegexp should be used instead. ??? example "Migrating a route with path placeholders" v2 syntax (no longer works in v3): ```yaml match: Host(`example.com`) && Path(`/products/{id}`) ``` v3 syntax using `PathRegexp`: ```yaml match: Host(`example.com`) && PathRegexp(`^/products/[^/]+$`) ``` For more complex patterns with multiple placeholders: v2 syntax: ```yaml match: Host(`example.com`) && Path(`/users/{userId}/orders/{orderId}`) ``` v3 syntax: ```yaml match: Host(`example.com`) && PathRegexp(`^/users/[^/]+/orders/[^/]+$`) ## matches any non-slash characters match: Host(`example.com`) && PathRegexp(`^/users/[a-zA-Z0-9_-]+/orders/[a-zA-Z0-9_-]+$`) ## restricts to alphanumeric, hyphens, and underscores ``` IPWhiteList In v3, we renamed the IPWhiteList middleware to IPAllowList without changing anything to the configuration. Deprecated Options Removal The tracing.datadog.globaltag option has been removed. The tls.caOptional option has been removed from the ForwardAuth middleware, as well as from the HTTP, Consul, Etcd, Redis, ZooKeeper, Consul Catalog, and Docker providers. sslRedirect, sslTemporaryRedirect, sslHost, sslForceHost and featurePolicy options of the Headers middleware have been removed. The forceSlash option of the StripPrefix middleware has been removed. The preferServerCipherSuites option has been removed. TCP LoadBalancer terminationDelay option The TCP LoadBalancer terminationDelay option has been deprecated. This option can now be configured directly on the TCPServersTransport level, please take a look at this documentation Kubernetes CRDs API Group traefik.containo.us In v3, the Kubernetes CRDs API Group traefik.containo.us has been removed. Please use the API Group traefik.io instead. Kubernetes Ingress API Group networking.k8s.io/v1beta1 In v3, the Kubernetes Ingress API Group networking.k8s.io/v1beta1 (removed since Kubernetes v1.22) support has been removed. Please use the API Group networking.k8s.io/v1 instead. Traefik CRD API Version apiextensions.k8s.io/v1beta1 In v3, the Traefik CRD API Version apiextensions.k8s.io/v1beta1 (removed since Kubernetes v1.22) support has been removed. Please use the CRD definition with the API Version apiextensions.k8s.io/v1 instead. Migration Guide: From v2 to v3 How to Migrate from Traefik v2 to Traefik v3. {: .subtitle } !!! success "Streamlined Migration Process" Traefik v3 introduces minimal breaking changes and maintains backward compatibility with v2 syntax in routing configuration, offering a gradual migration path. With Traefik v3, we are introducing a streamlined transition process from v2. Minimal breaking changes have been made to specific options in the install configuration, and we are ensuring backward compatibility with v2 syntax in the routing configuration. This will offer a gradual path for adopting the v3 syntax, allowing users to progressively migrate their Kubernetes ingress resources, Docker labels, etc., to the new format. Migration Overview The migration process consists of three progressive steps designed to minimize risk and ensure a smooth transition: !!! abstract "Migration Steps" Step 1: Prepare configurations and test v3 Step 2: Migrate production instances to Traefik v3 Step 3: Progressively migrate routing configuration Step 1: Prepare Configurations and Test v3 !!! info "Preparation Phase" This step focuses on updating install configurations and enabling backward compatibility for a safe testing environment. Configuration Updates Review and Update install Configuration Check the changes in install configurations and operations brought by Traefik v3. Modify your configurations accordingly. Enable v2 Compatibility Mode Add the following configuration to maintain v2 syntax compatibility: # install configuration core: defaultRuleSyntax: v2 !!! note "Backward Compatibility" This snippet in the install configuration makes the v2 format the default rule matchers syntax. Testing Phase Start Your Test Environment Start Traefik v3 with the updated configuration Monitor the startup logs for any errors Test routing to your applications Validation Checklist ✅ Traefik starts without error logs ✅ All routes are functioning correctly ✅ Applications are accessible through Traefik !!! success "Ready for Next Step" If you don't get any error logs while testing, you are good to go! Otherwise, follow the remaining migration options highlighted in the logs. Once your Traefik test instances are starting and routing to your applications, proceed to the next step. Step 2: Migrate Production Instances to Traefik v3 !!! warning "Production Migration" This is the critical step where you migrate your production environment. Proper monitoring and rollback preparation are essential. Migration Strategy Progressive Deployment We strongly advise you to follow a progressive migration strategy (Kubernetes rolling update mechanism, for example) to migrate your production instances to v3. Required Preparations !!! danger "Critical Requirements" - ✅ Real-time monitoring solution for ingress traffic (monitoring guide) - ✅ Rollback plan ready for immediate execution - ✅ Team availability during migration window Migration Execution During Migration: Monitor continuously: Watch ingress traffic for any errors or anomalies Be prepared to rollback: Have your rollback procedure ready to execute immediately Use debug logs: Leverage debug and access logs to understand any issues that arise Validation Steps: Monitor response times and error rates Verify all critical application paths are working Check that SSL/TLS termination is functioning correctly Validate middleware behavior !!! success "Migration Complete" Once every Traefik instance is updated, you will be on Traefik v3! Step 3: Progressively Migrate Routing Configuration !!! info "Optional Immediate Step" This step can be done later in the process, as Traefik v3 is compatible with the v2 format for routing configuration. Enable Traefik logs to get some help if any deprecated option is in use. Migration Process Review Routing Configuration Changes Check the changes in routing configuration to understand what updates are needed. Progressive Router Migration Select a router to migrate first (start with non-critical services) Switch to v3 syntax for that specific router Test thoroughly to ensure ingress traffic is not impacted Deploy and validate the updated resource Remove the old v2 resource once validation is complete Repeat for each remaining router Migration Best Practices !!! tip "Migration Strategy" - Start with development or staging environments - Migrate one service at a time - Test each migration thoroughly before proceeding - Keep detailed logs of what was changed Final Configuration Cleanup Once all Ingress resources are migrated to v3 syntax, remove the compatibility configuration: # Remove this from install configuration core: defaultRuleSyntax: v2 # ← Delete this entire section !!! success "🎉 Migration Complete!" You are now fully migrated to Traefik v3 and can take advantage of all the new features and improvements! Post-Migration Verification Final Checklist: ✅ All routers use v3 syntax ✅ v2 compatibility mode disabled ✅ No deprecated warnings in logs ✅ All applications functioning correctly ✅ Performance metrics stable {% include-markdown "includes/traefik-for-business-applications.md" %} Migration: Steps needed between the v2 versions The multiple minor versions of Traefik v2 introduced a number of changes, which may require one to update their configuration when they migrate. For more information about the changes between Traefik v2 minor versions, please refer to the v2 documentation. Migration: Steps needed between the versions This guide provides detailed migration steps for upgrading between different Traefik v3 versions. Each section covers breaking changes, deprecations, and configuration updates required for a smooth transition. v3.8.0 Kubernetes Gateway API Provider Starting with v3.8.0, the Kubernetes Gateway API provider requires the Gateway API CRDs to be updated to v1.6.1. The v1.5.x CRDs are no longer supported. TCPRoute has graduated to the Standard channel and is now consumed through its v1 version, so it no longer requires the experimentalChannel option. As a result, the experimentalChannel option does not enable any resource at the moment, and can be safely removed from the install configuration. Existing TCPRoute objects are preserved and served through their v1 version once the CRDs are updated. The Standard channel CRDs no longer serve the deprecated v1alpha2 version, so manifests still authored as gateway.networking.k8s.io/v1alpha2 are rejected by the apiserver and must be updated to gateway.networking.k8s.io/v1. Apply Updated CRDs: kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.1/standard-install.yaml For the experimental channel: kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.1/experimental-install.yaml Listener Isolation Starting with v3.8.0, the Kubernetes Gateway API provider generates a multi-layer router structure for HTTP and TLS-terminated (HTTPS) listeners. Each server name such a listener defines now produces a parent router, holding the listener entry point and, for a TLS-terminated (HTTPS) listener, its TLS configuration. The routers built from the HTTPRoute and GRPCRoute resources attached to that listener become child routers of this parent. A parent router is scoped to the requests its server name is the most specific match for, which isolates the listeners of a Gateway from each other: a request is only handled by the routes of the listener that matches it best. This change is internal to the provider: no configuration update is required. However, if you inspect the generated dynamic configuration, for example through the API, you will see these new parent and child routers instead of the previous flat, per-route routers. Listener TLS Options The parent router of a TLS-terminated (HTTPS) listener carries a set of TLS options dedicated to that listener, which is what allows Traefik to answer a misdirected request with a 421 Misdirected Request. As a consequence, the default TLS options is not applied to those listeners anymore. For the same reason, a server name served both by a listener and by a router coming from another provider, on the same entry point, is now served with two different sets of TLS options. Traefik reports this as a conflict, and falls back to the default TLS options for that server name, or disables the routers involved when the core.strictTLSOptions option is enabled. ListenerSet Support Starting with v3.8.0, the Kubernetes Gateway API provider supports ListenerSet resources from the Standard channel. Therefore, in the corresponding RBACs (see KubernetesGateway provider RBACs) the listenersets and listenersets/status rights have been added. Required RBAC Updates: ... - apiGroups: - gateway.networking.k8s.io resources: - listenersets verbs: - get - list - watch - apiGroups: - gateway.networking.k8s.io resources: - listenersets/status verbs: - update ... ClusterTrustBundle Support Starting with v3.8.0, the Kubernetes Gateway API provider supports ClusterTrustBundle references in the caCertificateRefs of BackendTLSPolicy resources and of the Gateway frontend TLS validation. This requires the cluster to serve the certificates.k8s.io/v1 API, available since Kubernetes v1.37. When the API is not served, or when Traefik is not allowed to watch ClusterTrustBundle resources, such references are reported as unsupported kinds. Therefore, in the corresponding RBACs (see KubernetesGateway provider RBACs) the clustertrustbundles right has been added. Required RBAC Updates: ... - apiGroups: - certificates.k8s.io resources: - clustertrustbundles verbs: - list - watch ... labelSelector option deprecation Starting with v3.8.0, the labelSelector option of the Kubernetes Gateway API provider is deprecated and will be removed in the next major version. The new gatewayClass option replaces it and selects the GatewayClass to watch by name. When both options are set Traefik will now raise an error. Wildcard Host Matching Starting with v3.8.0, the Host and HostSNI matchers support a double wildcard prefix: Host(`**.example.com`) matches every subdomain of example.com, nested ones included, where Host(`*.example.com`) keeps matching its direct subdomains only. The stars of a double wildcard do not count toward the length of the rule its default priority is computed from, so that such a router always ranks below the single wildcard and the exact hosts it covers. The default priority of the existing rules is unchanged. As ACME only issues single-level wildcard certificates, the ACME certificate resolvers refuse a **.example.com domain, and a Host(`**.example.com`) router gets no certificate. peerCertURI option deprecation Starting with v3.8.0, the peerCertURI option is deprecated in the ServersTransport and ServersTransportTCP configurations and will be removed in the next major version. The new peerCertSANs option replaces it and supports multiple Subject Alternative Names (SANs) of type URI or DNSName. Please check out the ServersTransport and ServersTransportTCP documentation for more details. Kubernetes CRD Provider To use the new peerCertSANs field on ServersTransport and ServersTransportTCP resources with the Kubernetes CRD provider, you need to update your CRDs. Apply Updated CRDs: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.8/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml ConfigMap references in plugin configurations Starting with v3.8.0, a string of a plugin configuration in the form urn:k8s:configmap:: is replaced with the value of that key of the ConfigMap. Until v3.8.0, the plugin received this string as is. If the ConfigMap or the key does not exist, or if the reference is malformed, the Middleware is left out of the routing configuration. See Referencing a Secret or a ConfigMap in a plugin configuration. Tap Middleware Starting with v3.8.0, the new tap middleware sends a copy of the requests and the responses going through it to Traefik services, as JSON records. Kubernetes CRD Provider To use the new tap middleware with the Kubernetes CRD provider, you need to update your CRDs. Apply Updated CRDs: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.8/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml Buffering Middleware Starting with v3.8.0, the buffering middleware supports the new disableRequestBuffer and disableResponseBuffer options. Kubernetes CRD Provider To use the new disableRequestBuffer and disableResponseBuffer options with the Kubernetes CRD provider, you need to update your CRDs. Apply Updated CRDs: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.8/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml Router Responding Timeouts Starting with v3.8.0, the new router option respondingTimeouts, which includes readTimeout and writeTimeout, can be used to override the entry point timeouts for a given router. Kubernetes CRD Provider To use the new respondingTimeouts option on IngressRoute routes with the Kubernetes CRD provider, you need to update your CRDs. Apply Updated CRDs: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.8/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml Mirroring Service Starting with v3.8.0, the mirroring service supports the new streamBody option, which streams the request body to the mirrors instead of buffering it in memory. Kubernetes CRD Provider To use the new streamBody option on TraefikService resources with the Kubernetes CRD provider, you need to update your CRDs. Apply Updated CRDs: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.8/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml v3.7.17 Starting with v3.7.17, Traefik is built with Go 1.27. GODEBUG TLS Settings Go 1.27 removed the tlsrsakex, tls10server and tls3des GODEBUG settings. Setting them in the GODEBUG environment variable has no effect anymore. For the incoming connections, the RSA key exchange and 3DES cipher suites, as well as TLS 1.0 and 1.1, can still be enabled with the cipherSuites and minVersion fields of the TLS options, referenced in the TLS configuration of a router or of an entrypoint. For the connections to the backends, they can still be enabled with the cipherSuites and minVersion fields of the ServersTransport. Please check out the go documentation for more details. Maximum Number of Request Header Values Go 1.27 limits the number of header values a request can carry to 500. A request exceeding this limit is rejected with a 431 Request Header Fields Too Large response, for HTTP/1 and HTTP/2. This limit can be changed with the new maxHeaderValueCount entry point option. As the rejection happens before the routing, the rejected requests are not reported in the access logs. Please check out the go documentation for more details. Ingress-NGINX Provider: generated names Until v3.7.17, the Ingress-NGINX provider joined the namespace and the resource names with dashes in the names of the routers, services, middlewares and serversTransports it generates. An Ingress named dev-web in the team namespace and an Ingress named web in the team-dev namespace thus produced the same names, and one silently overrode the other. Starting with v3.7.17, the generated names include the length of the namespace and of each resource name: the router of an Ingress named whoami in the default namespace is now default-7-whoami-6-rule-0-path-0 instead of default-whoami-rule-0-path-0. The routers of an Ingress defaultBackend now also include the index of their rule ( default-7-whoami-6-rule-0-default-backend), and the TCP routers of an Ingress carrying the nginx.ingress.kubernetes.io/ssl-passthrough annotation keep the dots of their host. Dashboards, alerts, API queries and references from other providers relying on the previous names must be updated. v3.7.16 Kubernetes CRD and Ingress-NGINX Providers: Secret references in middlewares Until v3.7.16, the routing configuration of a middleware held the values that the provider read from Kubernetes Secrets. Starting with v3.7.16, it holds a reference to the Secret key instead, in the form urn:k8s:secret::. Traefik reads the value when it builds the middleware, so the behavior of the middleware does not change. The API, the dashboard and the support dump show the references. v3.7.15 CONNECT Requests Starting with v3.7.15, Traefik rejects every CONNECT request with a 501 Not Implemented response, whatever the HTTP version used by the client, and never forwards it to the backend. HTTP/1 CONNECT requests were already rejected since v3.7.9. CONNECT requests sent over HTTP/2 or HTTP/3 could seem to work in some cases, but they were not handled specifically, while a CONNECT tunnel requires a dedicated handling to be safe. For security reasons, Traefik now rejects them as well. As the rejection happens before the routing, the rejected requests are not reported in the access logs. They are only visible at the DEBUG log level. To tunnel traffic through a forward proxy exposed by Traefik, route it with a TCP router instead. Kubernetes Gateway API Provider: backend protocol Until v3.7.15, the Kubernetes Gateway API provider used HTTPS to reach the backend of an HTTPRoute when the Service port had no appProtocol and was either the port 443 or a port whose name starts with https. Starting with v3.7.15, the port number and the port name do not select HTTPS anymore, and such a backend is reached with plain HTTP. This follows the Gateway API specification, where only the appProtocol of the Service port or a BackendTLSPolicy selects the protocol used to reach the backend. To keep using HTTPS, set the Service port appProtocol to https, or attach a BackendTLSPolicy to the Service. v3.7.14 Ingress-NGINX Provider: generated names Until v3.7.14, the Ingress-NGINX provider replaced the dots of the Ingress and Secret names with dashes in the names of the routers, services, serversTransports and TLS options it generates. Two resources named my.ingress and my-ingress thus produced the same names, and one silently overrode the other. Starting with v3.7.14, the resource names are kept as is: the router of an Ingress named my.ingress is now default-my.ingress-rule-0-path-0 instead of default-my-ingress-rule-0-path-0. Dashboards, alerts and API queries relying on the previous names must be updated. The routers and middlewares generated on the HTTP entry points for an Ingress carrying the nginx.ingress.kubernetes.io/ssl-passthrough annotation are renamed as well. They are now named after the Ingress rule and path they come from, --rule--path- instead of ---http. Kubernetes Gateway API Provider: routes that match a request equally well Until v3.7.14, two routes on the same listener could give routers with the very same rule. This occurs, for example, with a route that has no host name and a route that has the host name of the listener. One of the two routes served the requests, but you could not know which one. The route could also change at each reload of the configuration. Starting with v3.7.14, only the route that has precedence serves the requests. The specification gives precedence to the older route, then to the first route in alphabetical order by {namespace}/{name}. Traefik does not create the routers of the other routes. Traefik writes a warning in the log, and gives the name of the router that serves the rule. Kubernetes Gateway API Provider: TLSRoute router names Until v3.7.14, a TLSRoute attached to several TLS listeners sharing an entry point gave routers with the same name, and only one of them was kept. Starting with v3.7.14, the hash suffix of the TLSRoute router names is also derived from the router rule, so the names of all the TLSRoute routers, and of the services derived from them, change. Dashboards, alerts and API queries relying on the previous names must be updated. OpenTelemetry Metrics: exponential histograms Until v3.7.14, the traefik_*_request_duration_seconds histograms were always exported with explicit buckets, even when OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION was set to base2_exponential_bucket_histogram. Starting with v3.7.14, these histograms follow this environment variable, and the metrics.otlp.explicitBoundaries option only applies to explicit bucket histograms. Dashboards and alerts relying on the bucket series of these histograms must be updated when the exponential aggregation is enabled. v3.7.13 h2c Upgrade Requests Starting with v3.7.13, Traefik does not forward the Upgrade: h2c and HTTP2-Settings request headers to the backends anymore. Traefik does not implement the deprecated h2c upgrade mechanism, it only serves unencrypted HTTP/2 with prior knowledge. Forwarding those headers let a backend accept an upgrade that Traefik itself had not negotiated with the client. A backend that used to accept such an upgrade now serves those requests over HTTP/1.1. To reach a backend over unencrypted HTTP/2, declare its servers with the h2c scheme: ## Dynamic configuration http: services: my-service: loadBalancer: servers: - url: "h2c://private-ip-server-1:8080" ## Dynamic configuration [http.services] [http.services.my-service.loadBalancer] [[http.services.my-service.loadBalancer.servers]] url = "h2c://private-ip-server-1:8080" The providers exposing a scheme instead of a server URL take it the same way, with the traefik.http.services..loadbalancer.server.scheme=h2c label, the scheme: h2c option of the Kubernetes CRD, or the traefik.ingress.kubernetes.io/service.serversscheme: h2c Kubernetes Ingress annotation. Request Target Validation Starting with v3.7.13, a request whose target is rootless, that is a target made of a scheme followed by something that does not start with a slash, is rejected with a 400 Bad Request response. Such a target is none of the four forms allowed by rfc9112#section-3.2. A rootless target, for instance http:example.com/admin, carries no path, hence escaping the path handling and the routing rules while still designating a resource on the backend. This rejection is not configurable, as allowing such a target would reintroduce the bypass. As the validation happens before the routing, the rejected requests are not reported in the access logs. They are only visible at the DEBUG log level. Consul Catalog and Nomad: colliding service configurations The Consul Catalog and the Nomad providers build the configuration of each service instance separately, and then merge all of them together. Until v3.7.13, the instances were identified by the normalized concatenation of their node, service name and service ID, which is ambiguous: two distinct instances could produce the same identifier, and the configuration of all but the last of them was silently discarded. Starting with v3.7.13, this identifier is unambiguous, and every instance contributes to the merge. !!! warning "Newly detected conflicts" The configurations that were previously discarded are now merged. A router or a middleware defined by several instances is only kept if all of them define it identically, and a service only if the instances agree on everything but their servers, which are then pooled together. Otherwise the resource is removed altogether, an error is logged, and a router served before the upgrade can disappear. The merge order changes as well, and with it the order of the servers of a load-balancer. v3.7.12 AliasHeadersStrategy From version v3.7.12 onwards, a new aliasHeadersStrategy entry point option deprecates and replaces the underscoreHeadersStrategy option introduced in v3.6.20. Go canonicalizes header names on dashes only, so it handles X-Auth-User, X_Auth_User and X.Auth.User as three distinct headers, while the backends deriving their variable names from the header names (CGI, WSGI, PHP, NGINX, ...) uppercase the name and replace every character that is neither a letter nor a digit with an underscore: for them, the three names above are the same HTTP_X_AUTH_USER variable. The underscoreHeadersStrategy option only handles the header names containing an underscore character, which leaves the other aliasing forms untouched. Its behavior is unchanged. Underscores are only one of the characters building such an alias: every character HTTP allows in a header name except the letters, the digits and the dash does, that is !, #, $, %, &, ', *, +, ., ^, _, `, | and ~. The aliasHeadersStrategy option handles them all: keep (default): request headers with an aliasing name are forwarded as is. delete: any request header whose name contains a character which is neither a letter, a digit, nor a dash is silently removed from the request. reject: any request carrying a header whose name contains a character which is neither a letter, a digit, nor a dash is rejected with a 400 Bad Request response. The default value is keep, so the existing behavior is preserved. entryPoints: websecure: address: ':443' http: aliasHeadersStrategy: delete [entryPoints.websecure] address = ":443" [entryPoints.websecure.http] aliasHeadersStrategy = "delete" --entryPoints.websecure.address=:443 --entryPoints.websecure.http.aliasHeadersStrategy=delete Setting underscoreHeadersStrategy logs a deprecation warning. Configuring both options with different values makes the install configuration invalid. Traefik now logs a warning at startup for every entry point left without this option configured, as the middlewares managing request headers rely on it to not be spoofed with an aliasing name. Please check out the entry point aliasHeadersStrategy option and the Headers with Aliasing Names documentation for more details. TCP and UDP Weighted Services: Negative Weights Negative weights in a TCP or UDP weighted service are now rejected when the service is built. Such a configuration previously made the load-balancer selection loop endlessly while holding its lock, which consumed a CPU core and blocked every subsequent connection to that service until Traefik was restarted. A weighted service declaring a negative weight is now reported as disabled in the API, with the error attached, and the routers referencing it are not created. Replace any negative weight with a positive one, or with 0 to take a child service out of the rotation. TCP and UDP Weighted Services: Child Service Errors When a child of a TCP or UDP weighted service cannot be built, for instance because it does not exist, the parent weighted service is now reported as disabled in the API, with the error attached, as the HTTP weighted service already was. Such a parent service previously reported neither an error nor a status. This only changes what is reported: the routers referencing the parent service were already not created. v3.7.11 Safe naming configuration option Starting with v3.7.11, the new safeNaming provider option enables collision-safe naming for the routers, middlewares and services generated by the Kubernetes CRD provider, instead of the current naming scheme, under which names can collide across namespaces or resources. Generated names are derived from the identity of the object they come from instead of being flattened and normalized, and the ones generated for a route are derived from the route index instead of its rule. For example, for a Kubernetes Service named whoami and an IngressRoute named test.route, both in the default namespace: default-whoami-80 -> default_whoami_80 default-test-route-6b204d94623b3df4370c -> default_test.route_0 The option is disabled by default, which preserves the existing behavior. !!! warning "Observability" These names are user-visible: they appear in the dashboard and API, in the access logs `RouterName` and `ServiceName` fields, and in the `router` and `service` labels of the metrics. Dashboards, alerting rules, and log queries that match on Kubernetes CRD router, middleware or service names must be updated accordingly when `safeNaming` is enabled. !!! warning "Cross-provider references" The generated names are also the ones the other providers reference. When `safeNaming` is enabled, a namespaced `@kubernetescrd` reference, such as the `traefik.ingress.kubernetes.io/router.middlewares` annotation on an Ingress, must be of form `namespace_name@kubernetescrd` instead of `namespace-name@kubernetescrd`. A reference left in the legacy form is not resolved, and the routers using it are not created. Please check out the safeNaming provider documentation for more details. Conflicting TLS options The TLS options are configured on a router, but they are applied during the TLS handshake, before the routing occurs, and are therefore mapped to the host names found in the router rule rather than to the router itself. When several routers on the same entry point serve the same host name with different TLS options, Traefik cannot decide which options to apply, and falls back to the default TLS options for that host name. The default TLS options being the fallback of the conflict resolution, they should not be less secure than the options they can replace: a router relying on a mutual TLS authentication ( clientAuth), for example, no longer enforces it if a conflict on its host name falls back to default TLS options that do not require it. See GHSA-g55h-rg46-x9c5 for more details. Starting with v3.7.11, the new core.strictTLSOptions install configuration option disables this fallback: the routers involved in the conflict are marked in error and are not built at all. The option is disabled by default, to preserve the existing behavior, but enabling it is recommended: ## Install configuration core: strictTLSOptions: true ## Install configuration [core] strictTLSOptions = true ## Install configuration --core.strictTLSOptions=true !!! warning "Disabled routers" This option fails closed: a conflict disables all the routers serving the conflicting host name on the concerned entry point, until the conflict is resolved. Please check out the Conflicting TLS Options documentation for more details. Kubernetes CRD: cluster-wide default TLSOption and TLSStore In the Kubernetes CRD provider, the TLSOption and the TLSStore named default are cluster-wide, whatever the namespace they are defined in. Anyone allowed to create one in a single namespace can therefore replace the TLS policy, mutual TLS authentication included, of the routers that do not reference TLS options explicitly. Starting with v3.7.11, the new defaultTLSResourcesNamespace provider option reserves these resources to a namespace the cluster operator controls. The option is empty by default, to preserve the existing behavior, but setting it is recommended: ## Install configuration providers: kubernetesCRD: defaultTLSResourcesNamespace: traefik ## Install configuration [providers.kubernetesCRD] defaultTLSResourcesNamespace = "traefik" ## Install configuration --providers.kubernetescrd.defaultTLSResourcesNamespace=traefik !!! warning "Ignored resources" A `default` resource defined outside of the configured namespace is ignored, and cannot be referenced under its namespaced name either. For a `TLSStore`, this also applies to the certificates it defines. Please check out the Kubernetes CRD provider documentation for more details. v3.7.10 Kubernetes Gateway API Provider: generated router, middleware, and service names Starting with v3.7.10, the Kubernetes Gateway API provider derives the hash suffix of the router names it generates from all the route, Gateway, and listener identifying fields, instead of from the route rule alone. This is required to prevent distinct routes whose namespace, name, Gateway, and listener happen to concatenate to the same string from colliding on a single generated router name. Generated router names keep the same overall shape: ---gw---ep--- but the suffix changes, since it is no longer computed from the route rule alone. For example, an HTTPRoute named http-app-1 in the default namespace previously generated the router httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-af329269dd38031b03e3 and is now generated as httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93. Middleware names are derived from the router name, so they change accordingly, for example -requestheadermodifier-0. Generated service names were previously built from the backend reference only: -- They are now prefixed with the route rule they are generated for: -svc--- For example, a whoami backend in the default namespace previously exposed as default-whoami-http-80@kubernetesgateway is now exposed as httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-svc-default-whoami-0@kubernetesgateway. !!! warning "Observability" These names are user-visible: they appear in the dashboard and API, in the access logs `RouterName` and `ServiceName` fields, and in the `router`/`service` labels of the metrics. Dashboards, alerting rules, and log queries that match on Gateway API router, middleware, or service names must be updated accordingly. Kubernetes Gateway API Provider Starting with v3.7.10, the Kubernetes Gateway API provider supports version v1.6.1 of the specification. TCPRoute graduated to the Standard channel in Gateway API v1.6.0, with a new v1 version. Traefik v3.7 still watches TCPRoute through its v1alpha2 version, which the Standard channel CRDs no longer serve. If you use TCPRoute and upgrade to Gateway API v1.6.1 CRDs, you must install the experimental channel CRDs. The experimentalChannel option remains required to enable TCPRoute support in Traefik. !!! warning "Standard channel CRDs with experimentalChannel enabled" Traefik cannot watch the `v1alpha2` version of `TCPRoute`, and the Kubernetes Gateway provider never completes its startup: no Gateway API resource is served, not only `TCPRoute`. No error is logged, Traefik keeps running, and other providers are unaffected. Traefik v3.7 remains backward compatible with the v1.5.x CRDs: upgrading the CRDs in the cluster is only required to rely on the v1.6.1 resources. !!! note "Upcoming in v3.8" Traefik `v3.8` will require updating the Gateway API CRDs to `v1.6.x`, and in return the `experimentalChannel` option will no longer be needed for `TCPRoute`. (Optional) Apply v1.6.1 CRDs: kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.1/standard-install.yaml For the experimental channel (needed for TCPRoute): kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.1/experimental-install.yaml v3.7.9 HTTP/1 CONNECT requests Starting with v3.7.9, HTTP/1 CONNECT requests are rejected with a 501 Not Implemented response. HTTP/1 CONNECT requests were not functional before this change, so this rejection makes it explicit. v3.7.8 Kubernetes CRD: Errors middleware errorRequestHeaders The errorRequestHeaders option, introduced in v3.6.15 for the Errors middleware, was not exposed on the Kubernetes CRD provider. Starting with v3.7.8, it can now be configured on the Middleware CRD. To use this new option, the Kubernetes CRDs must be updated in the cluster before upgrading Traefik. To do so, please apply the CRDs manifest for v3.7: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.7/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml Please check out the Error Pages middleware documentation for more details. v3.7.7 Wildcard Host matcher From version v3.7.7 onwards, the Host matcher treats a bare * as a catch-all, consistent with the TCP HostSNI(* ) matcher. Host(`*`) now matches every request regardless of its host, including requests with no host at all. Previously, the * was treated as a single wildcard label, so Host(`*`) only matched hosts made of a single segment (e.g. localhost) and not multi-segment hosts (e.g. example.com). Please check out the HTTP routing rules documentation for more details. v3.7.6 Kubernetes Gateway API Provider: generated service and middleware names Starting with v3.7.6, the Kubernetes Gateway API provider derives the name of the services and middlewares it generates from the route rule they belong to, instead of from the backend reference alone. This is required to prevent distinct route rules referencing the same backend from colliding on a single generated configuration. Generated service names were previously built from the backend reference only: -- They are now prefixed with the route rule they are generated for: ---gw---ep----svc--- For example, a whoami backend in the default namespace previously exposed as default-whoami-http-80@kubernetesgateway is now exposed as httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-af329269dd38031b03e3-svc-default-whoami-0@kubernetesgateway. !!! warning "Observability" These names are user-visible: they appear in the dashboard and API, in the access logs `ServiceName` field, and in the `service` label of the metrics. Dashboards, alerting rules, and log queries that match on Gateway API service names must be updated accordingly. UnderscoreHeadersStrategy !!! warning "Deprecated since v3.7.12" Please use the [`aliasHeadersStrategy`](../reference/install-configuration/entrypoints.md#opt-http-aliasHeadersStrategy) option instead, which handles every aliasing character instead of the underscore only. From version v3.6.20 onwards, a new underscoreHeadersStrategy entry point option defines how request headers with underscores in their names are handled before routing: keep (default): request headers with underscores are forwarded as is. delete: any request header whose name contains an underscore character is silently removed from the request. reject: any request carrying a header whose name contains an underscore character is rejected with a 400 Bad Request response. The default value is keep, so the existing behavior is preserved. This option exists because underscores are valid characters in HTTP header names, but Go canonicalizes header names only on dashes. As a result, a middleware managing a header in its dash form (e.g. X-Auth-User set by the ForwardAuth authResponseHeaders option) does not see, and therefore cannot overwrite or remove, an underscore variant of that header (e.g. X_Auth_User). Many backends map both forms to the same variable (CGI, WSGI, PHP, NGINX, ...): for them, X-Auth-User and X_Auth_User are the same header. Against such a backend, a client can smuggle the underscore variant past a middleware that only manages the dash form, and have the backend read the spoofed value, bypassing the protection the middleware was meant to provide. !!! warning "Security" When an entry point fronts a backend that interprets underscores and dashes in header names identically, keeping the default `keep` strategy is not recommended, as it leaves the backend open to the header spoofing described above. Set `underscoreHeadersStrategy` to `delete` or `reject` on such entry points. v3.7.3 Kubernetes Gateway API Provider Starting with v3.7.3, the QPS and Burst values of the Kubernetes client used by the Kubernetes Gateway API provider have been increased to 50 and 100 respectively (10x the default values of the Kubernetes client). The Kubernetes Gateway API provider writes status updates intensively to comply with the Kubernetes Gateway API specification. This change helps avoid performance issues related to Kubernetes API rate limiting, which can increase the setup time when a new routing configuration is built. These values are configurable through the kubernetesGateway.qps and kubernetesGateway.burst provider options. BasicAuth Middleware From version v3.7.3 onwards, the BasicAuth middleware requires a non-empty users configuration in order to be built successfully. Previously, the middleware would be built successfully but always return a 401 status code for any request. Now, an error occurs and any routers using it will be unmounted. For the same request, a 404 status code is served instead of a 401 status code. StripPrefix and StripPrefixRegex Middleware From version v3.7.3 onwards, the StripPrefix middleware and the StripPrefixRegex middleware reject requests ( 400 Bad Request) when stripping the configured prefix produces a path that differs from its normalised form (i.e. a path containing . or .. segments that would be collapsed by normalisation). This prevents the stripped path from being interpreted as a different resource by the upstream service. Examples with a configured prefix of /api: Request path Path after strip Normalised path Result /api/foo /foo /foo 200 (sent) /api/ / / 200 (sent) /api./foo /./foo /foo 400 /api../foo /../foo /foo 400 v3.7.1 Kubernetes providers: crossProviderNamespaces In v3.7.1, a new crossProviderNamespaces option is available on the Kubernetes CRD, Ingress, and Gateway providers. Traefik offers the possibility to reference resources from one provider to another (cross-provider references). However, in the context of Kubernetes providers, those references (e.g. myservice@kubernetescrd) allow a user to cross namespace boundaries, as well as exposing @internal services, that only the operator should be able to expose. This new crossProviderNamespaces option restricts in which namespaces Kubernetes resources are allowed to use cross-provider references. The behavior is as follows: Value Behavior not set All Kubernetes resources can declare cross-provider references. [] Every Kubernetes resource declaring a cross-provider reference is rejected. ["ns-a"] Only Kubernetes resources in the listed namespaces can declare cross-provider references. Please check out the Kubernetes CRD, Kubernetes Ingress, and Kubernetes Gateway provider documentation for more details. v3.7.0 Ingress NGINX Provider Starting with v3.7.0, the Ingress NGINX provider now supports the nginx.ingress.kubernetes.io/custom-headers annotation to add custom headers to the response forwarded to the client. Therefore, in the corresponding RBACs (see KubernetesIngressNGINX provider RBACs) the configmaps right has been added. Required RBAC Updates: ... - apiGroups: - "" resources: - configmaps verbs: - list - watch ... Kubernetes Gateway API Provider Starting with v3.7.0, the Kubernetes Gateway API provider supports version v1.5.1 of the specification, which requires the Gateway API CRDs to be updated. TLSRoute has graduated to the Standard channel and no longer requires the experimentalChannel option. The experimentalChannel option is now only needed for TCPRoute. Apply Updated CRDs: kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml For the experimental channel: kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/experimental-install.yaml Kubernetes CRD Provider To use the new options of the retry middleware or the new ingressClassName field with the Kubernetes CRD provider, you need to update your CRDs. Apply Updated CRDs: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.7/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml Wildcard Host and HostSNI Since v3.7.0, the Host and HostSNI matchers support wildcard subdomain matching (e.g., *.example.com). This allows matching any direct subdomain of a domain with a single-level wildcard prefix. For example, *.example.com matches foo.example.com but not foo.bar.example.com or example.com itself. This feature is only available with the v3 rule syntax (the default). TLSOptions with Wildcard Domains Since v3.7.0, TLSOptions can now be associated with routers using wildcard Host and HostSNI matchers (e.g., Host(*.example.com )). This enables configuring different TLS options for wildcard domains. Previously, TLSOptions selection was limited to exact Host matches, and using HostRegexp or wildcards would fall back to the default TLS options with a warning message like: No domain found in rule HostRegexp(...) the TLS option foo cannot be applied. Note: TLSOptions for HostRegexp matchers remains unsupported. Use wildcard Host matchers as an alternative. v3.6.25 Kubernetes Gateway API Provider: generated router, middleware, and service names Starting with v3.6.25, the Kubernetes Gateway API provider derives the hash suffix of the router names it generates from all the route, Gateway, and listener identifying fields, instead of from the route rule alone. This is required to prevent distinct routes whose namespace, name, Gateway, and listener happen to concatenate to the same string from colliding on a single generated router name. Generated router names keep the same overall shape: ---gw---ep--- but the suffix changes, since it is no longer computed from the route rule alone. For example, an HTTPRoute named http-app-1 in the default namespace previously generated the router httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-af329269dd38031b03e3 and is now generated as httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93. Middleware names are derived from the router name, so they change accordingly, for example -requestheadermodifier-0. Generated service names were previously built from the backend reference only: -- They are now prefixed with the route rule they are generated for: -svc--- For example, a whoami backend in the default namespace previously exposed as default-whoami-http-80@kubernetesgateway is now exposed as httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-svc-default-whoami-0@kubernetesgateway. !!! warning "Observability" These names are user-visible: they appear in the dashboard and API, in the access logs `RouterName` and `ServiceName` fields, and in the `router`/`service` labels of the metrics. Dashboards, alerting rules, and log queries that match on Gateway API router, middleware, or service names must be updated accordingly. v3.6.24 Kubernetes CRD: Errors middleware errorRequestHeaders The errorRequestHeaders option, introduced in v3.6.15 for the Errors middleware, was not exposed on the Kubernetes CRD provider. Starting with v3.6.24, it can now be configured on the Middleware CRD. To use this new option, the Kubernetes CRDs must be updated in the cluster before upgrading Traefik. To do so, please apply the CRDs manifest for v3.6: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.6/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml Please check out the Error Pages middleware documentation for more details. HTTP/1 CONNECT requests Starting with v3.6.24, HTTP/1 CONNECT requests are rejected with a 501 Not Implemented response. HTTP/1 CONNECT requests were not functional before this change, so this rejection makes it explicit. v3.6.22 UnderscoreHeadersStrategy !!! warning "Deprecated since v3.7.12" Please use the [`aliasHeadersStrategy`](../reference/install-configuration/entrypoints.md#opt-http-aliasHeadersStrategy) option instead, which handles every aliasing character instead of the underscore only. From version v3.6.22 onwards, a new underscoreHeadersStrategy entry point option defines how request headers with underscores in their names are handled before routing: keep (default): request headers with underscores are forwarded as is. delete: any request header whose name contains an underscore character is silently removed from the request. reject: any request carrying a header whose name contains an underscore character is rejected with a 400 Bad Request response. The default value is keep, so the existing behavior is preserved. This option exists because underscores are valid characters in HTTP header names, but Go canonicalizes header names only on dashes. As a result, a middleware managing a header in its dash form (e.g. X-Auth-User set by the ForwardAuth authResponseHeaders option) does not see, and therefore cannot overwrite or remove, an underscore variant of that header (e.g. X_Auth_User). Many backends map both forms to the same variable (CGI, WSGI, PHP, NGINX, ...): for them, X-Auth-User and X_Auth_User are the same header. Against such a backend, a client can smuggle the underscore variant past a middleware that only manages the dash form, and have the backend read the spoofed value, bypassing the protection the middleware was meant to provide. !!! warning "Security" When an entry point fronts a backend that interprets underscores and dashes in header names identically, keeping the default `keep` strategy is not recommended, as it leaves the backend open to the header spoofing described above. Set `underscoreHeadersStrategy` to `delete` or `reject` on such entry points. v3.6.19 Kubernetes Gateway API Provider Starting with v3.6.19, the QPS and Burst values of the Kubernetes client used by the Kubernetes Gateway API provider have been increased to 50 and 100 respectively (10x the default values of the Kubernetes client). The Kubernetes Gateway API provider writes status updates intensively to comply with the Kubernetes Gateway API specification. This change helps avoid performance issues related to Kubernetes API rate limiting, which can increase the setup time when a new routing configuration is built. These values are configurable through the kubernetesGateway.qps and kubernetesGateway.burst provider options. BasicAuth Middleware From version v3.6.19 onwards, the BasicAuth middleware requires a non-empty users configuration in order to be built successfully. Previously, the middleware would be built successfully but always return a 401 status code for any request. Now, an error occurs and any routers using it will be unmounted. For the same request, a 404 status code is served instead of a 401 status code. StripPrefix and StripPrefixRegex Middleware From version v3.6.19 onwards, the StripPrefix middleware and the StripPrefixRegex middleware reject requests ( 400 Bad Request) when stripping the configured prefix produces a path that differs from its normalised form (i.e. a path containing . or .. segments that would be collapsed by normalisation). This prevents the stripped path from being interpreted as a different resource by the upstream service. Examples with a configured prefix of /api: Request path Path after strip Normalised path Result /api/foo /foo /foo 200 (sent) /api/ / / 200 (sent) /api./foo /./foo /foo 400 /api../foo /../foo /foo 400 v3.6.17 Kubernetes providers: crossProviderNamespaces In v3.6.17, a new crossProviderNamespaces option is available on the Kubernetes CRD, Ingress, and Gateway providers. Traefik offers the possibility to reference resources from one provider to another (cross-provider references). However, in the context of Kubernetes providers, those references (e.g. myservice@kubernetescrd) allow a user to cross namespace boundaries, as well as exposing @internal services, that only the operator should be able to expose. This new crossProviderNamespaces option restricts in which namespaces Kubernetes resources are allowed to use cross-provider references. The behavior is as follows: Value Behavior not set All Kubernetes resources can declare cross-provider references. [] Every Kubernetes resource declaring a cross-provider reference is rejected. ["ns-a"] Only Kubernetes resources in the listed namespaces can declare cross-provider references. Please check out the Kubernetes CRD, Kubernetes Ingress, and Kubernetes Gateway provider documentation for more details. v3.6.16 Docker provider: minimum Docker Engine version Starting with v3.6.16, the Docker provider requires Docker API version v1.40 or above (Docker Engine v19.03). Users running older (end of life) versions of Docker Engine should update their Docker Engine or use the DOCKER_API_VERSION environment variable to override the API version used by Traefik. v3.6.15 In v3.6.15, a new errorRequestHeaders option has been added to the Errors middleware. By default, the behavior is unchanged: all original request headers are forwarded to the error page service. If the error page service is in a separate trust domain, consider using errorRequestHeaders to restrict which headers are forwarded. Please check out the Error Pages middleware documentation for more details. v3.6.14 Kubernetes CRD: Chain middleware and allowCrossNamespace In v3.6.14, the Chain middleware now honors the Kubernetes CRD provider's allowCrossNamespace option. Previously, a Chain could reference middlewares in other namespaces regardless of the allowCrossNamespace configuration. If allowCrossNamespace is set to false (the default) and a Chain middleware references a middleware in a different namespace from its own, the whole Chain is now rejected and an error is logged. ForwardAuth middleware: trustForwardHeader Starting with v3.6.14, the trustForwardHeader option has been deprecated and will be removed in the next major version. Configure the trusted IPs at the EntryPoint level by using the forwardedHeaders.trustedIPs option, and set trustForwardHeader to true on this middleware. When trustForwardHeader is not explicitly set, Traefik logs a warning as its behavior is inconsistent: some X-Forwarded-* headers (e.g. X-Forwarded-For, X-Forwarded-Proto) are removed while others (e.g. X-Forwarded-Prefix) are forwarded untouched. To silence the warning and avoid security concerns, explicitly set trustForwardHeader to true or false in your ForwardAuth middleware configuration. Please check out the ForwardAuth middleware documentation for more details. v3.6.9 maxResponseBodySize configuration on ForwardAuth middleware In v3.6.9, a new maxResponseBodySize option has been added to the ForwardAuth middleware configuration. The default value for this option is -1, which means there is no limit to the response body size. However, it is strongly recommended to set this option to a suitable value to avoid performance and security issues, such as DoS attacks and memory exhaustion. Please check out the ForwardAuth middleware documentation for more details. Kubernetes CRD Provider To use the new maxResponseBodySize option in the ForwardAuth middleware with the Kubernetes CRD provider, you need to update your CRDs. Apply Updated CRDs: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.6/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml v3.6.8 Health Check Request Path Since v3.6.8, the configured path for the health check request is now verified to be a relative URL, and the health check will fail if it is not. v3.6.7 Encoded Characters Configuration Default Values Since v3.6.7, the options for encoded characters now have a true default value. This means that Traefik will not reject requests with a path containing a specific set of encoded characters by default. It is now up to the users to configure the security hardening of encoded characters. Here is the list of the encoded characters that can be configured to false to disallow them: Encoded Character Character Config options Default value %2f or %2F / (slash) entryPoints. .http.encodedCharacters .allowEncodedSlash true %5c or %5C \ (backslash) entryPoints. .http.encodedCharacters .allowEncodedBackSlash true %00 NULL (null character) entryPoints. .http.encodedCharacters .allowEncodedNullCharacter true %3b or %3B ; (semicolon) entryPoints. .http.encodedCharacters .allowEncodedSemicolon true %25 % (percent) entryPoints. .http.encodedCharacters .allowEncodedPercent true %3f or %3F ? (question mark) entryPoints. .http.encodedCharacters .allowEncodedQuestionMark true %23 # (hash) entryPoints. .http.encodedCharacters .allowEncodedHash true Note: This check is not done against query parameters, but only against the request path as defined in RFC3986 section-3. Please check out the entrypoint encodedCharacters option documentation for more details. v3.6.4 Encoded Characters in Request Path Starting with v3.6.4, for security reasons, Traefik now rejects requests with a path containing a specific set of encoded characters by default. When such a request is received, Traefik responds with a 400 Bad Request status code. Here is the list of the encoded characters that are rejected by default, along with the corresponding configuration option to allow them: Encoded Character Character Config option to allow the encoded character %2f or %2F / (slash) entryPoints. .http.encodedCharacters .allowEncodedSlash %5c or %5C \ (backslash) entryPoints. .http.encodedCharacters .allowEncodedBackSlash %00 NULL (null character) entryPoints. .http.encodedCharacters .allowEncodedNullCharacter %3b or %3B ; (semicolon) entryPoints. .http.encodedCharacters .allowEncodedSemicolon %25 % (percent) entryPoints. .http.encodedCharacters .allowEncodedPercent %3f or %3F ? (question mark) entryPoints. .http.encodedCharacters .allowEncodedQuestionMark %23 # (hash) entryPoints. .http.encodedCharacters .allowEncodedHash Please check out the entrypoint encodedCharacters option documentation for more details. v3.6.2 Ingress NGINX Provider The KubernetesIngressNGINX Provider is no longer experimental in v3.6.2 and can be enabled without the experimental.kubernetesIngressNGINX option. Deprecated Configuration: ??? example "Experimental kubernetesIngressNGINX option (deprecated)" ```yaml tab="File (YAML)" experimental: kubernetesIngressNGINX: true ``` ```toml tab="File (TOML)" [experimental] kubernetesIngressNGINX=true ``` ```bash tab="CLI" --experimental.kubernetesIngressNGINX=true ``` Migration Steps: Remove the kubernetesIngressNGINX option from the experimental section Configure the provider using the kubernetesIngressNGINX Provider documentation v3.6.0 Kubernetes Gateway API Provider Starting with v3.6.0, the Kubernetes Gateway API provider only supports version v1.4.0 of the specification, which requires the Gateway API CRDs to be updated. Apply Updated CRDs: kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml For the experimental channel: kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/experimental-install.yaml Kubernetes CRD Provider To use the new leasttime load-balancer algorithm with the Kubernetes CRD provider, you need to update your CRDs. Apply Updated CRDs: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.6/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml v3.5.4 Certificate Metric Renamed with OpenTelemetry Starting with v3.5.4, and when using OpenTelemetry, the traefik_tls_certs_not_after_milliseconds metric is renamed to traefik_tls_certs_not_after_seconds. This change aligns the metric name with its real unit precision, which is in seconds. v3.5.2 Deprecation of ProxyProtocol option Starting with v3.5.2, the proxyProtocol option for TCP LoadBalancer is deprecated. This option can now be configured at the TCPServersTransport level, please check out the documentation for more details. Kubernetes CRD Provider To use the new proxyprotocol option in the Kubernetes CRD provider, you need to update your CRDs. Apply Updated CRDs: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.5/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml v3.5.0 Observability TraceVerbosity on Routers and Entrypoints Starting with v3.5.0, a new traceVerbosity option is available for both entrypoints and routers. This option allows you to control the level of detail for tracing spans. Routers can override the value inherited from their entrypoint. Impact: If you rely on tracing, review your configuration to explicitly set the desired verbosity level. Existing configurations will default to minimal unless overridden, which will result in fewer spans being generated than before. Possible values are: minimal: produces a single server span and one client span for each request processed by a router. detailed: enables the creation of additional spans for each middleware executed for each request processed by a router. See the updated documentation for entrypoints and dynamic routers. K8s Resource Attributes Since v3.5.0, the semconv attributes k8s.pod.name and k8s.pod.uid are injected automatically in OTel resource attributes when OTel tracing/logs/metrics are enabled. For that purpose, the following right has to be added to the Traefik Kubernetes RBACs: ... - apiGroups: - "" resources: - pods verbs: - get ... v3.4.5 MultiPath TCP Since v3.4.5, the MultiPath TCP support introduced with v3.4.2 has been removed. It appears that enabling MPTCP on some platforms can cause Traefik to stop with the following error logs message: set tcp X.X.X.X:X->X.X.X.X:X: setsockopt: operation not supported However, it can be re-enabled by setting the multipathtcp variable in the GODEBUG environment variable, see the related go documentation. v3.4.1 Request Path Normalization Starting with v3.4.1, request paths are now normalized according to RFC 3986 standards for better consistency and security. Normalization Process: Unreserved Character Decoding: Characters like %2E (.) are decoded to their literal form Case Normalization: Percent-encoded characters are uppercased ( %2e becomes %2E) This follows RFC 3986 percent-encoding normalization and case normalization standards. Processing Order: Path normalization (cannot be disabled) Path sanitization (if enabled) Reserved Character Handling in Routing Starting with v3.4.1, reserved characters (per RFC 3986) remain encoded during router rule matching to prevent routing ambiguity. Why This Matters: Reserved characters change the meaning of request paths when decoded. Keeping them encoded during routing prevents security vulnerabilities and ensures predictable routing behavior. Request Path Matching Examples The following table illustrates how path matching behavior has changed: Request Path Router Rule Traefik v3.4.0 Traefik v3.4.1 Explanation /foo%2Fbar PathPrefix(`/foo/bar`) Match No match %2F (/) stays encoded, preventing false matches /foo/../bar PathPrefix(`/foo`) No match No match Path traversal is sanitized away /foo/../bar PathPrefix(`/bar`) Match Match Resolves to /bar after sanitization /foo/%2E%2E/bar PathPrefix(`/foo`) Match No match Encoded dots normalized then sanitized /foo/%2E%2E/bar PathPrefix(`/bar`) No match Match Resolves to /bar after normalization + sanitization v3.3 to v3.4 Kubernetes CRD Provider Load-Balancing Strategy Updates Starting with v3.4, HTTP service definitions now support additional load-balancing strategies for better traffic distribution. Apply Updated CRDs: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.4/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml New Strategy Values: wrr (Weighted Round Robin) p2c (Power of Two Choices) !!! warning "Deprecation" The RoundRobin strategy is deprecated but still supported (equivalent to wrr). It will be removed in the next major release. Refer to the HTTP Services Load Balancing documentation for detailed information. ServersTransport CA Certificate Configuration A new rootCAs option has been added to the ServersTransport and ServersTransportTCP CRDs. It supports both ConfigMaps and Secrets for CA certificates and replaces the rootCAsSecrets option. Apply Updates: # Update CRDs kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.4/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml # Update RBACs kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.4/docs/content/reference/dynamic-configuration/kubernetes-crd-rbac.yml New Configuration Format: --- apiVersion: traefik.io/v1alpha1 kind: ServersTransport metadata: name: foo namespace: bar spec: rootCAs: - configMap: ca-config-map - secret: ca-secret --- apiVersion: traefik.io/v1alpha1 kind: ServersTransportTCP metadata: name: foo namespace: bar spec: rootCAs: - configMap: ca-config-map - secret: ca-secret !!! warning "Deprecation" The rootCAsSecrets option (Secrets only) is still supported but deprecated. It will be removed in the next major release. Rule Syntax Configuration In v3.4, rule syntax configuration options will be removed in the next major version. Deprecated Options: core.defaultRuleSyntax (static configuration) ruleSyntax (router option) These options were transitional helpers for migrating from v2 to v3 syntax. Please ensure all router rules use v3 syntax before the next major release. v3.3.6 Request Path Sanitization Starting with v3.3.6, incoming request paths are now automatically cleaned before processing for security and consistency. What's Changed: The following path segments are now interpreted and collapsed: /../ (parent directory references) /./ (current directory references) Duplicate slash segments ( //) Disabling Sanitization: # EntryPoint HTTP configuration entryPoints: web: address: ":80" http: sanitizePath: false # Not recommended !!! danger "Security Warning" Setting sanitizePath: false is not safe. This option should only be used with legacy clients that don't properly URL-encode data. Always ensure requests are properly URL-encoded instead of disabling this security feature. Example Risk: Base64 data containing "/" characters can lead to unsafe routing when path sanitization is disabled and the data isn't URL-encoded. v3.3.5 Compress Middleware Default Encodings In v3.3.5, the default compression algorithms have been reordered to favor gzip compression. New Default: gzip, br, zstd This change affects requests that either: Don't specify preferred algorithms in the Accept-Encoding header Have no order preference in their Accept-Encoding header The reordering helps ensure better compatibility with older clients that may not support newer compression algorithms. v3.3.4 OpenTelemetry Request Duration Metric In v3.3.4, the OpenTelemetry Request Duration metric unit has been standardized to match other providers and naming conventions. Change Details: Metric: traefik_(entrypoint|router|service)_request_duration_seconds Old Unit: Milliseconds New Unit: Seconds This change ensures consistency across all metrics providers and follows standard naming conventions. v3.2 to v3.3 ACME DNS Certificate Resolver In v3.3, DNS challenge configuration options have been reorganized for better clarity. Migration Required: Deprecated Option New Option acme.dnsChallenge.delaybeforecheck acme.dnsChallenge.propagation.delayBeforeChecks acme.dnsChallenge.disablepropagationcheck acme.dnsChallenge.propagation.disableChecks Tracing Global Attributes In v3.3, the tracing configuration has been clarified to better reflect its purpose. Migration Required: Old: tracing.globalAttributes New: tracing.resourceAttributes The old option name was misleading as it specifically adds resource attributes for the collector, not global span attributes. v3.2.2 Swarm Provider Label Updates In v3.2.2, Swarm-specific labels have been deprecated and will be removed in a future version. Migration Required: Deprecated Label New Label traefik.docker.network traefik.swarm.network traefik.docker.lbswarm traefik.swarm.lbswarm v3.2.1 X-Forwarded-Prefix Header Changes In v3.2.1, the X-Forwarded-Prefix header is now handled like other X-Forwarded-* headers - Traefik removes it when sent from untrusted sources. This change improves security by preventing header spoofing from untrusted clients. Refer to the Forwarded headers documentation for configuration details. v3.1 to v3.2 Kubernetes CRD Provider New optional fields have been added to several CRDs. These updates are backward compatible and only add new functionality. Apply the latest CRDs: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.3/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml Updated Resources: TraefikService (PR #11032) RateLimit & InFlightReq middlewares (PR #9747) Compress middleware (PR #10943) Kubernetes Gateway Provider Standard Channel Starting with v3.2, the Kubernetes Gateway Provider now supports GRPCRoute resources. Therefore, in the corresponding RBACs (see KubernetesGateway provider RBACs), the grcroutes and grpcroutes/status rights have to be added. Required RBAC Updates: ... - apiGroups: - gateway.networking.k8s.io resources: - grpcroutes verbs: - get - list - watch - apiGroups: - gateway.networking.k8s.io resources: - grpcroutes/status verbs: - update ... Kubernetes Gateway Provider Experimental Channel Due to breaking changes in Kubernetes Gateway v1.2.0-rc1, Traefik v3.3 only supports Kubernetes Gateway v1.2.x when experimental features are enabled. New Feature: BackendTLSPolicy Support The provider now supports BackendTLSPolicy resources. Therefore, in the corresponding RBACs (see KubernetesGateway provider RBACs), the backendtlspolicies and backendtlspolicies/status rights have to be added. Required RBAC Updates: ... - apiGroups: - "" resources: - configmaps verbs: - get - list - watch - apiGroups: - gateway.networking.k8s.io resources: - backendtlspolicies verbs: - get - list - watch - apiGroups: - gateway.networking.k8s.io resources: - backendtlspolicies/status verbs: - update ... v3.1.0 to v3.1.1 IngressClass Lookup The disableIngressClassLookup option has been deprecated and will be removed in the next major version. Migration Required: Old: disableIngressClassLookup New: disableClusterScopeResources The new option provides broader control over cluster scope resources discovery, including both IngressClass and Nodes resources. v3.0 to v3.1 Kubernetes Provider RBACs Starting with v3.1, Traefik's Kubernetes Providers use the EndpointSlices API (requires Kubernetes >=v1.21) for service endpoint discovery. This change also introduces NodePort load-balancing capabilities. The following RBAC updates are required for all Kubernetes providers: Remove endpoints permissions and add endpointslices: # Remove this section from your RBAC # - apiGroups: [""] # resources: ["endpoints"] # verbs: ["get", "list", "watch"] # Add this section instead - apiGroups: - discovery.k8s.io resources: - endpointslices verbs: - list - watch Add nodes permissions for NodePort support: - apiGroups: - "" resources: - nodes verbs: - get - list - watch !!! note "Affected Providers" These changes apply to: - [KubernetesIngress](../reference/install-configuration/providers/kubernetes/kubernetes-ingress.md) provider - [KubernetesCRD](../reference/install-configuration/providers/kubernetes/kubernetes-crd.md#requirements) provider - [KubernetesGateway](../reference/install-configuration/providers/kubernetes/kubernetes-gateway.md#requirements) provider Gateway API: KubernetesGateway Provider The KubernetesGateway Provider is no longer experimental in v3.1 and can be enabled without the experimental.kubernetesgateway option. Deprecated Configuration: ??? example "Experimental kubernetesgateway option (deprecated)" ```yaml tab="File (YAML)" experimental: kubernetesgateway: true ``` ```toml tab="File (TOML)" [experimental] kubernetesgateway=true ``` ```bash tab="CLI" --experimental.kubernetesgateway=true ``` Migration Steps: Remove the kubernetesgateway option from the experimental section Configure the provider using the KubernetesGateway Provider documentation Logs and Access Logs Logs concern everything that happens to Traefik itself (startup, configuration, events, shutdown, and so on). Configuration Example To enable and configure logs in Traefik Proxy, you can use the static configuration file or Helm values if you are using the Helm chart. log: filePath: "/path/to/log-file.log" format: json level: INFO [log] filePath = "/path/to/log-file.log" format = "json" level = "INFO" log: filePath: "/path/to/log-file.log" format: json level: INFO Access Logs Access logs concern everything that happens to the requests handled by Traefik. Configuration Example To enable and configure access logs in Traefik Proxy, you can use the static configuration file or Helm values if you are using the Helm chart. The following example enables access logs in JSON format, filters them to only include specific status codes, and customizes the fields that are kept or dropped. accessLog: format: json filters: statusCodes: - "200" - "400-404" - "500-503" fields: names: ClientUsername: drop headers: defaultMode: keep names: User-Agent: redact Content-Type: keep [accessLog] format = "json" [accessLog.filters] statusCodes = ["200", "400-404", "500-503"] [accessLog.fields] [accessLog.fields.names] ClientUsername = "drop" [accessLog.fields.headers] defaultMode = "keep" [accessLog.fields.headers.names] "User-Agent" = "redact" "Content-Type" = "keep" # values.yaml accessLog: enabled: true format: json filters: statusCodes: - "200" - "400-404" - "500-503" fields: names: ClientUsername: drop headers: defaultMode: keep names: User-Agent: redact Content-Type: keep Per-Router Access Logs You can enable or disable access logs for a specific router. This is useful for turning off logging for noisy routes while keeping it on globally. Here's an example of disabling access logs on a specific router: http: routers: my-router: rule: "Host(`example.com`)" service: my-service observability: accessLogs: false [http.routers.my-router.observability] accessLogs = false # ingressroute.yaml apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: my-router spec: routes: - kind: Rule match: Host(`example.com`) services: - name: my-service port: 80 observability: accessLogs: false labels: - "traefik.http.routers.my-router.observability.accesslogs=false" { // ... "Tags": [ "traefik.http.routers.my-router.observability.accesslogs=false" ] } When the observability options are not defined on a router, it inherits the behavior from the entrypoint's observability configuration, or the global one. Log Formats Traefik Proxy supports the following log formats: common - Traefik's extended CLF format (default) genericCLF - Generic CLF format compatible with standard log analyzers json - JSON format for structured logging Origin vs. Downstream Status Access logs report two status codes, named relative to Traefik: Client <---- DownstreamStatus ---- Traefik <---- OriginStatus ---- Backend OriginStatus is the outcome of proxying the request to a backend. It is either the status returned by that backend or the computed status code, when the backend could not be reached or did not answer properly ( 502, 504, ...). DownstreamStatus is what Traefik returned to the client, after the middleware chain has run. Both are equal when the request is proxied unchanged. When both are set but differ, a middleware rewrote the response. When OriginStatus is empty (logged as 0), the request was never proxied to a backend: the response comes from routing (no matching router) or from a middleware (authentication, rate limiting, redirection). !!! info Both fields are only available with the `json` format. The `common` and `genericCLF` formats, and the `statusCodes` filter, use the `DownstreamStatus` value. Access Log Filters You can configure Traefik Proxy to only record access logs for requests that match certain criteria. This is useful for reducing the volume of logs and focusing on specific events. The available filters are: Status Codes: Keep logs only for requests with specific HTTP status codes or ranges (e.g., 200, 400-404). Retry Attempts: Keep logs only when a request retry has occurred. Minimum Duration: Keep logs only for requests that take longer than a specified duration. Log Fields Customization When using the json format, you can customize which fields are included in your access logs. Request Fields: You can choose to keep, drop, or redact any of the standard request fields. A complete list of available fields like ClientHost, RequestMethod, and Duration can be found in the reference documentation. Request Headers: You can also specify which request headers should be included in the logs, and whether their values should be kept, dropped, or redacted. Request Query Parameters: You can choose to keep or drop the query parameters for a request. !!! info For detailed configuration options, refer to the [reference documentation](../reference/install-configuration/observability/logs-and-accesslogs.md). Metrics Metrics in Traefik Proxy offer a comprehensive view of your infrastructure's health. They allow you to monitor critical indicators like incoming traffic volume. Metrics graphs and visualizations are helpful during incident triage in understanding the causes and implementing proactive measures. Available Metrics Providers Traefik Proxy supports the following metrics providers: OpenTelemetry Prometheus Datadog InfluxDB 2.X StatsD Configuration To enable metrics in Traefik Proxy, you need to configure the metrics provider in your static configuration file or helm values if you are using the Helm chart. The following example shows how to configure the OpenTelemetry provider to send metrics to a collector. metrics: otlp: http: endpoint: http://myotlpcollector:4318/v1/metrics [metrics.otlp.http] endpoint = "http://myotlpcollector:4318/v1/metrics" # values.yaml metrics: # Disable Prometheus (enabled by default) prometheus: null # Enable providing OTel metrics otlp: enabled: true http: enabled: true endpoint: http://myotlpcollector:4318/v1/metrics Per-Router Metrics You can enable or disable metrics collection for a specific router. This can be useful for excluding certain routes from your metrics data. Here's an example of disabling metrics on a specific router: http: routers: my-router: rule: "Host(`example.com`)" service: my-service observability: metrics: false [http.routers.my-router.observability] metrics = false # ingressroute.yaml apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: my-router spec: routes: - kind: Rule match: Host(`example.com`) services: - name: my-service port: 80 observability: metrics: false labels: - "traefik.http.routers.my-router.observability.metrics=false" { // ... "Tags": [ "traefik.http.routers.my-router.observability.metrics=false" ] } When the observability options are not defined on a router, it inherits the behavior from the entrypoint's observability configuration, or the global one. !!! info For detailed configuration options, refer to the reference documentation. Observability Overview Traefik Proxy provides comprehensive monitoring and observability capabilities to maintain reliability and efficiency: Logs and Access Logs provide real-time insight into the health of your system. They enable swift error detection and intervention through alerts. By centralizing logs, you can streamline the debugging process during incident resolution. Metrics offer a comprehensive view of your infrastructure's health. They allow you to monitor critical indicators like incoming traffic volume. Metrics graphs and visualizations are helpful during incident triage in understanding the causes and implementing proactive measures. Tracing enables tracking the flow of operations within your system. Using traces and spans, you can identify performance bottlenecks and pinpoint applications causing slowdowns to optimize response times effectively. Configuration Example You can enable access logs, metrics, and tracing globally: accessLog: {} metrics: otlp: {} tracing: {} [accessLog] [metrics.otlp] [tracing.otlp] # values.yaml accessLog: enabled: true metrics: otlp: enabled: true tracing: otlp: enabled: true You can disable access logs, metrics, and tracing for a specific entrypoint: entryPoints: EntryPoint0: address: ':8000/udp' observability: accessLogs: false tracing: false metrics: false [entryPoints.EntryPoint0.observability] accessLogs = false tracing = false metrics = false additionalArguments: - "--entrypoints.entrypoint0.observability.accesslogs=false" - "--entrypoints.entrypoint0.observability.tracing=false" - "--entrypoints.entrypoint0.observability.metrics=false" !!! note A router with its own observability configuration will override the global default. {% include-markdown "includes/traefik-for-business-applications.md" %} Tracing Tracing in Traefik Proxy allows you to track the flow of operations within your system. Using traces and spans, you can identify performance bottlenecks and pinpoint applications causing slowdowns to optimize response times effectively. Traefik Proxy uses OpenTelemetry to export traces. OpenTelemetry is an open-source observability framework. You can send traces to an OpenTelemetry collector, which can then export them to a variety of backends like Jaeger, Zipkin, or Datadog. Configuration To enable tracing in Traefik Proxy, you need to configure it in your static configuration file or Helm values if you are using the Helm chart. The following example shows how to configure the OpenTelemetry provider to send traces to a collector via HTTP. tracing: otlp: http: endpoint: http://myotlpcollector:4318/v1/traces [tracing.otlp.http] endpoint = "http://myotlpcollector:4318/v1/traces" # values.yaml tracing: otlp: enabled: true http: enabled: true endpoint: http://myotlpcollector:4318/v1/traces !!! info For detailed configuration options, refer to the tracing reference documentation. Per-Router Tracing You can enable or disable tracing for a specific router. This is useful for turning off tracing for specific routes while keeping it on globally. Here's an example of disabling tracing on a specific router: http: routers: my-router: rule: "Host(`example.com`)" service: my-service observability: tracing: false [http.routers.my-router.observability] tracing = false # ingressoute.yaml apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: my-router spec: routes: - kind: Rule match: Host(`example.com`) services: - name: my-service port: 80 observability: tracing: false labels: - "traefik.http.routers.my-router.observability.tracing=false" { // ... "Tags": [ "traefik.http.routers.my-router.observability.tracing=false" ] } When the observability options are not defined on a router, it inherits the behavior from the entrypoint's observability configuration, or the global one. include-api-examples # Dynamic Configuration labels: - "traefik.http.routers.api.rule=Host(`traefik.example.com`)" - "traefik.http.routers.api.service=api@internal" - "traefik.http.routers.api.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" # Dynamic Configuration deploy: labels: - "traefik.http.routers.api.rule=Host(`traefik.example.com`)" - "traefik.http.routers.api.service=api@internal" - "traefik.http.routers.api.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" # Dummy service for Swarm port detection. The port can be any valid integer value. - "traefik.http.services.dummy-svc.loadbalancer.server.port=9999" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: traefik-dashboard spec: routes: - match: Host(`traefik.example.com`) kind: Rule services: - name: api@internal kind: TraefikService middlewares: - name: auth --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: auth spec: basicAuth: secret: secretName # Kubernetes secret named "secretName" # Dynamic Configuration - "traefik.http.routers.api.rule=Host(`traefik.example.com`)" - "traefik.http.routers.api.service=api@internal" - "traefik.http.routers.api.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" # Dynamic Configuration http: routers: api: rule: Host(`traefik.example.com`) service: api@internal middlewares: - auth middlewares: auth: basicAuth: users: - "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/" - "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0" # Dynamic Configuration [http.routers.my-api] rule = "Host(`traefik.example.com`)" service = "api@internal" middlewares = ["auth"] [http.middlewares.auth.basicAuth] users = [ "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", ] include-dashboard-custom-path-examples # Dynamic Configuration labels: - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && PathPrefix(`/traefik`)" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" # Dynamic Configuration deploy: labels: - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && PathPrefix(`/traefik`)" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" # Dummy service for Swarm port detection. The port can be any valid integer value. - "traefik.http.services.dummy-svc.loadbalancer.server.port=9999" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: traefik-dashboard spec: routes: - match: Host(`traefik.example.com`) && PathPrefix(`/traefik`) kind: Rule services: - name: api@internal kind: TraefikService middlewares: - name: auth --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: auth spec: basicAuth: secret: secretName # Kubernetes secret named "secretName" # Dynamic Configuration - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && PathPrefix(`/traefik`)" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" # Dynamic Configuration http: routers: dashboard: rule: Host(`traefik.example.com`) && PathPrefix(`/traefik`) service: api@internal middlewares: - auth middlewares: auth: basicAuth: users: - "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/" - "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0" # Dynamic Configuration [http.routers.my-api] rule = "Host(`traefik.example.com`) && PathPrefix(`/traefik`)" service = "api@internal" middlewares = ["auth"] [http.middlewares.auth.basicAuth] users = [ "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", ] include-dashboard-examples # Dynamic Configuration labels: - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" # Dynamic Configuration deploy: labels: - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" # Dummy service for Swarm port detection. The port can be any valid integer value. - "traefik.http.services.dummy-svc.loadbalancer.server.port=9999" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: traefik-dashboard spec: routes: - match: Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`)) kind: Rule services: - name: api@internal kind: TraefikService middlewares: - name: auth --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: auth spec: basicAuth: secret: secretName # Kubernetes secret named "secretName" # Dynamic Configuration - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" # Dynamic Configuration http: routers: dashboard: rule: Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`)) service: api@internal middlewares: - auth middlewares: auth: basicAuth: users: - "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/" - "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0" # Dynamic Configuration [http.routers.my-api] rule = "Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))" service = "api@internal" middlewares = ["auth"] [http.middlewares.auth.basicAuth] users = [ "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", ] Traefik API & Dashboard Documentation Traefik exposes a number of information through API endpoints, such as the configuration of your routers, services, middlewares, etc. The dashboard, which is the central place that displays the current active routes handled by Traefik, fetches the data from this API. The dashboard in action Security Enabling the API and the dashboard in production is not recommended, because it will expose all configuration elements, including sensitive data, for which access should be reserved to administrators. In production, it should be at least secured by authentication and authorizations. !!! info It's recommended to NOT publicly exposing the API's port, keeping it restricted to internal networks (as in the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege), applied to networks). Configuration Example Enable the dashboard: api: {} [api] --api=true Expose the dashboard: apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: traefik-dashboard spec: routes: - match: Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`)) kind: Rule services: - name: api@internal kind: TraefikService middlewares: - name: auth --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: auth spec: basicAuth: secret: secretName # Kubernetes secret named "secretName" # Create an IngressRoute for the dashboard ingressRoute: dashboard: enabled: true # Custom match rule with host domain matchRule: Host(`traefik.example.com`) entryPoints: ["websecure"] # Add custom middlewares : authentication and redirection middlewares: - name: traefik-dashboard-auth # Create the custom middlewares used by the IngressRoute dashboard (can also be created in another way). # /!\ Yes, you need to replace "changeme" password with a better one. /!\ extraObjects: - apiVersion: v1 kind: Secret metadata: name: traefik-dashboard-auth-secret type: kubernetes.io/basic-auth stringData: username: admin password: changeme - apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: traefik-dashboard-auth spec: basicAuth: secret: traefik-dashboard-auth-secret # Dynamic Configuration labels: - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" # Dynamic Configuration deploy: labels: - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" # Dummy service for Swarm port detection. The port can be any valid integer value. - "traefik.http.services.dummy-svc.loadbalancer.server.port=9999" # Dynamic Configuration - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" # Dynamic Configuration http: routers: dashboard: rule: Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`)) service: api@internal middlewares: - auth middlewares: auth: basicAuth: users: - "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/" - "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0" # Dynamic Configuration [http.routers.my-api] rule = "Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))" service = "api@internal" middlewares = ["auth"] [http.middlewares.auth.basicAuth] users = [ "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", ] Configuration Options The API and the dashboard can be configured: In the Helm Chart: You can find the options to customize the Traefik installation enabling the dashboard here. In the Traefik Static Configuration as described below. Field Description Default Required api Enable api/dashboard. When set to true, its sub option api.dashboard is also set to true. false No api.basePath Defines the base path where the API and Dashboard will be exposed. Please note that this option is incompatible with the insecure mode. / No api.dashboard Enable dashboard. true No api.debug Enable additional endpoints for debugging and profiling. false No api.disableDashboardAd Disable the advertisement from the dashboard. false No api.insecure Enable the API and the dashboard on the entryPoint named traefik. Please note that this mode is incompatible with the custom API base path option. false No Endpoints All the following endpoints must be accessed with a GET HTTP request. Path Description /api/http/routers Lists all the HTTP routers information. /api/http/routers/{name} Returns the information of the HTTP router specified by name. /api/http/services Lists all the HTTP services information. /api/http/services/{name} Returns the information of the HTTP service specified by name. /api/http/middlewares Lists all the HTTP middlewares information. /api/http/middlewares/{name} Returns the information of the HTTP middleware specified by name. /api/tcp/routers Lists all the TCP routers information. /api/tcp/routers/{name} Returns the information of the TCP router specified by name. /api/tcp/services Lists all the TCP services information. /api/tcp/services/{name} Returns the information of the TCP service specified by name. /api/tcp/middlewares Lists all the TCP middlewares information. /api/tcp/middlewares/{name} Returns the information of the TCP middleware specified by name. /api/udp/routers Lists all the UDP routers information. /api/udp/routers/{name} Returns the information of the UDP router specified by name. /api/udp/services Lists all the UDP services information. /api/udp/services/{name} Returns the information of the UDP service specified by name. /api/entrypoints Lists all the entry points information. /api/entrypoints/{name} Returns the information of the entry point specified by name. /api/overview Returns statistic information about HTTP, TCP and about enabled features and providers. /api/support-dump Returns an archive that contains the anonymized static configuration and the runtime configuration. /api/rawdata Returns information about dynamic configurations, errors, status and dependency relations. /api/version Returns information about Traefik version. /debug/vars See the expvar Go documentation. /debug/pprof/ See the pprof Index Go documentation. /debug/pprof/cmdline See the pprof Cmdline Go documentation. /debug/pprof/profile See the pprof Profile Go documentation. /debug/pprof/symbol See the pprof Symbol Go documentation. /debug/pprof/trace See the pprof Trace Go documentation. !!! note "Base Path Configuration" By default, Traefik exposes its API and Dashboard under the `/` base path. It's possible to configure it with `api.basePath`. When configured, all endpoints (api, dashboard, debug) are using it. Dashboard The dashboard is available by default on the path /dashboard/. !!! note - The trailing slash `/` in `/dashboard/` is mandatory. This limitation can be mitigated using the [RedirectRegex Middleware](../../reference/routing-configuration/http/middlewares/redirectregex.md). - There is also a redirect from the path `/` to `/dashboard/`, but you should not rely on this behavior, as it is subject to change and may complicate routing rules. As mentioned above in the Security section, it is important to secure access to both the dashboard and the API. You need to define a routing configuration within Traefik. This involves setting up a router attached to the service api@internal, which allows you to: Implement security features using middlewares, such as authentication (basicAuth, digestAuth, forwardAuth) or allowlisting. Define a router rule for accessing the dashboard through Traefik. Dashboard Router Rule To ensure proper access to the dashboard, the router rule you define must match requests intended for the /api and /dashboard paths. We recommend using either a Host-based rule to match all requests on the desired domain or explicitly defining a rule that includes both path prefixes. Here are some examples: # The dashboard can be accessed on http://traefik.example.com/dashboard/ rule = "Host(`traefik.example.com`)" # The dashboard can be accessed on http://example.com/dashboard/ or http://traefik.example.com/dashboard/ rule = "PathPrefix(`/api`) || PathPrefix(`/dashboard`)" # The dashboard can be accessed on http://traefik.example.com/dashboard/ rule = "Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))" {% include-markdown "includes/traefik-for-business-applications.md" %} Boot Environment Traefik Proxy’s configuration is divided into two main categories: Install Configuration: (formerly known as the static configuration) Defines parameters that require Traefik to restart when changed. This includes entry points, providers, API/dashboard settings, and logging levels. Routing Configuration: (formerly known as the dynamic configuration) Involves elements that can be updated without restarting Traefik, such as routers, services, and middlewares. This section focuses on setting up the install configuration, which is essential for Traefik’s initial boot. Configuration Methods Traefik offers multiple methods to define install configuration. !!! warning "Note" It’s crucial to choose one method and stick to it, as mixing different configuration options is not supported and can lead to unexpected behavior. Here are the methods available for configuring the Traefik proxy: File CLI Environment Variables Helm File You can define the install configuration in a file using formats like YAML or TOML. Configuration Example entryPoints: web: address: ":80" websecure: address: ":443" providers: docker: {} api: dashboard: true log: level: INFO [entryPoints] [entryPoints.web] address = ":80" [entryPoints.websecure] address = ":443" [providers] [providers.docker] [api] dashboard = true [log] level = "INFO" Configuration File At startup, Traefik searches for install configuration in a file named traefik.yml (or traefik.yaml or traefik.toml) in the following directories: /etc/traefik/ $XDG_CONFIG_HOME/ $HOME/.config/ . (the current working directory). You can override this behavior using the configFile argument like this: traefik --configFile=foo/bar/myconfigfile.yml CLI Using the CLI, you can pass install configuration directly as command-line arguments when starting Traefik. Configuration Example traefik \ --entryPoints.web.address=":80" \ --entryPoints.websecure.address=":443" \ --providers.docker \ --api.dashboard \ --log.level=INFO Environment Variables You can also set the install configuration using environment variables. Each option corresponds to an environment variable prefixed with TRAEFIK_. Configuration Example TRAEFIK_ENTRYPOINTS_WEB_ADDRESS=":80" TRAEFIK_ENTRYPOINTS_WEBSECURE_ADDRESS=":443" TRAEFIK_PROVIDERS_DOCKER=true TRAEFIK_API_DASHBOARD=true TRAEFIK_LOG_LEVEL="INFO" traefik Helm When deploying Traefik Proxy using Helm in a Kubernetes cluster, the install configuration is defined in a values.yaml file. You can find the official Traefik Helm chart on GitHub Configuration Example ports: web: exposedPort: 80 websecure: exposedPort: 443 additionalArguments: - "--providers.kubernetescrd.ingressClass=traefik" - "--log.level=INFO" helm repo add traefik https://traefik.github.io/charts helm repo update helm install traefik traefik/traefik -f values.yaml configuration-options Install Configuration Options Configuration Options Field Description Default accesslog Access log settings. false accesslog.addinternals Enables access log for internal services (ping, dashboard, etc...). false accesslog.bufferingsize Number of access log lines to process in a buffered way. 0 accesslog.dualoutput Enables access log output alongside OTLP. By default, this output is disabled when OTLP is configured. false accesslog.fields.defaultmode Default mode for fields: keep drop accesslog.fields.headers.defaultmode Default mode for fields: keep drop accesslog.fields.headers.names.name Override mode for headers accesslog.fields.names.name Override mode for fields accesslog.fields.queryparameters.defaultmode Default mode for query parameters: keep drop accesslog.filepath Access log file path. Stdout is used when omitted or empty. accesslog.filters.minduration Keep access logs when request took longer than the specified duration. 0 accesslog.filters.retryattempts Keep access logs when at least one retry happened. false accesslog.filters.statuscodes Keep access logs with status codes in the specified range. accesslog.format Access log format: json, common, or genericCLF common accesslog.otlp Settings for OpenTelemetry. false accesslog.otlp.grpc gRPC configuration for the OpenTelemetry collector. false accesslog.otlp.grpc.endpoint Sets the gRPC endpoint (host:port) of the collector. localhost:4317 accesslog.otlp.grpc.headers.name Headers sent with payload. accesslog.otlp.grpc.insecure Disables client transport security for the exporter. false accesslog.otlp.grpc.tls.ca TLS CA accesslog.otlp.grpc.tls.cert TLS cert accesslog.otlp.grpc.tls.insecureskipverify TLS insecure skip verify false accesslog.otlp.grpc.tls.key TLS key accesslog.otlp.http HTTP configuration for the OpenTelemetry collector. false accesslog.otlp.http.endpoint Sets the HTTP endpoint (scheme://host:port/path) of the collector. https://localhost:4318 accesslog.otlp.http.headers.name Headers sent with payload. accesslog.otlp.http.tls.ca TLS CA accesslog.otlp.http.tls.cert TLS cert accesslog.otlp.http.tls.insecureskipverify TLS insecure skip verify false accesslog.otlp.http.tls.key TLS key accesslog.otlp.resourceattributes.name Defines additional resource attributes (key:value). accesslog.otlp.servicename Defines the service name resource attribute. traefik api Enable api/dashboard. false api.basepath Defines the base path where the API and Dashboard will be exposed. / api.dashboard Activate dashboard. true api.dashboardname Custom name for the dashboard. api.debug Enable additional endpoints for debugging and profiling. false api.disabledashboardad Disable ad in the dashboard. false api.insecure Activate API directly on the entryPoint named traefik. false certificatesresolvers.name Certificates resolvers configuration. false certificatesresolvers.name.acme.cacertificates Specify the paths to PEM encoded CA Certificates that can be used to authenticate an ACME server with an HTTPS certificate not issued by a CA in the system-wide trusted root list. certificatesresolvers.name.acme.caserver CA server to use. https://acme-v02.api.letsencrypt.org/directory certificatesresolvers.name.acme.caservername Specify the CA server name that can be used to authenticate an ACME server with an HTTPS certificate not issued by a CA in the system-wide trusted root list. certificatesresolvers.name.acme.casystemcertpool Define if the certificates pool must use a copy of the system cert pool. false certificatesresolvers.name.acme.certificatesduration Certificates' duration in hours. 2160 certificatesresolvers.name.acme.certificatetimeout Timeout for obtaining the certificate during the finalization request. 30 certificatesresolvers.name.acme.clientresponseheadertimeout Timeout for receiving the response headers when communicating with the ACME server. 30 certificatesresolvers.name.acme.clienttimeout Timeout for a complete HTTP transaction with the ACME server. 120 certificatesresolvers.name.acme.disablecommonname Disable the common name in the CSR. false certificatesresolvers.name.acme.dnschallenge Activate DNS-01 Challenge. false certificatesresolvers.name.acme.dnschallenge.delaybeforecheck (Deprecated) Assume DNS propagates after a delay in seconds rather than finding and querying nameservers. 0 certificatesresolvers.name.acme.dnschallenge.disablepropagationcheck (Deprecated) Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. [not recommended] false certificatesresolvers.name.acme.dnschallenge.propagation DNS propagation checks configuration certificatesresolvers.name.acme.dnschallenge.propagation.delaybeforechecks Defines the delay before checking the challenge TXT record propagation. 0 certificatesresolvers.name.acme.dnschallenge.propagation.disableanschecks Disables the challenge TXT record propagation checks against authoritative nameservers. false certificatesresolvers.name.acme.dnschallenge.propagation.disablechecks Disables the challenge TXT record propagation checks (not recommended). false certificatesresolvers.name.acme.dnschallenge.propagation.requireallrns Requires the challenge TXT record to be propagated to all recursive nameservers. false certificatesresolvers.name.acme.dnschallenge.provider Use a DNS-01 based challenge provider rather than HTTPS. certificatesresolvers.name.acme.dnschallenge.resolvers Use following DNS servers to resolve the FQDN authority. certificatesresolvers.name.acme.eab.hmacencoded Base64 encoded HMAC key from External CA. certificatesresolvers.name.acme.eab.kid Key identifier from External CA. certificatesresolvers.name.acme.email Email address used for registration. certificatesresolvers.name.acme.emailaddresses CSR email addresses to use. certificatesresolvers.name.acme.httpchallenge Activate HTTP-01 Challenge. false certificatesresolvers.name.acme.httpchallenge.delay Delay between the creation of the challenge and the validation. 0 certificatesresolvers.name.acme.httpchallenge.entrypoint HTTP challenge EntryPoint certificatesresolvers.name.acme.keytype KeyType used for generating certificate private key. Allow value 'EC256', 'EC384', 'RSA2048', 'RSA4096', 'RSA8192'. RSA4096 certificatesresolvers.name.acme.preferredchain Preferred chain to use. certificatesresolvers.name.acme.profile Certificate profile to use. certificatesresolvers.name.acme.reuseprivatekey Reuse the private key from the previous certificate generation during the renewal. true certificatesresolvers.name.acme.storage Storage to use. acme.json certificatesresolvers.name.acme.tlschallenge Activate TLS-ALPN-01 Challenge. false certificatesresolvers.name.acme.tlschallenge.delay Delay between the creation of the challenge and the validation. 0 certificatesresolvers.name.tailscale Enables Tailscale certificate resolution. true core.defaultrulesyntax Defines the rule parser default syntax (v2 or v3) v3 core.stricttlsoptions Disables the unsafe fallback to the default TLS options for the routers with conflicting TLS options. false entrypoints.name Entry points definition. false entrypoints.name.address Entry point address. entrypoints.name.allowacmebypass Enables handling of ACME TLS and HTTP challenges with custom routers. false entrypoints.name.asdefault Adds this EntryPoint to the list of default EntryPoints to be used on routers that don't have any Entrypoint defined. false entrypoints.name.forwardedheaders.addxforwardedschemeheaders Add the X-Forwarded-Scheme and X-Scheme headers. false entrypoints.name.forwardedheaders.connection List of Connection headers that are allowed to pass through the middleware chain before being removed. entrypoints.name.forwardedheaders.insecure Trust all forwarded headers. false entrypoints.name.forwardedheaders.notappendxforwardedfor Disable appending RemoteAddr to X-Forwarded-For header. Defaults to false (appending is enabled). false entrypoints.name.forwardedheaders.trustedips Trust only forwarded headers from selected IPs. entrypoints.name.http HTTP configuration. entrypoints.name.http.aliasheadersstrategy Defines the strategy to handle the requests carrying a header whose name aliases another header name (keep, delete, and reject). entrypoints.name.http.encodedcharacters.allowencodedbackslash Defines whether requests with encoded back slash characters in the path are allowed. true entrypoints.name.http.encodedcharacters.allowencodedhash Defines whether requests with encoded hash characters in the path are allowed. true entrypoints.name.http.encodedcharacters.allowencodednullcharacter Defines whether requests with encoded null characters in the path are allowed. true entrypoints.name.http.encodedcharacters.allowencodedpercent Defines whether requests with encoded percent characters in the path are allowed. true entrypoints.name.http.encodedcharacters.allowencodedquestionmark Defines whether requests with encoded question mark characters in the path are allowed. true entrypoints.name.http.encodedcharacters.allowencodedsemicolon Defines whether requests with encoded semicolon characters in the path are allowed. true entrypoints.name.http.encodedcharacters.allowencodedslash Defines whether requests with encoded slash characters in the path are allowed. true entrypoints.name.http.encodequerysemicolons Defines whether request query semicolons should be URLEncoded. false entrypoints.name.http.maxheaderbytes Maximum size of request headers in bytes. 1048576 entrypoints.name.http.maxheadervaluecount Maximum number of request header values. 500 entrypoints.name.http.middlewares Default middlewares for the routers linked to the entry point. entrypoints.name.http.redirections.entrypoint.permanent Applies a permanent redirection. true entrypoints.name.http.redirections.entrypoint.priority Priority of the generated router. 9223372036854775806 entrypoints.name.http.redirections.entrypoint.scheme Scheme used for the redirection. https entrypoints.name.http.redirections.entrypoint.to Targeted entry point of the redirection. entrypoints.name.http.sanitizepath Defines whether to enable request path sanitization (removal of /./, /../ and multiple slash sequences). true entrypoints.name.http.tls Default TLS configuration for the routers linked to the entry point. false entrypoints.name.http.tls.certresolver Default certificate resolver for the routers linked to the entry point. entrypoints.name.http.tls.domains Default TLS domains for the routers linked to the entry point. entrypoints.name.http.tls.domains[0].main Default subject name. entrypoints.name.http.tls.domains[0].sans Subject alternative names. entrypoints.name.http.tls.options Default TLS options for the routers linked to the entry point. entrypoints.name.http.underscoreheadersstrategy Defines the strategy to handle requests with headers with underscores (keep, delete, and reject). (Deprecated: please use aliasHeadersStrategy instead) entrypoints.name.http2.maxconcurrentstreams Specifies the number of concurrent streams per connection that each client is allowed to initiate. 250 entrypoints.name.http2.maxdecoderheadertablesize Specifies the maximum size of the HTTP2 HPACK header table on the decoding (receiving from client) side. 4096 entrypoints.name.http2.maxencoderheadertablesize Specifies the maximum size of the HTTP2 HPACK header table on the encoding (sending to client) side. 4096 entrypoints.name.http3 HTTP/3 configuration. false entrypoints.name.http3.advertisedport UDP port to advertise, on which HTTP/3 is available. 0 entrypoints.name.observability.accesslogs Enables access-logs for this entryPoint. true entrypoints.name.observability.metrics Enables metrics for this entryPoint. true entrypoints.name.observability.traceverbosity Defines the tracing verbosity level for this entryPoint. minimal entrypoints.name.observability.tracing Enables tracing for this entryPoint. true entrypoints.name.proxyprotocol Proxy-Protocol configuration. false entrypoints.name.proxyprotocol.insecure Trust all. false entrypoints.name.proxyprotocol.trustedips Trust only selected IPs. entrypoints.name.reuseport Enables EntryPoints from the same or different processes listening on the same TCP/UDP port. false entrypoints.name.transport.keepalivemaxrequests Maximum number of requests before closing a keep-alive connection. 0 entrypoints.name.transport.keepalivemaxtime Maximum duration before closing a keep-alive connection. 0 entrypoints.name.transport.lifecycle.gracetimeout Duration to give active requests a chance to finish before Traefik stops. 10 entrypoints.name.transport.lifecycle.requestacceptgracetimeout Duration to keep accepting requests before Traefik initiates the graceful shutdown procedure. 0 entrypoints.name.transport.respondingtimeouts.idletimeout IdleTimeout is the maximum amount duration an idle (keep-alive) connection will remain idle before closing itself. If zero, no timeout is set. 180 entrypoints.name.transport.respondingtimeouts.readtimeout ReadTimeout is the maximum duration for reading the entire request, including the body. If zero, no timeout is set. 60 entrypoints.name.transport.respondingtimeouts.writetimeout WriteTimeout is the maximum duration before timing out writes of the response. If zero, no timeout is set. 0 entrypoints.name.udp.timeout Timeout defines how long to wait on an idle session before releasing the related resources. 3 experimental.abortonpluginfailure Defines whether all plugins must be loaded successfully for Traefik to start. false experimental.fastproxy Enables the FastProxy implementation. false experimental.fastproxy.debug Enable debug mode for the FastProxy implementation. false experimental.knative Allow the Knative provider usage. false experimental.kubernetesgateway (Deprecated) Allow the Kubernetes gateway api provider usage. false experimental.kubernetesingressnginx Allow the Kubernetes Ingress NGINX provider usage. false experimental.localplugins.name Local plugins configuration. false experimental.localplugins.name.modulename Plugin's module name. experimental.localplugins.name.settings Plugin's settings (works only for wasm plugins). experimental.localplugins.name.settings.envs Environment variables to forward to the wasm guest. experimental.localplugins.name.settings.mounts Directory to mount to the wasm guest. experimental.localplugins.name.settings.useunsafe Allow the plugin to use unsafe and syscall packages. false experimental.otlplogs Enables the OpenTelemetry logs integration. false experimental.plugins.name.hash plugin's hash to validate' experimental.plugins.name.modulename plugin's module name. experimental.plugins.name.settings Plugin's settings (works only for wasm plugins). experimental.plugins.name.settings.envs Environment variables to forward to the wasm guest. experimental.plugins.name.settings.mounts Directory to mount to the wasm guest. experimental.plugins.name.settings.useunsafe Allow the plugin to use unsafe and syscall packages. false experimental.plugins.name.version plugin's version. global.aliasheadersstrategy Defines the default strategy to handle the requests carrying a header whose name aliases another header name (keep, delete, and reject). It applies to every entry point that does not set http.aliasHeadersStrategy explicitly and does not use the deprecated http.underscoreHeadersStrategy. global.checknewversion Periodically check if a new version has been released. true global.notappendxforwardedfor Disable appending RemoteAddr to X-Forwarded-For header. Defaults to false (appending is enabled). false global.sendanonymoususage Periodically send anonymous usage statistics. If the option is not specified, it will be disabled by default. false hostresolver Enable CNAME Flattening. false hostresolver.cnameflattening A flag to enable/disable CNAME flattening false hostresolver.resolvconfig resolv.conf used for DNS resolving /etc/resolv.conf hostresolver.resolvdepth The maximal depth of DNS recursive resolving 5 log Traefik log settings. false log.compress Determines if the rotated log files should be compressed using gzip. false log.filepath Traefik log file path. Stdout is used when omitted or empty. log.format Traefik log format: json common log.level Log level set to traefik logs. ERROR log.maxage Maximum number of days to retain old log files based on the timestamp encoded in their filename. 0 log.maxbackups Maximum number of old log files to retain. 0 log.maxsize Maximum size in megabytes of the log file before it gets rotated. 0 log.nocolor When using the 'common' format, disables the colorized output. false log.otlp Settings for OpenTelemetry. false log.otlp.grpc gRPC configuration for the OpenTelemetry collector. false log.otlp.grpc.endpoint Sets the gRPC endpoint (host:port) of the collector. localhost:4317 log.otlp.grpc.headers.name Headers sent with payload. log.otlp.grpc.insecure Disables client transport security for the exporter. false log.otlp.grpc.tls.ca TLS CA log.otlp.grpc.tls.cert TLS cert log.otlp.grpc.tls.insecureskipverify TLS insecure skip verify false log.otlp.grpc.tls.key TLS key log.otlp.http HTTP configuration for the OpenTelemetry collector. false log.otlp.http.endpoint Sets the HTTP endpoint (scheme://host:port/path) of the collector. https://localhost:4318 log.otlp.http.headers.name Headers sent with payload. log.otlp.http.tls.ca TLS CA log.otlp.http.tls.cert TLS cert log.otlp.http.tls.insecureskipverify TLS insecure skip verify false log.otlp.http.tls.key TLS key log.otlp.resourceattributes.name Defines additional resource attributes (key:value). log.otlp.servicename Defines the service name resource attribute. traefik metrics.addinternals Enables metrics for internal services (ping, dashboard, etc...). false metrics.datadog Datadog metrics exporter type. false metrics.datadog.addentrypointslabels Enable metrics on entry points. true metrics.datadog.address Datadog's address. localhost:8125 metrics.datadog.addrouterslabels Enable metrics on routers. false metrics.datadog.addserviceslabels Enable metrics on services. true metrics.datadog.prefix Prefix to use for metrics collection. traefik metrics.datadog.pushinterval Datadog push interval. 10 metrics.influxdb2 InfluxDB v2 metrics exporter type. false metrics.influxdb2.addentrypointslabels Enable metrics on entry points. true metrics.influxdb2.additionallabels.name Additional labels (influxdb tags) on all metrics metrics.influxdb2.address InfluxDB v2 address. http://localhost:8086 metrics.influxdb2.addrouterslabels Enable metrics on routers. false metrics.influxdb2.addserviceslabels Enable metrics on services. true metrics.influxdb2.bucket InfluxDB v2 bucket ID. metrics.influxdb2.org InfluxDB v2 org ID. metrics.influxdb2.pushinterval InfluxDB v2 push interval. 10 metrics.influxdb2.token InfluxDB v2 access token. It accepts either a token value or a file path to the token. metrics.otlp OpenTelemetry metrics exporter type. false metrics.otlp.addentrypointslabels Enable metrics on entry points. true metrics.otlp.addrouterslabels Enable metrics on routers. false metrics.otlp.addserviceslabels Enable metrics on services. true metrics.otlp.explicitboundaries Boundaries for latency metrics. 0.005000, 0.010000, 0.025000, 0.050000, 0.075000, 0.100000, 0.250000, 0.500000, 0.750000, 1.000000, 2.500000, 5.000000, 7.500000, 10.000000 metrics.otlp.grpc gRPC configuration for the OpenTelemetry collector. false metrics.otlp.grpc.endpoint Sets the gRPC endpoint (host:port) of the collector. localhost:4317 metrics.otlp.grpc.headers.name Headers sent with payload. metrics.otlp.grpc.insecure Disables client transport security for the exporter. false metrics.otlp.grpc.tls.ca TLS CA metrics.otlp.grpc.tls.cert TLS cert metrics.otlp.grpc.tls.insecureskipverify TLS insecure skip verify false metrics.otlp.grpc.tls.key TLS key metrics.otlp.http HTTP configuration for the OpenTelemetry collector. false metrics.otlp.http.endpoint Sets the HTTP endpoint (scheme://host:port/path) of the collector. https://localhost:4318 metrics.otlp.http.headers.name Headers sent with payload. metrics.otlp.http.tls.ca TLS CA metrics.otlp.http.tls.cert TLS cert metrics.otlp.http.tls.insecureskipverify TLS insecure skip verify false metrics.otlp.http.tls.key TLS key metrics.otlp.pushinterval Period between calls to collect a checkpoint. 10 metrics.otlp.resourceattributes.name Defines additional resource attributes (key:value). metrics.otlp.servicename Defines the service name resource attribute. traefik metrics.prometheus Prometheus metrics exporter type. false metrics.prometheus.addentrypointslabels Enable metrics on entry points. true metrics.prometheus.addrouterslabels Enable metrics on routers. false metrics.prometheus.addserviceslabels Enable metrics on services. true metrics.prometheus.buckets Buckets for latency metrics. 0.100000, 0.300000, 1.200000, 5.000000 metrics.prometheus.entrypoint EntryPoint traefik metrics.prometheus.headerlabels.name Defines the extra labels for the requests_total metrics, and for each of them, the request header containing the value for this label. metrics.prometheus.manualrouting Manual routing false metrics.statsd StatsD metrics exporter type. false metrics.statsd.addentrypointslabels Enable metrics on entry points. true metrics.statsd.address StatsD address. localhost:8125 metrics.statsd.addrouterslabels Enable metrics on routers. false metrics.statsd.addserviceslabels Enable metrics on services. true metrics.statsd.prefix Prefix to use for metrics collection. traefik metrics.statsd.pushinterval StatsD push interval. 10 ocsp OCSP configuration. false ocsp.responderoverrides.name Defines a map of OCSP responders to replace for querying OCSP servers. ping Enable ping. false ping.entrypoint EntryPoint traefik ping.manualrouting Manual routing false ping.terminatingstatuscode Terminating status code 503 providers.consul Enables Consul provider. false providers.consul.endpoints KV store endpoints. 127.0.0.1:8500 providers.consul.namespaces Sets the namespaces used to discover the configuration (Consul Enterprise only). providers.consul.rootkey Root key used for KV store. traefik providers.consul.tls.ca TLS CA providers.consul.tls.cert TLS cert providers.consul.tls.insecureskipverify TLS insecure skip verify false providers.consul.tls.key TLS key providers.consul.token Per-request ACL token. providers.consulcatalog Enables Consul Catalog provider. false providers.consulcatalog.cache Use local agent caching for catalog reads. false providers.consulcatalog.connectaware Enable Consul Connect support. false providers.consulcatalog.connectbydefault Consider every service as Connect capable by default. false providers.consulcatalog.constraints Constraints is an expression that Traefik matches against the container's labels to determine whether to create any route for that container. providers.consulcatalog.defaultrule Default rule. Host( {{ normalize .Name }}) providers.consulcatalog.endpoint.address The address of the Consul server providers.consulcatalog.endpoint.datacenter Data center to use. If not provided, the default agent data center is used providers.consulcatalog.endpoint.endpointwaittime WaitTime limits how long a Watch will block. If not provided, the agent default values will be used 0 providers.consulcatalog.endpoint.httpauth.password Basic Auth password providers.consulcatalog.endpoint.httpauth.username Basic Auth username providers.consulcatalog.endpoint.scheme The URI scheme for the Consul server providers.consulcatalog.endpoint.tls.ca TLS CA providers.consulcatalog.endpoint.tls.cert TLS cert providers.consulcatalog.endpoint.tls.insecureskipverify TLS insecure skip verify false providers.consulcatalog.endpoint.tls.key TLS key providers.consulcatalog.endpoint.token Token is used to provide a per-request ACL token which overrides the agent's default token providers.consulcatalog.exposedbydefault Expose containers by default. true providers.consulcatalog.namespaces Sets the namespaces used to discover services (Consul Enterprise only). providers.consulcatalog.prefix Prefix for consul service tags. traefik providers.consulcatalog.refreshinterval Interval for check Consul API. 15 providers.consulcatalog.requireconsistent Forces the read to be fully consistent. false providers.consulcatalog.servicename Name of the Traefik service in Consul Catalog (needs to be registered via the orchestrator or manually). traefik providers.consulcatalog.stale Use stale consistency for catalog reads. false providers.consulcatalog.strictchecks A list of service health statuses to allow taking traffic. passing, warning providers.consulcatalog.watch Watch Consul API events. false providers.docker Enables Docker provider. false providers.docker.allowemptyservices Disregards the Docker containers health checks with respect to the creation or removal of the corresponding services. false providers.docker.constraints Constraints is an expression that Traefik matches against the container's labels to determine whether to create any route for that container. providers.docker.defaultrule Default rule. Host( {{ normalize .Name }}) providers.docker.endpoint Docker server endpoint. Can be a TCP or a Unix socket endpoint. unix:///var/run/docker.sock providers.docker.exposedbydefault Expose containers by default. true providers.docker.httpclienttimeout Client timeout for HTTP connections. 0 providers.docker.network Default Docker network used. providers.docker.password Password for Basic HTTP authentication. providers.docker.tls.ca TLS CA providers.docker.tls.cert TLS cert providers.docker.tls.insecureskipverify TLS insecure skip verify false providers.docker.tls.key TLS key providers.docker.usebindportip Use the ip address from the bound port, rather than from the inner network. false providers.docker.username Username for Basic HTTP authentication. providers.docker.watch Watch Docker events. true providers.ecs Enables AWS ECS provider. false providers.ecs.accesskeyid AWS credentials access key ID to use for making requests. providers.ecs.autodiscoverclusters Auto discover cluster. false providers.ecs.clusters ECS Cluster names. default providers.ecs.constraints Constraints is an expression that Traefik matches against the container's labels to determine whether to create any route for that container. providers.ecs.defaultrule Default rule. Host( {{ normalize .Name }}) providers.ecs.ecsanywhere Enable ECS Anywhere support. false providers.ecs.exposedbydefault Expose services by default. true providers.ecs.healthytasksonly Determines whether to discover only healthy tasks. false providers.ecs.refreshseconds Polling interval (in seconds). 15 providers.ecs.region AWS region to use for requests. providers.ecs.secretaccesskey AWS credentials access key to use for making requests. providers.etcd Enables Etcd provider. false providers.etcd.endpoints KV store endpoints. 127.0.0.1:2379 providers.etcd.password Password for authentication. providers.etcd.rootkey Root key used for KV store. traefik providers.etcd.syncperiod Interval at which the client updates its list of endpoints from the etcd cluster membership. A value of 0 disables this auto-sync. 0 providers.etcd.tls.ca TLS CA providers.etcd.tls.cert TLS cert providers.etcd.tls.insecureskipverify TLS insecure skip verify false providers.etcd.tls.key TLS key providers.etcd.username Username for authentication. providers.file.debugloggeneratedtemplate Enable debug logging of generated configuration template. false providers.file.directory Load dynamic configuration from one or more .yml or .toml files in a directory. providers.file.filename Load dynamic configuration from a file. providers.file.watch Watch provider. true providers.http Enables HTTP provider. false providers.http.endpoint Load configuration from this endpoint. providers.http.headers.name Define custom headers to be sent to the endpoint. providers.http.maxresponsebodysize Defines the maximum size of the response body in bytes. -1 providers.http.pollinterval Polling interval for endpoint. 5 providers.http.polltimeout Polling timeout for endpoint. 5 providers.http.tls.ca TLS CA providers.http.tls.cert TLS cert providers.http.tls.insecureskipverify TLS insecure skip verify false providers.http.tls.key TLS key providers.knative Enables Knative provider. false providers.knative.certauthfilepath Kubernetes certificate authority file path (not needed for in-cluster client). providers.knative.endpoint Kubernetes server endpoint (required for external cluster client). providers.knative.labelselector Kubernetes label selector to use. providers.knative.namespaces Kubernetes namespaces. providers.knative.privateentrypoints Entrypoint names used to expose the Ingress privately. If empty local Ingresses are skipped. providers.knative.privateservice Kubernetes service used to expose the networking controller privately. providers.knative.privateservice.name Name of the Kubernetes service. providers.knative.privateservice.namespace Namespace of the Kubernetes service. providers.knative.publicentrypoints Entrypoint names used to expose the Ingress publicly. If empty an Ingress is exposed on all entrypoints. providers.knative.publicservice Kubernetes service used to expose the networking controller publicly. providers.knative.publicservice.name Name of the Kubernetes service. providers.knative.publicservice.namespace Namespace of the Kubernetes service. providers.knative.throttleduration Ingress refresh throttle duration 0 providers.knative.token Kubernetes bearer token (not needed for in-cluster client). providers.kubernetescrd Enables Kubernetes CRD provider. false providers.kubernetescrd.allowcrossnamespace Allow cross namespace resource reference. false providers.kubernetescrd.allowemptyservices Allow the creation of services without endpoints. false providers.kubernetescrd.allowexternalnameservices Allow ExternalName services. false providers.kubernetescrd.certauthfilepath Kubernetes certificate authority file path (not needed for in-cluster client). providers.kubernetescrd.crossprovidernamespaces List of namespaces from which IngressRoute, IngressRouteTCP, IngressRouteUDP, and TraefikService are allowed to declare cross-provider references. providers.kubernetescrd.defaulttlsresourcesnamespace Namespace allowed to define the default TLSOption and TLSStore resources. When empty, they can be defined in any namespace. providers.kubernetescrd.disableclusterscoperesources Disables the lookup of cluster scope resources (incompatible with IngressClasses and NodePortLB enabled services). false providers.kubernetescrd.endpoint Kubernetes server endpoint (required for external cluster client). providers.kubernetescrd.ingressclass Value of ingressClassName field or kubernetes.io/ingress.class annotation to watch for. providers.kubernetescrd.labelselector Kubernetes label selector to use. providers.kubernetescrd.namespaces Kubernetes namespaces. providers.kubernetescrd.nativelbbydefault Defines whether to use Native Kubernetes load-balancing mode by default. false providers.kubernetescrd.safenaming Enable collision-safe naming for the Kubernetes CRD provider. false providers.kubernetescrd.throttleduration Ingress refresh throttle duration 0 providers.kubernetescrd.token Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token. providers.kubernetesgateway Enables Kubernetes Gateway API provider. false providers.kubernetesgateway.burst Defines the maximum burst of requests to the Kubernetes API server. 100 providers.kubernetesgateway.certauthfilepath Kubernetes certificate authority file path (not needed for in-cluster client). providers.kubernetesgateway.crossprovidernamespaces List of namespaces from which Gateway API routes are allowed to declare TraefikService backendRef references. providers.kubernetesgateway.endpoint Kubernetes server endpoint (required for external cluster client). providers.kubernetesgateway.experimentalchannel Toggles Experimental Channel resources support. Requires the Experimental Channel CRDs. false providers.kubernetesgateway.gatewayclass Name of the GatewayClass to watch for. If empty, all GatewayClasses are processed. providers.kubernetesgateway.gateways Scopes the provider to specific Gateways. providers.kubernetesgateway.gateways[0].name Defines the resource name. providers.kubernetesgateway.gateways[0].namespace Defines the resource namespace. providers.kubernetesgateway.labelselector Kubernetes label selector to select specific GatewayClasses (Deprecated, please use the GatewayClass option instead). providers.kubernetesgateway.namespaces Kubernetes namespaces. providers.kubernetesgateway.nativelbbydefault Defines whether to use Native Kubernetes load-balancing by default. false providers.kubernetesgateway.qps Defines the maximum QPS to the Kubernetes API server. Setting this to a negative value will disable client-side ratelimiting. 50 providers.kubernetesgateway.retrymaxrequestbodybytes Defines the maximum request body size (in bytes) buffered for HTTPRoute retries. If negative, the limit is disabled. 2097152 providers.kubernetesgateway.statusaddress.hostname Hostname used for Kubernetes Gateway status address. providers.kubernetesgateway.statusaddress.ip IP used to set Kubernetes Gateway status address. providers.kubernetesgateway.statusaddress.service Published Kubernetes Service to copy status addresses from. providers.kubernetesgateway.statusaddress.service.name Name of the Kubernetes service. providers.kubernetesgateway.statusaddress.service.namespace Namespace of the Kubernetes service. providers.kubernetesgateway.throttleduration Kubernetes refresh throttle duration 0 providers.kubernetesgateway.token Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token. providers.kubernetesingress Enables Kubernetes Ingress provider. false providers.kubernetesingress.allowemptyservices Allow creation of services without endpoints. false providers.kubernetesingress.allowexternalnameservices Allow ExternalName services. false providers.kubernetesingress.certauthfilepath Kubernetes certificate authority file path (not needed for in-cluster client). providers.kubernetesingress.crossprovidernamespaces List of namespaces from which Ingresses or Services are allowed to declare Middlewares, TLSOptions, or ServersTransport references. providers.kubernetesingress.disableclusterscoperesources Disables the lookup of cluster scope resources (incompatible with IngressClasses and NodePortLB enabled services). false providers.kubernetesingress.disableingressclasslookup Disables the lookup of IngressClasses (Deprecated, please use DisableClusterScopeResources). false providers.kubernetesingress.endpoint Kubernetes server endpoint (required for external cluster client). providers.kubernetesingress.ingressclass Value of kubernetes.io/ingress.class annotation or IngressClass name to watch for. providers.kubernetesingress.ingressendpoint.hostname Hostname used for Kubernetes Ingress endpoints. providers.kubernetesingress.ingressendpoint.ip IP used for Kubernetes Ingress endpoints. providers.kubernetesingress.ingressendpoint.publishedservice Published Kubernetes Service to copy status from. providers.kubernetesingress.labelselector Kubernetes Ingress label selector to use. providers.kubernetesingress.namespaces Kubernetes namespaces. providers.kubernetesingress.nativelbbydefault Defines whether to use Native Kubernetes load-balancing mode by default. false providers.kubernetesingress.reportnodeinternalips Report node internal IPs in Ingress status. false providers.kubernetesingress.strictprefixmatching Make prefix matching strictly comply with the Kubernetes Ingress specification (path-element-wise matching instead of character-by-character string matching). false providers.kubernetesingress.throttleduration Ingress refresh throttle duration 0 providers.kubernetesingress.token Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token. providers.kubernetesingressnginx Enables Kubernetes Ingress NGINX provider. false providers.kubernetesingressnginx.allowcrossnamespaceresources Allow Ingress to reference resources (e.g. ConfigMaps, Secrets) in different namespaces. false providers.kubernetesingressnginx.allowsnippetannotations Enables to parse and add -snippet annotations/directives. false providers.kubernetesingressnginx.certauthfilepath Kubernetes certificate authority file path (not needed for in-cluster client). providers.kubernetesingressnginx.clientbodybuffersize Default buffer size for reading client request body. 16384 providers.kubernetesingressnginx.controllerclass Ingress Class Controller value this controller satisfies. k8s.io/ingress-nginx providers.kubernetesingressnginx.customhttperrors Defines which status should result in calling the default backend to return an error page. providers.kubernetesingressnginx.defaultbackendservice Service used to serve HTTP requests not matching any known server name (catch-all). Takes the form 'namespace/name'. providers.kubernetesingressnginx.disablenontlsrouters Disables the creation of non-TLS routers for Ingress resources. Cannot be used together with httpEntryPoint. false providers.kubernetesingressnginx.disablesvcexternalname Disable support for Services of type ExternalName. false providers.kubernetesingressnginx.endpoint Kubernetes server endpoint (required for external cluster client). providers.kubernetesingressnginx.globalallowedresponseheaders List of allowed response headers inside the custom headers annotations. providers.kubernetesingressnginx.globalauthurl URL to the service that provides authentication for all the locations. Per ingress auth-url annotation has precedence over this option. providers.kubernetesingressnginx.httpentrypoint Defines the EntryPoint to use for HTTP requests. providers.kubernetesingressnginx.httpsentrypoint Defines the EntryPoint to use for HTTPS requests. providers.kubernetesingressnginx.ingressclass Name of the ingress class this controller satisfies. nginx providers.kubernetesingressnginx.ingressclassbyname Define if Ingress Controller should watch for Ingress Class by Name together with Controller Class. false providers.kubernetesingressnginx.ipallowliststrategy.depth 0 providers.kubernetesingressnginx.ipallowliststrategy.excludedips providers.kubernetesingressnginx.ipallowliststrategy.ipv6subnet 0 providers.kubernetesingressnginx.proxybodysize Default maximum size of a client request body in bytes. 1048576 providers.kubernetesingressnginx.proxybuffering Defines whether to enable response buffering. false providers.kubernetesingressnginx.proxybuffersize Default buffer size for reading the response body. 8192 providers.kubernetesingressnginx.proxybuffersnumber Default number of buffers for reading a response. 4 providers.kubernetesingressnginx.proxyconnecttimeout Amount of time to wait until a connection to a server can be established. Timeout value is unitless and in seconds. 60 providers.kubernetesingressnginx.proxynextupstream Defines in which cases a request should be retried. error timeout providers.kubernetesingressnginx.proxynextupstreamtimeout Limits the total elapsed time to retry the request if the backend server does not reply. Timeout value is unitless and in seconds. 0 providers.kubernetesingressnginx.proxynextupstreamtries Limits the number of possible tries if the backend server does not reply. 3 providers.kubernetesingressnginx.proxyreadtimeout Amount of time between two successive read operations. Timeout value is unitless and in seconds. 60 providers.kubernetesingressnginx.proxyrequestbuffering Defines whether to enable request buffering. false providers.kubernetesingressnginx.proxysendtimeout Amount of time between two successive write operations. Timeout value is unitless and in seconds. 60 providers.kubernetesingressnginx.publishservice Service fronting the Ingress controller. Takes the form 'namespace/name'. providers.kubernetesingressnginx.publishstatusaddress Customized address (or addresses, separated by comma) to set as the load-balancer status of Ingress objects this controller satisfies. providers.kubernetesingressnginx.strictvalidatepathtype Defines whether to reject the entire ingress when any path contains regex characters and pathType is Prefix or Exact. true providers.kubernetesingressnginx.throttleduration Ingress refresh throttle duration. 0 providers.kubernetesingressnginx.token Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token. providers.kubernetesingressnginx.upstreamkeepalivetimeout Defines the idle timeout for keep-alive connections to upstream servers. Timeout value is unitless and in seconds. 60 providers.kubernetesingressnginx.watchingresswithoutclass Define if Ingress Controller should also watch for Ingresses without an IngressClass or the annotation specified. false providers.kubernetesingressnginx.watchnamespace Namespace the controller watches for updates to Kubernetes objects. All namespaces are watched if this parameter is left empty. providers.kubernetesingressnginx.watchnamespaceselector Selector selects namespaces the controller watches for updates to Kubernetes objects. providers.nomad Enables Nomad provider. false providers.nomad.allowemptyservices Allow the creation of services without endpoints. false providers.nomad.constraints Constraints is an expression that Traefik matches against the Nomad service's tags to determine whether to create route(s) for that service. providers.nomad.defaultrule Default rule. Host( {{ normalize .Name }}) providers.nomad.endpoint.address The address of the Nomad server, including scheme and port. http://127.0.0.1:4646 providers.nomad.endpoint.endpointwaittime WaitTime limits how long a Watch will block. If not provided, the agent default values will be used 0 providers.nomad.endpoint.region Nomad region to use. If not provided, the local agent region is used. providers.nomad.endpoint.tls.ca TLS CA providers.nomad.endpoint.tls.cert TLS cert providers.nomad.endpoint.tls.insecureskipverify TLS insecure skip verify false providers.nomad.endpoint.tls.key TLS key providers.nomad.endpoint.token Token is used to provide a per-request ACL token. providers.nomad.exposedbydefault Expose Nomad services by default. true providers.nomad.namespaces Sets the Nomad namespaces used to discover services. providers.nomad.prefix Prefix for nomad service tags. traefik providers.nomad.refreshinterval Interval for polling Nomad API. 15 providers.nomad.stale Use stale consistency for catalog reads. false providers.nomad.throttleduration Watch throttle duration. 0 providers.nomad.watch Watch Nomad Service events. false providers.plugin.name Plugins configuration. providers.precedence Defines the routing precedence between providers. kubernetesgateway, kubernetescrd, kubernetes, kubernetesingressnginx, swarm, docker, file, redis, knative, consul, consulcatalog, nomad, etcd, ecs, http, zookeeper, rest providers.providersthrottleduration Backends throttle duration: minimum duration between 2 events from providers before applying a new configuration. It avoids unnecessary reloads if multiples events are sent in a short amount of time. 2 providers.redis Enables Redis provider. false providers.redis.db Database to be selected after connecting to the server. 0 providers.redis.endpoints KV store endpoints. 127.0.0.1:6379 providers.redis.password Password for authentication. providers.redis.rootkey Root key used for KV store. traefik providers.redis.sentinel.latencystrategy Defines whether to route commands to the closest master or replica nodes (mutually exclusive with RandomStrategy and ReplicaStrategy). false providers.redis.sentinel.mastername Name of the master. providers.redis.sentinel.password Password for Sentinel authentication. providers.redis.sentinel.randomstrategy Defines whether to route commands randomly to master or replica nodes (mutually exclusive with LatencyStrategy and ReplicaStrategy). false providers.redis.sentinel.replicastrategy Defines whether to route all commands to replica nodes (mutually exclusive with LatencyStrategy and RandomStrategy). false providers.redis.sentinel.usedisconnectedreplicas Use replicas disconnected with master when cannot get connected replicas. false providers.redis.sentinel.username Username for Sentinel authentication. providers.redis.tls.ca TLS CA providers.redis.tls.cert TLS cert providers.redis.tls.insecureskipverify TLS insecure skip verify false providers.redis.tls.key TLS key providers.redis.username Username for authentication. providers.rest Enables Rest provider. false providers.rest.insecure Activate REST Provider directly on the entryPoint named traefik. false providers.swarm Enables Docker Swarm provider. false providers.swarm.allowemptyservices Disregards the Docker containers health checks with respect to the creation or removal of the corresponding services. false providers.swarm.constraints Constraints is an expression that Traefik matches against the container's labels to determine whether to create any route for that container. providers.swarm.defaultrule Default rule. Host( {{ normalize .Name }}) providers.swarm.endpoint Docker server endpoint. Can be a TCP or a Unix socket endpoint. unix:///var/run/docker.sock providers.swarm.exposedbydefault Expose containers by default. true providers.swarm.httpclienttimeout Client timeout for HTTP connections. 0 providers.swarm.network Default Docker network used. providers.swarm.password Password for Basic HTTP authentication. providers.swarm.refreshseconds Polling interval for swarm mode. 15 providers.swarm.tls.ca TLS CA providers.swarm.tls.cert TLS cert providers.swarm.tls.insecureskipverify TLS insecure skip verify false providers.swarm.tls.key TLS key providers.swarm.usebindportip Use the ip address from the bound port, rather than from the inner network. false providers.swarm.username Username for Basic HTTP authentication. providers.swarm.watch Watch Docker events. true providers.zookeeper Enables ZooKeeper provider. false providers.zookeeper.endpoints KV store endpoints. 127.0.0.1:2181 providers.zookeeper.password Password for authentication. providers.zookeeper.rootkey Root key used for KV store. traefik providers.zookeeper.username Username for authentication. serverstransport.forwardingtimeouts.dialtimeout The amount of time to wait until a connection to a backend server can be established. If zero, no timeout exists. 30 serverstransport.forwardingtimeouts.idleconntimeout The maximum period for which an idle HTTP keep-alive connection will remain open before closing itself 90 serverstransport.forwardingtimeouts.readtimeout Defines a timeout for reading a response from the proxied server. The timeout between two successive read operations. If zero, no timeout exists. 0 serverstransport.forwardingtimeouts.responseheadertimeout The amount of time to wait for a server's response headers after fully writing the request (including its body, if any). If zero, no timeout exists. 0 serverstransport.forwardingtimeouts.writetimeout Defines a timeout for transmitting a request to the proxied server. The timeout between two successive write operations. If zero, no timeout exists. 0 serverstransport.insecureskipverify Disable SSL certificate verification. false serverstransport.maxidleconnsperhost If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used. If negative, disables connection reuse. 200 serverstransport.rootcas Add cert file for self-signed certificate. serverstransport.spiffe Defines the SPIFFE configuration. false serverstransport.spiffe.ids Defines the allowed SPIFFE IDs (takes precedence over the SPIFFE TrustDomain). serverstransport.spiffe.trustdomain Defines the allowed SPIFFE trust domain. spiffe.workloadapiaddr Defines the workload API address. tcpserverstransport.dialkeepalive Defines the interval between keep-alive probes for an active network connection. If zero, keep-alive probes are sent with a default value (currently 15 seconds), if supported by the protocol and operating system. Network protocols or operating systems that do not support keep-alives ignore this field. If negative, keep-alive probes are disabled 15 tcpserverstransport.dialtimeout Defines the amount of time to wait until a connection to a backend server can be established. If zero, no timeout exists. 30 tcpserverstransport.terminationdelay Defines the delay to wait before fully terminating the connection, after one connected peer has closed its writing capability. 0 tcpserverstransport.tls Defines the TLS configuration. false tcpserverstransport.tls.insecureskipverify Disables SSL certificate verification. false tcpserverstransport.tls.rootcas Defines a list of CA secret used to validate self-signed certificate tcpserverstransport.tls.spiffe Defines the SPIFFE TLS configuration. false tcpserverstransport.tls.spiffe.ids Defines the allowed SPIFFE IDs (takes precedence over the SPIFFE TrustDomain). tcpserverstransport.tls.spiffe.trustdomain Defines the allowed SPIFFE trust domain. tracing Tracing configuration. false tracing.addinternals Enables tracing for internal services (ping, dashboard, etc...). false tracing.capturedrequestheaders Request headers to add as attributes for server and client spans. tracing.capturedresponseheaders Response headers to add as attributes for server and client spans. tracing.globalattributes.name (Deprecated) Defines additional resource attributes (key:value). tracing.otlp Settings for OpenTelemetry. false tracing.otlp.grpc gRPC configuration for the OpenTelemetry collector. false tracing.otlp.grpc.endpoint Sets the gRPC endpoint (host:port) of the collector. localhost:4317 tracing.otlp.grpc.headers.name Headers sent with payload. tracing.otlp.grpc.insecure Disables client transport security for the exporter. false tracing.otlp.grpc.tls.ca TLS CA tracing.otlp.grpc.tls.cert TLS cert tracing.otlp.grpc.tls.insecureskipverify TLS insecure skip verify false tracing.otlp.grpc.tls.key TLS key tracing.otlp.http HTTP configuration for the OpenTelemetry collector. false tracing.otlp.http.endpoint Sets the HTTP endpoint (scheme://host:port/path) of the collector. https://localhost:4318 tracing.otlp.http.headers.name Headers sent with payload. tracing.otlp.http.tls.ca TLS CA tracing.otlp.http.tls.cert TLS cert tracing.otlp.http.tls.insecureskipverify TLS insecure skip verify false tracing.otlp.http.tls.key TLS key tracing.resourceattributes.name Defines additional resource attributes (key:value). tracing.safequeryparams Query params to not redact. tracing.samplerate Sets the rate between 0.0 and 1.0 of requests to trace. 1.000000 tracing.servicename Defines the service name resource attribute. traefik Traefik EntryPoints Documentation Listening for Incoming Connections/Requests {: .subtitle } Configuration Example entryPoints: web: address: :80 http: redirections: entryPoint: to: websecure scheme: https permanent: true observability: accessLogs: false metrics: false tracing: false websecure: address: :443 http: tls: {} middlewares: - default-auth@kubernetescrd - default-strip@kubernetescrd [entryPoints] [entryPoints.web] address = ":80" [entryPoints.web.http] [entryPoints.web.http.redirections.entryPoint] to = "websecure" scheme = "https" permanent = true [entryPoints.web.observability] accessLogs = false metrics = false tracing = false [entryPoints.websecure] address = ":443" [entryPoints.websecure.http] middlewares = ["default-auth@kubernetescrd", "default-strip@kubernetescrd"] [entryPoints.websecure.http.tls] ## Values file ports: web: port: :80 websecure: port: :443 tls: enabled: true middlewares: - default-auth@kubernetescrd - default-strip@kubernetescrd additionalArguments: - --entryPoints.web.http.redirections.entryPoint.to=websecure - --entryPoints.web.http.redirections.entryPoint.scheme=https - --entryPoints.web.http.redirections.entryPoint.permanent=true - --entryPoints.web.observability.accessLogs=false - --entryPoints.web.observability.metrics=false - --entryPoints.web.observability.tracing=false !!! tip In the Helm Chart, the entryPoints `web` (port 80), `websecure` (port 443), `traefik` (port 8080) and `metrics` (port 9100) are created by default. The entryPoints `web`, `websecure` are exposed by default using a Service. The default behaviors can be overridden in the Helm Chart. Configuration Options Field Description Default Required address Define the port, and optionally the hostname, on which to listen for incoming connections and packets. It also defines the protocol to use (TCP or UDP). If no protocol is specified, the default is TCP. The format is:`[host]:port[/tcp|/udp] - Yes asDefault Mark the entryPoint to be in the list of default entryPoints. entryPointsin this list are used (by default) on HTTP and TCP routers that do not define their own entryPoints option. More information here. false No allowACMEByPass Enables handling of ACME TLS and HTTP challenges with custom routers instead of the internal ACME router. false No forwardedHeaders. connection List of Connection headers that are allowed to pass through the middleware chain before being removed. - No forwardedHeaders. addXForwardedSchemeHeaders Add the compatibility headers X-Forwarded-Scheme and X-Scheme. false No forwardedHeaders. insecure Set the insecure mode to always trust the forwarded headers information ( X-Forwarded-*). We recommend to use this option only for tests purposes, not in production. false No forwardedHeaders. trustedIPs Set the IPs or CIDR from where Traefik trusts the forwarded headers information ( X-Forwarded-*). - No forwardedHeaders. notAppendXForwardedFor When set to true, Traefik will not append the client's RemoteAddr to the X-Forwarded-For header. The existing header is preserved as-is. If no X-Forwarded-For header exists, none will be added. false No http.redirections. entryPoint.to The target element to enable (permanent) redirecting of all incoming requests on an entry point to another one. The target element can be an entry point name (ex: websecure), or a port ( :443). - Yes http.redirections. entryPoint.scheme The target scheme to use for (permanent) redirection of all incoming requests. https No http.redirections. entryPoint.permanent Enable permanent redirecting of all incoming requests on an entry point to another one changing the scheme. The target element, it can be an entry point name (ex: websecure), or a port ( :443). true No http.redirections. entryPoint.priority Default priority applied to the routers attached to the entryPoint. MaxInt-1 ( 2147483646 on 32-bit, 9223372036854775806 on 64-bit) No http.encodedCharacters Defines which encoded characters are allowed in the request path. More information here. false No http.encodedCharacters. allowEncodedSlash Defines whether requests with encoded slash characters in the path are allowed. true No http.encodedCharacters. allowEncodedBackSlash Defines whether requests with encoded back slash characters in the path are allowed. true No http.encodedCharacters. allowEncodedNullCharacter Defines whether requests with encoded null characters in the path are allowed. true No http.encodedCharacters. allowEncodedSemicolon Defines whether requests with encoded semicolon characters in the path are allowed. true No http.encodedCharacters. allowEncodedPercent Defines whether requests with encoded percent characters in the path are allowed. true No http.encodedCharacters. allowEncodedQuestionMark Defines whether requests with encoded question mark characters in the path are allowed. true No http.encodedCharacters. allowEncodedHash Defines whether requests with encoded hash characters in the path are allowed. true No http.encodeQuerySemicolons Enable query semicolons encoding. Use this option to avoid non-encoded semicolons to be interpreted as query parameter separators by Traefik. When using this option, the non-encoded semicolons characters in query will be transmitted encoded to the backend. More information here. false No http.aliasHeadersStrategy Defines the strategy to handle the requests carrying a header whose name aliases another header name (keep, delete, and reject). More information here. keep No http.sanitizePath Defines whether to enable the request path sanitization. More information here. true No http.maxHeaderBytes Set the maximum size of request headers in bytes. 1048576 No http.maxHeaderValueCount Set the maximum number of request header values Traefik reads for each request. A request exceeding this limit is rejected with a 431 Request Header Fields Too Large status. Comma-separated values in a single header line count as one value, while values sent on multiple header lines count once per line. This option applies to HTTP/1 and HTTP/2 only; it has no effect on HTTP/3 requests. 500 No http.middlewares Set the list of middlewares that are prepended by default to the list of middlewares of each router associated to the named entry point. More information here. - No http.tls Enable TLS on every router attached to the entryPoint. If no certificate are set, a default self-signed certificate is generated by Traefik. We recommend to not use self signed certificates in production. - No http.tls.options Apply TLS options on every router attached to the entryPoint. These options apply only while the router does not define its own tls section. Defining a router tls section (even empty, or with any field such as certResolver) replaces the entrypoint TLS configuration for that router (no merge). More information in the dedicated section and HTTP TLS overview. - No http.tls.certResolver Apply a certificate resolver on every router attached to the entryPoint. Like http.tls.options, this applies only while the router does not define its own tls section. Defining a router tls section (even empty, or with any field such as certResolver) replaces the entrypoint TLS configuration for that router (no merge). More information in the dedicated section and HTTP TLS overview. - No http2. maxConcurrentStreams Set the number of concurrent streams per connection that each client is allowed to initiate. The value must be greater than zero. 250 No http2. maxDecoderHeaderTableSize Set the maximum size of the decoder header compression table. This controls the maximum size of the header cache that the server is willing to maintain so the client does not need to repeatedly send the same header across requests in the same http2 connection. This value is only a maximum, the other end of the connection can use a lower size. 4096 No http2. maxEncoderHeaderTableSize Set the maximum size of the encoder header compression table. This controls the maximum size of the header cache that the server is willing to maintain when sending headers to the client, allowing the server to reduce the amount of duplicate headers it is sending in responses. This value is only a maximum, the other end of the connection can use a lower size. 4096 No http3 Enable HTTP/3 protocol on the entryPoint. HTTP/3 requires a TCP entryPoint. as HTTP/3 always starts as a TCP connection that then gets upgraded to UDP. In most scenarios, this entryPoint is the same as the one used for TLS traffic. More information here. - No http3.advertisedPort Set the UDP port to advertise as the HTTP/3 authority. It defaults to the entryPoint's address port. It can be used to override the authority in the alt-svc header, for example if the public facing port is different from where Traefik is listening. - No observability. accessLogs Defines whether a router attached to this EntryPoint produces access-logs by default. Nonetheless, a router defining its own observability configuration will opt-out from this default. true No observability. metrics Defines whether a router attached to this EntryPoint produces metrics by default. Nonetheless, a router defining its own observability configuration will opt-out from this default. true No observability. tracing Defines whether a router attached to this EntryPoint produces traces by default. Nonetheless, a router defining its own observability configuration will opt-out from this default. true No observability. traceVerbosity Defines the tracing verbosity level for routers attached to this EntryPoint. Possible values: minimal (default), detailed. Routers can override this value in their own observability configuration. More information here. minimal No proxyProtocol. trustedIPs Enable PROXY protocol with Trusted IPs. Traefik supports PROXY protocol version 1 and 2. If PROXY protocol header parsing is enabled for the entry point, this entry point can accept connections with or without PROXY protocol headers. If the PROXY protocol header is passed, then the version is determined automatically. More information here. - No proxyProtocol. insecure Enable PROXY protocol trusting every incoming connection. Every remote client address will be replaced ( trustedIPs) won't have any effect). Traefik supports PROXY protocol version 1 and 2. If PROXY protocol header parsing is enabled for the entry point, this entry point can accept connections with or without PROXY protocol headers. If the PROXY protocol header is passed, then the version is determined automatically. We recommend to use this option only for tests purposes, not in production. More information here. - No reusePort Enable entryPoints from the same or different processes listening on the same TCP/UDP port by utilizing the SO_REUSEPORT socket option. It also allows the kernel to act like a load balancer to distribute incoming connections between entry points. More information here. false No transport. respondingTimeouts. readTimeout Set the timeouts for incoming requests to the Traefik instance. This is the maximum duration for reading the entire request, including the body. Setting them has no effect for UDP entryPoints. If zero, no timeout exists. Can be provided in a format supported by time.ParseDuration or as raw values (digits). If no units are provided, the value is parsed assuming seconds. 60s (seconds) No transport. respondingTimeouts. writeTimeout Maximum duration before timing out writes of the response. It covers the time from the end of the request header read to the end of the response write. If zero, no timeout exists. Can be provided in a format supported by time.ParseDuration or as raw values (digits). If no units are provided, the value is parsed assuming seconds. 0s (seconds) No transport. respondingTimeouts. idleTimeout Maximum duration an idle (keep-alive) connection will remain idle before closing itself. If zero, no timeout exists Can be provided in a format supported by time.ParseDuration or as raw values (digits). If no units are provided, the value is parsed assuming seconds 180s (seconds) No transport. lifeCycle. graceTimeOut Set the duration to give active requests a chance to finish before Traefik stops. Can be provided in a format supported by time.ParseDuration or as raw values (digits). If no units are provided, the value is parsed assuming seconds In this time frame no new requests are accepted. 10s (seconds) No transport. lifeCycle. requestAcceptGraceTimeout Set the duration to keep accepting requests prior to initiating the graceful termination period (as defined by the transportlifeCycle.graceTimeOut option). This option is meant to give downstream load-balancers sufficient time to take Traefik out of rotation. Can be provided in a format supported by time.ParseDuration or as raw values (digits). If no units are provided, the value is parsed assuming seconds 0s (seconds) No transport. keepAliveMaxRequests Set the maximum number of requests Traefik can handle before sending a Connection: Close header to the client (for HTTP2, Traefik sends a GOAWAY). Zero means no limit. 0 No transport. keepAliveMaxTime Set the maximum duration Traefik can handle requests before sending a Connection: Close header to the client (for HTTP2, Traefik sends a GOAWAY). Zero means no limit. 0s (seconds) No udp.timeout Define how long to wait on an idle session before releasing the related resources. The Timeout value must be greater than zero. 3s (seconds) No asDefault If there is no entryPoint with the asDefault option set to true, then the list of default entryPoints includes all HTTP/TCP entryPoints. If at least one entryPoint has the asDefault option set to true, then the list of default entryPoints includes only entryPoints that have the asDefault option set to true. Some built-in entryPoints are always excluded from the list, namely: traefik. The asDefault option has no effect on UDP entryPoints. When a UDP router does not define the entryPoints option, it is attached to all available UDP entryPoints. allowACMEByPass By default, Traefik creates an internal router with the highest possible priority ( MaxInt) to handle ACME HTTP and TLS challenges. This ensures that certificate challenges always succeed, but it also prevents any user-defined router from intercepting challenge requests on the same entrypoint. When allowACMEByPass is set to true on an entrypoint: The internal ACME HTTP challenge router is created without an explicit high priority, allowing user-defined routers to handle challenge requests instead. The TLS-ALPN challenge passthrough is enabled on the entrypoint, allowing user-defined TLS routers to handle TLS challenges. This is useful when you need custom handling of ACME challenges, for example when using a dedicated service to solve HTTP-01 or TLS-ALPN-01 challenges. !!! note When no TLS challenge resolver is configured, `allowACMEByPass` is implicitly enabled for TLS passthrough on all entrypoints. !!! note When `allowACMEByPass` is enabled and the entrypoint has an HTTP redirect configured (via `http.redirections.entryPoint`), the redirect router automatically excludes the ACME challenge path (`/.well-known/acme-challenge/`). This allows user-defined ACME challenge routers to handle challenge requests without being overridden by the redirect. entryPoints: web: address: ":80" allowACMEByPass: true [entryPoints.web] address = ":80" allowACMEByPass = true --entryPoints.web.address=:80 --entryPoints.web.allowACMEByPass=true http.middlewares You can attach a list of middlewares to each entryPoint. The middlewares will take effect only if the rule matches, and before forwarding the request to the service. Middlewares are applied in the same order as their declaration. Middlewares are applied by default to every router exposed through the EntryPoint (the Middlewares declared on the IngressRoute or the Ingress are applied after the ones declared on the Entrypoint) Middlewares must be referenced by their fully qualified name, including the provider namespace suffix ( @). The exact value depends on the provider that declares the middleware: Provider Format Example File @file strip@file Docker @docker strip@docker Kubernetes CRD -@kubernetescrd default-auth@kubernetescrd When safeNaming is enabled, the Kubernetes CRD value becomes _@kubernetescrd, using the same _ separator as the other names generated by the provider. entryPoints: web: address: :80 http: middlewares: - default-auth@kubernetescrd - strip@file ports: web: port: :80 http: middlewares: - default-auth@kubernetescrd - strip@file encodeQuerySemicolons Behavior examples: EncodeQuerySemicolons Request Query Resulting Request Query false foo=bar;baz=bar foo=bar&baz=bar true foo=bar;baz=bar foo=bar%3Bbaz=bar false foo=bar&baz=bar;foo foo=bar&baz=bar&foo true foo=bar&baz=bar;foo foo=bar&baz=bar%3Bfoo aliasHeadersStrategy Optional, Default=keep The aliasHeadersStrategy option defines how the request headers whose name aliases another header name are handled before routing: keep: request headers with an aliasing name are forwarded as is (default). delete: any request header whose name contains a character which is neither a letter, a digit, nor a dash is silently removed from the request. reject: any request carrying a header whose name contains a character which is neither a letter, a digit, nor a dash is rejected with a 400 Bad Request response. Go canonicalizes header names on dashes only, so it handles X-Auth-User, X_Auth_User and X.Auth.User as three distinct headers, while the backends deriving their variable names from the header names (CGI, WSGI, PHP, NGINX, ...) read them all as the same HTTP_X_AUTH_USER variable. Underscores and dots are not the only characters concerned: every character HTTP allows in a header name except the letters, the digits and the dash builds such an alias, that is !, #, $, %, &, ', *, +, ., ^, _, `, | and ~. See the Headers with Aliasing Names security documentation for more details. The middlewares managing request headers (e.g. the ForwardAuth authResponseHeaders option) only manage the canonical form of the headers they set, and rely on this option to not be spoofed with an aliasing name. Traefik logs a warning at startup for every entry point left without this option configured. A default for every entry point can be set once with the global.aliasHeadersStrategy option. An explicit per-entry-point value always takes precedence, and when neither is set the behavior is unchanged ( keep). Entry points that still use the deprecated underscoreHeadersStrategy option are left alone, so their behavior is unchanged as well. !!! warning "Security" Backends normalizing the header names can be spoofed with an aliasing name of a header they trust. Setting the `aliasHeadersStrategy` option to `delete` or `reject` is recommended when such backends are exposed. The `delete` and `reject` strategies apply to every request header: a legitimate header whose name contains such a character (e.g. `X_Request_Id`) is dropped or rejected as well. entryPoints: websecure: address: ':443' http: aliasHeadersStrategy: delete [entryPoints.websecure] address = ":443" [entryPoints.websecure.http] aliasHeadersStrategy = "delete" --entryPoints.websecure.address=:443 --entryPoints.websecure.http.aliasHeadersStrategy=delete Examples AliasHeadersStrategy Request Headers Result keep X-Auth-User: legit X.Auth.User: spoof X!Auth!User: spoof X-Auth-User: legit X.Auth.User: spoof X!Auth!User: spoof reach the backend delete X-Auth-User: legit X.Auth.User: spoof X!Auth!User: spoof Only X-Auth-User: legit reaches the backend reject X-Auth-User: legit X.Auth.User: spoof X!Auth!User: spoof Request rejected with 400 Bad Request sanitizePath The sanitizePath option defines whether to enable the request path sanitization. When disabled, the incoming request path is passed to the backend as is. This can be useful when dealing with legacy clients that are not url-encoding data in the request path. For example, as base64 uses the “/” character internally, if it's not url encoded, it can lead to unsafe routing when the sanitizePath option is set to false. !!! warning "Security" Setting the sanitizePath option to false is not safe. Ensure every request is properly url encoded instead. Examples SanitizePath Request Path Resulting Request Path false /./foo/bar /./foo/bar true /./foo/bar /foo/bar false /foo/../bar /foo/../bar true /foo/../bar /bar false /foo/bar// /foo/bar// true /foo/bar// /foo/bar/ false /./foo/../bar// /./foo/../bar// true /./foo/../bar// /bar/ Encoded Characters You can configure Traefik to control the handling of encoded characters in request paths for security purposes. By default, Traefik do not reject requests with path containing certain encoded characters that could be used in path traversal or other security attacks. !!! info This check is not done against the request query parameters, but only against the request path as defined in [RFC3986 section-3](https://datatracker.ietf.org/doc/html/rfc3986#section-3). !!! info "Security Considerations" When your backend is not fully compliant with [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) and notably decode encoded reserved characters in the request path, it is recommended to set these options to `false` to avoid split-view situation and helps prevent path traversal attacks or other malicious attempts to bypass security controls. Here is the list of the encoded characters that are allowed by default: Encoded Character Character %2f or %2F / (slash) %5c or %5C \ (backslash) %00 NULL (null character) %3b or %3B ; (semicolon) %25 % (percent) %3f or %3F ? (question mark) %23 # (hash) Forwarded Headers You can configure Traefik to trust the forwarded headers information ( X-Forwarded-*). ??? info " forwardedHeaders.trustedIPs" Trusting Forwarded Headers from specific IPs. ```yaml tab="File (YAML)" ## Static configuration entryPoints: web: address: ":80" forwardedHeaders: trustedIPs: - "127.0.0.1/32" - "192.168.1.7" ``` ```toml tab="File (TOML)" ## Static configuration [entryPoints] [entryPoints.web] address = ":80" [entryPoints.web.forwardedHeaders] trustedIPs = ["127.0.0.1/32", "192.168.1.7"] ``` ```bash tab="CLI" ## Static configuration --entryPoints.web.address=:80 --entryPoints.web.forwardedHeaders.trustedIPs=127.0.0.1/32,192.168.1.7 ``` ??? info " forwardedHeaders.insecure" Insecure Mode (Always Trusting Forwarded Headers). ```yaml tab="File (YAML)" ## Static configuration entryPoints: web: address: ":80" forwardedHeaders: insecure: true ``` ```toml tab="File (TOML)" ## Static configuration [entryPoints] [entryPoints.web] address = ":80" [entryPoints.web.forwardedHeaders] insecure = true ``` ```bash tab="CLI" ## Static configuration --entryPoints.web.address=:80 --entryPoints.web.forwardedHeaders.insecure ``` ??? info " forwardedHeaders.connection" As per RFC7230, Traefik respects the Connection options from the client request. By doing so, it removes any header field(s) listed in the request Connection header and the Connection header field itself when empty. The removal happens as soon as the request is handled by Traefik, thus the removed headers are not available when the request passes through the middleware chain. The `connection` option lists the Connection headers allowed to passthrough the middleware chain before their removal. ```yaml tab="File (YAML)" ## Static configuration entryPoints: web: address: ":80" forwardedHeaders: connection: - foobar ``` ```toml tab="File (TOML)" ## Static configuration [entryPoints] [entryPoints.web] address = ":80" [entryPoints.web.forwardedHeaders] connection = ["foobar"] ``` ```bash tab="CLI" ## Static configuration --entryPoints.web.address=:80 --entryPoints.web.forwardedHeaders.connection=foobar ``` ??? info " forwardedHeaders.addXForwardedSchemeHeaders" Add the compatibility headers `X-Forwarded-Scheme` and `X-Scheme` next to `X-Forwarded-Proto`. This is primarily useful when migrating from ingress-nginx and your applications still rely on these legacy headers. When enabled, these compatibility headers follow the same value as `X-Forwarded-Proto`. ```yaml tab="File (YAML)" ## Static configuration entryPoints: websecure: address: ":443" forwardedHeaders: addXForwardedSchemeHeaders: true ``` ```toml tab="File (TOML)" ## Static configuration [entryPoints] [entryPoints.websecure] address = ":443" [entryPoints.websecure.forwardedHeaders] addXForwardedSchemeHeaders = true ``` ```bash tab="CLI" ## Static configuration --entryPoints.websecure.address=:443 --entryPoints.websecure.forwardedHeaders.addXForwardedSchemeHeaders=true ``` HTTP3 As HTTP/3 actually uses UDP, when Traefik is configured with a TCP entryPoint on port N with HTTP/3 enabled, the underlying HTTP/3 server that is started automatically listens on UDP port N too. As a consequence, it means port N cannot be used by another UDP entryPoint. Since HTTP/3 requires the use of TLS, only routers with TLS enabled will be usable with HTTP/3. ProxyProtocol and Load-Balancers The replacement of the remote client address will occur only for IP addresses listed in trustedIPs. This is where you specify your load balancer IPs or CIDR ranges. When queuing Traefik behind another load-balancer, make sure to configure PROXY protocol on both sides. Not doing so could introduce a security risk in your system (enabling request forgery). reusePort Examples Many processes on the same EntryPoint: entryPoints: web: address: ":80" reusePort: true ## Values file additionalArguments: - --entryPoints.web.reusePort=true Many processes on the same EntryPoint on another host: entryPoints: web: address: ":80" reusePort: true privateWeb: address: "192.168.1.2:80" reusePort: true additionalArguments: - --entryPoints.web.reusePort=true - --entryPoints.privateWeb.address=192.168.1.2:80 - --entryPoints.privateWeb.reusePort=true Supported platforms The reusePort option currently works only on Linux, FreeBSD, OpenBSD and Darwin. It will be ignored on other platforms. There is a known bug in the Linux kernel that may cause unintended TCP connection failures when using the reusePort option. For more details, see here. Canary deployment Use the reusePort option with the other option transport.lifeCycle.gracetimeout to do canary deployments against Traefik itself. Like upgrading Traefik version or reloading the static configuration without any service downtime. traceVerbosity observability.traceVerbosity defines the tracing verbosity level for routers attached to this EntryPoint. Routers can override this value in their own observability configuration. Possible values are: minimal: produces a single server span and one client span for each request processed by a router. detailed: enables the creation of additional spans for each middleware executed for each request processed by a router. Systemd Socket Activation Traefik supports systemd socket activation. When a socket activation file descriptor name matches an EntryPoint name, the corresponding file descriptor will be used as the TCP/UDP listener for the matching EntryPoint. systemd-socket-activate -l 80 -l 443 --fdname web:websecure ./traefik --entrypoints.web --entrypoints.websecure !!! warning "EntryPoint Address" When a socket activation file descriptor name matches an EntryPoint name, its address configuration is ignored. To support UDP routing, the address must have the `/udp` suffix (`--entrypoints.my-udp-entrypoint.address=/udp`). !!! warning "Docker Support" Socket activation is not supported by Docker but works with Podman containers. !!! warning "Multiple listeners in socket file" Each systemd socket file must contain only one Listen directive, except in the case of HTTP/3, where the file must include both ListenStream and ListenDatagram directives. To set up TCP and UDP listeners on the same port, use multiple socket files with different entrypoints names. Traefik FastProxy Experimental Configuration Overview This guide provides instructions on how to configure and use the new experimental fastProxy install configuration option in Traefik. The fastProxy option introduces a high-performance reverse proxy designed to enhance the performance of routing. !!! info "Limitations" Please note that the new fast proxy implementation does not work with HTTP/2. This means that when a H2C or HTTPS request with [HTTP2 enabled](../../routing-configuration/http/load-balancing/serverstransport.md#opt-disableHTTP2) is sent to a backend, the fallback proxy is the regular one. Additionnaly, observability features like tracing and OTEL semconv metrics are not supported for the moment. !!! warning "Experimental" The `fastProxy` option is currently experimental and subject to change in future releases. Use with caution in production environments. Enabling FastProxy The fastProxy option is an install configuration parameter. To enable it, you need to configure it in your Traefik install configuration experimental: fastProxy: {} [experimental.fastProxy] --experimental.fastProxy Configuration Options Option Type Default Description experimental.fastProxy.debug bool false Enable debug mode for the FastProxy implementation. Traefik Plugins Experimental Configuration Overview This guide provides instructions on how to configure and use the new experimental plugins install configuration option in Traefik. The plugins option introduces a system to extend Traefik capabilities with custom middlewares and providers. !!! warning "Experimental" The `plugins` option is currently experimental and subject to change in future releases. Use with caution in production environments. Enabling Plugins The plugins option is an install configuration parameter. To enable a plugin, you need to define it in your Traefik install configuration experimental: plugins: plugin-name: # The name of the plugin in the routing configuration moduleName: "github.com/github-organization/github-repository" # The plugin module name version: "vX.XX.X" # The version to use [experimental.plugins.plugin-name] moduleName = "github.com/github-organization/github-repository" # The plugin module name version = "vX.XX.X" # The version to use # The plugin module name # With plugin-name the name of the plugin in the routing configuration --experimental.plugins.plugin-name.modulename=github.com/github-organization/github-repository --experimental.plugins.plugin-name.version=vX.XX.X # The version to use To learn more about how to add a new plugin to a Traefik instance, please refer to the developer documentation. Plugin Options Field Description Type Required moduleName Plugin's module name. string Yes version Plugin's version. string Yes hash Plugin's hash to validate. string No settings Plugin's settings (works only for wasm plugins). object No settings.envs Environment variables to forward to the wasm guest. []string No settings.mounts Directory to mount to the wasm guest. []string No settings.useUnsafe Allow the plugin to use unsafe and syscall packages. bool No Local Plugins Local plugins allow you to use plugins from a local directory, without publishing them to the Traefik plugin catalog. experimental: localPlugins: plugin-name: # The name of the plugin in the routing configuration moduleName: "github.com/github-organization/github-repository" # The plugin module name [experimental.localPlugins.plugin-name] moduleName = "github.com/github-organization/github-repository" # The plugin module name # The plugin module name # With plugin-name the name of the plugin in the routing configuration --experimental.localplugins.plugin-name.modulename=github.com/github-organization/github-repository Local Plugin Options Field Description Type Required moduleName Plugin's module name. string Yes settings Plugin's settings (works only for wasm plugins). object No settings.envs Environment variables to forward to the wasm guest. []string No settings.mounts Directory to mount to the wasm guest. []string No settings.useUnsafe Allow the plugin to use unsafe and syscall packages. bool No CLI & Ping Checking the Health of your Traefik Instances {: .subtitle } CLI The CLI can be used to make a request to the /ping endpoint to check the health of Traefik. Its exit status is 0 if Traefik is healthy and 1 otherwise. This can be used with HEALTHCHECK instruction or any other health check orchestration mechanism. Usage traefik healthcheck [command] [flags] [arguments] Example: $ traefik healthcheck OK: http://:8082/ping Ping The /ping health-check URL is enabled with the command-line --ping or config file option [ping]. The entryPoint where the /ping is active can be customized with the entryPoint option, whose default value is traefik (port 8080). Path Method Description /ping GET, HEAD An endpoint to check for Traefik process liveness. Return a code 200 with the content: OK Configuration Example To enable the API handler: ping: {} [ping] --ping=true Configuration Options Field Description Default Required ping.entryPoint Enables /ping on a dedicated EntryPoint. traefik No ping.manualRouting Disables the default internal router in order to allow one to create a custom router for the ping@internal service when set to true. false No ping.terminatingStatusCode Defines the status code for the ping handler during a graceful shut down. See more information here 503 No terminatingStatusCode During the period in which Traefik is gracefully shutting down, the ping handler returns a 503 status code by default. If Traefik is behind, for example a load-balancer doing health checks (such as the Kubernetes LivenessProbe), another code might be expected as the signal for graceful termination. In that case, the terminatingStatusCode can be used to set the code returned by the ping handler during termination. ping: terminatingStatusCode: 204 [ping] terminatingStatusCode = 204 --ping.terminatingStatusCode=204 Traefik Logs Documentation Logs concern everything that happens to Traefik itself (startup, configuration, events, shutdown, and so on). Configuration Example log: filePath: "/path/to/log-file.log" format: json level: INFO [log] filePath = "/path/to/log-file.log" format = "json" level = "INFO" --log.filePath=/path/to/log-file.log --log.format=json --log.level=INFO Configuration Options The section below describe how to configure Traefik logs using the static configuration. Field Description Default Required log.filePath By default, the logs are written to the standard output. You can configure a file path instead using the filePath option. When filePath is specified, Traefik will write logs only to that file (not to standard output). - No log.format Log format ( commonor json). The fields displayed with the format common cannot be customized. "common" No log.level Log level ( TRACE, DEBUG, INFO, WARN, ERROR, FATAL, and PANIC) ERROR No log.noColor When using the format common, disables the colorized output. false No log.maxSize Maximum size in megabytes of the log file before it gets rotated. 100MB No log.maxAge Maximum number of days to retain old log files based on the timestamp encoded in their filename. A day is defined as 24 hours and may not exactly correspond to calendar days due to daylight savings, leap seconds, etc. By default files are not removed based on their age. 0 No log.maxBackups Maximum number of old log files to retain. The default is to retain all old log files. 0 No log.compress Compress log files in gzip after rotation. Compression is always enabled when log rotation is active; this field has no effect. false No OpenTelemetry Traefik supports OpenTelemetry for logging. To enable OpenTelemetry, you need to set the following in the static configuration: experimental: otlpLogs: true [experimental] otlpLogs = true --experimental.otlpLogs=true !!! warning This is an experimental feature. !!! note "Stdio logs remain available" When OTLP logging is enabled, standard output (stdio) logs are still available and will continue to be written alongside OTLP exports. Configuration Example experimental: otlpLogs: true log: otlp: http: endpoint: https://collector:4318/v1/logs headers: Authorization: Bearer auth_asKXRhIMplM7El1JENjrotGouS1LYRdL [experimental] otlpLogs = true [log.otlp] http.endpoint = "https://collector:4318/v1/logs" http.headers.Authorization = "Bearer auth_asKXRhIMplM7El1JENjrotGouS1LYRdL" --experimental.otlpLogs=true --log.otlp.http.endpoint=https://collector:4318/v1/logs --log.otlp.http.headers.Authorization=Bearer auth_asKXRhIMplM7El1JENjrotGouS1LYRdL Configuration Options Field Description Default Required log.otlp.serviceName Service name used in selected backend. "traefik" No log.otlp.resourceAttributes Defines additional resource attributes to be sent to the collector. See resourceAttributes for details. [] No log.otlp.http This instructs the exporter to send logs to the OpenTelemetry Collector using HTTP. No log.otlp.http.endpoint The endpoint of the OpenTelemetry Collector. (format= ://:) https://localhost:4318 No log.otlp.http.headers Additional headers sent with logs by the exporter to the OpenTelemetry Collector. [ ] No log.otlp.http.tls Defines the Client TLS configuration used by the exporter to send logs to the OpenTelemetry Collector. No log.otlp.http.tls.ca The path to the certificate authority used for the secure connection to the OpenTelemetry Collector, it defaults to the system bundle. No log.otlp.http.tls.cert The path to the certificate to use for the OpenTelemetry Collector. No log.otlp.http.tls.key The path to the key to use for the OpenTelemetry Collector. No log.otlp.http.tls.insecureSkipVerify Instructs the OpenTelemetry Collector to accept any certificate presented by the server regardless of the hostname in the certificate. false No log.otlp.grpc This instructs the exporter to send logs to the OpenTelemetry Collector using gRPC. No log.otlp.grpc.endpoint The endpoint of the OpenTelemetry Collector. (format= :) localhost:4317 No log.otlp.grpc.headers Additional headers sent with logs by the exporter to the OpenTelemetry Collector. [ ] No log.otlp.grpc.insecure Instructs the exporter to send logs to the OpenTelemetry Collector using an insecure protocol. false No log.otlp.grpc.tls Defines the Client TLS configuration used by the exporter to send logs to the OpenTelemetry Collector. No log.otlp.grpc.tls.ca The path to the certificate authority used for the secure connection to the OpenTelemetry Collector, it defaults to the system bundle. No log.otlp.grpc.tls.cert The path to the certificate to use for the OpenTelemetry Collector. No log.otlp.grpc.tls.key The path to the key to use for the OpenTelemetry Collector. No log.otlp.grpc.tls.insecureSkipVerify Instructs the OpenTelemetry Collector to accept any certificate presented by the server regardless of the hostname in the certificate. false No resourceAttributes The resourceAttributes option allows setting the resource attributes sent along the traces. Traefik also supports the OTEL_RESOURCE_ATTRIBUTES env variable to set up the resource attributes. !!! info "Kubernetes Resource Attributes Detection" Additionally, Traefik automatically discovers the following [Kubernetes resource attributes](https://opentelemetry.io/docs/specs/semconv/non-normative/k8s-attributes/) when running in a Kubernetes cluster: - `k8s.namespace.name` - `k8s.pod.uid` - `k8s.pod.name` Note that this automatic detection can fail, like if the Traefik pod is running in host network mode. In this case, you should provide the attributes with the option or the env variable. AccessLogs Access logs concern everything that happens to the requests handled by Traefik. !!! note "Stdio logs are not enabled by default alongside OTLP exports" If you would like Stdio access logs to be available, use accessLog.dualOutput option. Configuration Example accessLog: # JSON format format: json # Filter on status codes, retry attempts and minimal duration filters: statusCodes: - "200" - "300-302" retryAttempts: true minDuration: "10ms" fields: # Keep all the fields by default defaultMode: keep names: # Drop the Field ClientUserName ClientUsername: drop headers: # Keep all the headers by default defaultMode: keep names: # Redact the User-Agent header value User-Agent: redact # Drop the Authorization header value Authorization: drop queryParameters: # Drop all query parameters defaultMode: drop [accessLog] format = "json" [accessLog.filters] statusCodes = [ "200", "300-302" ] retryAttempts = true minDuration = "10ms" [accessLog.fields] defaultMode = "keep" [accessLog.fields.names] ClientUsername = "drop" [accessLog.fields.headers] defaultMode = "keep" [accessLog.fields.headers.names] User-Agent = "redact" Authorization = "drop" [accessLog.fields.queryParameters] defaultMode = "drop" --accesslog=true --accesslog.dualoutput=true --accesslog.format=json --accesslog.filters.statuscodes=200,300-302 --accesslog.filters.retryattempts --accesslog.filters.minduration=10ms --accesslog.fields.defaultmode=keep --accesslog.fields.names.ClientUsername=drop --accesslog.fields.headers.defaultmode=keep --accesslog.fields.headers.names.User-Agent=redact --accesslog.fields.headers.names.Authorization=drop --accesslog.fields.queryparameters.defaultmode=drop Configuration Options The section below describes how to configure Traefik access logs using the static configuration. Field Description Default Required accesslog.filePath By default, the access logs are written to the standard output. You can configure a file path instead using the filePath option. No accesslog.dualOutput Force Stdio logging, even if OTLP is configured. By default, Stdio logging is disabled when OTLP is enabled for performance reasons. false No accesslog.format By default, logs are written using the Traefik Common Log Format (CLF). Available formats: common (Traefik extended CLF), genericCLF (standard CLF compatible with analyzers), or json. If the given format is unsupported, the default ( common) is used instead. "common" No accesslog.bufferingSize To process access logs asynchronously, set bufferingSize to a value greater than zero. The value specifies the capacity, in log lines, of the in-memory queue. Traefik writes queued log lines continuously and does not wait for the queue to become full. A larger queue reduces the chance that access logging blocks requests under load. 0 No accesslog.addInternals Enables access logs for internal resources (e.g.: ping@internal). false No accesslog.filters.statusCodes Limit the access logs to requests with a status codes in the specified range. [ ] No accesslog.filters.retryAttempts Keep the access logs when at least one retry has happened. false No accesslog.filters.minDuration Keep access logs when requests take longer than the specified duration (provided in seconds or as a valid duration format, see time.ParseDuration). 0 No accesslog.fields.defaultMode Mode to apply by default to the access logs fields ( keep or drop). keep No accesslog.fields.names Set the fields list to display in the access logs (format name:mode). Available fields list here. [ ] No accesslog.fields.headers.defaultMode Mode to apply by default to the access logs headers ( keep, redact or drop). drop No accesslog.fields.headers.names Set the headers list to display in the access logs (format name:mode). [ ] No accesslog.fields.queryParameters.defaultMode Mode to apply by default to the access logs query parameters ( keep or drop) keep No OpenTelemetry Traefik supports OpenTelemetry for access logs. To enable OpenTelemetry, you need to set the following in the static configuration: experimental: otlpLogs: true [experimental] otlpLogs = true --experimental.otlpLogs=true !!! warning This is an experimental feature. Configuration Example experimental: otlpLogs: true accesslog: # Keep Stdio logs alongside OTEL logging dualOutput: true otlp: http: endpoint: https://collector:4318/v1/logs headers: Authorization: Bearer auth_asKXRhIMplM7El1JENjrotGouS1LYRdL [experimental] otlpLogs = true [accessLog] dualOutput = true [accesslog.otlp] http.endpoint = "https://collector:4318/v1/logs" http.headers.Authorization = "Bearer auth_asKXRhIMplM7El1JENjrotGouS1LYRdL" --experimental.otlpLogs=true --accesslog.otlp.http.endpoint=https://collector:4318/v1/logs --accesslog.otlp.http.headers.Authorization=Bearer auth_asKXRhIMplM7El1JENjrotGouS1LYRdL Configuration Options Field Description Default Required accesslog.otlp.serviceName Defines the service name resource attribute. "traefik" No accesslog.otlp.resourceAttributes Defines additional resource attributes to be sent to the collector. See resourceAttributes for details. [] No accesslog.otlp.http This instructs the exporter to send access logs to the OpenTelemetry Collector using HTTP. No accesslog.otlp.http.endpoint The endpoint of the OpenTelemetry Collector. (format= ://:) https://localhost:4318 No accesslog.otlp.http.headers Additional headers sent with access logs by the exporter to the OpenTelemetry Collector. [ ] No accesslog.otlp.http.tls Defines the Client TLS configuration used by the exporter to send access logs to the OpenTelemetry Collector. No accesslog.otlp.http.tls.ca The path to the certificate authority used for the secure connection to the OpenTelemetry Collector, it defaults to the system bundle. No accesslog.otlp.http.tls.cert The path to the certificate to use for the OpenTelemetry Collector. No accesslog.otlp.http.tls.key The path to the key to use for the OpenTelemetry Collector. No accesslog.otlp.http.tls.insecureSkipVerify Instructs the OpenTelemetry Collector to accept any certificate presented by the server regardless of the hostname in the certificate. false No accesslog.otlp.grpc This instructs the exporter to send access logs to the OpenTelemetry Collector using gRPC. No accesslog.otlp.grpc.endpoint The endpoint of the OpenTelemetry Collector. (format= :) localhost:4317 No accesslog.otlp.grpc.headers Additional headers sent with access logs by the exporter to the OpenTelemetry Collector. [ ] No accesslog.otlp.grpc.insecure Instructs the exporter to send access logs to the OpenTelemetry Collector using an insecure protocol. false No accesslog.otlp.grpc.tls Defines the Client TLS configuration used by the exporter to send access logs to the OpenTelemetry Collector. No accesslog.otlp.grpc.tls.ca The path to the certificate authority used for the secure connection to the OpenTelemetry Collector, it defaults to the system bundle. No accesslog.otlp.grpc.tls.cert The path to the certificate to use for the OpenTelemetry Collector. No accesslog.otlp.grpc.tls.key The path to the key to use for the OpenTelemetry Collector. No accesslog.otlp.grpc.tls.insecureSkipVerify Instructs the OpenTelemetry Collector to accept any certificate presented by the server regardless of the hostname in the certificate. false No resourceAttributes The resourceAttributes option allows setting the resource attributes sent along the traces. Traefik also supports the OTEL_RESOURCE_ATTRIBUTES env variable to set up the resource attributes. !!! info "Kubernetes Resource Attributes Detection" Additionally, Traefik automatically discovers the following [Kubernetes resource attributes](https://opentelemetry.io/docs/specs/semconv/non-normative/k8s-attributes/) when running in a Kubernetes cluster: - `k8s.namespace.name` - `k8s.pod.uid` - `k8s.pod.name` Note that this automatic detection can fail, like if the Traefik pod is running in host network mode. In this case, you should provide the attributes with the option or the env variable. Traefik CLF format fields It's the default format provided by Traefik. Below the fields displayed with the Traefik CLF format: - [] " " "" "" "" "" ms !!! info " is the downstream status" In both CLF formats, `` is the `DownstreamStatus`, the status sent to the client. The backend status (`OriginStatus`) is only available with the `json` format. Generic CLF format fields Below the fields displayed with the generic CLF format: - [] " " "" "" JSON format fields Field Description StartUTC The time at which request processing started. StartLocal The local time at which request processing started. Duration The total time taken (in nanoseconds) by processing the response, including the origin server's time but not the log writing time. RouterName The name of the Traefik router. ServiceName The name of the Traefik backend. ServiceURL The URL of the Traefik backend. ServiceAddr The IP:port of the Traefik backend (extracted from ServiceURL). ClientAddr The remote address in its original form (usually IP:port). ClientHost The remote IP address from which the client request was received. ClientPort The remote TCP port from which the client request was received. ClientUsername The username provided in the URL, if present. RequestAddr The HTTP Host header (usually IP:port). This is treated as not a header by the Go API. RequestHost The HTTP Host server name (not including port). RequestPort The TCP port from the HTTP Host. RequestMethod The HTTP method. RequestPath The HTTP request URI, not including the scheme, host or port. RequestProtocol The version of HTTP requested. RequestScheme The HTTP scheme requested http or https. RequestLine The RequestMethod, + RequestPath and RequestProtocol. RequestContentSize The number of bytes in the request entity (a.k.a. body) sent by the client. OriginDuration The time taken (in nanoseconds) by the origin server ('upstream') to return its response. OriginContentSize The content length specified by the origin server, or 0 if unspecified. OriginStatus The HTTP status code resulting from proxying the request to a backend: either the one returned by that backend, or the one computed when the server could not be reached ( 502, 504, ...). See Origin vs. Downstream Status. OriginStatusLine OriginStatus + Status code explanation DownstreamStatus The HTTP status code sent to the client, after the middleware chain has run. See Origin vs. Downstream Status. DownstreamStatusLine The DownstreamStatus and status code explanation. DownstreamContentSize The number of bytes in the response entity returned to the client. This is in addition to the "Content-Length" header, which may be present in the origin response. RequestCount The number of requests received since the Traefik instance started. GzipRatio The response body compression ratio achieved. Overhead The processing time overhead (in nanoseconds) caused by Traefik. RetryAttempts The amount of attempts the request was retried. TLSVersion The TLS version used by the connection (e.g. 1.2) (if connection is TLS). TLSCipher The TLS cipher used by the connection (e.g. TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) (if connection is TLS). TLSClientSubject The string representation of the TLS client certificate's Subject (e.g. CN=username,O=organization). KubernetesIngressNamespace The namespace of the Kubernetes Ingress resource the router handles. Emitted when the router originates from the Kubernetes Ingress or Kubernetes Ingress Nginx provider. KubernetesIngressName The name of the Kubernetes Ingress resource the router handles. Emitted when the router originates from the Kubernetes Ingress or Kubernetes Ingress Nginx provider. KubernetesIngressRouteNamespace The namespace of the Kubernetes IngressRoute (CRD) the router handles. Emitted when the router originates from the Kubernetes CRD provider. KubernetesIngressRouteName The name of the Kubernetes IngressRoute (CRD) the router handles. Emitted when the router originates from the Kubernetes CRD provider. KubernetesServiceNamespace The namespace of the Kubernetes Service that handled the request. Available with all Kubernetes providers. Stamped per request from the actual backend chosen by the load balancing strategy, so it reflects the real target even under multi-service routes, TraefikService weighted/mirroring, or cross-namespace references. KubernetesServiceName The name of the Kubernetes Service that handled the request. See KubernetesServiceNamespace for the per-request semantics. KubernetesServicePort The port of the Kubernetes Service that handled the request. See KubernetesServiceNamespace for the per-request semantics. Log Rotation Traefik does not rotate the access log file. When Traefik receives a USR1 signal, it closes and opens again the access log file. This lets an external program, such as logrotate, rotate the access log file. The USR1 signal has no effect on the Traefik log file. Traefik rotates the Traefik log file with the options log.maxSize, log.maxAge, and log.maxBackups. !!! warning This does not work on Windows due to the lack of USR signals. Time Zones Traefik will timestamp each log line in UTC time by default. It is possible to configure the Traefik to timestamp in a specific timezone by ensuring the following configuration has been made in your environment: Provide time zone data to /etc/localtime or /usr/share/zoneinfo (based on your distribution) or set the environment variable TZ to the desired timezone. Specify the field StartLocal by dropping the field named StartUTC (available on the default Common Log Format (CLF) as well as JSON): accesslog.fields.names.StartUTC=drop. Example utilizing Docker Compose: services: traefik: image: traefik:v3.8 environment: - TZ=US/Alaska command: - --accesslog.fields.names.StartUTC=drop - --providers.docker ports: - 80:80 volumes: - /var/run/docker.sock:/var/run/docker.sock {% include-markdown "includes/traefik-for-business-applications.md" %} Metrics Traefik provides metrics in the OpenTelemetry format as well as the following vendor specific backends: Datadog InfluxDB2 Prometheus StatsD Traefik Proxy has an official Grafana dashboard for both on-premises and Kubernetes deployments. Open Telemetry !!! info "Default protocol" The OpenTelemetry exporter will export metrics to the collector using HTTP by default to https://localhost:4318. Configuration Example To enable the OpenTelemetry metrics: metrics: otlp: {} [metrics] [metrics.otlp] --metrics.otlp=true # values.yaml metrics: # Disable Prometheus (enabled by default) prometheus: null # Enable providing OTel metrics otlp: enabled: true http: enabled: true !!! tip "Helm Chart Configuration" Traefik can be configured to provide metrics in the OpenTelemetry format using the Helm Chart values. To know more about the Helm Chart options, refer to the [Helm Chart](https://github.com/traefik/traefik-helm-chart/blob/master/traefik/VALUES.md) (Find options `metrics.otlp`). Configuration Options Field Description Default Required metrics.addInternals Enables metrics for internal resources (e.g.: ping@internal). false No metrics.otlp.serviceName Defines the service name resource attribute. "traefik" No metrics.otlp.resourceAttributes Defines additional resource attributes to be sent to the collector. See resourceAttributes for details. [] No metrics.otlp.addEntryPointsLabels Enable metrics on entry points. true No metrics.otlp.addRoutersLabels Enable metrics on routers. false No metrics.otlp.addServicesLabels Enable metrics on services. true No metrics.otlp.explicitBoundaries Explicit boundaries for Histogram data points. Only applies to explicit bucket histogram exports. ".005, .01, .025, .05, .075, .1, .25, .5, .75, 1, 2.5, 5, 7.5, 10" No metrics.otlp.pushInterval Interval at which metrics are sent to the OpenTelemetry Collector. 10s No metrics.otlp.http This instructs the exporter to send the metrics to the OpenTelemetry Collector using HTTP. Setting the sub-options with their default values. null/false No metrics.otlp.http.endpoint URL of the OpenTelemetry Collector to send metrics to. Format=" ://:" "https://localhost:4318" Yes metrics.otlp.http.headers Additional headers sent with metrics by the exporter to the OpenTelemetry Collector. - No metrics.otlp.http.tls.ca Path to the certificate authority used for the secure connection to the OpenTelemetry Collector, it defaults to the system bundle. "" No metrics.otlp.http.tls.cert Path to the public certificate used for the secure connection to the OpenTelemetry Collector. When using this option, setting the key option is required. "" No metrics.otlp.http.tls.key Defines the path to the private key used for the TLS connection. "" No metrics.otlp.http.tls.insecureskipverify Allow the TLS connection to the OpenTelemetry Collector accepts any certificate presented by the server regardless of the hostnames it covers. false Yes metrics.otlp.grpc This instructs the exporter to send metrics to the OpenTelemetry Collector using gRPC. null/false No metrics.otlp.grpc.endpoint Address of the OpenTelemetry Collector to send metrics to. Format=" :" "localhost:4317" Yes metrics.otlp.grpc.headers Additional headers sent with metrics by the exporter to the OpenTelemetry Collector. - No metrics.otlp.grpc.insecure Allows exporter to send metrics to the OpenTelemetry Collector without using a secured protocol. false Yes metrics.otlp.grpc.tls.ca Path to the certificate authority used for the secure connection to the OpenTelemetry Collector, it defaults to the system bundle. - No metrics.otlp.grpc.tls.cert Path to the public certificate used for the secure connection to the OpenTelemetry Collector. When using this option, setting the key option is required. - No metrics.otlp.grpc.tls.key Defines the path to the private key used for the TLS connection. - No metrics.otlp.grpc.tls.insecureskipverify Allow the TLS connection to the OpenTelemetry Collector accepts any certificate presented by the server regardless of the hostnames it covers. false Yes resourceAttributes The resourceAttributes option allows setting the resource attributes sent along the traces. Traefik also supports the OTEL_RESOURCE_ATTRIBUTES env variable to set up the resource attributes. !!! info "Kubernetes Resource Attributes Detection" Additionally, Traefik automatically discovers the following [Kubernetes resource attributes](https://opentelemetry.io/docs/specs/semconv/non-normative/k8s-attributes/) when running in a Kubernetes cluster: - `k8s.namespace.name` - `k8s.pod.uid` - `k8s.pod.name` Note that this automatic detection can fail, like if the Traefik pod is running in host network mode. In this case, you should provide the attributes with the option or the env variable. Vendors Datadog Configuration Example To enable the Datadog: metrics: datadog: {} [metrics] [metrics.datadog] --metrics.datadog=true Configuration Options Field Description Default Required metrics.addInternals Enables metrics for internal resources (e.g.: ping@internal). false No datadog.address Defines the address for the exporter to send metrics to datadog-agent. More information here localhost:8125 Yes datadog.addEntryPointsLabels Enable metrics on entry points. true No datadog.addRoutersLabels Enable metrics on routers. false No datadog.addServicesLabels Enable metrics on services. true No datadog.pushInterval Defines the interval used by the exporter to push metrics to datadog-agent. 10s No datadog.prefix Defines the prefix to use for metrics collection. "traefik" No address Address instructs exporter to send metrics to datadog-agent at this address. This address can be a Unix Domain Socket (UDS) in the following format: unix:///path/to/datadog.socket. When the prefix is set to unix, the socket type will be automatically determined. To explicitly define the socket type and avoid automatic detection, you can use the prefixes unixgram for SOCK_DGRAM (datagram sockets) and unixstream for SOCK_STREAM (stream sockets), respectively. metrics: datadog: address: localhost:8125 [metrics] [metrics.datadog] address = "localhost:8125" --metrics.datadog.address=localhost:8125 InfluxDB v2 Configuration Example To enable the InfluxDB2: metrics: influxDB2: address: http://localhost:8086 [metrics] [metrics.influxDB2] address: http://localhost:8086 --metrics.influxdb2=true Configuration Options Field Description Default Required metrics.addInternals Enables metrics for internal resources (e.g.: ping@internal). false No metrics.influxDB2.addEntryPointsLabels Enable metrics on entry points. true No metrics.influxDB2.addRoutersLabels Enable metrics on routers. false No metrics.influxDB2.addServicesLabels Enable metrics on services. true No metrics.influxDB2.additionalLabels Additional labels (InfluxDB tags) on all metrics. - No metrics.influxDB2.pushInterval The interval used by the exporter to push metrics to InfluxDB server. 10s No metrics.influxDB2.address Address of the InfluxDB v2 instance. "http://localhost:8086" Yes metrics.influxDB2.token Token with which to connect to InfluxDB v2. - Yes metrics.influxDB2.org Organisation where metrics will be stored. - Yes metrics.influxDB2.bucket Bucket where metrics will be stored. - Yes Prometheus Configuration Example To enable the Prometheus: metrics: prometheus: buckets: - 0.1 - 0.3 - 1.2 - 5.0 [metrics] [metrics.prometheus] [metrics.prometheus.buckets] - 0.1 - 0.3 - 1.2 - 5.0 --metrics.prometheus=true Configuration Options Field Description Default Required metrics.addInternals Enables metrics for internal resources (e.g.: ping@internals). false No metrics.prometheus.addEntryPointsLabels Enable metrics on entry points. true No metrics.prometheus.addRoutersLabels Enable metrics on routers. false No metrics.prometheus.addServicesLabels Enable metrics on services. true No metrics.prometheus.buckets Buckets for latency metrics. "0.100000, 0.300000, 1.200000, 5.000000" No metrics.prometheus.manualRouting Set to true, it disables the default internal router in order to allow creating a custom router for the prometheus@internal service. false No metrics.prometheus.entryPoint Traefik Entrypoint name used to expose metrics. "traefik" No metrics.prometheus.headerLabels Defines extra labels extracted from request headers for the requests_total metrics. More information here. Yes headerLabels Defines the extra labels for the requests_total metrics, and for each of them, the request header containing the value for this label. If the header is not present in the request it will be added nonetheless with an empty value. The label must be a valid label name for Prometheus metrics, otherwise, the Prometheus metrics provider will fail to serve any Traefik-related metric. !!! note "How to provide the Host header value" The Host header is never present in the Header map of a request, as per go documentation says: ```Golang // For incoming requests, the Host header is promoted to the // Request.Host field and removed from the Header map. ``` As a workaround, to obtain the Host of a request as a label, use instead the `X-Forwarded-Host` header. Configuration Example Here is an example of the entryPoint requests_total metric with an additional "useragent" label. When configuring the label in Static Configuration: # static_configuration.yaml metrics: prometheus: headerLabels: useragent: User-Agent curl -H "User-Agent: foobar" http://localhost traefik_entrypoint_requests_total\{code="200",entrypoint="web",method="GET",protocol="http",useragent="foobar"\} 1 StatsD Configuration Example To enable the Statsd: metrics: statsD: address: localhost:8125 [metrics] [metrics.statsD] address: localhost:8125 --metrics.statsd=true Configuration Options Field Description Default Required metrics.addInternals Enables metrics for internal resources (e.g.: ping@internals). false No metrics.statsD.addEntryPointsLabels Enable metrics on entry points. true No metrics.statsD.addRoutersLabels Enable metrics on routers. false No metrics.statsD.addServicesLabels Enable metrics on services. true No metrics.statsD.pushInterval The interval used by the exporter to push metrics to DataDog server. 10s No metrics.statsD.address Address instructs exporter to send metrics to statsd at this address. "127.0.0.1:8125" Yes metrics.statsD.prefix The prefix to use for metrics collection. "traefik" No Metrics Provided Global Metrics === "OpenTelemetry" Metric Type Labels Description traefik_config_reloads_total Count The total count of configuration reloads. traefik_config_last_reload_success Gauge The timestamp of the last configuration reload success. traefik_open_connections Gauge entrypoint, protocol The current count of open connections, by entrypoint and protocol. traefik_tls_certs_not_after Gauge The expiration date of certificates. === "Prometheus" Metric Type Labels Description traefik_config_reloads_total Count The total count of configuration reloads. traefik_config_last_reload_success Gauge The timestamp of the last configuration reload success. traefik_open_connections Gauge entrypoint, protocol The current count of open connections, by entrypoint and protocol. traefik_tls_certs_not_after Gauge The expiration date of certificates. === "Datadog" Metric Type Labels Description config.reload.total Count The total count of configuration reloads. config.reload.lastSuccessTimestamp Gauge The timestamp of the last configuration reload success. open.connections Gauge entrypoint, protocol The current count of open connections, by entrypoint and protocol. tls.certs.notAfterTimestamp Gauge The expiration date of certificates. === "InfluxDB2" Metric Type Labels Description traefik.config.reload.total Count The total count of configuration reloads. traefik.config.reload.lastSuccessTimestamp Gauge The timestamp of the last configuration reload success. traefik.open.connections Gauge entrypoint, protocol The current count of open connections, by entrypoint and protocol. traefik.tls.certs.notAfterTimestamp Gauge The expiration date of certificates. === "StatsD" Metric Type Labels Description {prefix}.config.reload.total Count The total count of configuration reloads. {prefix}.config.reload.lastSuccessTimestamp Gauge The timestamp of the last configuration reload success. {prefix}.open.connections Gauge entrypoint, protocol The current count of open connections, by entrypoint and protocol. {prefix}.tls.certs.notAfterTimestamp Gauge The expiration date of certificates. !!! note "{prefix} Default Value" By default, {prefix} value is traefik. Labels Here is a comprehensive list of labels that are provided by the global metrics: Label Description example entrypoint Entrypoint that handled the connection "example_entrypoint" protocol Connection protocol "TCP" OpenTelemetry Semantic Conventions Traefik Proxy follows official OpenTelemetry semantic conventions v1.23.1. HTTP Server Metric Type Labels Description http.server.request.duration Histogram error.type, http.request.method, http.response.status_code, network.protocol.name, server.address, server.port, url.scheme Duration of HTTP server requests Labels Here is a comprehensive list of labels that are provided by the metrics: Label Description example error.type Describes a class of error the operation ended with "500" http.request.method HTTP request method "GET" http.response.status_code HTTP response status code "200" network.protocol.name OSI application layer or non-OSI equivalent "http/1.1" network.protocol.version Version of the protocol specified in network.protocol.name "1.1" server.address Name of the local HTTP server that received the request "example.com" server.port Port of the local HTTP server that received the request "80" url.scheme The URI scheme component identifying the used protocol "http" HTTP Client Metric Type Labels Description http.client.request.duration Histogram error.type, http.request.method, http.response.status_code, network.protocol.name, server.address, server.port, url.scheme Duration of HTTP client requests Labels Here is a comprehensive list of labels that are provided by the metrics: Label Description example error.type Describes a class of error the operation ended with "500" http.request.method HTTP request method "GET" http.response.status_code HTTP response status code "200" network.protocol.name OSI application layer or non-OSI equivalent "http/1.1" network.protocol.version Version of the protocol specified in network.protocol.name "1.1" server.address Name of the local HTTP server that received the request "example.com" server.port Port of the local HTTP server that received the request "80" url.scheme The URI scheme component identifying the used protocol "http" HTTP Metrics On top of the official OpenTelemetry semantic conventions, Traefik provides its own metrics to monitor the incoming traffic. EntryPoint Metrics === "OpenTelemetry" | Metric | Type | [Labels](#labels) | Description | |-----------------------|-----------|--------------------|--------------------------| | `traefik_entrypoint_requests_total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total count of HTTP requests received by an entrypoint. | | `traefik_entrypoint_requests_tls_total` | Count | `tls_version`, `tls_cipher`, `entrypoint` | The total count of HTTPS requests received by an entrypoint. | | `traefik_entrypoint_request_duration_seconds` | Histogram | `code`, `method`, `protocol`, `entrypoint` | Request processing duration histogram on an entrypoint. | | `traefik_entrypoint_requests_bytes_total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total size of HTTP requests in bytes handled by an entrypoint. | | `traefik_entrypoint_responses_bytes_total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total size of HTTP responses in bytes handled by an entrypoint. | === "Prometheus" | Metric | Type | [Labels](#labels) | Description | |-----------------------|-----------|------------------------|-------------------------| | `traefik_entrypoint_requests_total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total count of HTTP requests received by an entrypoint. | | `traefik_entrypoint_requests_tls_total` | Count | `tls_version`, `tls_cipher`, `entrypoint` | The total count of HTTPS requests received by an entrypoint. | | `traefik_entrypoint_request_duration_seconds` | Histogram | `code`, `method`, `protocol`, `entrypoint` | Request processing duration histogram on an entrypoint. | | `traefik_entrypoint_requests_bytes_total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total size of HTTP requests in bytes handled by an entrypoint. | | `traefik_entrypoint_responses_bytes_total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total size of HTTP responses in bytes handled by an entrypoint. | === "Datadog" | Metric | Type | [Labels](#labels) | Description | |-----------------------|-----------|------------------|---------------------------| | `entrypoint.requests.total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total count of HTTP requests received by an entrypoint. | | `entrypoint.requests.tls.total` | Count | `tls_version`, `tls_cipher`, `entrypoint` | The total count of HTTPS requests received by an entrypoint. | | `entrypoint.request.duration.seconds` | Histogram | `code`, `method`, `protocol`, `entrypoint` | Request processing duration histogram on an entrypoint. | | `entrypoint.requests.bytes.total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total size of HTTP requests in bytes handled by an entrypoint. | | `entrypoint.responses.bytes.total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total size of HTTP responses in bytes handled by an entrypoint. | === "InfluxDB2" | Metric | Type | [Labels](#labels) | Description | |------------|-----------|-------------------|-----------------| | `traefik.entrypoint.requests.total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total count of HTTP requests received by an entrypoint. | | `traefik.entrypoint.requests.tls.total` | Count | `tls_version`, `tls_cipher`, `entrypoint` | The total count of HTTPS requests received by an entrypoint. | | `traefik.entrypoint.request.duration.seconds` | Histogram | `code`, `method`, `protocol`, `entrypoint` | Request processing duration histogram on an entrypoint. | | `traefik.entrypoint.requests.bytes.total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total size of HTTP requests in bytes handled by an entrypoint. | | `traefik.entrypoint.responses.bytes.total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total size of HTTP responses in bytes handled by an entrypoint. | === "StatsD" | Metric | Type | [Labels](#labels) | Description | |----------------------------|-------|--------------------------|--------------------------------------------------------------------| | `{prefix}.entrypoint.requests.total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total count of HTTP requests received by an entrypoint. | | `{prefix}.entrypoint.requests.tls.total` | Count | `tls_version`, `tls_cipher`, `entrypoint` | The total count of HTTPS requests received by an entrypoint. | | `{prefix}.entrypoint.request.duration.seconds` | Histogram | `code`, `method`, `protocol`, `entrypoint` | Request processing duration histogram on an entrypoint. | | `{prefix}.entrypoint.requests.bytes.total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total size of HTTP requests in bytes handled by an entrypoint. | | `{prefix}.entrypoint.responses.bytes.total` | Count | `code`, `method`, `protocol`, `entrypoint` | The total size of HTTP responses in bytes handled by an entrypoint. | !!! note "{prefix} Default Value" By default, {prefix} value is traefik. Router Metrics === "OpenTelemetry" | Metric | Type | [Labels](#labels) | Description | |-----------------------|-----------|----------------------|--------------------------------| | `traefik_router_requests_total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total count of HTTP requests handled by a router. | | `traefik_router_requests_tls_total` | Count | `tls_version`, `tls_cipher`, `router`, `service` | The total count of HTTPS requests handled by a router. | | `traefik_router_request_duration_seconds` | Histogram | `code`, `method`, `protocol`, `router`, `service` | Request processing duration histogram on a router. | | `traefik_router_requests_bytes_total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total size of HTTP requests in bytes handled by a router. | | `traefik_router_responses_bytes_total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total size of HTTP responses in bytes handled by a router. | === "Prometheus" | Metric | Type | [Labels](#labels) | Description | |-----------------------|-----------|---------------------------------------------------|----------------------------------------------------------------| | `traefik_router_requests_total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total count of HTTP requests handled by a router. | | `traefik_router_requests_tls_total` | Count | `tls_version`, `tls_cipher`, `router`, `service` | The total count of HTTPS requests handled by a router. | | `traefik_router_request_duration_seconds` | Histogram | `code`, `method`, `protocol`, `router`, `service` | Request processing duration histogram on a router. | | `traefik_router_requests_bytes_total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total size of HTTP requests in bytes handled by a router. | | `traefik_router_responses_bytes_total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total size of HTTP responses in bytes handled by a router. | === "Datadog" | Metric | Type | [Labels](#labels) | Description | |-------------|-----------|---------------|---------------------| | `router.requests.total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total count of HTTP requests handled by a router. | | `router.requests.tls.total` | Count | `tls_version`, `tls_cipher`, `router`, `service` | The total count of HTTPS requests handled by a router. | | `router.request.duration.seconds` | Histogram | `code`, `method`, `protocol`, `router`, `service` | Request processing duration histogram on a router. | | `router.requests.bytes.total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total size of HTTP requests in bytes handled by a router. | | `router.responses.bytes.total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total size of HTTP responses in bytes handled by a router. | === "InfluxDB2" | Metric | Type | [Labels](#labels) | Description | |-----------------------|-----------|---------------------------------------------------|----------------------------------------------------------------| | `traefik.router.requests.total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total count of HTTP requests handled by a router. | | `traefik.router.requests.tls.total` | Count | `tls_version`, `tls_cipher`, `router`, `service` | The total count of HTTPS requests handled by a router. | | `traefik.router.request.duration.seconds` | Histogram | `code`, `method`, `protocol`, `router`, `service` | Request processing duration histogram on a router. | | `traefik.router.requests.bytes.total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total size of HTTP requests in bytes handled by a router. | | `traefik.router.responses.bytes.total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total size of HTTP responses in bytes handled by a router. | === "StatsD" | Metric | Type | [Labels](#labels) | Description | |-----------------------|-----------|---------------|-------------| | `{prefix}.router.requests.total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total count of HTTP requests handled by a router. | | `{prefix}.router.requests.tls.total` | Count | `tls_version`, `tls_cipher`, `router`, `service` | The total count of HTTPS requests handled by a router. | | `{prefix}.router.request.duration.seconds` | Histogram | `code`, `method`, `protocol`, `router`, `service` | Request processing duration histogram on a router. | | `{prefix}.router.requests.bytes.total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total size of HTTP requests in bytes handled by a router. | | `{prefix}.router.responses.bytes.total` | Count | `code`, `method`, `protocol`, `router`, `service` | The total size of HTTP responses in bytes handled by a router. | !!! note "{prefix} Default Value" By default, {prefix} value is traefik. Service Metrics === "OpenTelemetry" | Metric | Type | Labels | Description | |-----------------------|-----------|------------|------------| | `traefik_service_requests_total` | Count | `code`, `method`, `protocol`, `service` | The total count of HTTP requests processed on a service. | | `traefik_service_requests_tls_total` | Count | `tls_version`, `tls_cipher`, `service` | The total count of HTTPS requests processed on a service. | | `traefik_service_request_duration_seconds` | Histogram | `code`, `method`, `protocol`, `service` | Request processing duration histogram on a service. | | `traefik_service_retries_total` | Count | `service` | The count of requests retries on a service. | | `traefik_service_server_up` | Gauge | `service`, `url` | Current service's server status, 0 for a down or 1 for up. Only for services configured with healthcheck. | | `traefik_service_requests_bytes_total` | Count | `code`, `method`, `protocol`, `service` | The total size of requests in bytes received by a service. | | `traefik_service_responses_bytes_total` | Count | `code`, `method`, `protocol`, `service` | The total size of responses in bytes returned by a service. | === "Prometheus" | Metric | Type | Labels | Description | |-----------------------|-----------|-------|------------| | `traefik_service_requests_total` | Count | `code`, `method`, `protocol`, `service` | The total count of HTTP requests processed on a service. | | `traefik_service_requests_tls_total` | Count | `tls_version`, `tls_cipher`, `service` | The total count of HTTPS requests processed on a service. | | `traefik_service_request_duration_seconds` | Histogram | `code`, `method`, `protocol`, `service` | Request processing duration histogram on a service. | | `traefik_service_retries_total` | Count | `service` | The count of requests retries on a service. | | `traefik_service_server_up` | Gauge | `service`, `url` | Current service's server status, 0 for a down or 1 for up. Only for services configured with healthcheck. | | `traefik_service_requests_bytes_total` | Count | `code`, `method`, `protocol`, `service` | The total size of requests in bytes received by a service. | | `traefik_service_responses_bytes_total` | Count | `code`, `method`, `protocol`, `service` | The total size of responses in bytes returned by a service. | === "Datadog" | Metric | Type | Labels | Description | |-----------------------|-----------|--------|------------------| | `service.requests.total` | Count | `code`, `method`, `protocol`, `service` | The total count of HTTP requests processed on a service. | | `router.service.tls.total` | Count | `tls_version`, `tls_cipher`, `service` | The total count of HTTPS requests processed on a service. | | `service.request.duration.seconds` | Histogram | `code`, `method`, `protocol`, `service` | Request processing duration histogram on a service. | | `service.retries.total` | Count | `service` | The count of requests retries on a service. | | `service.server.up` | Gauge | `service`, `url` | Current service's server status, 0 for a down or 1 for up. Only for services configured with healthcheck. | | `service.requests.bytes.total` | Count | `code`, `method`, `protocol`, `service` | The total size of requests in bytes received by a service. | | `service.responses.bytes.total` | Count | `code`, `method`, `protocol`, `service` | The total size of responses in bytes returned by a service. | === "InfluxDB2" | Metric | Type | Labels | Description | |-----------------------|-----------|-----------------------------------------|-------------------------------------------------------------| | `traefik.service.requests.total` | Count | `code`, `method`, `protocol`, `service` | The total count of HTTP requests processed on a service. | | `traefik.service.requests.tls.total` | Count | `tls_version`, `tls_cipher`, `service` | The total count of HTTPS requests processed on a service. | | `traefik.service.request.duration.seconds` | Histogram | `code`, `method`, `protocol`, `service` | Request processing duration histogram on a service. | | `traefik.service.retries.total` | Count | `service` | The count of requests retries on a service. | | `traefik.service.server.up` | Gauge | `service`, `url` | Current service's server status, 0 for a down or 1 for up. Only for services configured with healthcheck. | | `traefik.service.requests.bytes.total` | Count | `code`, `method`, `protocol`, `service` | The total size of requests in bytes received by a service. | | `traefik.service.responses.bytes.total` | Count | `code`, `method`, `protocol`, `service` | The total size of responses in bytes returned by a service. | === "StatsD" | Metric | Type | Labels | Description | |-----------------------|-----------|-----|---------| | `{prefix}.service.requests.total` | Count | `code`, `method`, `protocol`, `service` | The total count of HTTP requests processed on a service. | | `{prefix}.service.requests.tls.total` | Count | `tls_version`, `tls_cipher`, `service` | The total count of HTTPS requests processed on a service. | | `{prefix}.service.request.duration.seconds` | Histogram | `code`, `method`, `protocol`, `service` | Request processing duration histogram on a service. | | `{prefix}.service.retries.total` | Count | `service` | The count of requests retries on a service. | | `{prefix}.service.server.up` | Gauge | `service`, `url` | Current service's server status, 0 for a down or 1 for up. Only for services configured with healthcheck. | | `{prefix}.service.requests.bytes.total` | Count | `code`, `method`, `protocol`, `service` | The total size of requests in bytes received by a service. | | `{prefix}.service.responses.bytes.total` | Count | `code`, `method`, `protocol`, `service` | The total size of responses in bytes returned by a service. | !!! note "{prefix} Default Value" By default, {prefix} value is traefik. Labels Here is a comprehensive list of labels that are provided by the metrics: Label Description example cn Certificate Common Name "example.com" code Request code "200" entrypoint Entrypoint that handled the request "example_entrypoint" method Request Method "GET" protocol Request protocol "http" router Router that handled the request "example_router" sans Certificate Subject Alternative NameS "example.com" serial Certificate Serial Number "123..." service Service that handled the request "example_service@provider" tls_cipher TLS cipher used for the request "TLS_FALLBACK_SCSV" tls_version TLS version used for the request "1.0" url Service server url "http://example.com" !!! info " method label value" If the HTTP method verb on a request is not one defined in the set of common methods for [`HTTP/1.1`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) or the [`PRI`](https://datatracker.ietf.org/doc/html/rfc7540#section-11.6) verb (for `HTTP/2`), then the value for the method label becomes `EXTENSION_METHOD`. Tracing Visualize the Requests Flow {: .subtitle } The tracing system allows developers to visualize call flows in their infrastructure. Traefik uses OpenTelemetry, an open standard designed for distributed tracing. Configuration Example To enable the tracing: tracing: {} [tracing] --tracing=true tracing: otlp: enabled: true Configuration Options Field Description Default Required tracing.addInternals Enables tracing for internal resources (e.g.: ping@internal). false No tracing.serviceName Defines the service name resource attribute. "traefik" No tracing.resourceAttributes Defines additional resource attributes to be sent to the collector. See resourceAttributes for details. {} No tracing.sampleRate The proportion of requests to trace, specified between 0.0 and 1.0. Since Traefik supports parent-based sampling ratios, root spans (i.e., spans initiated by Traefik) are sampled according to this rate, while child spans inherit the sampling decision of their parent (i.e., the tracing context from incoming requests). See sampleRate for details. 1.0 No tracing.capturedRequestHeaders Defines the list of request headers to add as attributes. It applies to client and server kind spans. [] No tracing.capturedResponseHeaders Defines the list of response headers to add as attributes. It applies to client and server kind spans. [] False tracing.safeQueryParams By default, all query parameters are redacted. Defines the list of query parameters to not redact. [] No tracing.otlp.http This instructs the exporter to send the tracing to the OpenTelemetry Collector using HTTP. Setting the sub-options with their default values. null/false No tracing.otlp.http.endpoint URL of the OpenTelemetry Collector to send tracing to. Format=" ://:" "https://localhost:4318" Yes tracing.otlp.http.headers Additional headers sent with tracing by the exporter to the OpenTelemetry Collector. No tracing.otlp.http.tls.ca Path to the certificate authority used for the secure connection to the OpenTelemetry Collector, it defaults to the system bundle. "" No tracing.otlp.http.tls.cert Path to the public certificate used for the secure connection to the OpenTelemetry Collector. When using this option, setting the key option is required. "" No tracing.otlp.http.tls.key Defines the path to the private key used for the TLS connection. "" No tracing.otlp.http.tls.insecureskipverify If insecureSkipVerify is true, the TLS connection to the OpenTelemetry Collector accepts any certificate presented by the server regardless of the hostnames it covers. false Yes tracing.otlp.grpc This instructs the exporter to send tracing to the OpenTelemetry Collector using gRPC. false No tracing.otlp.grpc.endpoint Address of the OpenTelemetry Collector to send tracing to. Format=" :" "localhost:4317" Yes tracing.otlp.grpc.headers Additional headers sent with tracing by the exporter to the OpenTelemetry Collector. [] No tracing.otlp.grpc.insecure Allows exporter to send tracing to the OpenTelemetry Collector without using a secured protocol. false Yes tracing.otlp.grpc.tls.ca Path to the certificate authority used for the secure connection to the OpenTelemetry Collector, it defaults to the system bundle. "" No tracing.otlp.grpc.tls.cert Path to the public certificate used for the secure connection to the OpenTelemetry Collector. When using this option, setting the key option is required. "" No tracing.otlp.grpc.tls.key Defines the path to the private key used for the TLS connection. "" No tracing.otlp.grpc.tls.insecureskipverify If insecureSkipVerify is true, the TLS connection to the OpenTelemetry Collector accepts any certificate presented by the server regardless of the hostnames it covers. false Yes sampleRate The sampleRate option controls trace sampling using a ParentBased(TraceIDRatioBased) strategy. !!! info "Sampling Strategy Behavior" - **Root spans** (trace originating at Traefik): Sampled according to the configured `sampleRate` using trace ID ratio-based sampling. - **Child spans** (requests with existing trace context): Inherit the sampling decision from the parent span, regardless of the local `sampleRate`. This ensures consistent sampling decisions across distributed traces: once a trace is sampled, all spans in that trace are sampled, providing complete end-to-end visibility. resourceAttributes The resourceAttributes option allows setting the resource attributes sent along the traces. Traefik also supports the OTEL_RESOURCE_ATTRIBUTES env variable to set up the resource attributes. !!! info "Kubernetes Resource Attributes Detection" Additionally, Traefik automatically discovers the following [Kubernetes resource attributes](https://opentelemetry.io/docs/specs/semconv/non-normative/k8s-attributes/) when running in a Kubernetes cluster: - `k8s.namespace.name` - `k8s.pod.uid` - `k8s.pod.name` Note that this automatic detection can fail, like if the Traefik pod is running in host network mode. In this case, you should provide the attributes with the option or the env variable. Traefik & Docker !!! tip "The Quick Start Uses Docker" If you have not already read it, maybe you would like to go through the [quick start guide](../../../getting-started/index.md) that uses the Docker provider. Configuration Example You can enable the Docker provider as detailed below: providers: docker: {} [providers.docker] --providers.docker=true Attach labels to containers (in your Docker compose file) services: my-container: # ... labels: - traefik.http.routers.my-container.rule=Host(`example.com`) Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.docker.endpoint Specifies the Docker API endpoint. See here for more information "unix:///var/run/docker.sock" No providers.docker.username Defines the username for Basic HTTP authentication. This should be used when the Docker daemon socket is exposed through an HTTP proxy that requires Basic HTTP authentication. "" No providers.docker.password Defines the password for Basic HTTP authentication. This should be used when the Docker daemon socket is exposed through an HTTP proxy that requires Basic HTTP authentication. "" No providers.docker.useBindPortIP Instructs Traefik to use the IP/Port attached to the container's binding instead of its inner network IP/Port. See here for more information false No providers.docker.exposedByDefault Expose containers by default through Traefik. If set to false, containers that do not have a traefik.enable=true label are ignored from the resulting routing configuration. See here for additional information true No providers.docker.network Defines a default docker network to use for connections to all containers. This option can be overridden on a per-container basis with the traefik.docker.network label. "" No providers.docker.defaultRule Defines what routing rule to apply to a container if no rule is defined by a label. See here for more information. "Host(`{{ normalize .Name }}`)" No providers.docker.httpClientTimeout Defines the client timeout for HTTP connections. Accepts a duration string (e.g., 30s, 1m30s) or an integer value in seconds. If its value is 0, no timeout is set. 0 No providers.docker.watch Instructs Traefik to watch Docker events or not. true No providers.docker.constraints Defines an expression that Traefik matches against the container labels to determine whether to create any route for that container. See here for more information. "" No providers.docker.allowEmptyServices Instructs the provider to create any servers load balancer defined for Docker containers regardless of the healthiness of the corresponding containers. false No providers.docker.tls.ca Defines the path to the certificate authority used for the secure connection to Docker, it defaults to the system bundle. "" No providers.docker.tls.cert Defines the path to the public certificate used for the secure connection to Docker. When using this option, setting the key option is required. "" Yes providers.docker.tls.key Defines the path to the private key used for the secure connection to Docker. When using this option, setting the cert option is required. "" Yes providers.docker.tls.insecureSkipVerify Instructs the provider to accept any certificate presented by the Docker server when establishing a TLS connection, regardless of the hostnames the certificate covers. false No endpoint See the Docker API Access section for more information. ??? example "Using the docker.sock" The docker-compose file shares the docker sock with the Traefik container ```yaml services: traefik: image: traefik:v3.1 # The official v3 Traefik docker image ports: - "80:80" volumes: - /var/run/docker.sock:/var/run/docker.sock ``` We specify the docker.sock in traefik's configuration file. ```yaml tab="File (YAML)" providers: docker: endpoint: "unix:///var/run/docker.sock" # ... ``` ```toml tab="File (TOML)" [providers.docker] endpoint = "unix:///var/run/docker.sock" # ... ``` ```bash tab="CLI" --providers.docker.endpoint=unix:///var/run/docker.sock # ... ``` ??? example "Using SSH" Using Docker 18.09+ you can connect Traefik to daemon using SSH. We specify the SSH host and user in Traefik's configuration file. Note that if the server requires public keys for authentication, you must have them accessible for the user running Traefik. ```yaml tab="File (YAML)" providers: docker: endpoint: "ssh://traefik@192.168.2.5:2022" # ... ``` ```toml tab="File (TOML)" [providers.docker] endpoint = "ssh://traefik@192.168.2.5:2022" # ... ``` ```bash tab="CLI" --providers.docker.endpoint=ssh://traefik@192.168.2.5:2022 # ... ``` ??? example "Using HTTP" Using Docker Engine API you can connect Traefik to remote daemon using HTTP. ```yaml tab="File (YAML)" providers: docker: endpoint: "http://127.0.0.1:2375" # ... ``` ```toml tab="File (TOML)" [providers.docker] endpoint = "http://127.0.0.1:2375" # ... ``` ```bash tab="CLI" --providers.docker.endpoint=http://127.0.0.1:2375 # ... ``` ??? example "Using TCP" Using Docker Engine API you can connect Traefik to remote daemon using TCP. ```yaml tab="File (YAML)" providers: docker: endpoint: "tcp://127.0.0.1:2375" # ... ``` ```toml tab="File (TOML)" [providers.docker] endpoint = "tcp://127.0.0.1:2375" # ... ``` ```bash tab="CLI" --providers.docker.endpoint=tcp://127.0.0.1:2375 # ... ``` providers: docker: endpoint: "unix:///var/run/docker.sock" [providers.docker] endpoint = "unix:///var/run/docker.sock" --providers.docker.endpoint=unix:///var/run/docker.sock useBindPortIP Traefik routes requests to the IP/port of the matching container. When setting useBindPortIP=true, you tell Traefik to use the IP/Port attached to the container's binding instead of its inner network IP/Port. When used in conjunction with the traefik.http.services..loadbalancer.server.port label (that tells Traefik to route requests to a specific port), Traefik tries to find a binding on port traefik.http.services..loadbalancer.server.port. If it cannot find such a binding, Traefik falls back on the internal network IP of the container, but still uses the traefik.http.services..loadbalancer.server.port that is set in the label. ??? example "Examples of usebindportip in different situations." | port label | Container's binding | Routes to | |--------------------|----------------------------------------------------|----------------| | - | - | IntIP:IntPort | | - | ExtPort:IntPort | IntIP:IntPort | | - | ExtIp:ExtPort:IntPort | ExtIp:ExtPort | | LblPort | - | IntIp:LblPort | | LblPort | ExtIp:ExtPort:LblPort | ExtIp:ExtPort | | LblPort | ExtIp:ExtPort:OtherPort | IntIp:LblPort | | LblPort | ExtIp1:ExtPort1:IntPort1 & ExtIp2:LblPort:IntPort2 | ExtIp2:LblPort | !!! info "" In the above table: - `ExtIp` stands for "external IP found in the binding" - `IntIp` stands for "internal network container's IP", - `ExtPort` stands for "external Port found in the binding" - `IntPort` stands for "internal network container's port." providers: docker: useBindPortIP: true # ... [providers.docker] useBindPortIP = true # ... --providers.docker.useBindPortIP=true # ... defaultRule The defaultRule option defines what routing rule to apply to a container if no rule is defined by a label. It must be a valid Go template, and can use sprig template functions. The container name can be accessed with the ContainerName identifier. The service name can be accessed with the Name identifier. The template has access to all the labels defined on this container with the Labels identifier. providers: docker: defaultRule: "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)" # ... [providers.docker] defaultRule = "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)" # ... --providers.docker.defaultRule='Host(`{{ .Name }}.{{ index .Labels "customLabel"}}`)' # ... ??? info "Default rule and Traefik service" The exposure of the Traefik container, combined with the default rule mechanism, can lead to create a router targeting itself in a loop. In this case, to prevent an infinite loop, Traefik adds an internal middleware to refuse the request if it comes from the same router. constraints The constraints option can be set to an expression that Traefik matches against the container labels to determine whether to create any route for that container. If none of the container labels match the expression, no route for that container is created. If the expression is empty, all detected containers are included. The expression syntax is based on the Label("key", "value"), and LabelRegex("key", "value") functions, as well as the usual boolean logic, as shown in examples below. !!! tip "Constraints key limitations" Note that `traefik.*` is a reserved label namespace for configuration and can not be used as a key for custom constraints. ??? example "Constraints Expression Examples" ```toml # Includes only containers having a label with key `a.label.name` and value `foo` constraints = "Label(`a.label.name`, `foo`)" ``` ```toml # Excludes containers having any label with key `a.label.name` and value `foo` constraints = "!Label(`a.label.name`, `value`)" ``` ```toml # With logical AND. constraints = "Label(`a.label.name`, `valueA`) && Label(`another.label.name`, `valueB`)" ``` ```toml # With logical OR. constraints = "Label(`a.label.name`, `valueA`) || Label(`another.label.name`, `valueB`)" ``` ```toml # With logical AND and OR, with precedence set by parentheses. constraints = "Label(`a.label.name`, `valueA`) && (Label(`another.label.name`, `valueB`) || Label(`yet.another.label.name`, `valueC`))" ``` ```toml # Includes only containers having a label with key `a.label.name` and a value matching the `a.+` regular expression. constraints = "LabelRegex(`a.label.name`, `a.+`)" ``` For additional information, refer to Restrict the Scope of Service Discovery. providers: docker: constraints: "Label(`a.label.name`,`foo`)" # ... [providers.docker] constraints = "Label(`a.label.name`,`foo`)" # ... --providers.docker.constraints=Label(`a.label.name`,`foo`) # ... Routing Configuration When using Docker as a provider, Traefik uses container labels to retrieve its routing configuration. See the list of labels in the dedicated routing section. Routing Configuration with Labels By default, Traefik watches for container level labels on a standalone Docker Engine. When using Docker Compose, labels are specified by the directive labels from the "services" objects. !!! tip "Not Only Docker" Please note that any tool like Nomad, Terraform, Ansible, etc. that is able to define a Docker container with labels can work with Traefik and the Docker provider. Port Detection Traefik retrieves the private IP and port of containers from the Docker API. Port detection for private communication works as follows: If a container exposes a single port, then Traefik uses this port. If a container exposes multiple ports, then Traefik uses the lowest port. E.g. if 80 and 8080 are exposed, Traefik will use 80. If a container does not expose any port, or the selection from multiple ports does not fit, then you must manually specify which port Traefik should use for communication by using the label traefik.http.services..loadbalancer.server.port (Read more on this label in the dedicated section in routing). Host networking When exposing containers that are configured with host networking, the IP address of the host is resolved as follows: try a lookup of host.docker.internal if the lookup was unsuccessful, try a lookup of host.containers.internal, (Podman equivalent of host.docker.internal) if that lookup was also unsuccessful, fall back to 127.0.0.1 On Linux, for versions of Docker older than 20.10.0, for host.docker.internal to be defined, it should be provided as an extra_host to the Traefik container, using the --add-host flag. For example, to set it to the IP address of the bridge interface ( docker0 by default): --add-host=host.docker.internal:172.17.0.1. IPv4 & IPv6 When using a docker stack that uses IPv6, Traefik will use the IPv4 container IP before its IPv6 counterpart. Therefore, on an IPv6 Docker stack, Traefik will use the IPv6 container IP. Docker API Access Traefik requires access to the docker socket to get its dynamic configuration. You can specify which Docker API Endpoint to use with the directive endpoint. !!! warning "Security Note" Accessing the Docker API without any restriction is a security concern: If Traefik is attacked, then the attacker might get access to the underlying host. {: #security-note } As explained in the [Docker Daemon Attack Surface documentation](https://docs.docker.com/engine/security/#docker-daemon-attack-surface): !!! quote [...] only **trusted** users should be allowed to control your Docker daemon [...] ??? success "Solutions" Expose the Docker socket over TCP or SSH, instead of the default Unix socket file. It allows different implementation levels of the [AAA (Authentication, Authorization, Accounting) concepts](https://en.wikipedia.org/wiki/AAA_(computer_security)), depending on your security assessment: - Authentication with Client Certificates as described in ["Protect the Docker daemon socket."](https://docs.docker.com/engine/security/protect-access/) - Authorize and filter requests to restrict possible actions with [the TecnativaDocker Socket Proxy](https://github.com/Tecnativa/docker-socket-proxy). - Authorization with the [Docker Authorization Plugin Mechanism](https://web.archive.org/web/20190920092526/https://docs.docker.com/engine/extend/plugins_authorization/) - Accounting at networking level, by exposing the socket only inside a Docker private network, only available for Traefik. - Accounting at container level, by exposing the socket on a another container than Traefik's. - Accounting at kernel level, by enforcing kernel calls with mechanisms like [SELinux](https://en.wikipedia.org/wiki/Security-Enhanced_Linux), to only allows an identified set of actions for Traefik's process (or the "socket exposer" process). - SSH public key authentication (SSH is supported with Docker > 18.09) - Authentication using HTTP Basic authentication through an HTTP proxy that exposes the Docker daemon socket. ??? info "More Resources and Examples" - ["Paranoid about mounting /var/run/docker.sock?"](https://medium.com/@containeroo/traefik-2-0-paranoid-about-mounting-var-run-docker-sock-22da9cb3e78c) - [Traefik and Docker: A Discussion with Docker Captain, Bret Fisher](https://blog.traefik.io/traefik-and-docker-a-discussion-with-docker-captain-bret-fisher-7f0b9a54ff88) - [KubeCon EU 2018 Keynote, Running with Scissors, from Liz Rice](https://www.youtube.com/watch?v=ltrV-Qmh3oY) - [Don't expose the Docker socket (not even to a container)](https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container/) - [A thread on Hacker News about sharing the `/var/run/docker.sock` file](https://news.ycombinator.com/item?id=17983623) - [To DinD or not to DinD](https://blog.loof.fr/2018/01/to-dind-or-not-do-dind.html) - [Traefik issue GH-4174 about security with Docker socket](https://github.com/traefik/traefik/issues/4174) - [Inspecting Docker Activity with Socat](https://developers.redhat.com/blog/2015/02/25/inspecting-docker-activity-with-socat/) - [Letting Traefik run on Worker Nodes](https://blog.mikesir87.io/2018/07/letting-traefik-run-on-worker-nodes/) - [Docker Socket Proxy from Tecnativa](https://github.com/Tecnativa/docker-socket-proxy) {% include-markdown "includes/traefik-for-business-applications.md" %} Overview Providers are infrastructure components, whether orchestrators, container engines, cloud providers, or key-value stores. The idea is that Traefik queries the provider APIs in order to find relevant information about routing, and when Traefik detects a change, it dynamically updates the routes. Provider Categories While each provider is different, you can think of each as belonging to one of four categories: Label-based: each deployed container has a set of labels attached to it Key-Value-based: each deployed container updates a key-value store with relevant information Annotation-based: a separate object, with annotations, defines the characteristics of the container File-based: uses files to define configuration Provider Namespace When you declare certain objects in the Traefik dynamic configuration, such as middleware, services, TLS options or server transports, they reside in their provider's namespace. For example, if you declare a middleware using a Docker label, it resides in the Docker provider namespace. If you use multiple providers and wish to reference such an object declared in another provider (e.g. referencing a cross-provider object like middleware), then the object name should be suffixed by the @ separator, and the provider name. For the list of the providers names, see the supported providers table below. @ !!! important "Kubernetes Namespace vs Traefik Namespace" As Kubernetes also has its own notion of namespace, one should not confuse the _provider namespace_ with the _Kubernetes Namespace_ of a resource when in the context of cross-provider usage. In this case, since the definition of a Traefik dynamic configuration object is not in Kubernetes, specifying a Kubernetes Namespace when referring to the resource does not make any sense. On the other hand, if you were to declare a middleware as a Custom Resource in Kubernetes and use the non-CRD Ingress objects, you would have to add the Kubernetes Namespace of the middleware to the annotation like this `-@kubernetescrd`. When [`safeNaming`](./kubernetes/kubernetes-crd.md#safenaming) is enabled, the value becomes `_@kubernetescrd`, using the same `_` separator as the other names generated by the provider. Supported Providers Below is the list of the currently supported providers in Traefik. Provider Type Configuration Type Provider Name Docker Orchestrator Label docker Docker Swarm Orchestrator Label swarm Kubernetes IngressRoute Orchestrator Custom Resource kubernetescrd Kubernetes Ingress Orchestrator Ingress kubernetes Kubernetes Ingress NGINX Orchestrator Ingress-NGINX kubernetesIngressNGINX Kubernetes Gateway API Orchestrator Gateway API Resource kubernetesgateway Consul Catalog Orchestrator Label consulcatalog Nomad Orchestrator Label nomad ECS Orchestrator Label ecs File Manual YAML/TOML format file Consul KV KV consul Etcd KV KV etcd ZooKeeper KV KV zookeeper Redis KV KV redis HTTP Manual JSON/YAML format http !!! info "More Providers" The current version of Traefik does not yet support every provider that Traefik v2.11 did. See the [previous version (v2.11)](https://doc.traefik.io/traefik/v2.11/) for more information. Referencing a Traefik Dynamic Configuration Object from Another Provider Declaring the add-foo-prefix in the file provider. http: middlewares: add-foo-prefix: addPrefix: prefix: "/foo" [http.middlewares] [http.middlewares.add-foo-prefix.addPrefix] prefix = "/foo" Using the add-foo-prefix middleware from other providers: your-container: image: your-docker-image labels: # Attach add-foo-prefix@file middleware (declared in file) - "traefik.http.routers.my-container.middlewares=add-foo-prefix@file" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: ingressroutestripprefix spec: entryPoints: - web routes: - match: Host(`example.com`) kind: Rule services: - name: whoami port: 80 middlewares: - name: add-foo-prefix@file # namespace: bar # A namespace specification such as above is ignored # when the cross-provider syntax is used. apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress namespace: appspace annotations: "traefik.ingress.kubernetes.io/router.middlewares": add-foo-prefix@file spec: Restrict the Scope of Service Discovery By default, Traefik creates routes for all detected containers. If you want to limit the scope of the Traefik service discovery, i.e. disallow route creation for some containers, you can do so in two different ways: With Consul Catalog, Docker, ECS, Nomad and Swarm providers, you can set exposedByDefault to false and add a label traefik.enable=true on containers you want to expose Use a finer-grained mechanism based on label selector or constraints. !!! info "The following providers support constraints" - [Consul Catalog](./hashicorp/consul-catalog.md#constraints) - [Docker](./docker.md#constraints) - [ECS](./others/ecs.md#constraints) - [Nomad](./hashicorp/nomad.md#constraints) - [Swarm](./swarm.md#constraints) !!! info "The following providers support label selectors" - [Kubernetes CRD](./kubernetes/kubernetes-crd.md#opt-providers-kubernetesCRD-labelselector) - [Kubernetes Gateway API](./kubernetes/kubernetes-gateway.md#opt-providers-kubernetesGateway-labelselector) - [Kubernetes Ingress](./kubernetes/kubernetes-ingress.md#opt-providers-kubernetesIngress-labelselector) Providers Precedence providers.precedence Optional When two routers from different providers define the same rule with equal numeric priority, the precedence option determines which provider's route takes precedence. The list is ordered from highest to lowest precedence: a provider listed first wins over providers listed later. providers: precedence: - kubernetescrd - kubernetes - file [providers] precedence = ["kubernetescrd", "kubernetes", "file"] --providers.precedence=kubernetescrd,kubernetes,file Default precedence When precedence is not set, Traefik uses the following default order (highest precedence first): Position Provider name 1 kubernetesgateway 2 kubernetescrd 3 kubernetes 4 kubernetesingressnginx 5 swarm 6 docker 7 file 8 redis 9 knative 10 consul 11 consulcatalog 12 nomad 13 etcd 14 ecs 15 http 16 zookeeper 17 rest !!! note - `precedence` only acts as a **tiebreaker**: it is applied only when two routes from different providers share the same numeric `priority` value. An explicit router priority always takes precedence. - A provider absent from `precedence` loses to any listed provider. - Provider names are case-insensitive. {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik & Docker Swarm This provider works with Docker Swarm Mode. !!! tip "The Quick Start Uses Docker" If you have not already read it, maybe you would like to go through the [quick start guide](../../../getting-started/index.md) that uses the Docker provider. Configuration Example You can enable the Swarm provider as detailed below: providers: swarm: {} [providers.swarm] --providers.swarm=true Attach labels to a single service (not containers) while in Swarm mode (in your Docker compose file). When there is only one service, and the router does not specify a service, then that service is automatically assigned to the router. services: my-container: deploy: labels: - traefik.http.routers.my-container.rule=Host(`example.com`) - traefik.http.services.my-container-service.loadbalancer.server.port=8080 Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.swarm.endpoint Specifies the Docker API endpoint. See here for more information unix:///var/run/docker.sock Yes providers.swarm.username Defines the username for Basic HTTP authentication. This should be used when the Docker daemon socket is exposed through an HTTP proxy that requires Basic HTTP authentication. "" No providers.swarm.password Defines the password for Basic HTTP authentication. This should be used when the Docker daemon socket is exposed through an HTTP proxy that requires Basic HTTP authentication. "" No providers.swarm.useBindPortIP Instructs Traefik to use the IP/Port attached to the container's binding instead of its inner network IP/Port. See here for more information false No providers.swarm.exposedByDefault Expose containers by default through Traefik. If set to false, containers that do not have a traefik.enable=true label are excluded from the resulting routing configuration. See here for additional information true No providers.swarm.network Defines a default docker network to use for connections to all containers. This option can be overridden on a per-container basis with the traefik.swarm.network label. "" No providers.swarm.defaultRule Defines what routing rule to apply to a container if no rule is defined by a label. See here for more information "Host(`{{ normalize .Name }}`)" No providers.swarm.refreshSeconds Defines the polling interval for Swarm Mode. "15s" No providers.swarm.httpClientTimeout Defines the client timeout for HTTP connections. Accepts a duration string (e.g., "30s", "1m"). If its value is 0, no timeout is set. 0 No providers.swarm.watch Instructs Traefik to watch Docker events or not. true No providers.swarm.constraints Defines an expression that Traefik matches against the container labels to determine whether to create any route for that container. See here for more information. "" No providers.swarm.allowEmptyServices Instructs the provider to create any servers load balancer defined for Docker containers regardless of the healthiness of the corresponding containers. false No providers.swarm.tls.ca Defines the path to the certificate authority used for the secure connection to Docker, it defaults to the system bundle. "" No providers.swarm.tls.cert Defines the path to the public certificate used for the secure connection to Docker. When using this option, setting the key option is required. "" Yes providers.swarm.tls.key Defines the path to the private key used for the secure connection to Docker. When using this option, setting the cert option is required. "" Yes providers.swarm.tls.insecureSkipVerify Instructs the provider to accept any certificate presented by the Docker server when establishing a TLS connection, regardless of the hostnames the certificate covers. false No endpoint See the Docker Swarm API Access section for more information. ??? example "Using the docker.sock" The docker-compose file shares the docker sock with the Traefik container ```yaml services: traefik: image: traefik:v3.1 # The official v3 Traefik docker image ports: - "80:80" volumes: - /var/run/docker.sock:/var/run/docker.sock ``` We specify the docker.sock in traefik's configuration file. ```yaml tab="File (YAML)" providers: swarm: endpoint: "unix:///var/run/docker.sock" # ... ``` ```toml tab="File (TOML)" [providers.swarm] endpoint = "unix:///var/run/docker.sock" # ... ``` ```bash tab="CLI" --providers.swarm.endpoint=unix:///var/run/docker.sock # ... ``` ??? example "Using SSH" Using Docker 18.09+ you can connect Traefik to daemon using SSH. We specify the SSH host and user in Traefik's configuration file. Note that if the server requires public keys for authentication, you must have them accessible for the user running Traefik. ```yaml tab="File (YAML)" providers: swarm: endpoint: "ssh://traefik@192.168.2.5:2022" # ... ``` ```toml tab="File (TOML)" [providers.swarm] endpoint = "ssh://traefik@192.168.2.5:2022" # ... ``` ```bash tab="CLI" --providers.swarm.endpoint=ssh://traefik@192.168.2.5:2022 # ... ``` ??? example "Using HTTP" Using Docker Engine API you can connect Traefik to remote daemon using HTTP. ```yaml tab="File (YAML)" providers: swarm: endpoint: "http://127.0.0.1:2375" # ... ``` ```toml tab="Static Configuration (TOML)" [providers.swarm] endpoint = "http://127.0.0.1:2375" # ... ``` ```bash tab="CLI" --providers.swarm.endpoint=http://127.0.0.1:2375 # ... ``` ??? example "Using TCP" Using Docker Engine API you can connect Traefik to remote daemon using TCP. ```yaml tab="File (YAML)" providers: swarm: endpoint: "tcp://127.0.0.1:2375" # ... ``` ```toml tab="File (TOML)" [providers.swarm] endpoint = "tcp://127.0.0.1:2375" # ... ``` ```bash tab="CLI" --providers.swarm.endpoint=tcp://127.0.0.1:2375 # ... ``` providers: swarm: endpoint: "unix:///var/run/docker.sock" [providers.swarm] endpoint = "unix:///var/run/docker.sock" --providers.swarm.endpoint=unix:///var/run/docker.sock useBindPortIP Traefik routes requests to the IP/port of the matching container. When setting useBindPortIP=true, you tell Traefik to use the IP/Port attached to the container's binding instead of its inner network IP/Port. When used in conjunction with the traefik.http.services..loadbalancer.server.port label (that tells Traefik to route requests to a specific port), Traefik tries to find a binding on port traefik.http.services..loadbalancer.server.port. If it cannot find such a binding, Traefik falls back on the internal network IP of the container, but still uses the traefik.http.services..loadbalancer.server.port that is set in the label. ??? example "Examples of usebindportip in different situations." | port label | Container's binding | Routes to | |--------------------|----------------------------------------------------|----------------| | - | - | IntIP:IntPort | | - | ExtPort:IntPort | IntIP:IntPort | | - | ExtIp:ExtPort:IntPort | ExtIp:ExtPort | | LblPort | - | IntIp:LblPort | | LblPort | ExtIp:ExtPort:LblPort | ExtIp:ExtPort | | LblPort | ExtIp:ExtPort:OtherPort | IntIp:LblPort | | LblPort | ExtIp1:ExtPort1:IntPort1 & ExtIp2:LblPort:IntPort2 | ExtIp2:LblPort | !!! info "" In the above table: - `ExtIp` stands for "external IP found in the binding" - `IntIp` stands for "internal network container's IP", - `ExtPort` stands for "external Port found in the binding" - `IntPort` stands for "internal network container's port." providers: swarm: useBindPortIP: true # ... [providers.swarm] useBindPortIP = true # ... --providers.swarm.useBindPortIP=true # ... defaultRule The defaultRule option defines what routing rule to apply to a container if no rule is defined by a label. It must be a valid Go template, and can use sprig template functions. The container name can be accessed with the ContainerName identifier. The service name can be accessed with the Name identifier. The template has access to all the labels defined on this container with the Labels identifier. providers: swarm: defaultRule: "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)" # ... [providers.swarm] defaultRule = "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)" # ... --providers.swarm.defaultRule='Host(`{{ .Name }}.{{ index .Labels "customLabel"}}`)' # ... ??? info "Default rule and Traefik service" The exposure of the Traefik container, combined with the default rule mechanism, can lead to create a router targeting itself in a loop. In this case, to prevent an infinite loop, Traefik adds an internal middleware to refuse the request if it comes from the same router. constraints The constraints option can be set to an expression that Traefik matches against the container labels to determine whether to create any route for that container. If none of the container labels match the expression, no route for that container is created. If the expression is empty, all detected containers are included. The expression syntax is based on the Label("key", "value"), and LabelRegex("key", "value") functions, as well as the usual boolean logic, as shown in examples below. !!! tip "Constraints key limitations" Note that `traefik.*` is a reserved label namespace for configuration and can not be used as a key for custom constraints. ??? example "Constraints Expression Examples" ```toml # Includes only containers having a label with key `a.label.name` and value `foo` constraints = "Label(`a.label.name`, `foo`)" ``` ```toml # Excludes containers having any label with key `a.label.name` and value `foo` constraints = "!Label(`a.label.name`, `value`)" ``` ```toml # With logical AND. constraints = "Label(`a.label.name`, `valueA`) && Label(`another.label.name`, `valueB`)" ``` ```toml # With logical OR. constraints = "Label(`a.label.name`, `valueA`) || Label(`another.label.name`, `valueB`)" ``` ```toml # With logical AND and OR, with precedence set by parentheses. constraints = "Label(`a.label.name`, `valueA`) && (Label(`another.label.name`, `valueB`) || Label(`yet.another.label.name`, `valueC`))" ``` ```toml # Includes only containers having a label with key `a.label.name` and a value matching the `a.+` regular expression. constraints = "LabelRegex(`a.label.name`, `a.+`)" ``` For additional information, refer to Restrict the Scope of Service Discovery. providers: swarm: constraints: "Label(`a.label.name`,`foo`)" # ... [providers.swarm] constraints = "Label(`a.label.name`,`foo`)" # ... --providers.swarm.constraints=Label(`a.label.name`,`foo`) # ... Routing Configuration When using Docker as a provider, Traefik uses container labels to retrieve its routing configuration. See the list of labels in the dedicated routing section. Routing Configuration with Labels By default, Traefik watches for container level labels on a standalone Docker Engine. When using Docker Compose, labels are specified by the directive labels from the "services" objects. !!! tip "Not Only Docker" Please note that any tool like Nomad, Terraform, Ansible, etc. that is able to define a Docker container with labels can work with Traefik and the Swarm provider. While in Swarm Mode, Traefik uses labels found on services, not on individual containers. Therefore, if you use a compose file with Swarm Mode, labels should be defined in the deploy part of your service. This behavior is only enabled for docker-compose version 3+ (Compose file reference). Port Detection Traefik retrieves the private IP and port of containers from the Docker API. Docker Swarm does not provide any port detection information to Traefik. Therefore, you must specify the port to use for communication by using the label traefik.http.services..loadbalancer.server.port (Check the reference for this label in the routing section for Swarm). Host networking When exposing containers that are configured with host networking, the IP address of the host is resolved as follows: try a lookup of host.docker.internal if the lookup was unsuccessful, try a lookup of host.containers.internal, (Podman equivalent of host.docker.internal) if that lookup was also unsuccessful, fall back to 127.0.0.1 On Linux, for versions of Docker older than 20.10.0, for host.docker.internal to be defined, it should be provided as an extra_host to the Traefik container, using the --add-host flag. For example, to set it to the IP address of the bridge interface ( docker0 by default): --add-host=host.docker.internal:172.17.0.1 IPv4 & IPv6 When using a docker stack that uses IPv6, Traefik will use the IPv4 container IP before its IPv6 counterpart. Therefore, on an IPv6 Docker stack, Traefik will use the IPv6 container IP. Docker API Access Traefik requires access to the docker socket to get its dynamic configuration. You can specify which Docker API Endpoint to use with the directive endpoint. Since the Swarm API is only exposed on the manager nodes, these are the nodes that Traefik should be scheduled on by deploying Traefik with a constraint on the node "role": docker service create \ --constraint=node.role==manager \ #... \ services: traefik: # ... deploy: placement: constraints: - node.role == manager Scheduling Traefik on Worker Nodes Following the guidelines given in the previous section "Docker API Access", if you expose the Docker API through TCP, then Traefik can be scheduled on any node if the TCP socket is reachable. Please consider the security implications by reading the Security Note. A good example can be found on Bret Fisher's repository. Security Note Accessing the Docker API without any restriction is a security concern: If Traefik is attacked, then the attacker might get access to the underlying host. As explained in the Docker Daemon Attack Surface documentation: !!! quote [...] only **trusted** users should be allowed to control your Docker daemon [...] Solutions Expose the Docker socket over TCP or SSH, instead of the default Unix socket file. It allows different implementation levels of the AAA (Authentication, Authorization, Accounting) concepts, depending on your security assessment: Authentication with Client Certificates as described in "Protect the Docker daemon socket." Authorize and filter requests to restrict possible actions with the TecnativaDocker Socket Proxy. Authorization with the Docker Authorization Plugin Mechanism Accounting at networking level, by exposing the socket only inside a Docker private network, only available for Traefik. Accounting at container level, by exposing the socket on a another container than Traefik's. It allows scheduling of Traefik on worker nodes, with only the "socket exposer" container on the manager nodes. Accounting at kernel level, by enforcing kernel calls with mechanisms like SELinux, to only allows an identified set of actions for Traefik's process (or the "socket exposer" process). SSH public key authentication (SSH is supported with Docker > 18.09) Authentication using HTTP Basic authentication through an HTTP proxy that exposes the Docker daemon socket. More Resources and Examples "Paranoid about mounting /var/run/docker.sock?" Traefik and Docker: A Discussion with Docker Captain, Bret Fisher KubeCon EU 2018 Keynote, Running with Scissors, from Liz Rice Don't expose the Docker socket (not even to a container) A thread on Stack Overflow about sharing the /var/run/docker.sock file To DinD or not to DinD Traefik issue GH-4174 about security with Docker socket Inspecting Docker Activity with Socat Letting Traefik run on Worker Nodes Docker Socket Proxy from Tecnativa {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik & Consul Catalog Configuration Example You can enable the Consul Catalog provider as detailed below: providers: consulCatalog: {} [providers.consulCatalog] --providers.consulcatalog=true Attaching tags to services: - traefik.http.routers.my-router.rule=Host(`example.com`) Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.consulCatalog.refreshInterval Defines the polling interval. 15s No providers.consulCatalog.prefix Defines the prefix for Consul Catalog tags defining Traefik labels. traefik No providers.consulCatalog.requireConsistent Forces the read to be fully consistent. See here for more information. false No providers.consulCatalog.exposedByDefault Expose Consul Catalog services by default through Traefik. If set to false, services that do not have a traefik.enable=true tag are ignored from the resulting routing configuration. See here for additional information. true no providers.consulCatalog.defaultRule The Default Host rule for all services. See here for more information. "Host(`{{ normalize .Name }}`)" No providers.consulCatalog.connectAware Enable Consul Connect support. If set to true, Traefik will be enabled to communicate with Connect services. false No providers.consulCatalog.connectByDefault Consider every service as Connect capable by default. If set to true, Traefik will consider every Consul Catalog service to be Connect capable by default. The option can be overridden on an instance basis with the traefik.consulcatalog.connect tag. false No providers.consulCatalog.serviceName Defines the name of the Traefik service in Consul Catalog. "traefik" No providers.consulCatalog.constraints Defines an expression that Traefik matches against the container labels to determine whether to create any route for that container. See here for more information. "" No providers.consulCatalog.namespaces Defines the namespaces to query. See here for more information. "" no providers.consulCatalog.stale Instruct Traefik to use stale consistency for catalog reads. false no providers.consulCatalog.cache Instruct Traefik to use local agent caching for catalog reads. false no providers.consulCatalog.endpoint Defines the Consul server endpoint. - No providers.consulCatalog.endpoint.address Defines the address of the Consul server. 127.0.0.1:8500 no providers.consulCatalog.endpoint.scheme Defines the URI scheme for the Consul server. "" no providers.consulCatalog.endpoint.datacenter Defines the datacenter to use. If not provided in Traefik, Consul uses the default agent datacenter. "" no providers.consulCatalog.endpoint.token Defines a per-request ACL token which overwrites the agent's default token. "" no providers.consulCatalog.endpoint.endpointWaitTime Defines a duration for which a watch can block. If not provided, the agent default values will be used. "" no providers.consulCatalog.endpoint.httpAuth Defines authentication settings for the HTTP client using HTTP Basic Authentication. N/A no providers.consulCatalog.endpoint.httpAuth.username Defines the username to use for HTTP Basic Authentication. "" no providers.consulCatalog.endpoint.httpAuth.password Defines the password to use for HTTP Basic Authentication. "" no providers.consulCatalog.strictChecks Define which Consul Service health checks are allowed to take on traffic. ["passing", "warning"] no providers.consulCatalog.endpoint.tls.ca Defines the path to the certificate authority used for the secure connection to Consul Calatog, it defaults to the system bundle. "" No providers.consulCatalog.endpoint.tls.cert Defines the path to the public certificate used for the secure connection to Consul Calatog. When using this option, setting the key option is required. "" Yes providers.consulCatalog.endpoint.tls.key Defines the path to the private key used for the secure connection to Consul Catalog. When using this option, setting the cert option is required. "" Yes providers.consulCatalog.endpoint.tls.insecureSkipVerify Instructs the provider to accept any certificate presented by Consul Catalog when establishing a TLS connection, regardless of the hostnames the certificate covers. false No providers.consulCatalog.watch When set to true, watches for Consul changes (Consul watches checks). false No requireConsistent Forces the read to be fully consistent. Setting this option can be expensive due to an extra round-trip but prevents ever performing a stale read. For more information, see the Consul documentation on consistency. defaultRule The default host rule for all services. For a given service, if no routing rule was defined by a tag, it is defined by this defaultRule instead. The defaultRule must be set to a valid Go template, and can include sprig template functions. The service name can be accessed with the Name identifier, and the template has access to all the labels (i.e. tags beginning with the prefix) defined on this service. The option can be overridden on an instance basis with the traefik.http.routers.{name-of-your-choice}.rule tag. providers: consulCatalog: defaultRule: "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)" # ... [providers.consulCatalog] defaultRule = "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)" # ... --providers.consulcatalog.defaultRule="Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)" ??? info "Default rule and Traefik service" The exposure of the Traefik container, combined with the default rule mechanism, can lead to create a router targeting itself in a loop. In this case, to prevent an infinite loop, Traefik adds an internal middleware to refuse the request if it comes from the same router. constraints The constraints option can be set to an expression that Traefik matches against the service tags to determine whether to create any route for that service. If none of the service tags match the expression, no route for that service is created. If the expression is empty, all detected services are included. The expression syntax is based on the Tag(`tag`), and TagRegex(`tag`) functions, as well as the usual boolean logic, as shown in examples below. !!! tip "Constraints key limitations" Note that `traefik.*` is a reserved label namespace for configuration and can not be used as a key for custom constraints. ??? example "Constraints Expression Examples" ```toml # Includes only services having the tag `a.tag.name=foo` constraints = "Tag(`a.tag.name=foo`)" ``` ```toml # Excludes services having any tag `a.tag.name=foo` constraints = "!Tag(`a.tag.name=foo`)" ``` ```toml # With logical AND. constraints = "Tag(`a.tag.name`) && Tag(`another.tag.name`)" ``` ```toml # With logical OR. constraints = "Tag(`a.tag.name`) || Tag(`another.tag.name`)" ``` ```toml # With logical AND and OR, with precedence set by parentheses. constraints = "Tag(`a.tag.name`) && (Tag(`another.tag.name`) || Tag(`yet.another.tag.name`))" ``` ```toml # Includes only services having a tag matching the `a\.tag\.t.+` regular expression. constraints = "TagRegex(`a\.tag\.t.+`)" ``` providers: consulCatalog: constraints: "Tag(`a.tag.name`)" # ... [providers.consulCatalog] constraints = "Tag(`a.tag.name`)" # ... --providers.consulcatalog.constraints="Tag(`a.tag.name`)" # ... For additional information, refer to Restrict the Scope of Service Discovery. namespaces The namespaces option defines the namespaces in which the consul catalog services will be discovered. When using the namespaces option, the discovered configuration object names will be suffixed as shown below: @consulcatalog- !!! warning - The namespaces option only works with [Consul Enterprise](https://www.consul.io/docs/enterprise), which provides the [Namespaces](https://www.consul.io/docs/enterprise/namespaces) feature. - One should only define either the `namespaces` option or the `namespace` option. providers: consulCatalog: namespaces: - "ns1" - "ns2" # ... [providers.consulCatalog] namespaces = ["ns1", "ns2"] # ... --providers.consulcatalog.namespaces=ns1,ns2 # ... Routing Configuration See the dedicated section in routing. Traefik & Consul Configuration Example You can enable the Consul provider as detailed below: providers: consul: {} [providers.consul] --providers.consul=true Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.consul.endpoints Defines the endpoint to access Consul. "127.0.0.1:8500" yes providers.consul.rootKey Defines the root key of the configuration. "traefik" yes providers.consul.namespaces Defines the namespaces to query. See here for more information "" no providers.consul.token Defines a token with which to connect to Consul. "" no providers.consul.tls Defines the TLS configuration used for the secure connection to Consul - No providers.consul.tls.ca Defines the path to the certificate authority used for the secure connection to Consul, it defaults to the system bundle. - Yes providers.consul.tls.cert Defines the path to the public certificate used for the secure connection to Consul. When using this option, setting the key option is required. - Yes providers.consul.tls.key Defines the path to the private key used for the secure connection to Consul. When using this option, setting the cert option is required. - Yes providers.consul.tls.insecureSkipVerify Instructs the provider to accept any certificate presented by Consul when establishing a TLS connection, regardless of the hostnames the certificate covers. false No namespaces The namespaces option defines the namespaces to query. When using the namespaces option, the discovered configuration object names will be suffixed as shown below: @consul- !!! warning The namespaces option only works with [Consul Enterprise](https://www.consul.io/docs/enterprise), which provides the [Namespaces](https://www.consul.io/docs/enterprise/namespaces) feature. !!! warning One should only define either the `namespaces` option or the `namespace` option. providers: consul: namespaces: - "ns1" - "ns2" # ... [providers.consul] namespaces = ["ns1", "ns2"] # ... --providers.consul.namespaces=ns1,ns2 # ... Routing Configuration See the dedicated section in routing. Traefik & Nomad Service Discovery Configuration Example You can enable the Nomad provider with as detailed below: providers: nomad: {} [providers.nomad] --providers.nomad=true Attaching tags to services: ... service { name = "myService" tags = [ "traefik.http.routers.my-router.rule=Host(`example.com`)", ] } ... Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.nomad.namespaces Defines the namespaces in which the nomad services will be discovered. "" No providers.nomad.refreshInterval Defines the polling interval. This option is ignored when the watch option is enabled 15s No providers.nomad.watch Enables the watch mode to refresh the configuration on a per-event basis. false No providers.nomad.throttleDuration Defines how often the provider is allowed to handle service events from Nomad. This option is only compatible when the watch option is enabled 0s No providers.nomad.defaultRule The Default Host rule for all services. See here for more information "Host(`{{ normalize .Name }}`)" No providers.nomad.constraints Defines an expression that Traefik matches against the container labels to determine whether to create any route for that container. See here for more information. "" No providers.nomad.exposedByDefault Expose Nomad services by default in Traefik. If set to false, services that do not have a traefik.enable=true tag will be ignored from the resulting routing configuration. See here for additional information true No providers.nomad.allowEmptyServices Instructs the provider to create any servers load balancer defined for Nomad services even when those services are scaled to zero instances. false No providers.nomad.prefix Defines the prefix for Nomad service tags defining Traefik labels. traefik No providers.nomad.stale Instructs Traefik to use stale consistency for Nomad service API reads. See here for more information false No providers.nomad.endpoint.address Defines the Address of the Nomad server. http://127.0.0.1:4646 No providers.nomad.endpoint.region Defines the Nomad region to use. If not provided, the local agent region is used. "" No providers.nomad.endpoint.token Defines a per-request ACL token if Nomad ACLs are enabled. See here for more information "" No providers.nomad.endpoint.endpointWaitTime Defines a duration for which a watch can block. If not provided, the agent default values will be used. "" No providers.nomad.endpoint.tls Defines the TLS configuration used for the secure connection to the Nomad APi. - No providers.nomad.endpoint.tls.ca Defines the path to the certificate authority used for the secure connection to the Nomad API, it defaults to the system bundle. "" No providers.nomad.endpoint.tls.cert Defines the path to the public certificate used for the secure connection to the Nomad API. When using this option, setting the key option is required. '" Yes providers.nomad.endpoint.tls.key Defines the path to the private key used for the secure connection to the Nomad API. When using this option, setting the cert option is required. "" Yes providers.nomad.endpoint.tls.insecureSkipVerify Instructs the provider to accept any certificate presented by Nomad when establishing a TLS connection, regardless of the hostnames the certificate covers. false No namespaces The namespaces option defines the namespaces in which the nomad services will be discovered. When using the namespaces option, the discovered object names will be suffixed as shown below: @nomad- !!! warning One should only define either the `namespaces` option or the `namespace` option. providers: nomad: namespaces: - "ns1" - "ns2" # ... [providers.nomad] namespaces = ["ns1", "ns2"] # ... --providers.nomad.namespaces=ns1,ns2 # ... stale Use stale consistency for Nomad service API reads. !!! note "" This makes reads very fast and scalable at the cost of a higher likelihood of stale values. For more information, see the Nomad [documentation on consistency](https://www.nomadproject.io/api-docs#consistency-modes). providers: nomad: stale: true # ... [providers.nomad] stale = true # ... --providers.nomad.stale=true # ... token Token is used to provide a per-request ACL token, if Nomad ACLs are enabled. The appropriate ACL privilege for this token is 'read-job', as outlined in the Nomad documentation on ACL. providers: nomad: endpoint: token: test # ... [providers.nomad] [providers.nomad.endpoint] token = "test" # ... --providers.nomad.endpoint.token=test # ... defaultRule The default host rule for all services. For a given service, if no routing rule was defined by a tag, it is defined by this defaultRule instead. The defaultRule must be set to a valid Go template, and can include sprig template functions. The service name can be accessed with the Name identifier, and the template has access to all the labels (i.e. tags beginning with the prefix) defined on this service. The option can be overridden on an instance basis with the traefik.http.routers.{name-of-your-choice}.rule tag. providers: nomad: defaultRule: "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)" # ... [providers.nomad] defaultRule = "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)" # ... --providers.nomad.defaultRule='Host(`{{ .Name }}.{{ index .Labels "customLabel"}}`)' # ... ??? info "Default rule and Traefik service" The exposure of the Traefik container, combined with the default rule mechanism, can lead to create a router targeting itself in a loop. In this case, to prevent an infinite loop, Traefik adds an internal middleware to refuse the request if it comes from the same router. constraints The constraints option can be set to an expression that Traefik matches against the service tags to determine whether to create any route for that service. If none of the service tags match the expression, no route for that service is created. If the expression is empty, all detected services are included. The expression syntax is based on the Tag(`tag`), and TagRegex(`tag`) functions, as well as the usual boolean logic, as shown in examples below. !!! tip "Constraints key limitations" Note that `traefik.*` is a reserved label namespace for configuration and can not be used as a key for custom constraints. ??? example "Constraints Expression Examples" ```toml # Includes only services having the tag `a.tag.name=foo` constraints = "Tag(`a.tag.name=foo`)" ``` ```toml # Excludes services having any tag `a.tag.name=foo` constraints = "!Tag(`a.tag.name=foo`)" ``` ```toml # With logical AND. constraints = "Tag(`a.tag.name`) && Tag(`another.tag.name`)" ``` ```toml # With logical OR. constraints = "Tag(`a.tag.name`) || Tag(`another.tag.name`)" ``` ```toml # With logical AND and OR, with precedence set by parentheses. constraints = "Tag(`a.tag.name`) && (Tag(`another.tag.name`) || Tag(`yet.another.tag.name`))" ``` ```toml # Includes only services having a tag matching the `a\.tag\.t.+` regular expression. constraints = "TagRegex(`a\.tag\.t.+`)" ``` providers: nomad: constraints: "Tag(`a.tag.name`)" # ... [providers.nomad] constraints = "Tag(`a.tag.name`)" # ... --providers.nomad.constraints="Tag(`a.tag.name`)" # ... For additional information, refer to Restrict the Scope of Service Discovery. Routing Configuration See the dedicated section in routing. Traefik & Knative The Traefik Knative provider integrates with Knative Serving to provide advanced traffic management and routing capabilities for serverless applications. Knative is a Kubernetes-based platform that enables serverless workloads with features like scale-to-zero, automatic scaling, and revision management. The provider watches Knative Ingress resources and automatically configures Traefik routing rules, enabling seamless integration between Traefik's networking capabilities and Knative's serverless platform. Requirements {% include-markdown "includes/kubernetes-requirements.md" %} Install/update the Knative CRDs. kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.20.0/serving-crds.yaml Install the Knative Serving core components. kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.20.0/serving-core.yaml Update the config-network configuration to use the Traefik ingress class. kubectl patch configmap/config-network \ -n knative-serving \ --type merge \ -p '{"data":{"ingress.class":"traefik.ingress.networking.knative.dev"}}' Add a custom domain to your Knative configuration (Optional). kubectl patch configmap config-domain \ -n knative-serving \ --type='merge' \ -p='{"data":{"example.com":""}}' Install/update the Traefik RBAC. kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.8/docs/content/reference/dynamic-configuration/kubernetes-knative-rbac.yml Configuration Example As this provider is an experimental feature, it needs to be enabled in the experimental and in the provider sections of the configuration. You can enable the Knative provider as detailed below: experimental: knative: true providers: knative: {} [experimental.knative] [providers.knative] --experimental.knative=true --providers.knative=true The Knative provider uses the Knative API to retrieve its routing configuration. The provider then watches for incoming Knative events and derives the corresponding dynamic configuration from it. Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.knative.endpoint Server endpoint URL. More information here. providers.knative.token Bearer token used for the Kubernetes client configuration. providers.knative.certAuthFilePath Path to the certificate authority file. Used for the Kubernetes client configuration. providers.knative.namespaces Array of namespaces to watch. If left empty, watch all namespaces. providers.knative.labelSelector Allow filtering Knative Ingress objects using label selectors. providers.knative.throttleDuration Minimum amount of time to wait between two Kubernetes events before producing a new configuration. This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration. If empty, every event is caught. 0 providers.knative.privateEntrypoints Entrypoint names used to expose the Ingress privately. If empty local Ingresses are skipped. providers.knative.privateService Kubernetes service used to expose the networking controller privately. providers.knative.privateService.desc Name of the private Kubernetes service. providers.knative.privateService.namespace Namespace of the private Kubernetes service. providers.knative.publicEntrypoints Entrypoint names used to expose the Ingress publicly. If empty an Ingress is exposed on all entrypoints. providers.knative.publicService Kubernetes service used to expose the networking controller publicly. providers.knative.publicService.desc Name of the public Kubernetes service. providers.knative.publicService.namespace Namespace of the public Kubernetes service. endpoint The Kubernetes server endpoint URL. When deployed into Kubernetes, Traefik reads the environment variables KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT or KUBECONFIG to construct the endpoint. The access token is looked up in /var/run/secrets/kubernetes.io/serviceaccount/token and the SSL CA certificate in /var/run/secrets/kubernetes.io/serviceaccount/ca.crt. Both are mounted automatically when deployed inside Kubernetes. The endpoint may be specified to override the environment variable values inside a cluster. When the environment variables are not found, Traefik tries to connect to the Knative API server with an external-cluster client. In this case, the endpoint is required. Specifically, it may be set to the URL used by kubectl proxy to connect to a Knative cluster using the granted authentication and authorization of the associated kubeconfig. providers: knative: endpoint: "http://localhost:8080" # ... [providers.knative] endpoint = "http://localhost:8080" # ... --providers.knative.endpoint=http://localhost:8080 Routing Configuration See the dedicated section in routing. {% include-markdown "includes/traefik-for-business-applications.md" %} Kubernetes Custom Resources Traefik provides some Kubernetes Custom Resources, such as IngressRoute, Middleware, etc. When using KubernetesCRD as a provider, Traefik uses Custom Resource Definition to retrieve its routing configuration. Traefik Custom Resource Definitions are listed below. When Traefik is installed using the Helm Chart, by default, the provider kubernetesCRD is enabled. Requirements When you install Traefik without using the Helm Chart, or when you are upgrading the stack using Helm, ensure that you satisfy the following requirements: Add/update all the Traefik resources definitions Add/update the RBAC for the Traefik custom resources # Install Traefik Resource Definitions: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.8/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml # Install RBAC for Traefik: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.8/docs/content/reference/dynamic-configuration/kubernetes-crd-rbac.yml Configuration Example You can enable the kubernetesCRD provider as detailed below: providers: kubernetesCRD: {} [providers.kubernetesCRD] --providers.kubernetescrd=true ## Values file providers: kubernetesCRD: enabled: true Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.kubernetesCRD.endpoint Server endpoint URL. More information here. "" No providers.kubernetesCRD.token Bearer token used for the Kubernetes client configuration (not needed for in-cluster client). It accepts either a token value or a file path to the token. "" No providers.kubernetesCRD.certAuthFilePath Path to the certificate authority file. Used for the Kubernetes client configuration. "" No providers.kubernetesCRD.namespaces Array of namespaces to watch. If left empty, watch all namespaces. [] No providers.kubernetesCRD.labelSelector Allow filtering on specific resource objects only using label selectors. Only to Traefik Custom Resources (they all must match the filter). No effect on Kubernetes Secrets, EndpointSlices and Services. See label-selectors for details. "" No providers.kubernetesCRD.ingressClass Value of spec.ingressClassName field (or the deprecated kubernetes.io/ingress.class annotation) that identifies resource objects to be processed. If empty, resources missing the field/annotation, having an empty value, or the value traefik are processed. The spec.ingressClassName field takes precedence over the annotation. "" No providers.kubernetesCRD.throttleDuration Minimum amount of time to wait between two Kubernetes events before producing a new configuration. This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration. If empty, every event is caught. 0s No providers.kubernetesCRD.allowEmptyServices Allows creating a route to reach a service that has no endpoint available. It allows Traefik to handle the requests and responses targeting this service (applying middleware or observability operations) before returning a 503 HTTP Status. false No providers.kubernetesCRD.allowCrossNamespace Allows the IngressRoutes to reference resources in namespaces other than theirs. false No providers.kubernetesCRD.allowExternalNameServices Allows the IngressRoutes to reference ExternalName services. false No providers.kubernetesCRD.crossProviderNamespaces List of namespaces from which IngressRoute, IngressRouteTCP, IngressRouteUDP, and TraefikService are allowed to declare cross-provider references (e.g. myservice@file). When unset, all namespaces are allowed. When set to [], every cross-provider reference is rejected. [] No providers.kubernetesCRD.nativeLBByDefault Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik for every IngressRoute by default. It can be overridden in the Service. false No providers.kubernetesCRD.disableClusterScopeResources Prevent from discovering cluster scope resources ( IngressClass and Nodes). By doing so, it alleviates the requirement of giving Traefik the rights to look up for cluster resources. Furthermore, Traefik will not handle IngressRoutes with IngressClass references, therefore such Ingresses will be ignored (please note that annotations are not affected by this option). This will also prevent from using the NodePortLB options on services. false No providers.kubernetesCRD.defaultTLSResourcesNamespace Restricts the namespace in which the TLSOption and the TLSStore named default can be defined. More information here. "" No providers.kubernetesCRD.safeNaming Enables collision-safe naming for the routers, middlewares and services generated by the provider. When unset, the legacy naming scheme is used and a warning is logged on startup. More information here. false No endpoint The Kubernetes server endpoint URL. When deployed into Kubernetes, Traefik reads the environment variables KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT or KUBECONFIG to construct the endpoint. The access token is looked up in /var/run/secrets/kubernetes.io/serviceaccount/token and the SSL CA certificate in /var/run/secrets/kubernetes.io/serviceaccount/ca.crt. Both are mounted automatically when deployed inside Kubernetes. The endpoint may be specified to override the environment variable values inside a cluster. When the environment variables are not found, Traefik tries to connect to the Kubernetes API server with an external-cluster client. In this case, the endpoint is required. Specifically, it may be set to the URL used by kubectl proxy to connect to a Kubernetes cluster using the granted authentication and authorization of the associated kubeconfig. providers: kubernetesCRD: endpoint: "http://localhost:8080" # ... [providers.kubernetesCRD] endpoint = "http://localhost:8080" # ... --providers.kubernetesCRD.endpoint=http://localhost:8080 defaultTLSResourcesNamespace The TLSOption and the TLSStore named default are cluster-wide, whatever the namespace they are defined in: the former holds the TLS enforcement policy of every router that does not reference a TLSOption explicitly, the latter holds the default certificate served by every entry point. This option allows the cluster operator to reserve their definition to a namespace they control. When the option is not set, a TLSOption or a TLSStore named default is taken into account whatever its namespace, which is the default and backward compatible behavior. When it is set to a namespace, only the resources named default in this namespace are taken into account. !!! warning "Ignored resources" A `TLSOption` or a `TLSStore` named `default` defined outside of the configured namespace is ignored, and cannot be referenced under its namespaced name either. For a `TLSStore`, this also applies to the certificates it defines. providers: kubernetesCRD: defaultTLSResourcesNamespace: traefik # ... [providers.kubernetesCRD] defaultTLSResourcesNamespace = "traefik" # ... --providers.kubernetesCRD.defaultTLSResourcesNamespace=traefik safeNaming By default, the Kubernetes CRD provider generates the names of the routers, middlewares and services it builds by joining the namespace and the name of the object they come from, which can produce the same name for two distinct objects, one silently replacing the other. safeNaming enables collision-safe naming instead: generated names are derived from the identity of the object they come from, and Kubernetes Services referenced from several parents (a route with several services, or a Weighted/Mirroring/HighestRandomWeight TraefikService) are scoped to their parent instead of being shared by identity. Value Behavior not set Current naming is used (default, backward compatible), and a warning is logged on startup. true Collision-safe naming is used. false Current naming is used, and the startup warning is silenced. !!! warning "Startup warning" When `safeNaming` is left unset, a warning is logged on startup, since the current naming scheme is collision-prone. It is recommended to explicitly set this option, to `true` on new setups, or to `false` to keep the current behavior and silence the warning. When safeNaming is enabled, the generated names are no longer normalized: their components are joined with a _ separator, which cannot appear in a Kubernetes namespace or name, and the ones generated for a route are derived from the route index instead of its rule. For example, for a Kubernetes Service named whoami and an IngressRoute named test.route, both in the default namespace: default-whoami-80 -> default_whoami_80 default-test-route-6b204d94623b3df4370c -> default_test.route_0 The services generated for the Kubernetes Services referenced by a TraefikService (weighted, mirroring or highest random weight), or by a route with several services, are named after the parent declaring the reference, followed by the index of the reference, and the namespace, the name and the port of the referenced Kubernetes Service: default-whoami-80 -> default_wrr1_wrr_1_default_whoami_80 Each of these references carries its own options ( serversTransport, scheme, sticky, healthCheck, ...), which were not part of the generated name before: two references to the same Kubernetes Service with different options were collapsed into a single service, and the last one built silently won. With safeNaming enabled, they are distinct services, which also means that the servers of a Kubernetes Service referenced from several parents are health checked once per reference, instead of once for all of them. !!! warning "Observability" These names are user-visible: they appear in the dashboard and API, in the access logs `RouterName` and `ServiceName` fields, and in the `router` and `service` labels of the metrics. Dashboards, alerting rules, and log queries that match on Kubernetes CRD router, middleware or service names must be updated accordingly when `safeNaming` is enabled. !!! warning "Cross-provider references" The generated names are also the ones the other providers reference. When `safeNaming` is enabled, a namespaced `@kubernetescrd` reference, such as the `traefik.ingress.kubernetes.io/router.middlewares` annotation on an Ingress, must be of form `namespace_name@kubernetescrd` instead of `namespace-name@kubernetescrd`. A reference left in the legacy form is not resolved, and the routers using it are not created. For a TLS options reference, the TLS handshake is refused on the host names served by those routers. providers: kubernetesCRD: safeNaming: true # ... [providers.kubernetesCRD] safeNaming = true # ... --providers.kubernetesCRD.safeNaming=true Routing Configuration Traefik CRDs are building blocks that you can assemble according to your needs. The available custom resources are in the table below: Resource Purpose IngressRoute HTTP Routing Middleware Tweaks the HTTP requests before they are sent to your service TraefikService Abstraction for HTTP loadbalancing/mirroring TLSOptions Allows configuring some parameters of the TLS connection TLSStores Allows configuring the default TLS store ServersTransport Allows configuring the transport between Traefik and the backends IngressRouteTCP TCP Routing MiddlewareTCP Tweaks the TCP requests before they are sent to your service ServersTransportTCP Allows configuring the transport between Traefik and the backends IngressRouteUDP UDP Routing Particularities The usage of name and namespace to refer to another Kubernetes resource. The usage of secret for sensitive data (TLS certificates and credentials). Full Example For additional information on exposing services with Kubernetes, refer to the Kubernetes guide. {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik & Kubernetes with Gateway API The Kubernetes Gateway provider is a Traefik implementation of the Gateway API specification from the Kubernetes Special Interest Groups (SIGs). This provider supports Standard version v1.6.3 of the Gateway API specification. It fully supports all HTTPRoute core and some extended features, like BackendTLSPolicy, GRPCRoute, ListenerSet, and TLSRoute resources from the Standard channel, as well as TCPRoute from the Experimental channel. For more details, check out the conformance report. !!! info "Using The Helm Chart" When using the Traefik [Helm Chart](../../../../getting-started/kubernetes.md#install-traefik), the RBAC (Role-Based Access Control) are automatically managed for you. Requirements {% include-markdown "includes/kubernetes-requirements.md" %} Install/update the Kubernetes Gateway API CRDs. # Install Gateway API CRDs from the Standard channel. kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.3/standard-install.yaml !!! warning " experimentalChannel requires the Experimental channel CRDs" The `experimentalChannel` option makes Traefik watch `TCPRoute` and `TLSRoute` resources, which the Standard channel CRDs do not provide. Enabling it without installing the Experimental channel CRDs (`experimental-install.yaml`) prevents the Kubernetes Gateway provider from starting: no Gateway API resource is served at all, not only `TCPRoute` and `TLSRoute`. Traefik keeps running and the other providers are unaffected. If you are not using the Helm Chart, install/update the Traefik RBAC for Gateway API. # Install Traefik RBACs for Gateway API. kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.8/docs/content/reference/dynamic-configuration/kubernetes-gateway-rbac.yml Configuration Example You can enable the kubernetesGateway provider as detailed below: providers: kubernetesGateway: {} # ... [providers.kubernetesGateway] # ... --providers.kubernetesgateway=true ## Values file providers: kubernetesGateway: enabled: true Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.kubernetesGateway.endpoint Server endpoint URL. More information here. "" No providers.kubernetesGateway.experimentalChannel Toggles support for the Experimental Channel resources (Gateway API release channels documentation). false No providers.kubernetesGateway.token Bearer token used for the Kubernetes client configuration. Accepts either the token value directly or a path to a file containing the token. "" No providers.kubernetesGateway.certAuthFilePath Path to the certificate authority file. Used for the Kubernetes client configuration. "" No providers.kubernetesGateway.namespaces Array of namespaces to watch. If left empty, watch all namespaces. [] No providers.kubernetesGateway.gatewayClass Name of the GatewayClass to watch for. If left empty, Traefik processes all GatewayClass objects. Use it to bind a Traefik instance to a dedicated GatewayClass. "" No providers.kubernetesGateway.gateways Scopes the provider to specific Gateways. [] No providers.kubernetesGateway.gateways[0].name Gateway name. "" No providers.kubernetesGateway.gateways[0].namespace Gateway namespace. "" No providers.kubernetesGateway.throttleDuration Minimum amount of time to wait between two Kubernetes events before producing a new configuration. This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration. If empty, every event is caught. 0s No providers.kubernetesGateway.nativeLBByDefault Defines whether to use Native Kubernetes load-balancing mode by default. For more information, please check out the traefik.io/service.nativelb service annotation documentation. false No providers.kubernetesGateway.retryMaxRequestBodyBytes Defines the maximum request body size (in bytes) buffered for HTTPRoute retries. If negative, the limit is disabled. A request with a larger body is forwarded without retry. 2097152 No providers.kubernetesGateway. statusAddress.hostname Hostname copied to the Gateway status.addresses. "" No providers.kubernetesGateway. statusAddress.ip IP address copied to the Gateway status.addresses, and currently only supports one IP value (IPv4 or IPv6). "" No providers.kubernetesGateway. statusAddress.service.namespace The namespace of the Kubernetes service to copy status addresses from. When using third parties tools like External-DNS, this option can be used to copy the service loadbalancer.status (containing the service's endpoints IPs) to the Gateway status.addresses. "" No providers.kubernetesGateway. statusAddress.service.name The name of the Kubernetes service to copy status addresses from. When using third parties tools like External-DNS, this option can be used to copy the service loadbalancer.status (containing the service's endpoints IPs) to the Gateway status.addresses. "" No providers.kubernetesGateway.crossProviderNamespaces List of namespaces from which Gateway API routes ( HTTPRoute, TCPRoute, TLSRoute) are allowed to declare a backendRef of kind TraefikService. When unset, all namespaces are allowed. When set to [], every such backendRef is rejected and the route is dropped. [] No providers.kubernetesGateway.qps Defines the maximum QPS to the Kubernetes API server. Setting this to a negative value will disable client-side ratelimiting. 50 No providers.kubernetesGateway.burst Defines the maximum burst of requests to the Kubernetes API server. 100 No endpoint The Kubernetes server endpoint URL. When deployed into Kubernetes, Traefik reads the environment variables KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT or KUBECONFIG to construct the endpoint. The access token is looked up in /var/run/secrets/kubernetes.io/serviceaccount/token and the SSL CA certificate in /var/run/secrets/kubernetes.io/serviceaccount/ca.crt. Both are mounted automatically when deployed inside Kubernetes. The endpoint may be specified to override the environment variable values inside a cluster. When the environment variables are not found, Traefik tries to connect to the Kubernetes API server with an external-cluster client. In this case, the endpoint is required. Specifically, it may be set to the URL used by kubectl proxy to connect to a Kubernetes cluster using the granted authentication and authorization of the associated kubeconfig. providers: kubernetesGateway: endpoint: "http://localhost:8080" # ... [providers.kubernetesGateway] endpoint = "http://localhost:8080" # ... --providers.kubernetesgateway.endpoint=http://localhost:8080 Routing Configuration See the dedicated section in routing. !!! tip "Routing Configuration" When using the Kubernetes Gateway API provider, Traefik uses the Gateway API CRDs to retrieve its routing configuration. Check out the Gateway API concepts [documentation](https://gateway-api.sigs.k8s.io/concepts/api-overview/), and the dedicated [routing section](../../../../reference/routing-configuration/kubernetes/gateway-api.md) in the Traefik documentation. {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik & Ingresses with NGINX Annotations This provider is a Kubernetes Ingress controller that manages access to cluster services by supporting the Ingress specification. It also supports many of the ingress-nginx annotations on Ingresses, enabling teams to migrate from NGINX Ingress Controller to Traefik with minimal configuration changes. !!! warning "NGINX Ingress Controller Retirement" The Kubernetes NGINX Ingress Controller project has announced its retirement in **March 2026** and will no longer receive updates or security patches. Traefik provides a migration path by supporting NGINX annotations, allowing you to transition your workloads without rewriting all your Ingress configurations. **→ See the [NGINX to Traefik Migration Guide](../../../../migrate/nginx-to-traefik.md) for step-by-step instructions.** For more information about the NGINX Ingress Controller retirement, see the [official Kubernetes blog announcement](https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement). Requirements When you install Traefik without using the Helm Chart, ensure that you add/update the RBAC for the Traefik Kubernetes Ingress NGINX provider. !!! note "Additional RBAC for Namespace Selector" When using the `watchNamespaceSelector` option, Traefik requires permissions to list and watch namespaces. These permissions are included in the RBAC configuration below. # Install RBAC for Traefik Ingress NGINX provider: kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.8/docs/content/reference/dynamic-configuration/kubernetes-ingress-nginx-rbac.yml Ingress Discovery This provider discovers all Ingresses in the cluster by default, which may lead to duplicated routers if you are also using the standard Kubernetes Ingress provider. Best Practices: Use IngressClass to specify which Ingresses should be handled by this provider Configure watchNamespace to limit discovery to a single namespace Use watchNamespaceSelector to target Ingresses based on namespace labels IngressClass Selection Logic By default, the provider selects all IngressClasses whose spec.controller matches controllerClass (default: k8s.io/ingress-nginx) and picks up every Ingress referencing any of them. Setting ingressClassByName: true adds a second inclusion path: IngressClasses whose name matches ingressClass are also picked up, even if their spec.controller does not match controllerClass. It does not narrow down the controller-based selection — both paths apply independently. Configuration Example You can enable the Kubernetes Ingress NGINX provider as detailed below: providers: kubernetesIngressNGINX: # Namespace discovery watchNamespace: "default" # OR use namespace selector (mutually exclusive with watchNamespace) # watchNamespaceSelector: "environment=production" # IngressClass configuration ingressClass: "nginx" controllerClass: "k8s.io/ingress-nginx" watchIngressWithoutClass: false ingressClassByName: false globalAuthURL: "http://foo.com/auth" proxyConnectTimeout: 60 proxyReadTimeout: 60 proxySendTimeout: 60 proxyRequestBuffering: false clientBodyBufferSize: "16384" # 16k proxyBuffering: false proxyBodySize: "1048576" # 1m proxyBufferSize: "8192" # 8k proxyBuffersNumber: 4 upstreamKeepaliveTimeout: 60 customHTTPErrors: - "404" - "503" allowCrossNamespaceResources: true allowSnippetAnnotations: false globalAllowedResponseHeaders: - "X-Custom-Header1" - "X-Custom-Header2" ipAllowListStrategy: depth: 2 strictValidatePathType: false [providers.kubernetesIngressNGINX] # Namespace discovery watchNamespace = "default" # OR use namespace selector (mutually exclusive with watchNamespace) # watchNamespaceSelector = "environment=production" # IngressClass configuration ingressClass = "nginx" controllerClass = "k8s.io/ingress-nginx" watchIngressWithoutClass = false ingressClassByName = false globalAuthURL = "http://foo.com/auth" proxyConnectTimeout = 60 proxyReadTimeout = 60 proxySendTimeout = 60 proxyRequestBuffering = false clientBodyBufferSize = "16384" # 16k proxyBuffering = false proxyBodySize = "1048576" # 1m proxyBufferSize = "8192" # 8k proxyBuffersNumber = 4 upstreamKeepaliveTimeout = 60 customHTTPErrors = ["404", "503"] allowCrossNamespaceResources = true allowSnippetAnnotations = false globalAllowedResponseHeaders = ["X-Custom-Header1", "X-Custom-Header2"] strictValidatePathType = false [providers.kubernetesIngressNGINX.ipAllowListStrategy] depth = 2 --providers.kubernetesingressnginx=true --providers.kubernetesingressnginx.watchnamespace=default --providers.kubernetesingressnginx.ingressclass=nginx --providers.kubernetesingressnginx.controllerclass=k8s.io/ingress-nginx --providers.kubernetesingressnginx.watchingresswithoutclass=false --providers.kubernetesingressnginx.ingressclassbyname=false --providers.kubernetesingressnginx.globalauthurl=http://foo.com/auth --providers.kubernetesingressnginx.proxyconnecttimeout=60 --providers.kubernetesingressnginx.proxyreadtimeout=60 --providers.kubernetesingressnginx.proxysendtimeout=60 --providers.kubernetesingressnginx.proxyrequestbuffering=false --providers.kubernetesingressnginx.clientbodybuffersize=16384 # 16k --providers.kubernetesingressnginx.proxybuffering=false --providers.kubernetesingressnginx.proxybodysize=1048576 # 1m --providers.kubernetesingressnginx.proxybuffersize=8192 # 8k --providers.kubernetesingressnginx.proxybuffersnumber=4 --providers.kubernetesingressnginx.upstreamkeepalimetimeout=60 --providers.kubernetesingressnginx.customhttperrors=404,503 --providers.kubernetesingressnginx.allowCrossNamespaceResources=true --providers.kubernetesingressnginx.allowsnippetannotations=false --providers.kubernetesingressnginx.globalAllowedResponseHeaders=X-Custom-Header1,X-Custom-Header2 --providers.kubernetesingressnginx.ipallowliststrategy.depth=2 --providers.kubernetesingressnginx.strictvalidatepathtype=false providers: kubernetesIngressNginx: # -- Enable Kubernetes Ingress NGINX provider enabled: true # Namespace discovery # -- Namespace the controller watches for updates to Kubernetes objects # When using rbac.namespaced, it will watch helm release namespace and namespaces listed in this array namespaces: - default # OR use namespace selector (mutually exclusive with namespaces) # namespaceSelector: "environment=production" # IngressClass configuration # -- Name of the ingress class this controller satisfies ingressClass: "nginx" # -- Ingress Class Controller value this controller satisfies controllerClass: "k8s.io/ingress-nginx" # -- Define if Ingress Controller should also watch for Ingresses without an IngressClass or the annotation specified watchIngressWithoutClass: false # -- Define if Ingress Controller should watch for Ingress Class by Name together with Controller Class ingressClassByName: false This provider watches for incoming Ingress events and automatically translates NGINX annotations into Traefik's dynamic configuration, creating the corresponding routers, services, middlewares, and other components needed to route traffic to your cluster services. Configuration Options Field Description Default Required providers.providers ThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers. kubernetesIngressNGINX. endpoint Server endpoint URL. More information here. "" No providers. kubernetesIngressNGINX. token Bearer token used for the Kubernetes client configuration. "" No providers. kubernetesIngressNGINX. certAuthFilePath Path to the certificate authority file. Used for the Kubernetes client configuration. "" No providers. kubernetesIngressNGINX. throttleDuration Minimum amount of time to wait between two Kubernetes events before producing a new configuration. This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration. If empty, every event is caught. 0s No providers. kubernetesIngressNGINX. globalAuthURL URL to the service that provides authentication for all the locations. Per-ingress auth-url annotation has precedence over this option. "" No providers. kubernetesIngressNGINX. watchNamespace Namespace the controller watches for updates to Kubernetes objects. All namespaces are watched if this parameter is left empty. "" No providers. kubernetesIngressNGINX. watchNamespaceSelector Selector selects namespaces the controller watches for updates to Kubernetes objects. "" No providers. kubernetesIngressNGINX. ingressClass Name of the IngressClass this controller handles. When ingressClassByName is true, IngressClasses with this name are included in discovery regardless of their spec.controller value. "nginx" No providers. kubernetesIngressNGINX. controllerClass Ingress Class Controller value this controller satisfies. "k8s.io/ingress-nginx" No providers. kubernetesIngressNGINX. watchIngressWithoutClass Define if Ingress Controller should also watch for Ingresses without an IngressClass or the annotation specified. false No providers. kubernetesIngressNGINX. ingressClassByName When true, any IngressClass whose name matches ingressClass is include in discovery, even if its spec.controller does not match controllerClass. This is evaluated alongside the controller-based selection, not instead of it. false No providers. kubernetesIngressNGINX. publishService Service fronting the Ingress controller. Takes the form namespace/name. "" No providers. kubernetesIngressNGINX. publishStatusAddress Customized address (or addresses, separated by comma) to set as the load-balancer status of Ingress objects this controller satisfies. "" No providers. kubernetesIngressNGINX. defaultBackendService Service used to serve HTTP requests not matching any known server name (catch-all). Takes the form 'namespace/name'. "" No providers. kubernetesIngressNGINX. disableSvcExternalName Disable support for Services of type ExternalName. false No providers. kubernetesIngressNGINX. proxyConnectTimeout Amount of time to wait until a connection to a server can be established. The value is unitless and in seconds. This is used as the global connection timeout when no ingress-specific timeout is configured. An ingress-specific timeout can be configured using nginx.ingress.kubernetes.io/proxy-connect-timeout annotation. 60 No providers. kubernetesIngressNGINX. proxyReadTimeout Amount of time between two successive read operations. The value is unitless and in seconds. This is used as the global read timeout when no ingress-specific timeout is configured. An ingress-specific timeout can be configured using nginx.ingress.kubernetes.io/proxy-read-timeout annotation. 60 No providers. kubernetesIngressNGINX. proxySendTimeout Amount of time between two successive write operations. The value is unitless and in seconds. This is used as the global send timeout when no ingress-specific timeout is configured. An ingress-specific timeout can be configured using nginx.ingress.kubernetes.io/proxy-send-timeout annotation. 60 No providers. kubernetesIngressNGINX. proxyrequestbuffering Defines whether request buffering is enabled by default for all ingresses. false No providers. kubernetesIngressNGINX. clientBodyBufferSize Default buffer size for reading client request body in bytes. 16384 No providers. kubernetesIngressNGINX. proxybuffering Defines whether response buffering is enabled by default for all ingresses. false No providers. kubernetesIngressNGINX. proxyBodySize Default maximum size of a client request body in bytes. 1048576 No providers. kubernetesIngressNGINX. proxyBufferSize Default buffer size for reading the response body in bytes. 8192 No providers. kubernetesIngressNGINX. proxyBuffersNumber Default number of buffers for reading a response. 4 No providers. kubernetesIngressNGINX. proxyNextUpstream Defines in which cases a request should be retried. Accepted values are a space-separated list of: error, timeout, http_XXX (e.g. http_502), non_idempotent, and off (disables retry). This is used as the global proxy-next-upstream configuration when no ingress-specific value is configured. An ingress-specific configuration can be set using nginx.ingress.kubernetes.io/proxy-next-upstream annotation. "error timeout" No providers. kubernetesIngressNGINX. proxyNextUpstreamTries Limits the number of possible tries if the backend server does not reply. 0 means unlimited tries, which is capped to the number of available servers. This is used as the global retry count configuration when no ingress-specific value is configured. An ingress-specific retry limit can be set using nginx.ingress.kubernetes.io/proxy-next-upstream-tries annotation. 3 No providers. kubernetesIngressNGINX. proxyNextUpstreamTimeout Limits the total elapsed time to retry the request if the backend server does not reply. Timeout value is unitless and in seconds. 0 means no timeout. This is used as the global retry timeout when no ingress-specific value is configured. An ingress-specific retry timeout can be set using nginx.ingress.kubernetes.io/proxy-next-upstream-timeout annotation. 0 No providers. kubernetesIngressNGINX. upstreamKeepaliveTimeout Defines the idle timeout for keep-alive connections to upstream servers. The value is unitless and in seconds. 60 No providers. kubernetesIngressNGINX. customHTTPErrors Defines which status should result in calling the default backend to return an error page. [] No providers. kubernetesIngressNGINX. allowCrossNamespaceResources Allow Ingress to reference resources (e.g. ConfigMaps, Secrets) in different namespaces. false No providers. kubernetesIngressNGINX. globalAllowedResponseHeaders List of allowed response headers inside the custom headers annotations. It is required to configure it for the custom headers annotations to take effect. [] No providers. kubernetesIngressNGINX. ipAllowListStrategy Defines the IP strategy to determine the client IP for allowlist-source-range and whitelist-source-range annotations. When set, the strategy is applied to every generated IPAllowList middleware. - No providers. kubernetesIngressNGINX. ipAllowListStrategy. depth Number of trusted proxy hops to skip when extracting the client IP from the X-Forwarded-For header. 0 disables depth-based extraction. 0 No providers. kubernetesIngressNGINX. ipAllowListStrategy. excludedIPs List of IPs to exclude when scanning the X-Forwarded-For header to find the client IP. [] No providers. kubernetesIngressNGINX. ipAllowListStrategy. ipv6Subnet IPv6 subnet size used to group IPv6 addresses when checking the allow list. 0 disables subnet grouping. 0 No providers. kubernetesIngressNGINX. httpentrypoint Defines the EntryPoint to use for HTTP requests. "" No providers. kubernetesIngressNGINX. httpsentrypoint Defines the EntryPoint to use for HTTPS requests. "" No providers. kubernetesIngressNGINX. disableNonTLSRouters Disables the creation of non-TLS routers for Ingress resources. Cannot be used together with httpEntryPoint. More information here. false No providers. kubernetesIngressNGINX. strictValidatePathType Defines whether to reject the entire ingress when any path contains regex characters and pathType is Prefix or Exact. true No disableNonTLSRouters Disables the creation of non-TLS routers for Ingress resources managed by this provider. The HTTP entryPoint itself is unaffected and keeps serving other providers. !!! note When `disableNonTLSRouters` is `true`, also set `httpsEntryPoint` if you want Ingress traffic served only on the HTTPS entryPoint. Otherwise the TLS routers may still bind to the default entryPoints (including non-TLS ones such as `web`). endpoint The Kubernetes server endpoint URL. When deployed into Kubernetes, Traefik reads the environment variables KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT or KUBECONFIG to construct the endpoint. The access token is looked up in /var/run/secrets/kubernetes.io/serviceaccount/token and the SSL CA certificate in /var/run/secrets/kubernetes.io/serviceaccount/ca.crt. Both are mounted automatically when deployed inside Kubernetes. The endpoint may be specified to override the environment variable values inside a cluster. When the environment variables are not found, Traefik tries to connect to the Kubernetes API server with an external-cluster client. In this case, the endpoint is required. Specifically, it may be set to the URL used by kubectl proxy to connect to a Kubernetes cluster using the granted authentication and authorization of the associated kubeconfig. providers: kubernetesIngressNGINX: endpoint: "http://localhost:8080" # ... [providers.kubernetesIngressNGINX] endpoint = "http://localhost:8080" # ... --providers.kubernetesingressnginx.endpoint=http://localhost:8080 Routing Configuration See the dedicated section in routing. {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik & Kubernetes The Traefik Kubernetes Ingress provider is a Kubernetes Ingress controller; i.e, it manages access to cluster services by supporting the Ingress specification. ??? warning "Ingress Backend Resource not supported" Referencing backend service endpoints using [`spec.rules.http.paths.backend.resource`](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/ingress-v1/#IngressBackend) is not supported. Use `spec.rules.http.paths.backend.service` instead. ??? warning "Ingress API frozen" The Kubernetes Ingress API is [frozen](https://kubernetes.io/docs/concepts/services-networking/ingress/) and will not receive further changes or updates. You are encouraged to use the [Kubernetes Gateway provider](./kubernetes-gateway.md) instead. Configuration Example You can enable the kubernetesIngress provider as detailed below: providers: kubernetesIngress: {} [providers.kubernetesIngress] --providers.kubernetesingress=true ## Values file providers: kubernetesIngress: enabled: true The provider then watches for incoming ingresses events, such as the example below, and derives the corresponding dynamic configuration from it, which in turn creates the resulting routers, services, handlers, etc. Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.kubernetesIngress.endpoint Server endpoint URL. More information here. "" No providers.kubernetesIngress.token Bearer token used for the Kubernetes client configuration. Accepts either the token value directly or a path to a file containing the token. "" No providers.kubernetesIngress.certAuthFilePath Path to the certificate authority file. Used for the Kubernetes client configuration. "" No providers.kubernetesIngress.namespaces Array of namespaces to watch. If left empty, watch all namespaces. No providers.kubernetesIngress.labelSelector Allow filtering on Ingress objects using label selectors. No effect on Kubernetes Secrets, EndpointSlices and Services. See label-selectors for details. "" No providers.kubernetesIngress.ingressClass The IngressClass resource name or the kubernetes.io/ingress.class annotation value that identifies resource objects to be processed. If empty, resources missing the annotation, having an empty value, or the value traefik are processed. "" No providers.kubernetesIngress.disableIngressClassLookup Deprecated: please use disableClusterScopeResources instead. Prevent to discover IngressClasses in the cluster. It alleviates the requirement of giving Traefik the rights to look IngressClasses up. Ignore Ingresses with IngressClass. Annotations are not affected by this option. false No providers.kubernetesIngress. ingressEndpoint.hostname Hostname used for Kubernetes Ingress endpoints. "" No providers.kubernetesIngress. ingressEndpoint.ip This IP will get copied to the Ingress status.loadbalancer.ip, and currently only supports one IP value (IPv4 or IPv6). "" No providers.kubernetesIngress. ingressEndpoint.publishedService The Kubernetes service to copy status from. More information here. "" No providers.kubernetesIngress.reportNodeInternalIPs Report node internal IPs in Ingress status. Incompatible with ingressEndpoint and disableClusterScopeResources. More information here. false No providers.kubernetesIngress.throttleDuration Minimum amount of time to wait between two Kubernetes events before producing a new configuration. This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration. If empty, every event is caught. 0s No providers.kubernetesIngress.allowEmptyServices Allows creating a route to reach a service that has no endpoint available. It allows Traefik to handle the requests and responses targeting this service (applying middleware or observability operations) before returning a 503 HTTP Status. false No providers.kubernetesIngress.allowExternalNameServices Allows the Ingress to reference ExternalName services. false No providers.kubernetesIngress.crossProviderNamespaces List of namespaces from which Ingresses or Services are allowed to use traefik.ingress.kubernetes.io/router.middlewares, traefik.ingress.kubernetes.io/router.tls.options, traefik.ingress.kubernetes.io/service.middlewares, or traefik.ingress.kubernetes.io/service.serverstransport annotations. When unset, all namespaces are allowed. When set to [], every cross-provider reference is rejected. [] No providers.kubernetesIngress.nativeLBByDefault Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik for every Ingress by default. It can be overridden in the Service false No providers.kubernetesIngress.disableClusterScopeResources Prevent from discovering cluster scope resources ( IngressClass and Nodes). By doing so, it alleviates the requirement of giving Traefik the rights to look up for cluster resources. Furthermore, Traefik will not handle Ingresses with IngressClass references, therefore such Ingresses will be ignored (please note that annotations are not affected by this option). This will also prevent from using the NodePortLB options on services and is incompatible with reportNodeInternalIPs. false No providers.kubernetesIngress.strictPrefixMatching Make prefix matching strictly comply with the Kubernetes Ingress specification (path-element-wise matching instead of character-by-character string matching). For example, a PathPrefix of /foo will match /foo, /foo/, and /foo/bar but not /foobar. false No endpoint The Kubernetes server endpoint URL. When deployed into Kubernetes, Traefik reads the environment variables KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT or KUBECONFIG to construct the endpoint. The access token is looked up in /var/run/secrets/kubernetes.io/serviceaccount/token and the SSL CA certificate in /var/run/secrets/kubernetes.io/serviceaccount/ca.crt. Both are mounted automatically when deployed inside Kubernetes. The endpoint may be specified to override the environment variable values inside a cluster. When the environment variables are not found, Traefik tries to connect to the Kubernetes API server with an external-cluster client. In this case, the endpoint is required. Specifically, it may be set to the URL used by kubectl proxy to connect to a Kubernetes cluster using the granted authentication and authorization of the associated kubeconfig. providers: kubernetesIngress: endpoint: "http://localhost:8080" # ... [providers.kubernetesIngress] endpoint = "http://localhost:8080" # ... --providers.kubernetesingress.endpoint=http://localhost:8080 ingressEndpoint.publishedService Format: namespace/servicename. The Kubernetes service to copy status from, depending on the service type: ClusterIP: The ExternalIPs of the service will be propagated to the ingress status. NodePort: The ExternalIP addresses of the nodes in the cluster will be propagated to the ingress status. LoadBalancer: The IPs from the service's loadBalancer.status field (which contains the endpoints provided by the load balancer) will be propagated to the ingress status. ExternalName: The hostname from the service's spec.externalName field will be propagated to the ingress status. When using third-party tools such as External-DNS, this option enables the copying of external service IPs to the ingress resources. providers: kubernetesIngress: ingressEndpoint: publishedService: "namespace/foo-service" # ... [providers.kubernetesIngress.ingressEndpoint] publishedService = "namespace/foo-service" # ... --providers.kubernetesingress.ingressendpoint.publishedservice=namespace/foo-service reportNodeInternalIPs When set to true, Traefik reports the internal IPs of all nodes in the cluster into the status.loadBalancer.ingress field of each managed Ingress resource. This is the equivalent of ingress-nginx's --report-node-internal-ip-address flag and is the recommended approach for bare-metal Kubernetes deployments where Traefik runs as a DaemonSet without a cloud LoadBalancer or MetalLB. This option requires cluster-scope access to Node resources and is mutually exclusive with ingressEndpoint and disableClusterScopeResources. providers: kubernetesIngress: reportNodeInternalIPs: true # ... [providers.kubernetesIngress] reportNodeInternalIPs = true # ... --providers.kubernetesingress.reportnodeinternalips=true Routing Configuration See the dedicated section in routing. Further To learn more about the various aspects of the Ingress specification that Traefik supports, many examples of Ingresses definitions are located in the test examples of the Traefik repository. {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik Consul Documentation --8<-- "content/reference/install-configuration/providers/hashicorp/consul.md" Traefik & etcd Configuration Example You can enable the etcd provider as detailed below: providers: etcd: {} [providers.etcd] --providers.etcd=true Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.etcd.endpoints Defines the endpoint to access etcd. "127.0.0.1:2379" Yes providers.etcd.rootKey Defines the root key for the configuration. "traefik" Yes providers.etcd.username Defines a username with which to connect to etcd. "" No providers.etcd.password Defines a password for connecting to etcd. "" No providers.etcd.syncPeriod Defines the interval at which the client updates its list of endpoints from the etcd cluster membership. A value of 0 disables this auto-sync. 0s No providers.etcd.tls Defines the TLS configuration used for the secure connection to etcd. - No providers.etcd.tls.ca Defines the path to the certificate authority used for the secure connection to etcd, it defaults to the system bundle. "" No providers.etcd.tls.cert Defines the path to the public certificate used for the secure connection to etcd. When using this option, setting the key option is required. "" No providers.etcd.tls.key Defines the path to the private key used for the secure connection to etcd. When using this option, setting the cert option is required. "" No providers.etcd.tls.insecureSkipVerify Instructs the provider to accept any certificate presented by etcd when establishing a TLS connection, regardless of the hostnames the certificate covers. false No Routing Configuration See the dedicated section in routing. Traefik & Redis !!! tip "Routing configuration updates" Updates to the routing configuration require Redis [keyspace notifications](https://redis.io/docs/latest/develop/use/keyspace-notifications/) to be enabled. Cloud-managed Redis services (e.g., GCP Memorystore, AWS ElastiCache) may disable this by default due to CPU performance concerns. For more information, see the [Redis documentation](https://redis.io/docs/latest/develop/use/keyspace-notifications/) or your cloud provider's documentation for configuration steps. Configuration Example You can enable the Redis provider as detailed below: providers: redis: {} [providers.redis] --providers.redis.endpoints=127.0.0.1:6379 Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.redis.endpoints Defines the endpoint to access Redis. "127.0.0.1:6379" Yes providers.redis.rootKey Defines the root key for the configuration. "traefik" Yes providers.redis.username Defines a username for connecting to Redis. "" No providers.redis.password Defines a password for connecting to Redis. "" No providers.redis.db Defines the database to be selected after connecting to the Redis. 0 No providers.redis.tls Defines the TLS configuration used for the secure connection to Redis. - No providers.redis.tls.ca Defines the path to the certificate authority used for the secure connection to Redis, it defaults to the system bundle. "" No providers.redis.tls.cert Defines the path to the public certificate used for the secure connection to Redis. When using this option, setting the key option is required. "" Yes providers.redis.tls.key Defines the path to the private key used for the secure connection to Redis. When using this option, setting the cert option is required. "" Yes providers.redis.tls.insecureSkipVerify Instructs the provider to accept any certificate presented by Redis when establishing a TLS connection, regardless of the hostnames the certificate covers. false No providers.redis.sentinel Defines the Sentinel configuration used to interact with Redis Sentinel. - No providers.redis.sentinel.masterName Defines the name of the Sentinel master. "" Yes providers.redis.sentinel.username Defines the username for Sentinel authentication. "" No providers.redis.sentinel.password Defines the password for Sentinel authentication. "" No providers.redis.sentinel.latencyStrategy Defines whether to route commands to the closest master or replica nodes (mutually exclusive with RandomStrategy and ReplicaStrategy). false No providers.redis.sentinel.randomStrategy Defines whether to route commands randomly to master or replica nodes (mutually exclusive with LatencyStrategy and ReplicaStrategy). false No providers.redis.sentinel.replicaStrategy Routes all commands exclusively to replica nodes (mutually exclusive with LatencyStrategy and RandomStrategy). false No providers.redis.sentinel.useDisconnectedReplicas Defines whether to use replicas disconnected with master when cannot get connected replicas. false false Routing Configuration See the dedicated section in routing. Traefik & ZooKeeper Configuration Example You can enable the ZooKeeper provider as detailed below: providers: zooKeeper: {} [providers.zooKeeper] --providers.zookeeper=true Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.zooKeeper.endpoints Defines the endpoint to access ZooKeeper. "127.0.0.1:2181" Yes providers.zooKeeper.rootKey Defines the root key for the configuration. "traefik" Yes providers.zooKeeper.username Defines a username with which to connect to zooKeeper. "" No providers.zooKeeper.password Defines a password for connecting to zooKeeper. "" No Routing Configuration See the dedicated section in routing. Traefik & AWS ECS Configuration Example You can enable the ECS provider with as detailed below: providers: ecs: {} [providers.ecs] --providers.ecs=true Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.ecs.autoDiscoverClusters Search for services in cluster list. If set to true service discovery is enabled for all clusters. false No providers.ecs.ecsAnywhere Enable ECS Anywhere support. false No providers.ecs.clusters Search for services in cluster list. This option is ignored if autoDiscoverClusters is set to true. ["default"] No providers.ecs.exposedByDefault Expose ECS services by default through Traefik. If set to false, containers that do not have a traefik.enable=true label are ignored from the resulting routing configuration. See here for additional information. true No providers.ecs.constraints Defines an expression that Traefik matches against the container labels to determine whether to create any route for that container. See here for more information. "" No providers.ecs.healthyTasksOnly Defines whether Traefik discovers only healthy tasks ( HEALTHY healthStatus). false No providers.ecs.defaultRule The Default Host rule for all services. See here for more information. "Host(`{{ normalize .Name }}`)" No providers.ecs.refreshSeconds Defines the polling interval (in seconds). 15 No providers.ecs.region Defines the region of the ECS instance. See here for more information. "" No providers.ecs.accessKeyID Defines the Access Key ID for the ECS instance. See here for more information. "" No providers.ecs.secretAccessKey Defines the Secret Access Key for the ECS instance. See here for more information. "" No constraints The constraints option can be set to an expression that Traefik matches against the container labels (task), to determine whether to create any route for that container. If none of the container labels match the expression, no route for that container is created. If the expression is empty, all detected containers are included. The expression syntax is based on the Label("key", "value"), and LabelRegex("key", "value") functions, as well as the usual boolean logic, as shown in examples below. !!! tip "Constraints key limitations" Note that `traefik.*` is a reserved label namespace for configuration and can not be used as a key for custom constraints. ??? example "Constraints Expression Examples" ```toml # Includes only containers having a label with key `a.label.name` and value `foo` constraints = "Label(`a.label.name`, `foo`)" ``` ```toml # Excludes containers having any label with key `a.label.name` and value `foo` constraints = "!Label(`a.label.name`, `value`)" ``` ```toml # With logical AND. constraints = "Label(`a.label.name`, `valueA`) && Label(`another.label.name`, `valueB`)" ``` ```toml # With logical OR. constraints = "Label(`a.label.name`, `valueA`) || Label(`another.label.name`, `valueB`)" ``` ```toml # With logical AND and OR, with precedence set by parentheses. constraints = "Label(`a.label.name`, `valueA`) && (Label(`another.label.name`, `valueB`) || Label(`yet.another.label.name`, `valueC`))" ``` ```toml # Includes only containers having a label with key `a.label.name` and a value matching the `a.+` regular expression. constraints = "LabelRegex(`a.label.name`, `a.+`)" ``` providers: ecs: constraints: "Label(`a.label.name`,`foo`)" # ... [providers.ecs] constraints = "Label(`a.label.name`,`foo`)" # ... --providers.ecs.constraints="Label(`a.label.name`,`foo`)" # ... For additional information, refer to Restrict the Scope of Service Discovery. defaultRule The defaultRule option defines what routing rule to apply to a container if no rule is defined by a label. It must be a valid Go template, and can use sprig template functions. The container service name can be accessed with the Name identifier, and the template has access to all the labels defined on this container. providers: ecs: defaultRule: "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)" # ... [providers.ecs] defaultRule = "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)" # ... --providers.ecs.defaultRule='Host(`{{ .Name }}.{{ index .Labels "customLabel"}}`)' # ... ??? info "Default rule and Traefik service" The exposure of the Traefik container, combined with the default rule mechanism, can lead to create a router targeting itself in a loop. In this case, to prevent an infinite loop, Traefik adds an internal middleware to refuse the request if it comes from the same router. Credentials This defines the credentials for the ECS instance If region is not provided, it is resolved from the EC2 metadata endpoint for EC2 tasks. In a FARGATE context it is resolved from the AWS_REGION environment variable. If accessKeyID and secretAccessKey are not provided, credentials are resolved in the following order: Using the environment variables AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN. Using shared credentials, determined by AWS_PROFILE and AWS_SHARED_CREDENTIALS_FILE, defaults to default and ~/.aws/credentials. Using EC2 instance role or ECS task role providers: ecs: region: us-east-1 accessKeyID: "abc" secretAccessKey: "123" # ... [providers.ecs] region = "us-east-1" accessKeyID = "abc" secretAccessKey = "123" --providers.ecs.region="us-east-1" --providers.ecs.accessKeyID="abc" --providers.ecs.secretAccessKey="123" # ... Policy Traefik needs the following policy to read ECS information: { "Version": "2012-10-17", "Statement": [ { "Sid": "TraefikECSReadAccess", "Effect": "Allow", "Action": [ "ecs:ListClusters", "ecs:DescribeClusters", "ecs:ListTasks", "ecs:DescribeTasks", "ecs:DescribeContainerInstances", "ecs:DescribeTaskDefinition", "ec2:DescribeInstances", "ssm:DescribeInstanceInformation" ], "Resource": [ "*" ] } ] } !!! info "ECS Anywhere" Please note that the `ssm:DescribeInstanceInformation` action is required for ECS anywhere instances discovery. File The file provider lets you define the install configuration in a YAML or TOML file. It supports providing configuration through a single configuration file or multiple separate files. !!! info The file provider is the default format used throughout the documentation to show samples of the configuration for many features. !!! tip The file provider can be a good solution for reusing common elements from other providers (e.g. declaring allowlist middlewares, basic authentication, ...) Configuration Example You can enable the file provider as detailed below: providers: file: directory: "/path/to/dynamic/conf" [providers.file] directory = "/path/to/dynamic/conf" --providers.file.directory=/path/to/dynamic/conf Declaring the Routers, Middlewares & Services: http: # Add the router routers: router0: entryPoints: - web middlewares: - my-basic-auth service: service-foo rule: Path(`/foo`) # Add the middleware middlewares: my-basic-auth: basicAuth: users: - test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/ - test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0 usersFile: etc/traefik/.htpasswd # Add the service services: service-foo: loadBalancer: servers: - url: http://foo/ - url: http://bar/ passHostHeader: false [http] # Add the router [http.routers] [http.routers.router0] entryPoints = ["web"] middlewares = ["my-basic-auth"] service = "service-foo" rule = "Path(`/foo`)" # Add the middleware [http.middlewares] [http.middlewares.my-basic-auth.basicAuth] users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"] usersFile = "etc/traefik/.htpasswd" # Add the service [http.services] [http.services.service-foo] [http.services.service-foo.loadBalancer] [[http.services.service-foo.loadBalancer.servers]] url = "http://foo/" [[http.services.service-foo.loadBalancer.servers]] url = "http://bar/" Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.file.filename Defines the path to the configuration file. "" Yes providers.file.directory Defines the path to the directory that contains the configuration files. The filename and directory options are mutually exclusive. It is recommended to use directory. "" Yes providers.file.watch Set the watch option to true to allow Traefik to automatically watch for file changes. It works with both the filename and the directory options. true No providers.file.debugLogGeneratedTemplate Enable debug logging of generated configuration template. false No !!! warning "Limitations" With the file provider, Traefik listens for file system notifications to update the dynamic configuration. If you use a mounted/bound file system in your orchestrator (like docker or kubernetes), the way the files are linked may be a source of errors. If the link between the file systems is broken, when a source file/directory is changed/renamed, nothing will be reported to the linked file/directory, so the file system notifications will be neither triggered nor caught. For example, in Docker, if the host file is renamed, the link to the mounted file is broken and the container's file is no longer updated. To avoid this kind of issue, it is recommended to: * set the Traefik [**directory**](#opt-providers-file-directory) configuration with the parent directory * mount/bind the parent directory As it is very difficult to listen to all file system notifications, Traefik uses [fsnotify](https://github.com/fsnotify/fsnotify). If using a directory with a mounted directory does not fix your issue, please check your file system compatibility with fsnotify. {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik & HTTP Provide your install configuration via an HTTP(S) endpoint and let Traefik do the rest! Configuration Example You can enable the HTTP provider as detailed below: providers: http: endpoint: "http://127.0.0.1:9000/api" [providers.http] endpoint = "http://127.0.0.1:9000/api" --providers.http.endpoint=http://127.0.0.1:9000/api Configuration Options Field Description Default Required providers.providersThrottleDuration Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event. If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded. This option cannot be set per provider, but the throttling algorithm applies to each of them independently. 2s No providers.http.endpoint Defines the HTTP(S) endpoint to poll. "" Yes providers.http.pollInterval Defines the polling interval. 5s No providers.http.pollTimeout Defines the polling timeout when connecting to the endpoint. 5s No providers.http.headers Defines custom headers to be sent to the endpoint. {} No providers.http.maxResponseBodySize Defines the maximum size of the response body in bytes. A value of -1 means unlimited. -1 No providers.http.tls.ca Defines the certificate authority used for the secure connection to the endpoint, it defaults to the system bundle. The value can be a file path or the PEM content directly. "" No providers.http.tls.cert Defines the public certificate used for the secure connection to the endpoint. The value can be a file path or the PEM content directly. When using this option, setting the key option is required. "" Yes providers.http.tls.key Defines the private key used for the secure connection to the endpoint. The value can be a file path or the PEM content directly. When using this option, setting the cert option is required. "" Yes providers.http.tls.insecureSkipVerify Instructs the provider to accept any certificate presented by endpoint when establishing a TLS connection, regardless of the hostnames the certificate covers. false No headers Defines custom headers to be sent to the endpoint. providers: http: headers: name: value [providers.http.headers] name = "value" [providers.http.headers] --providers.http.headers.name=value Routing Configuration The HTTP provider uses the same configuration as the File Provider in YAML or JSON format. OCSP Check certificate status and perform OCSP stapling. {: .subtitle } Overview OCSP Stapling When OCSP is enabled, Traefik checks the status of every certificate in the store that provides an OCSP responder URL, including the default certificate, and staples the OCSP response to the TLS handshake. The OCSP check is performed when the certificate is loaded, and once every hour until it is successful at the halfway point before the update date. Caching Traefik caches the OCSP response as long as the associated certificate is provided by the configuration. When a certificate is no longer provided, the OCSP response has a 24 hour TTL waiting to be provided again or eventually removed. The OCSP response is cached in memory and is not persisted between Traefik restarts. Configuration General Enabling OCSP is part of the install configuration. It can be defined by using a file (YAML or TOML) or CLI arguments: ## Static configuration ocsp: {} ## Static configuration [ocsp] ## Static configuration --ocsp=true Responder Overrides The responderOverrides option defines the OCSP responder URLs to use instead of the one provided by the certificate. This is useful when you want to use a different OCSP responder. ## Static configuration ocsp: responderOverrides: foo: bar ## Static configuration [ocsp] [ocsp.responderOverrides] foo = "bar" ## Static configuration --ocsp.responderoverrides.foo=bar SPIFFE Secure the backend connection with SPIFFE. {: .subtitle } SPIFFE (Secure Production Identity Framework For Everyone), provides a secure identity in the form of a specially crafted X.509 certificate, to every workload in an environment. Traefik is able to connect to the Workload API to obtain an X509-SVID used to secure the connection with SPIFFE enabled backends. !!! warning "SPIFFE can cause Traefik to stall" When using SPIFFE, Traefik will wait for the first SVID to be delivered before starting. If Traefik is hanging when waiting on SPIFFE SVID delivery, please double check that it is correctly registered as workload in your SPIFFE infrastructure. Workload API To enable SPIFFE globally, you need to set up the static configuration. The workloadAPIAddr option specifies the address of the SPIFFE Workload API. ## Static configuration. spiffe: workloadAPIAddr: localhost ## Static configuration [spiffe] workloadAPIAddr = "localhost" ## Static configuration. --spiffe.workloadAPIAddr=localhost ServersTransport Enabling SPIFFE does not imply that backend connections are going to use it automatically. Each ServersTransport or TCPServersTransport, that is meant to be secured with SPIFFE, must explicitly enable it (see SPIFFE with ServersTransport or SPIFFE with TCPServersTransport). Configuration Example serversTransport: spiffe: ids: - spiffe://trust-domain/id1 - spiffe://trust-domain/id2 trustDomain: "spiffe://trust-domain" [serversTransport.spiffe] ids = [ "spiffe://trust-domain/id1", "spiffe://trust-domain/id2" ] trustDomain = "spiffe://trust-domain" apiVersion: traefik.io/v1alpha1 kind: ServersTransportTCP metadata: name: mytransport namespace: default spec: spiffe: ids: - spiffe://trust-domain/id1 - spiffe://trust-domain/id2 Traefik & ACME Certificates Resolver Below is an example of a basic configuration for ACME in Traefik. entryPoints: web: address: ":80" websecure: address: ":443" certificatesResolvers: myresolver: acme: email: your-email@example.com storage: acme.json httpChallenge: # used during the challenge entryPoint: web [entryPoints] [entryPoints.web] address = ":80" [entryPoints.websecure] address = ":443" [certificatesResolvers.myresolver.acme] email = "your-email@example.com" storage = "acme.json" [certificatesResolvers.myresolver.acme.httpChallenge] # used during the challenge entryPoint = "web" --entryPoints.web.address=:80 --entryPoints.websecure.address=:443 # ... --certificatesresolvers.myresolver.acme.email=your-email@example.com --certificatesresolvers.myresolver.acme.storage=acme.json # used during the challenge --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web # Traefik entryPoints configuration for HTTP and HTTPS. entryPoints: web: address: ":80" websecure: address: ":443" certificatesResolvers: myresolver: acme: email: "your-email@example.com" storage: "/data/acme.json" # Path to store the certificate information. httpChallenge: # Entry point to use during the ACME HTTP-01 challenge. entryPoint: "web" Configuration Options ACME certificate resolvers have the following configuration options: Field Description Default Required acme.email Email address used for registration. "" Yes acme.caServer CA server to use. https://acme-v02.api.letsencrypt.org/directory No acme.preferredChain Preferred chain to use. If the CA offers multiple certificate chains, prefer the chain with an issuer matching this Subject Common Name. If no match, the default offered chain will be used. "" No acme.keyType KeyType to use. "RSA4096" No acme.disableCommonName Disable the common name in the CSR. false No acme.profile Certificate profile to use. "" No acme.caCertificates Specify the paths to PEM encoded CA Certificates that can be used to authenticate an ACME server with an HTTPS certificate not issued by a CA in the system-wide trusted root list. [] No acme.caSystemCertPool Defines if the certificates pool must use a copy of the system cert pool. false No acme.caServerName Specify the CA server name that can be used to authenticate an ACME server with an HTTPS certificate not issued by a CA in the system-wide trusted root list. "" No acme.emailAddresses CSR email addresses to use. [] No acme.eab Enable external account binding. No acme.eab.kid Key identifier from External CA. "" No acme.eab.hmacEncoded HMAC key from External CA, should be in Base64 URL Encoding without padding format. "" No acme.certificatesDuration The certificates' duration in hours, exclusively used to determine renewal dates. 2160 No acme.clientTimeout Timeout for HTTP Client used to communicate with the ACME server. 2m No acme.clientResponseHeaderTimeout Timeout for response headers for HTTP Client used to communicate with the ACME server. 30s No acme.certificateTimeout Timeout for obtaining the certificate during the finalization request. Set this if the ACME server is slow to issue a certificate. 30s No acme.dnsChallenge Enable DNS-01 challenge. More information here. - No acme.dnsChallenge.provider DNS provider to use. "" No acme.dnsChallenge.resolvers DNS servers to resolve the FQDN authority. [] No acme.dnsChallenge.propagation.delayBeforeChecks By default, the provider will verify the TXT DNS challenge record before letting ACME verify. If delayBeforeCheck is greater than zero, this check is delayed for the configured duration in seconds. This is Useful if internal networks block external DNS queries. 0s No acme.dnsChallenge.propagation.disableChecks Disables the challenge TXT record propagation checks, before notifying ACME that the DNS challenge is ready. Please note that disabling checks can prevent the challenge from succeeding. false No acme.dnsChallenge.propagation.requireAllRNS Enables the challenge TXT record to be propagated to all recursive nameservers. If you have disabled authoritative nameservers checks (with propagation.disableANSChecks), it is recommended to check all recursive nameservers instead. false No acme.dnsChallenge.propagation.disableANSChecks Disables the challenge TXT record propagation checks against authoritative nameservers. This option will skip the propagation check against the nameservers of the authority (SOA). It should be used only if the nameservers of the authority are not reachable. false No acme.httpChallenge Enable HTTP-01 challenge. More information here. No acme.httpChallenge.entryPoint EntryPoint to use for the HTTP-01 challenges. Must be reachable by Let's Encrypt through port 80 "" Yes acme.httpChallenge.delay The delay between the creation of the challenge and the validation. A value lower than or equal to zero means no delay. 0 No acme.tlsChallenge Enable TLS-ALPN-01 challenge. Traefik must be reachable by Let's Encrypt through port 443. More information here. - No acme.tlschallenge.delay The delay between the creation of the challenge and the validation. A value lower than or equal to zero means no delay. 0 No acme.storage File path used for certificates storage. "acme.json" Yes Automatic Certificate Renewal Traefik automatically tracks the expiry date of certificates it generates. Certificates that are no longer used may still be renewed, as Traefik does not currently check if the certificate is being used before renewing. By default, Traefik manages 90-day certificates and starts renewing them 30 days before their expiry. When using a certificate resolver that issues certificates with custom durations, the certificatesDuration option can be used to configure the certificates' duration. !!! note Certificates that are no longer used may still be renewed, as Traefik does not currently check if the certificate is being used before renewing. The Different ACME Challenges dnsChallenge The DNS-01 challenge to generate and renew ACME certificates by provisioning a DNS record. Traefik relies internally on Lego for ACME. You can find the list of all the supported DNS providers in their documentation with instructions about which environment variables need to be setup. !!! note CNAME are supported and even [encouraged](https://letsencrypt.org/2019/10/09/onboarding-your-customers-with-lets-encrypt-and-acme.html#the-advantages-of-a-cname "Link to The Advantages of a CNAME article"). If needed, CNAME support can be turned off with the following environment variable: ```env LEGO_DISABLE_CNAME_SUPPORT=true ``` ??? warning "Multiple DNS challenge" Multiple DNS challenge provider are not supported with Traefik, but you can use CNAME to handle that. For example, if you have `example.org` (account foo) and `example.com` (account bar) you can create a CNAME on `example.org` called `_acme-challenge.example.org` pointing to `challenge.example.com`. This way, you can obtain certificates for `example.org` with the bar account. ??? info " delayBeforeChecks" By default, the provider verifies the TXT record before letting ACME verify. You can delay this operation by specifying a delay (in seconds) with delayBeforeChecks (value must be greater than zero). This option is useful when internal networks block external DNS queries. tlsChallenge Use the TLS-ALPN-01 challenge to generate and renew ACME certificates by provisioning a TLS certificate. As described on the Let's Encrypt community forum, when using the TLS-ALPN-01 challenge, Traefik must be reachable by Let's Encrypt through port 443. ??? example "Configuring the tlsChallenge" ```yaml tab="File (YAML)" certificatesResolvers: myresolver: acme: # ... tlsChallenge: {} ``` ```toml tab="File (TOML)" [certificatesResolvers.myresolver.acme] # ... [certificatesResolvers.myresolver.acme.tlsChallenge] ``` ```bash tab="CLI" # ... --certificatesresolvers.myresolver.acme.tlschallenge=true ``` httpChallenge Use the HTTP-01 challenge to generate and renew ACME certificates by provisioning an HTTP resource under a well-known URI. As described on the Let's Encrypt community forum, when using the HTTP-01 challenge, certificatesresolvers.myresolver.acme.httpchallenge.entrypoint must be reachable by Let's Encrypt through port 80. ??? example "Using an EntryPoint Called web for the httpChallenge" ```yaml tab="File (YAML)" entryPoints: web: address: ":80" websecure: address: ":443" certificatesResolvers: myresolver: acme: # ... httpChallenge: entryPoint: web ``` ```toml tab="File (TOML)" [entryPoints] [entryPoints.web] address = ":80" [entryPoints.websecure] address = ":443" [certificatesResolvers.myresolver.acme] # ... [certificatesResolvers.myresolver.acme.httpChallenge] entryPoint = "web" ``` ```bash tab="CLI" --entryPoints.web.address=:80 --entryPoints.websecure.address=:443 # ... --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web ``` !!! info "" Redirection is fully compatible with the HTTP-01 challenge. Domain Definition A certificate resolver requests certificates for a set of domain names inferred from routers, according to the following: If the IngressRoute has a tls.domains option set, then the certificate resolver derives this router domain name from the main option of tls.domains. Otherwise, the certificate resolver derives the domain name from any Host() or HostSNI() matchers in the IngressRoute's rule. You can set SANs (alternative domains) for each main domain. Every domain must have A/AAAA records pointing to Traefik. Each domain & SAN will lead to a certificate request. ACME v2 supports wildcard certificates. As described in Let's Encrypt's post wildcard certificates can only be generated through a DNS-01 challenge. It is not possible to request a double wildcard certificate for a domain (for example *.*.local.com). For the same reason, a **.local.com domain is refused, and a Host(`**.local.com`) router gets no certificate. Most likely the root domain should receive a certificate too, so it needs to be specified as SAN and 2 DNS-01 challenges are invoked. In such a case the generated DNS TXT record for both domains is the same. Even though this behavior is DNS RFC compliant, it can lead to problems as all DNS providers keep DNS records cached for a given time (TTL) and this TTL can be greater than the challenge timeout making the DNS-01 challenge fail. The Traefik ACME client library lego supports some but not all DNS providers to work around this issue. The supported provider table indicates if they allow generating certificates for a wildcard domain and its root domain. Wildcard Domains ACME V2 supports wildcard certificates. As described in Let's Encrypt's post wildcard certificates can only be generated through a DNS-01 challenge. External Account Binding kid: Key identifier from External CA hmacEncoded: HMAC key from External CA, should be in Base64 URL Encoding without padding format certificatesResolvers: myresolver: acme: # ... eab: kid: abc-keyID-xyz hmacEncoded: abc-hmac-xyz [certificatesResolvers.myresolver.acme] # ... [certificatesResolvers.myresolver.acme.eab] kid = "abc-keyID-xyz" hmacEncoded = "abc-hmac-xyz" # ... --certificatesresolvers.myresolver.acme.eab.kid=abc-keyID-xyz --certificatesresolvers.myresolver.acme.eab.hmacencoded=abc-hmac-xyz Using LetsEncrypt with Kubernetes When using LetsEncrypt with kubernetes, there are some known caveats with both the Ingress and CRD providers. !!! note If you intend to run multiple instances of Traefik with LetsEncrypt, please ensure you read the sections on those provider pages. LetsEncrypt Support with the Ingress Provider By design, Traefik is a stateless application, meaning that it only derives its configuration from the environment it runs in, without additional configuration. For this reason, users can run multiple instances of Traefik at the same time to achieve HA, as is a common pattern in the kubernetes ecosystem. When using a single instance of Traefik Proxy with Let's Encrypt, you should encounter no issues. However, this could be a single point of failure. Unfortunately, it is not possible to run multiple instances of Traefik 2.0 with Let's Encrypt enabled, because there is no way to ensure that the correct instance of Traefik receives the challenge request, and subsequent responses. Early versions (v1.x) of Traefik used a KV store to attempt to achieve this, but due to sub-optimal performance that feature was dropped in 2.0. If you need Let's Encrypt with high availability in a Kubernetes environment, we recommend using Traefik Enterprise which includes distributed Let's Encrypt as a supported feature. If you want to keep using Traefik Proxy, LetsEncrypt HA can be achieved by using a Certificate Controller such as Cert-Manager. When using Cert-Manager to manage certificates, it creates secrets in your namespaces that can be referenced as TLS secrets in your ingress objects . Fallback If Let's Encrypt is not reachable, the following certificates will apply: Previously generated ACME certificates (before downtime) Expired ACME certificates Provided certificates !!! important For new (sub)domains which need Let's Encrypt authentication, the default Traefik certificate will be used until Traefik is restarted. {% include-markdown "includes/traefik-for-business-applications.md" %} Certificates Resolver In Traefik, TLS Certificates can be generated using Certificates Resolvers. In Traefik, two certificate resolvers exist: acme: It allows generating ACME certificates stored in a file (not distributed). tailscale: It allows provisioning TLS certificates for internal Tailscale services. The Certificates resolvers are defined in the static configuration. !!! note Referencing a certificate resolver Defining a certificate resolver does not imply that routers are going to use it automatically. Each router or entrypoint that is meant to use the resolver must explicitly reference it. {% include-markdown "includes/traefik-for-business-applications.md" %} Tailscale Provision TLS certificates for your internal Tailscale services. {: .subtitle } To protect a service with TLS, a certificate from a public Certificate Authority is needed. In addition to its vpn role, Tailscale can also provide certificates for the machines in your Tailscale network. Configuration Example To obtain a TLS certificate from the Tailscale daemon, a Tailscale certificate resolver needs to be configured as below. !!! example "Enabling Tailscale certificate resolution" ```yaml tab="File (YAML)" entryPoints: web: address: ":80" websecure: address: ":443" certificatesResolvers: myresolver: tailscale: {} ``` ```toml tab="File (TOML)" [entryPoints] [entryPoints.web] address = ":80" [entryPoints.websecure] address = ":443" [certificatesResolvers.myresolver.tailscale] ``` ```bash tab="CLI" --entrypoints.web.address=:80 --entrypoints.websecure.address=:443 # ... --certificatesresolvers.myresolver.tailscale=true ``` ??? example "Domain from Router's Rule Example" ```yaml tab="Docker & Swarm" labels: - traefik.http.routers.blog.rule=Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`) - traefik.http.routers.blog.tls.certresolver=myresolver ``` ```yaml tab="Docker (Swarm)" deploy: labels: - traefik.http.routers.blog.rule=Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`) - traefik.http.routers.blog.tls.certresolver=myresolver ``` ```yaml tab="Kubernetes" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: blogtls spec: entryPoints: - websecure routes: - match: Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`) kind: Rule services: - name: blog port: 8080 tls: certResolver: myresolver ``` ```yaml tab="File (YAML)" ## Dynamic configuration http: routers: blog: rule: "Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)" tls: certResolver: myresolver ``` ```toml tab="File (TOML)" ## Dynamic configuration [http.routers] [http.routers.blog] rule = "Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)" [http.routers.blog.tls] certResolver = "myresolver" ``` ??? example "Domain from Router's tls.domain Example" ```yaml tab="Docker & Swarm" labels: - traefik.http.routers.blog.rule=Path(`/metrics`) - traefik.http.routers.blog.tls.certresolver=myresolver - traefik.http.routers.blog.tls.domains[0].main=monitoring.yak-bebop.ts.net ``` ```yaml tab="Docker (Swarm)" deploy: labels: - traefik.http.routers.blog.rule=Path(`/metrics`) - traefik.http.routers.blog.tls.certresolver=myresolver - traefik.http.routers.blog.tls.domains[0].main=monitoring.yak-bebop.ts.net ``` ```yaml tab="Kubernetes" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: blogtls spec: entryPoints: - websecure routes: - match: Path(`/metrics`) kind: Rule services: - name: blog port: 8080 tls: certResolver: myresolver domains: - main: monitoring.yak-bebop.ts.net ``` ```yaml tab="File (YAML)" http: routers: blog: rule: "Path(`/metrics`)" tls: certResolver: myresolver domains: - main: "monitoring.yak-bebop.ts.net" ``` ```toml tab="File (TOML)" ## Dynamic configuration [http.routers] [http.routers.blog] rule = "Path(`/metrics`)" [http.routers.blog.tls] certResolver = "myresolver" [[http.routers.blog.tls.domains]] main = "monitoring.yak-bebop.ts.net" ``` !!! info "Referencing a certificate resolver" Defining a certificate resolver does not imply that routers are going to use it automatically. Each router or entrypoint that is meant to use the resolver must explicitly [reference](../../../routing-configuration/http/routing/router.md#opt-tls-certResolver) it. Domain Definition A certificate resolver requests certificates for a set of domain names inferred from routers, according to the following: If the router has a tls.domains option set, then the certificate resolver derives this router domain name from the main option of tls.domains. Otherwise, the certificate resolver derives the domain name from any Host() or HostSNI() matchers in the router's rule. !!! info "Tailscale Domain Format" A domain is only considered if it is a Tailscale-specific one—that is, in the form `machine-name.domains-alias.ts.net`. Tailscale Certificates Renewal Traefik automatically tracks the expiry date of each Tailscale certificate it fetches and starts to renew a certificate 14 days before its expiry to match the Tailscale daemon renewal policy. Providing Dynamic (Routing) Configuration to Traefik Dynamic configuration—now also known as routing configuration—defines how Traefik routes incoming requests to the correct services. This is distinct from install configuration (formerly known as static configuration), which sets up Traefik’s core components and providers. Depending on your environment and preferences, there are several ways to supply this routing configuration: File or Structured Provider: Use TOML or YAML files. Docker and ECS Providers: Use container labels. Kubernetes Providers: Use annotations. KV Providers : Use key-value pairs. Other Providers (Consul, Nomad, etc.) : Use tags. Using the File Provider The File provider allows you to define routing configuration in static files using either TOML or YAML syntax. This method is ideal for environments where services cannot be automatically discovered or when you prefer to manage configurations manually. Enabling the File Provider To enable the File provider, add the following to your Traefik install configuration: providers: file: directory: "/path/to/dynamic/conf" [providers.file] directory = "/path/to/dynamic/conf" ???+ example "Example using the file provider to declare routers & services" ```yaml tab="File (YAML)" http: routers: my-router: rule: "Host(`example.com`)" service: my-service services: my-service: loadBalancer: servers: - url: "http://localhost:8080" ``` ```toml tab="File (TOML)" [http] [http.routers] [http.routers.my-router] rule = "Host(`example.com`)" service = "my-service" [http.services] [http.services.my-service.loadBalancer] [[http.services.my-service.loadBalancer.servers]] url = "http://localhost:8080" ``` Using Labels With Docker and ECS When using Docker or Amazon ECS, you can define routing configuration using container labels. This method allows Traefik to automatically discover services and apply configurations without the need for additional files. ???+ example "Example with Docker" When deploying a Docker container, you can specify labels to define routing rules and services: ```yaml services: my-service: image: my-image labels: - "traefik.http.routers.my-router.rule=Host(`example.com`)" - "traefik.http.services.my-service.loadbalancer.server.port=80" ``` ???+ example "Example with ECS" In ECS, you can use task definition labels to achieve the same effect: ```yaml { "containerDefinitions": [ { "name": "my-service", "image": "my-image", "dockerLabels": { "traefik.http.routers.my-router.rule": "Host(`example.com`)", "traefik.http.services.my-service.loadbalancer.server.port": "80" } } ] } ``` Using Kubernetes Providers For Kubernetes providers, you can configure Traefik using the native Ingress or custom resources (like IngressRoute). Annotations in your Ingress or IngressRoute definition allow you to define routing rules and middleware settings. For example: ???+ example "Example with Kubernetes" ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: whoami namespace: apps annotations: traefik.ingress.kubernetes.io/router.entrypoints: websecure traefik.ingress.kubernetes.io/router.priority: "42" traefik.ingress.kubernetes.io/router.tls: "true" traefik.ingress.kubernetes.io/router.tls.options: apps-opt@kubernetescrd spec: rules: - host: my-domain.example.com http: paths: - path: / pathType: Prefix backend: service: name: whoami port: number: 80 tls: - secretName: supersecret ``` Using Key-Value Pairs With KV Providers For KV providers you can configure Traefik with key-value pairs. ???+ example "Examples" ```bash tab="etcd" # Set a router rule etcdctl put /traefik/http/routers/my-router/rule "Host(`example.com`)" # Define the service associated with the router etcdctl put /traefik/http/routers/my-router/service "my-service" # Set the backend server URL for the service etcdctl put /traefik/http/services/my-service/loadbalancer/servers/0/url "http://localhost:8080" ``` ```bash tab="Redis" # Set a router rule redis-cli set traefik/http/routers/my-router/rule "Host(`example.com`)" # Define the service associated with the router redis-cli set traefik/http/routers/my-router/service "my-service" # Set the backend server URL for the service redis-cli set traefik/http/services/my-service/loadbalancer/servers/0/url "http://localhost:8080" ``` ```bash tab="ZooKeeper" # Set a router rule create /traefik/http/routers/my-router/rule "Host(`example.com`)" # Define the service associated with the router create /traefik/http/routers/my-router/service "my-service" # Set the backend server URL for the service create /traefik/http/services/my-service/loadbalancer/servers/0/url "http://localhost:8080" ``` Using Tags With Other Providers For providers that do not support labels, such as Consul & Nomad, you can use tags to provide routing configuration. ???+ example "Example" ```json tab="Consul / Nomad" { "Name": "my-service", "Tags": [ "traefik.http.routers.my-router.rule=Host(`example.com`)", "traefik.http.services.my-service.loadbalancer.server.port=80" ], "Address": "localhost", "Port": 8080 } ``` ServersTransport ServersTransport allows you to configure the transport between Traefik and your HTTP servers. Configuration Example Declare the serversTransport: http: serversTransports: mytransport: serverName: "myhost" certificates: - "/path/to/cert1.pem" - "/path/to/cert2.pem" insecureSkipVerify: true rootCAs: - "/path/to/rootca1.pem" - "/path/to/rootca2.pem" maxIdleConnsPerHost: 100 disableHTTP2: true peerCertSANs: - type: DNSName value: foo.com - type: URI value: spiffe://example.org/peer forwardingTimeouts: dialTimeout: "30s" responseHeaderTimeout: "10s" readTimeout: "30s" writeTimeout: "30s" idleConnTimeout: "60s" readIdleTimeout: "5s" pingTimeout: "15s" spiffe: ids: - "spiffe://example.org/id1" - "spiffe://example.org/id2" trustDomain: "example.org" cipherSuites: - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 minVersion: VersionTLS12 maxVersion: VersionTLS12 [http.serversTransports.mytransport] serverName = "myhost" certificates = ["/path/to/cert1.pem", "/path/to/cert2.pem"] insecureSkipVerify = true rootCAs = ["/path/to/rootca1.pem", "/path/to/rootca2.pem"] maxIdleConnsPerHost = 100 disableHTTP2 = true peerCertSANs = [{type = "DNSName", value = "foo.com"}, {type = "URI", value = "spiffe://example.org/peer"}] cipherSuites = ["TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"] minVersion = "VersionTLS12" maxVersion = "VersionTLS12" [http.serversTransports.mytransport.forwardingTimeouts] dialTimeout = "30s" responseHeaderTimeout = "10s" readTimeout = "30s" writeTimeout = "30s" idleConnTimeout = "60s" readIdleTimeout = "5s" pingTimeout = "15s" [http.serversTransports.mytransport.spiffe] ids = ["spiffe://example.org/id1", "spiffe://example.org/id2"] trustDomain = "example.org" Attach the serversTransport to a service: ## Dynamic configuration http: services: Service01: loadBalancer: serversTransport: mytransport ## Dynamic configuration [http.services] [http.services.Service01] [http.services.Service01.loadBalancer] serversTransport = "mytransport" labels: - "traefik.http.services.Service01.loadBalancer.serversTransport=mytransport" { // ... "Tags": [ "traefik.http.services.Service01.loadBalancer.serversTransport=mytransport" ] } Configuration Options Field Description Default Required serverName Configures the server name that will be used as the SNI. "" No certificates Defines the list of certificates (as file paths, or data bytes) that will be set as client certificates for mTLS. [] No insecureSkipVerify Controls whether the server's certificate chain and host name is verified. false No rootCAs Set of root certificate authorities to use when verifying server certificates. (for mTLS connections). [] No cipherSuites Defines the cipher suites to use when contacting backend servers. [] No minVersion Defines the minimum TLS version to use when contacting backend servers. "" No maxVersion Defines the maximum TLS version to use when contacting backend servers. "" No maxIdleConnsPerHost Maximum idle (keep-alive) connections to keep per-host. If zero, DefaultMaxIdleConnsPerHost (2) is used. 0 No disableHTTP2 Disables HTTP/2 for connections with servers. false No peerCertSANs Defines the SANs (Subject Alternative Names) used to match against SANs during the peer certificate verification. [] No peerCertSANs[].type Defines the SAN type ( URI or DNSName) to match against the peer certificate's Subject Alternative Names. "" No peerCertSANs[].value Defines the SAN value to match against the peer certificate's Subject Alternative Names. "" No forwardingTimeouts.dialTimeout Amount of time to wait until a connection to a server can be established. 0 = no timeout 30s No forwardingTimeouts.responseHeaderTimeout Amount of time to wait for a server's response headers after fully writing the request (including its body, if any). 0 = no timeout 0s No forwardingTimeouts.readTimeout Defines a timeout for reading a response from the proxied server. The timeout between two successive read operations. The connection is closed if nothing is transmitted within this time. 0 = no timeout 0s No forwardingTimeouts.writeTimeout Defines a timeout for transmitting a request to the proxied server. The timeout between two successive write operations. The connection is closed if nothing is transmitted within this time. 0 = no timeout 0s No forwardingTimeouts.idleConnTimeout Maximum amount of time an idle (keep-alive) connection will remain idle before closing itself. 0 = no timeout 90s No forwardingTimeouts.readIdleTimeout Defines the timeout after which a health check using ping frame will be carried out if no frame is received on the HTTP/2 connection. 0s No forwardingTimeouts.pingTimeout Defines the timeout after which the HTTP/2 connection will be closed if a response to ping is not received. 15s No spiffe Defines the SPIFFE configuration. An empty spiffe section enables SPIFFE (that allows any SPIFFE ID). No spiffe.ids Defines the allowed SPIFFE IDs. This takes precedence over the SPIFFE TrustDomain. [] No spiffe.trustDomain Defines the SPIFFE trust domain. "" No Traefik HTTP Services Documentation Traefik services define how to distribute incoming traffic across your backend servers. This page covers two main concepts: Service Load Balancer: Routes traffic to backend servers using various load balancing strategies Advanced Service Types: Compose multiple services together for weighted distribution, mirroring, or failover Service Load Balancer The loadBalancer service type routes incoming requests to a list of backend servers. Each service has a load-balancer, even if there is only one server to forward traffic to. The load balancer supports multiple strategies for distributing traffic among servers: wrr (Weighted Round Robin) - Default strategy, distributes requests evenly across servers in rotation p2c (Power of Two Choices) - Selects two random servers and routes to the one with fewer active connections hrw (Highest Random Weight) - Uses consistent hashing based on client IP for session affinity leasttime - Routes to the server with lowest response time combined with fewest active connections Configuration Example http: services: my-service: loadBalancer: strategy: "wrr" servers: - url: "http://private-ip-server-1/" weight: 2 preservePath: true sticky: cookie: name: "sticky-cookie" healthcheck: path: "/health" interval: "10s" timeout: "3s" passiveHealthCheck: failureWindow: "3s" maxFailedAttempts: 3 passHostHeader: true serversTransport: "customTransport@file" responseForwarding: flushInterval: "150ms" [http.services] [http.services.my-service.loadBalancer] strategy = "wrr" [[http.services.my-service.loadBalancer.servers]] url = "http://private-ip-server-1/" [http.services.my-service.loadBalancer.sticky.cookie] name = "sticky-cookie" [http.services.my-service.loadBalancer.healthcheck] path = "/health" interval = "10s" timeout = "3s" [http.services.my-service.loadBalancer.passiveHealthCheck] failureWindow = "3s" maxFailedAttempts = 3 passHostHeader = true serversTransport = "customTransport@file" [http.services.my-service.loadBalancer.responseForwarding] flushInterval = "150ms" labels: - "traefik.http.services.my-service.loadBalancer.strategy=wrr" - "traefik.http.services.my-service.loadBalancer.servers[0].url=http://private-ip-server-1/" - "traefik.http.services.my-service.loadBalancer.servers[0].weight=2" - "traefik.http.services.my-service.loadBalancer.servers[0].preservePath=true" - "traefik.http.services.my-service.loadBalancer.sticky.cookie.name=sticky-cookie" - "traefik.http.services.my-service.loadBalancer.healthcheck.path=/health" - "traefik.http.services.my-service.loadBalancer.healthcheck.interval=10s" - "traefik.http.services.my-service.loadBalancer.healthcheck.timeout=3s" - "traefik.http.services.my-service.loadBalancer.passiveHealthCheck.failureWindow=3s" - "traefik.http.services.my-service.loadBalancer.passiveHealthCheck.maxFailedAttempts=3" - "traefik.http.services.my-service.loadBalancer.passHostHeader=true" - "traefik.http.services.my-service.loadBalancer.serversTransport=customTransport@file" - "traefik.http.services.my-service.loadBalancer.responseForwarding.flushInterval=150ms" { "Tags": [ "traefik.http.services.my-service.loadBalancer.strategy=wrr", "traefik.http.services.my-service.loadBalancer.servers[0].url=http://private-ip-server-1/", "traefik.http.services.my-service.loadBalancer.servers[0].weight=2", "traefik.http.services.my-service.loadBalancer.servers[0].preservePath=true", "traefik.http.services.my-service.loadBalancer.sticky.cookie.name=sticky-cookie", "traefik.http.services.my-service.loadBalancer.healthcheck.path=/health", "traefik.http.services.my-service.loadBalancer.healthcheck.interval=10s", "traefik.http.services.my-service.loadBalancer.healthcheck.timeout=3s", "traefik.http.services.my-service.loadBalancer.passiveHealthCheck.failureWindow=3s", "traefik.http.services.my-service.loadBalancer.passiveHealthCheck.maxFailedAttempts=3", "traefik.http.services.my-service.loadBalancer.passHostHeader=true", "traefik.http.services.my-service.loadBalancer.serversTransport=customTransport@file", "traefik.http.services.my-service.loadBalancer.responseForwarding.flushInterval=150ms" ] } Configuration Options Field Description Required servers Represents individual backend instances for your service Yes strategy Load balancing strategy for distributing traffic among servers. Valid values: wrr (default), p2c, hrw, leasttime. No sticky Defines a Set-Cookie header is set on the initial response to let the client know which server handles the first response. No healthcheck Configures health check to remove unhealthy servers from the load balancing rotation. No passiveHealthCheck Configures the passive health check to remove unhealthy servers from the load balancing rotation. No passHostHeader Allows forwarding of the client Host header to server. By default, passHostHeader is true. No serversTransport Allows to reference an HTTP ServersTransport configuration for the communication between Traefik and your servers. If no serversTransport is specified, the default@internal will be used. No responseForwarding Configures how Traefik forwards the response from the backend server to the client. No responseForwarding.flushInterval Specifies the interval in between flushes to the client while copying the response body. It is a duration in milliseconds, defaulting to 100ms. A negative value means to flush immediately after each write to the client. The FlushInterval is ignored when ReverseProxy recognizes a response as a streaming response; for such responses, writes are flushed to the client immediately. No Servers Servers represent individual backend instances for your service. The service loadBalancer servers option lets you configure the list of instances that will handle incoming requests. Configuration Options Field Description Required url Points to a specific instance. Yes for File provider, No for Docker provider weight Allows for weighted load balancing on the servers. No preservePath Allows to preserve the URL path. No Load Balancing Strategies The strategy option on the load balancer determines how traffic is distributed among the backend servers. Weighted Round Robin (wrr) The default strategy. Distributes requests evenly across all servers in rotation, respecting server weights. This strategy uses Earliest Deadline First (EDF) scheduling to provide weighted round-robin behavior. ??? example "WRR Load Balancing -- Using the File Provider" ```yaml tab="Structured (YAML)" ## Routing configuration http: services: my-service: loadBalancer: strategy: "wrr" servers: - url: "http://private-ip-server-1/" weight: 3 - url: "http://private-ip-server-2/" weight: 1 ``` ```toml tab="Structured (TOML)" ## Routing configuration [http.services] [http.services.my-service.loadBalancer] strategy = "wrr" [[http.services.my-service.loadBalancer.servers]] url = "http://private-ip-server-1/" weight = 3 [[http.services.my-service.loadBalancer.servers]] url = "http://private-ip-server-2/" weight = 1 ``` Power of Two Choices (p2c) Selects two servers at random and routes the request to the one with the fewest active connections. This algorithm provides better load distribution when servers have varying response times. ??? example "P2C Load Balancing -- Using the File Provider" ```yaml tab="Structured (YAML)" ## Routing configuration http: services: my-service: loadBalancer: strategy: "p2c" servers: - url: "http://private-ip-server-1/" - url: "http://private-ip-server-2/" - url: "http://private-ip-server-3/" ``` ```toml tab="Structured (TOML)" ## Routing configuration [http.services] [http.services.my-service.loadBalancer] strategy = "p2c" [[http.services.my-service.loadBalancer.servers]] url = "http://private-ip-server-1/" [[http.services.my-service.loadBalancer.servers]] url = "http://private-ip-server-2/" [[http.services.my-service.loadBalancer.servers]] url = "http://private-ip-server-3/" ``` Highest Random Weight (hrw) Uses consistent hashing (Rendezvous Hashing) based on the client's IP address to ensure requests from the same client are consistently routed to the same server. This provides session affinity without requiring sticky cookies. The algorithm computes a score for each available backend using a hash of the client's source IP combined with the backend's identifier, and assigns the client to the backend with the highest score. ??? example "HRW Load Balancing -- Using the File Provider" ```yaml tab="Structured (YAML)" ## Routing configuration http: services: my-service: loadBalancer: strategy: "hrw" servers: - url: "http://private-ip-server-1/" - url: "http://private-ip-server-2/" - url: "http://private-ip-server-3/" ``` ```toml tab="Structured (TOML)" ## Routing configuration [http.services] [http.services.my-service.loadBalancer] strategy = "hrw" [[http.services.my-service.loadBalancer.servers]] url = "http://private-ip-server-1/" [[http.services.my-service.loadBalancer.servers]] url = "http://private-ip-server-2/" [[http.services.my-service.loadBalancer.servers]] url = "http://private-ip-server-3/" ``` Least-Time Selects the server with the lowest average response time (Time To First Byte - TTFB), combined with the fewest active connections, weighted by server capacity. This strategy is ideal for heterogeneous backend environments where servers have varying performance characteristics, different hardware capabilities, or varying network latency. The algorithm continuously measures each backend's response time and tracks active connection counts. When routing a request, it calculates a score for each healthy server using the formula: (avg_response_time × (1 + active_connections)) / weight. The server with the lowest score receives the request. When multiple servers have identical scores, Weighted Round Robin (WRR) with Earliest Deadline First (EDF) scheduling is used as a tie-breaker. ??? example "Least-Time Load Balancing -- Using the File Provider" ```yaml tab="Structured (YAML)" ## Routing configuration http: services: my-service: loadBalancer: strategy: "leasttime" servers: - url: "http://private-ip-server-1/" - url: "http://private-ip-server-2/" - url: "http://private-ip-server-3/" ``` ```toml tab="Structured (TOML)" ## Routing configuration [http.services] [http.services.my-service.loadBalancer] strategy = "leasttime" [[http.services.my-service.loadBalancer.servers]] url = "http://private-ip-server-1/" [[http.services.my-service.loadBalancer.servers]] url = "http://private-ip-server-2/" [[http.services.my-service.loadBalancer.servers]] url = "http://private-ip-server-3/" ``` Health Check The healthcheck option configures health check to remove unhealthy servers from the load balancing rotation. Traefik will consider HTTP(s) servers healthy as long as they return a status code to the health check request (carried out every interval) between 2XX and 3XX, or matching the configured status. For gRPC servers, Traefik will consider them healthy as long as they return SERVING to gRPC health check v1 requests. To propagate status changes (e.g. all servers of this service are down) upwards, HealthCheck must also be enabled on the parent(s) of this service. Below are the available options for the health check mechanism: Field Description Default Required path Defines the server URL path for the health check endpoint. The configured path must be relative URL. "" Yes scheme Replaces the server URL scheme for the health check endpoint. No mode If defined to grpc, will use the gRPC health check protocol to probe the server. http No hostname Defines the value of hostname in the Host header of the health check request. "" No port Replaces the server URL port for the health check endpoint. No interval Defines the frequency of the health check calls for healthy targets. 30s No unhealthyInterval Defines the frequency of the health check calls for unhealthy targets. When not defined, it defaults to the interval value. - No timeout Defines the maximum duration Traefik will wait for a health check request before considering the server unhealthy. 5s No headers Defines custom headers to be sent to the health check endpoint. No followRedirects Defines whether redirects should be followed during the health check calls. true No method Defines the HTTP method that will be used while connecting to the endpoint. GET No status Defines the expected HTTP status code of the response to the health check request. No Sticky Sessions When sticky sessions are enabled, a Set-Cookie header is set on the initial response to let the client know which server handles the first response. On subsequent requests, to keep the session alive with the same server, the client should send the cookie with the value set. Stickiness on multiple levels When chaining or mixing load-balancers (e.g. a load-balancer of servers is one of the "children" of a load-balancer of services), for stickiness to work all the way, the option needs to be specified at all required levels. Which means the client needs to send a cookie with as many key/value pairs as there are sticky levels. Stickiness & Unhealthy Servers If the server specified in the cookie becomes unhealthy, the request will be forwarded to a new server (and the cookie will keep track of the new server). Cookie Name The default cookie name is an abbreviation of a sha1 (ex: _1d52e). MaxAge By default, the affinity cookie will never expire as the MaxAge option is set to zero. This option indicates the number of seconds until the cookie expires. When set to a negative number, the cookie expires immediately. Secure & HTTPOnly & SameSite flags By default, the affinity cookie is created without those flags. One however can change that through configuration. SameSite can be none, lax, strict or empty. Values are case-insensitive. Domain The Domain attribute of a cookie specifies the domain for which the cookie is valid. By setting the Domain attribute, the cookie can be shared across subdomains (for example, a cookie set for example.com would be accessible to www.example.com, api.example.com, etc.). This is particularly useful in cases where sticky sessions span multiple subdomains, ensuring that the session is maintained even when the client interacts with different parts of the infrastructure. ??? example "Adding Stickiness -- Using the File Provider" ```yaml tab="Structured (YAML)" ## Routing configuration http: services: my-service: loadBalancer: sticky: cookie: {} ``` ```toml tab="Structured (TOML)" ## Routing configuration [http.services] [http.services.my-service] [http.services.my-service.loadBalancer.sticky.cookie] ``` ??? example "Adding Stickiness with custom Options -- Using the File Provider" ```yaml tab="Structured (YAML)" ## Routing configuration http: services: my-service: loadBalancer: sticky: cookie: name: my_sticky_cookie_name secure: true domain: mysite.site httpOnly: true ``` ```toml tab="Structured (TOML)" ## Routing configuration [http.services] [http.services.my-service] [http.services.my-service.loadBalancer.sticky.cookie] name = "my_sticky_cookie_name" secure = true httpOnly = true domain = "mysite.site" sameSite = "none" ``` ??? example "Setting Stickiness on all the required levels -- Using the File Provider" ```yaml tab="Structured (YAML)" ## Routing configuration http: services: wrr1: weighted: sticky: cookie: name: lvl1 services: - name: whoami1 weight: 1 - name: whoami2 weight: 1 whoami1: loadBalancer: sticky: cookie: name: lvl2 servers: - url: http://127.0.0.1:8081 - url: http://127.0.0.1:8082 whoami2: loadBalancer: sticky: cookie: name: lvl2 servers: - url: http://127.0.0.1:8083 - url: http://127.0.0.1:8084 ``` ```toml tab="Structured (TOML)" ## Routing configuration [http.services] [http.services.wrr1] [http.services.wrr1.weighted.sticky.cookie] name = "lvl1" [[http.services.wrr1.weighted.services]] name = "whoami1" weight = 1 [[http.services.wrr1.weighted.services]] name = "whoami2" weight = 1 [http.services.whoami1] [http.services.whoami1.loadBalancer] [http.services.whoami1.loadBalancer.sticky.cookie] name = "lvl2" [[http.services.whoami1.loadBalancer.servers]] url = "http://127.0.0.1:8081" [[http.services.whoami1.loadBalancer.servers]] url = "http://127.0.0.1:8082" [http.services.whoami2] [http.services.whoami2.loadBalancer] [http.services.whoami2.loadBalancer.sticky.cookie] name = "lvl2" [[http.services.whoami2.loadBalancer.servers]] url = "http://127.0.0.1:8083" [[http.services.whoami2.loadBalancer.servers]] url = "http://127.0.0.1:8084" ``` To keep a session open with the same server, the client would then need to specify the two levels within the cookie for each request, e.g. with curl: curl -b "lvl1=whoami1; lvl2=http://127.0.0.1:8081" http://localhost:8000 Passive Health Check The passiveHealthCheck option configures passive health check to remove unhealthy servers from the load balancing rotation. Passive health checks rely on real traffic to assess server health. Traefik forwards requests as usual and evaluates each response or timeout, incrementing a failure counter whenever a request fails. If the number of successive failures within a specified time window exceeds the configured threshold, Traefik will automatically stop routing traffic to that server until it recovers. A server will be considered healthy again after the configured failure window has passed. Below are the available options for the passive health check mechanism: Field Description Default Required failureWindow Defines the time window during which the failed attempts must occur for the server to be marked as unhealthy. It also defines for how long the server will be considered unhealthy. 10s No maxFailedAttempts Defines the number of consecutive failed attempts allowed within the failure window before marking the server as unhealthy. 1 No Middlewares You can attach a list of middlewares to each HTTP service. The middlewares will take effect for all requests handled by the service, regardless of which router forwards the request. !!! info "Middlewares Execution Order" When both a router and a service have middlewares configured, the router middlewares are applied first, followed by the service middlewares. This means the request passes through router middlewares before reaching service middlewares. !!! info "Supported Providers" Service-level middlewares can be configured with the [File](../../../install-configuration/providers/others/file.md), [Docker](../../other-providers/docker.md), [Swarm](../../other-providers/docker.md), [Kubernetes IngressRoute](../../kubernetes/crd/http/ingressroute.md), [Kubernetes Ingress](../../kubernetes/ingress.md), and [Kubernetes Gateway API](../../kubernetes/gateway-api.md) providers. ??? example "Attaching Middlewares to a Service -- Using the File Provider" ```yaml tab="Structured (YAML)" ## Dynamic configuration http: services: my-service: middlewares: - add-header loadBalancer: servers: - url: "http://127.0.0.1:8080" middlewares: add-header: headers: customRequestHeaders: X-Custom-Header: "service-middleware" ``` ```toml tab="Structured (TOML)" ## Dynamic configuration [http.services] [http.services.my-service] middlewares = ["add-header"] [http.services.my-service.loadBalancer] [[http.services.my-service.loadBalancer.servers]] url = "http://127.0.0.1:8080" [http.middlewares] [http.middlewares.add-header.headers] [http.middlewares.add-header.headers.customRequestHeaders] X-Custom-Header = "service-middleware" ``` ??? example "Attaching Middlewares to a Service -- Using Docker Labels" ```yaml labels: # Define the middleware - "traefik.http.middlewares.add-header.headers.customRequestHeaders.X-Custom-Header=service-middleware" # Attach middleware to the service (at service level, not loadBalancer level) - "traefik.http.services.my-service.middlewares=add-header" # Configure the service - "traefik.http.services.my-service.loadbalancer.server.port=8080" ``` Advanced Service Types Advanced service types allow you to compose multiple services together for weighted distribution, consistent hashing, mirroring, or failover scenarios. These are distinct from load balancing strategies - they operate at the service level rather than the server level. !!! info "Key Difference" - **Load Balancing Strategies** (wrr, p2c, hrw, leasttime): Distribute traffic among **servers** within a single `loadBalancer` service - **Advanced Service Types** (weighted, highestRandomWeight, mirroring, failover): Distribute or manage traffic among multiple **services** Weighted Round robin The weighted service type load balances requests between multiple services based on weights. This is different from the wrr strategy - it operates on services, not servers. !!! info "Supported Providers" This service type can be defined currently with the [File](../../../install-configuration/providers/others/file.md) provider or [IngressRoute](../../../routing-configuration/kubernetes/crd/http/ingressroute.md). ## Routing configuration http: services: app: weighted: services: - name: appv1 weight: 3 - name: appv2 weight: 1 appv1: loadBalancer: servers: - url: "http://private-ip-server-1/" appv2: loadBalancer: servers: - url: "http://private-ip-server-2/" ## Routing configuration [http.services] [http.services.app] [[http.services.app.weighted.services]] name = "appv1" weight = 3 [[http.services.app.weighted.services]] name = "appv2" weight = 1 [http.services.appv1] [http.services.appv1.loadBalancer] [[http.services.appv1.loadBalancer.servers]] url = "http://private-ip-server-1/" [http.services.appv2] [http.services.appv2.loadBalancer] [[http.services.appv2.loadBalancer.servers]] url = "http://private-ip-server-2/" Health Check HealthCheck enables automatic self-healthcheck for this service, i.e. whenever one of its children is reported as down, this service becomes aware of it, and takes it into account (i.e. it ignores the down child) when running the load-balancing algorithm. In addition, if the parent of this service also has HealthCheck enabled, this service reports to its parent any status change. !!! note "Behavior" If HealthCheck is enabled for a given service and any of its descendants does not have it enabled, the creation of the service will fail. HealthCheck on Weighted services can be defined currently only with the [File provider](../../../install-configuration/providers/others/file.md). ## Routing configuration http: services: app: weighted: healthCheck: {} services: - name: appv1 weight: 3 - name: appv2 weight: 1 appv1: loadBalancer: healthCheck: path: /status interval: 10s timeout: 3s servers: - url: "http://private-ip-server-1/" appv2: loadBalancer: healthCheck: path: /status interval: 10s timeout: 3s servers: - url: "http://private-ip-server-2/" ## Routing configuration [http.services] [http.services.app] [http.services.app.weighted.healthCheck] [[http.services.app.weighted.services]] name = "appv1" weight = 3 [[http.services.app.weighted.services]] name = "appv2" weight = 1 [http.services.appv1] [http.services.appv1.loadBalancer] [http.services.appv1.loadBalancer.healthCheck] path = "/health" interval = "10s" timeout = "3s" [[http.services.appv1.loadBalancer.servers]] url = "http://private-ip-server-1/" [http.services.appv2] [http.services.appv2.loadBalancer] [http.services.appv2.loadBalancer.healthCheck] path = "/health" interval = "10s" timeout = "3s" [[http.services.appv2.loadBalancer.servers]] url = "http://private-ip-server-2/" Highest Random Weight The highestRandomWeight service type uses consistent hashing (Rendezvous Hashing) to load balance requests between multiple services. This ensures that requests from the same client IP are consistently routed to the same service. This is different from the hrw strategy on a loadBalancer - it operates on services, not servers. !!! info "Supported Providers" This service type can be defined currently only with the [File](../../../install-configuration/providers/others/file.md) provider. ## Routing configuration http: services: app: highestRandomWeight: services: - name: appv1 weight: 1 - name: appv2 weight: 1 appv1: loadBalancer: servers: - url: "http://private-ip-server-1/" appv2: loadBalancer: servers: - url: "http://private-ip-server-2/" ## Routing configuration [http.services] [http.services.app] [[http.services.app.highestRandomWeight.services]] name = "appv1" weight = 1 [[http.services.app.highestRandomWeight.services]] name = "appv2" weight = 1 [http.services.appv1] [http.services.appv1.loadBalancer] [[http.services.appv1.loadBalancer.servers]] url = "http://private-ip-server-1/" [http.services.appv2] [http.services.appv2.loadBalancer] [[http.services.appv2.loadBalancer.servers]] url = "http://private-ip-server-2/" Health Check HealthCheck enables automatic self-healthcheck for this service, similar to the Weighted Round Robin service type. !!! note "Behavior" If HealthCheck is enabled for a given service and any of its descendants does not have it enabled, the creation of the service will fail. HealthCheck on Highest Random Weight services can be defined currently only with the [File provider](../../../install-configuration/providers/others/file.md). ## Routing configuration http: services: app: highestRandomWeight: healthCheck: {} services: - name: appv1 weight: 1 - name: appv2 weight: 1 appv1: loadBalancer: healthCheck: path: /status interval: 10s timeout: 3s servers: - url: "http://private-ip-server-1/" appv2: loadBalancer: healthCheck: path: /status interval: 10s timeout: 3s servers: - url: "http://private-ip-server-2/" ## Routing configuration [http.services] [http.services.app] [http.services.app.highestRandomWeight.healthCheck] [[http.services.app.highestRandomWeight.services]] name = "appv1" weight = 1 [[http.services.app.highestRandomWeight.services]] name = "appv2" weight = 1 [http.services.appv1] [http.services.appv1.loadBalancer] [http.services.appv1.loadBalancer.healthCheck] path = "/health" interval = "10s" timeout = "3s" [[http.services.appv1.loadBalancer.servers]] url = "http://private-ip-server-1/" [http.services.appv2] [http.services.appv2.loadBalancer] [http.services.appv2.loadBalancer.healthCheck] path = "/health" interval = "10s" timeout = "3s" [[http.services.appv2.loadBalancer.servers]] url = "http://private-ip-server-2/" Mirroring The mirroring service type mirrors requests sent to a service to other services. Please note that by default the whole request is buffered in memory while it is being mirrored. See the maxBodySize option in the example below for how to modify this behaviour. You can also omit the request body by setting the mirrorBody option to false. To avoid buffering the request body, set the streamBody option to true: the mirrored requests are sent along with the main request, and the body is streamed to the mirrors while the main service reads it. A mirror falling more than 1 MiB behind the main service is aborted, so that it never slows the main request down, and a mirrored request is aborted when the main service does not read the whole body. The streamBody option has no effect when mirrorBody is false, and cannot be used with maxBodySize. !!! warning "Default behavior of percent" When configuring a `mirror` service, if the `percent` field is not set, it defaults to `0`, meaning **no traffic will be sent to the mirror**. !!! info "Supported Providers" This service type can be defined currently with the [File](../../../install-configuration/providers/others/file.md) provider or [IngressRoute](../../../routing-configuration/kubernetes/crd/http/ingressroute.md). ## Routing configuration http: services: mirrored-api: mirroring: service: appv1 # mirrorBody defines whether the request body should be mirrored. # Default value is true. mirrorBody: false # maxBodySize is the maximum size allowed for the body of the request. # If the body is larger, the request is not mirrored. # Default value is -1, which means unlimited size. maxBodySize: 1024 mirrors: - name: appv2 # Percent defines the percentage of requests that should be mirrored. # Default value is 0, which means no traffic will be sent to the mirror. percent: 10 appv1: loadBalancer: servers: - url: "http://private-ip-server-1/" appv2: loadBalancer: servers: - url: "http://private-ip-server-2/ ## Routing configuration [http.services] [http.services.mirrored-api] [http.services.mirrored-api.mirroring] service = "appv1" # maxBodySize is the maximum size in bytes allowed for the body of the request. # If the body is larger, the request is not mirrored. # Default value is -1, which means unlimited size. maxBodySize = 1024 # mirrorBody defines whether the request body should be mirrored. # Default value is true. mirrorBody = false [[http.services.mirrored-api.mirroring.mirrors]] name = "appv2" percent = 10 [http.services.appv1] [http.services.appv1.loadBalancer] [[http.services.appv1.loadBalancer.servers]] url = "http://private-ip-server-1/" [http.services.appv2] [http.services.appv2.loadBalancer] [[http.services.appv2.loadBalancer.servers]] url = "http://private-ip-server-2/" Health Check HealthCheck enables automatic self-healthcheck for this service, i.e. if the main handler of the service becomes unreachable, the information is propagated upwards to its parent. !!! note "Behavior" If HealthCheck is enabled for a given service and any of its descendants does not have it enabled, the creation of the service will fail. HealthCheck on Mirroring services can be defined currently only with the [File provider](../../../install-configuration/providers/others/file.md). ## Routing configuration http: services: mirrored-api: mirroring: healthCheck: {} service: appv1 mirrors: - name: appv2 percent: 10 appv1: loadBalancer: healthCheck: path: /status interval: 10s timeout: 3s servers: - url: "http://private-ip-server-1/" appv2: loadBalancer: servers: - url: "http://private-ip-server-2/" ## Routing configuration [http.services] [http.services.mirrored-api] [http.services.mirrored-api.mirroring] service = "appv1" [http.services.mirrored-api.mirroring.healthCheck] [[http.services.mirrored-api.mirroring.mirrors]] name = "appv2" percent = 10 [http.services.appv1] [http.services.appv1.loadBalancer] [http.services.appv1.loadBalancer.healthCheck] path = "/health" interval = "10s" timeout = "3s" [[http.services.appv1.loadBalancer.servers]] url = "http://private-ip-server-1/" [http.services.appv2] [http.services.appv2.loadBalancer] [http.services.appv2.loadBalancer.healthCheck] path = "/health" interval = "10s" timeout = "3s" [[http.services.appv2.loadBalancer.servers]] url = "http://private-ip-server-2/" Failover The failover service type forwards requests to a fallback service when the main service is unavailable. Failover can be triggered in two ways: Health check-based: When the main service becomes unreachable based on health checks. Status code-based: When the main service responds with specific HTTP status codes defined in the errors configuration. !!! info "Relation to HealthCheck" The failover service relies on the HealthCheck system to get notified when its main service becomes unreachable, which means HealthCheck needs to be enabled and functional on the main service. However, HealthCheck does not need to be enabled on the failover service itself for it to be functional. It is only required in order to propagate upwards the information when the failover itself becomes down (i.e. both its main and its fallback are down too). !!! info "Supported Providers" This service type can be defined with the File and Kubernetes CRD providers. HealthCheck HealthCheck enables automatic self-healthcheck for this service, i.e. if the main and the fallback services become unreachable, the information is propagated upwards to its parent. !!! note "Behavior" If HealthCheck is enabled for a given service and any of its descendants does not have it enabled, the creation of the service will fail. HealthCheck on a Failover service can be defined currently only with the [File provider](../../../install-configuration/providers/others/file.md). ## Routing configuration http: services: app: failover: healthCheck: {} service: main fallback: backup main: loadBalancer: healthCheck: path: /status interval: 10s timeout: 3s servers: - url: "http://private-ip-server-1/" backup: loadBalancer: healthCheck: path: /status interval: 10s timeout: 3s servers: - url: "http://private-ip-server-2/" ## Routing configuration [http.services] [http.services.app] [http.services.app.failover] service = "main" fallback = "backup" [http.services.app.failover.healthCheck] [http.services.main] [http.services.main.loadBalancer] [http.services.main.loadBalancer.healthCheck] path = "/status" interval = "10s" timeout = "3s" [[http.services.main.loadBalancer.servers]] url = "http://private-ip-server-1/" [http.services.backup] [http.services.backup.loadBalancer] [http.services.backup.loadBalancer.healthCheck] path = "/status" interval = "10s" timeout = "3s" [[http.services.backup.loadBalancer.servers]] url = "http://private-ip-server-2/" Errors The errors option enables status code-based failover. When the main service responds with an HTTP status code matching one of the configured ranges, Traefik automatically retries the request on the fallback service. To support request replay, the request body is buffered up to maxRequestBodyBytes. Requests with bodies larger than this limit receive a 413 Request Entity Too Large response. Below is a list of options available for the errors option and an example of how to configure it for a failover service: Field Description Default status List of HTTP status code ranges that trigger failover. Supports single codes ( "500") and ranges ( "500-504"). None maxRequestBodyBytes Maximum request body size (in bytes) to buffer for replay to the fallback service. Set to -1 for no limit. -1 ## Routing configuration http: services: app: failover: service: main fallback: backup errors: status: - "500-504" maxRequestBodyBytes: 1048576 main: loadBalancer: servers: - url: "http://private-ip-server-1/" backup: loadBalancer: servers: - url: "http://private-ip-server-2/" ## Routing configuration [http.services] [http.services.app] [http.services.app.failover] service = "main" fallback = "backup" [http.services.app.failover.errors] status = ["500-504"] maxRequestBodyBytes = 1048576 [http.services.main] [http.services.main.loadBalancer] [[http.services.main.loadBalancer.servers]] url = "http://private-ip-server-1/" [http.services.backup] [http.services.backup.loadBalancer] [[http.services.backup.loadBalancer.servers]] url = "http://private-ip-server-2/" Chaining Failover Services Failover services can be chained together for multi-level redundancy. In the following example, if the primary service fails, traffic goes to the secondary service. If both primary and secondary fail, traffic goes to the tertiary service. ## Routing configuration http: services: app: failover: healthCheck: {} service: primary-failover fallback: tertiary primary-failover: failover: healthCheck: {} service: primary fallback: secondary primary: loadBalancer: healthCheck: path: /health interval: 10s timeout: 3s servers: - url: "http://primary-server/" secondary: loadBalancer: healthCheck: path: /health interval: 10s timeout: 3s servers: - url: "http://secondary-server/" tertiary: loadBalancer: healthCheck: path: /health interval: 10s timeout: 3s servers: - url: "http://tertiary-server/" ## Routing configuration [http.services] [http.services.app] [http.services.app.failover] service = "primary-failover" fallback = "tertiary" [http.services.app.failover.healthCheck] [http.services.primary-failover] [http.services.primary-failover.failover] service = "primary" fallback = "secondary" [http.services.primary-failover.failover.healthCheck] [http.services.primary] [http.services.primary.loadBalancer] [http.services.primary.loadBalancer.healthCheck] path = "/health" interval = "10s" timeout = "3s" [[http.services.primary.loadBalancer.servers]] url = "http://primary-server/" [http.services.secondary] [http.services.secondary.loadBalancer] [http.services.secondary.loadBalancer.healthCheck] path = "/health" interval = "10s" timeout = "3s" [[http.services.secondary.loadBalancer.servers]] url = "http://secondary-server/" [http.services.tertiary] [http.services.tertiary.loadBalancer] [http.services.tertiary.loadBalancer.healthCheck] path = "/health" interval = "10s" timeout = "3s" [[http.services.tertiary.loadBalancer.servers]] url = "http://tertiary-server/" Traefik AddPrefix Documentation The addPrefix middleware updates the path of a request before forwarding it. Configuration Examples # Prefixing with /foo http: middlewares: add-foo: addPrefix: prefix: "/foo" # Prefixing with /foo [http.middlewares] [http.middlewares.add-foo.addPrefix] prefix = "/foo" # Prefixing with /foo labels: - "traefik.http.middlewares.add-foo.addprefix.prefix=/foo" // Prefixing with /foo { // ... "Tags": [ "traefik.http.middlewares.add-foo.addprefix.prefix=/foo" ] } # Prefixing with /foo apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: add-foo spec: addPrefix: prefix: /foo Configuration Options Field Description Default Required prefix String to add before the current path in the requested URL. It should include a leading slash ( /). "" Yes API Key Authentication !!! info "Traefik Hub Feature" This middleware is available exclusively in Traefik Hub. Learn more about Traefik Hub's advanced features. The API Key authentication middleware allows you to secure an API by requiring a secret key, base64 encoded or not, to be given, via an HTTP header, a cookie or a query parameter. Configuration Example apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-apikey namespace: apps spec: plugin: apiKey: keySource: headerAuthScheme: Bearer header: Authorization secretNonBase64Encoded: true secretValues: - "urn:k8s:secret:apikey:secret" - "urn:k8s:secret:apikey:othersecret" apiVersion: v1 kind: Secret type: Opaque metadata: name: apikey namespace: whoami stringData: secret: $2y$05$D4SPFxzfWKcx1OXfVhRbvOTH/QB0Lm6AXTk8.NOmU4rPLX2t6UUuW # htpasswd -nbB "" foo | cut -c 2- othersecret: $2y$05$HbLL.g5dUqJippH0RuAGL.RaM9wNS2cT7hp6.vbv5okdCmVBSDzzK # htpasswd -nbB "" bar | cut -c 2- Configuration Options Field Description Default Required keySource.header Defines the header name containing the secret sent by the client. Either keySource.header or keySource.query or keySource.cookie must be set. "" No keySource.headerAuthScheme Defines the scheme when using Authorization as header name. Check out the Authorization header documentation. "" No keySource.query Defines the query parameter name containing the secret sent by the client. Either keySource.header or keySource.query or keySource.cookie must be set. "" No keySource.cookie Defines the cookie name containing the secret sent by the client. Either keySource.header or keySource.query or keySource.cookie must be set. "" No secretNonBase64Encoded Defines whether the secret sent by the client is base64 encoded. false No secretValues Contain the hash of the API keys. Supported hashing algorithms are Bcrypt, SHA1 and MD5. The hash should be generated using htpasswd. Can reference a Kubernetes Secret using the URN format: urn:k8s:secret:[name]:[valueKey] [] Yes {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik BasicAuth Documentation The basicAuth middleware grants access to services to authorized users only. Configuration Examples # Declaring the user list http: middlewares: test-auth: basicAuth: users: - "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/" - "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0" # Declaring the user list [http.middlewares] [http.middlewares.test-auth.basicAuth] users = [ "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", ] # Declaring the user list # # Note: when used in docker-compose.yml all dollar signs in the hash need to be doubled for escaping. # To create user:password pair, it's possible to use this command: # echo $(htpasswd -nB user) | sed -e s/\\$/\\$\\$/g # # Also, note that dollar signs should NOT be doubled when not evaluated (e.g. Ansible docker_container module). labels: - "traefik.http.middlewares.test-auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" { // ... "Tags": [ "traefik.http.middlewares.test-auth.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0" ] } # Declaring the user list apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-auth spec: basicAuth: secret: secretName Configuration Options Field Description Default Required users Array of authorized users. Each user must be declared using the name:hashed-password format. (More information here) "" No usersFile Path to an external file that contains the authorized users for the middleware. The file content is a list of name:hashed-password. (More information here) "" No realm Allow customizing the realm for the authentication. "traefik" No headerField Allow defining a header field to store the authenticated user. "" No removeHeader Allow removing the authorization header before forwarding the request to your service. false No Passwords format Passwords must be hashed using MD5, SHA1, or BCrypt. Use htpasswd to generate the passwords. users & usersFile If both users and usersFile are provided, they are merged. The values in users have precedence over the contents of usersFile. Because referencing a file path isn’t feasible on Kubernetes, the users & usersFile field isn’t used in Kubernetes IngressRoute. Instead, use the secret field. Kubernetes Secrets The option users supports Kubernetes secrets. !!! note "Kubernetes kubernetes.io/basic-auth secret type" Kubernetes supports a special `kubernetes.io/basic-auth` secret type. This secret must contain two keys: `username` and `password`. Please note that these keys are not hashed or encrypted in any way, and therefore is less secure than other methods. You can find more information on the [Kubernetes Basic Authentication Secret Documentation](https://kubernetes.io/docs/concepts/configuration/secret/#basic-authentication-secret) {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik Buffering Documentation The buffering middleware limits the size of requests that can be forwarded to services. With buffering, Traefik reads the entire request into memory (possibly buffering large requests into disk), and rejects requests that are over a specified size limit. This can help services avoid large amounts of data ( multipart/form-data for example), and can minimize the time spent sending data to a Service !!! info When the middleware is attached, Traefik buffers the request body before forwarding it. As a result, Traefik can send the request upstream with a fixed `Content-Length` instead of streaming the original chunked body. Configuration Examples # Sets the maximum request body to 2MB and the maximum response body to 10MB, # and buffers bodies larger than 1MB on disk. http: middlewares: limit: buffering: maxRequestBodyBytes: 2000000 memRequestBodyBytes: 1000000 maxResponseBodyBytes: 10000000 memResponseBodyBytes: 1000000 # Sets the maximum request body to 2MB and the maximum response body to 10MB, # and buffers bodies larger than 1MB on disk. [http.middlewares] [http.middlewares.limit.buffering] maxRequestBodyBytes = 2000000 memRequestBodyBytes = 1000000 maxResponseBodyBytes = 10000000 memResponseBodyBytes = 1000000 # Sets the maximum request body to 2MB and the maximum response body to 10MB, # and buffers bodies larger than 1MB on disk. labels: - "traefik.http.middlewares.limit.buffering.maxRequestBodyBytes=2000000" - "traefik.http.middlewares.limit.buffering.memRequestBodyBytes=1000000" - "traefik.http.middlewares.limit.buffering.maxResponseBodyBytes=10000000" - "traefik.http.middlewares.limit.buffering.memResponseBodyBytes=1000000" // Sets the maximum request body to 2MB and the maximum response body to 10MB, // and buffers bodies larger than 1MB on disk. { // ... "Tags": [ "traefik.http.middlewares.limit.buffering.maxRequestBodyBytes=2000000", "traefik.http.middlewares.limit.buffering.memRequestBodyBytes=1000000", "traefik.http.middlewares.limit.buffering.maxResponseBodyBytes=10000000", "traefik.http.middlewares.limit.buffering.memResponseBodyBytes=1000000" ] } # Sets the maximum request body to 2MB and the maximum response body to 10MB, # and buffers bodies larger than 1MB on disk. apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: limit spec: buffering: maxRequestBodyBytes: 2000000 memRequestBodyBytes: 1000000 maxResponseBodyBytes: 10000000 memResponseBodyBytes: 1000000 Configuration Options Field Description Default Required maxRequestBodyBytes Maximum allowed body size for the request (in bytes). If the request exceeds the allowed size, it is not forwarded to the Service, and the client gets a 413 (Request Entity Too Large) response. 0 means unlimited. 0 No memRequestBodyBytes Threshold (in bytes) from which the request will be buffered on disk instead of in memory. 1048576 No maxResponseBodyBytes Maximum allowed response size from the Service (in bytes). If the response exceeds the allowed size, it is not forwarded to the client. The client gets a 500 (Internal Server Error) response instead. 0 means unlimited. 0 No memResponseBodyBytes Threshold (in bytes) from which the response will be buffered on disk instead of in memory. 1048576 No retryExpression Replay the request using retryExpression. More information here. "" No disableRequestBuffer Disables request body buffering so the request body is streamed directly to the backend. When true, maxRequestBodyBytes is not enforced. More information here. false No disableResponseBuffer Disables response body buffering so the response is streamed directly to the client. Required to forward streaming responses such as Server-Sent Events, gRPC streaming, or long-poll watch endpoints. When true, maxResponseBodyBytes is not enforced. More information here. false No Streaming By default, the buffering middleware reads the complete request body and the complete response body into an in-memory or on-disk buffer before forwarding them. This is incompatible with streaming responses such as Server-Sent Events, gRPC streaming, and Kubernetes watch endpoints, where chunks must reach the client as they are produced. For streaming responses, set disableResponseBuffer to true. This preserves the maxRequestBodyBytes enforcement on uploads while passing streaming responses through untouched. WebSocket connections are not affected by this option because the buffering middleware already steps aside when the downstream connection is hijacked. !!! warning "Limitations" Disabling a buffer also disables the size limit on the matching body: `maxRequestBodyBytes` is not enforced when `disableRequestBuffer` is `true`, and `maxResponseBodyBytes` is not enforced when `disableResponseBuffer` is `true`. `retryExpression` cannot be used when `disableRequestBuffer` or `disableResponseBuffer` is `true`, as replaying the request needs the buffered request body, and evaluating the expression needs the buffered response. When both options are `true`, the middleware forwards requests and responses untouched. retryExpression The retry expression is defined as a logical combination of the functions below with the operators AND ( &&) and OR ( ||). At least one function is required: Attempts() number of attempts (the first one counts). ResponseCode() response code of the Service. IsNetworkError() whether the response code is related to networking error. Traefik Chain Middleware Documentation The chain middleware enables you to define reusable combinations of other pieces of middleware. It makes it effortless to reuse the same groups. Configuration Example Below is an example of a Chain containing AllowList, BasicAuth, and RedirectScheme. # ... http: routers: router1: service: service1 middlewares: - secured rule: "Host(`mydomain`)" middlewares: secured: chain: middlewares: - https-only - known-ips - auth-users auth-users: basicAuth: users: - "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/" https-only: redirectScheme: scheme: https known-ips: ipAllowList: sourceRange: - "192.168.1.7" - "127.0.0.1/32" services: service1: loadBalancer: servers: - url: "http://127.0.0.1:80" # ... [http.routers] [http.routers.router1] service = "service1" middlewares = ["secured"] rule = "Host(`mydomain`)" [http.middlewares] [http.middlewares.secured.chain] middlewares = ["https-only", "known-ips", "auth-users"] [http.middlewares.auth-users.basicAuth] users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"] [http.middlewares.https-only.redirectScheme] scheme = "https" [http.middlewares.known-ips.ipAllowList] sourceRange = ["192.168.1.7", "127.0.0.1/32"] [http.services] [http.services.service1] [http.services.service1.loadBalancer] [[http.services.service1.loadBalancer.servers]] url = "http://127.0.0.1:80" labels: - "traefik.http.routers.router1.service=service1" - "traefik.http.routers.router1.middlewares=secured" - "traefik.http.routers.router1.rule=Host(`mydomain`)" - "traefik.http.middlewares.secured.chain.middlewares=https-only,known-ips,auth-users" - "traefik.http.middlewares.auth-users.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/" - "traefik.http.middlewares.https-only.redirectscheme.scheme=https" - "traefik.http.middlewares.known-ips.ipallowlist.sourceRange=192.168.1.7,127.0.0.1/32" - "traefik.http.services.service1.loadbalancer.server.port=80" { // ... "Tags": [ "traefik.http.routers.router1.service=service1", "traefik.http.routers.router1.middlewares=secured", "traefik.http.routers.router1.rule=Host(`mydomain`)", "traefik.http.middlewares.secured.chain.middlewares=https-only,known-ips,auth-users", "traefik.http.middlewares.auth-users.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "traefik.http.middlewares.https-only.redirectscheme.scheme=https", "traefik.http.middlewares.known-ips.ipallowlist.sourceRange=192.168.1.7,127.0.0.1/32", "traefik.http.services.service1.loadbalancer.server.port=80" ] } apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test namespace: default spec: entryPoints: - web routes: - match: Host(`mydomain`) kind: Rule services: - name: whoami port: 80 middlewares: - name: secured --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: secured spec: chain: middlewares: - name: https-only - name: known-ips - name: auth-users --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: auth-users spec: basicAuth: users: - test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/ --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: https-only spec: redirectScheme: scheme: https --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: known-ips spec: ipAllowList: sourceRange: - 192.168.1.7 - 127.0.0.1/32 Configuration Options Field Description Default Required middlewares List of middlewares to chain. The middlewares have to be in the same namespace as the chain middleware. [] Yes Traefik CircuitBreaker Documentation The HTTP circuit breaker prevents stacking requests to unhealthy Services, resulting in cascading failures. When your system is healthy, the circuit is closed (normal operations). When your system becomes unhealthy, the circuit opens, and the requests are no longer forwarded, but instead are handled by a fallback mechanism. To assess if your system is healthy, the circuit breaker constantly monitors the services. The circuit breaker only analyzes what happens after its position within the middleware chain. What happens before has no impact on its state. Each router gets its own instance of a given circuit breaker. One circuit breaker instance can be open while the other remains closed: their state is not shared. This is the expected behavior, we want you to be able to define what makes a service healthy without having to declare a circuit breaker for each route. Configuration Examples # Latency Check http: middlewares: latency-check: circuitBreaker: expression: "LatencyAtQuantileMS(50.0) > 100" # Latency Check [http.middlewares] [http.middlewares.latency-check.circuitBreaker] expression = "LatencyAtQuantileMS(50.0) > 100" # Latency Check labels: - "traefik.http.middlewares.latency-check.circuitbreaker.expression=LatencyAtQuantileMS(50.0) > 100" { //.. "Tags" : [ "traefik.http.middlewares.latency-check.circuitbreaker.expression=LatencyAtQuantileMS(50.0) > 100" ] } # Latency Check apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: latency-check spec: circuitBreaker: expression: LatencyAtQuantileMS(50.0) > 100 Configuration Options Field Description Default Required expression Condition to open the circuit breaker and applies the fallback mechanism instead of calling your services. More information here "" No checkPeriod The interval between successive checks of the circuit breaker condition (when in standby state). 100ms No fallbackDuration The duration for which the circuit breaker will wait before trying to recover (from a tripped state). 10s No recoveryDuration The duration for which the circuit breaker will try to recover (as soon as it is in recovering state). 10s No responseCode The status code that the circuit breaker will return while it is in the open state. 503 No expression The expression option can check four different metrics: Metrics Description Example NetworkErrorRatio The network error ratio to open the circuit breaker. NetworkErrorRatio() > 0.30 opens the circuit breaker at a 30% ratio of network errors ResponseCodeRatio The status code ratio to open the circuit breaker. More information below ResponseCodeRatio(500, 600, 0, 600) > 0.25 opens the circuit breaker if 25% of the requests returned a 5XX status (amongst the request that returned a status code from 0 to 5XX) LatencyAtQuantileMS The latency at a quantile in milliseconds to open the circuit breaker when a given proportion of your requests become too slow. Only floating point number (with the trailing .0) for the quantile value. LatencyAtQuantileMS(50.0) > 100 opens the circuit breaker when the median latency (quantile 50) reaches 100ms. RequestThreshold The total number of requests in the circuit breaker metrics window. ResponseCodeRatio(500, 600, 0, 600) > 0.25 && RequestThreshold() >= 20 opens the circuit breaker if 25% of the requests returned a 5XX status and at least 20 requests have been recorded. ResponseCodeRatio It accepts four parameters, from, to, dividedByFrom, dividedByTo. The operation that will be computed is sum( to -> from) / sum ( dividedByFrom -> dividedByTo). If sum ( dividedByFrom -> dividedByTo) equals 0, then ResponseCodeRatio returns 0. from is inclusive, to is exclusive. Using Multiple Metrics You can combine multiple metrics using operators in your expression. Supported operators are: AND ( &&) OR ( ||) For example, ResponseCodeRatio(500, 600, 0, 600) > 0.30 || NetworkErrorRatio() > 0.10 triggers the circuit breaker when 30% of the requests return a 5XX status code, or when the ratio of network errors reaches 10%. For example, ResponseCodeRatio(500, 600, 0, 600) > 0.30 && RequestThreshold() >= 20 triggers the circuit breaker only when 30% of the requests return a 5XX status code and at least 20 requests have been recorded. Operators Here is the list of supported operators: Greater than ( >) Greater or equal than ( >=) Lesser than ( <) Lesser or equal than ( <=) Equal ( ==) Not Equal ( !=) Fallback mechanism By default the fallback mechanism returns a HTTP 503 Service Unavailable to the client instead of calling the target service. The response code can be configured. State There are three possible states for your circuit breaker: Closed (your service operates normally). Open (the fallback mechanism takes over your service). Recovering (the circuit breaker tries to resume normal operations by progressively sending requests to your service). Closed While the circuit is closed, the circuit breaker only collects metrics to analyze the behavior of the requests. At specified intervals ( checkPeriod), the circuit breaker evaluates expression to decide if its state must change. Open While open, the fallback mechanism takes over the normal service calls for a duration of FallbackDuration. The fallback mechanism returns a HTTP 503 (or ResponseCode) to the client. After this duration, it enters the recovering state. Recovering While recovering, the circuit breaker sends linearly increasing amounts of requests to your service (for RecoveryDuration). If your service fails during recovery, the circuit breaker opens again. If the service operates normally during the entire recovery duration, then the circuit breaker closes. Traefik Compress Documentation The compress middleware compresses response. It supports Gzip, Brotli and Zstandard compression Configuration Examples # Enable compression http: middlewares: test-compress: compress: {} # Enable compression [http.middlewares] [http.middlewares.test-compress.compress] # Enable compression labels: - "traefik.http.middlewares.test-compress.compress=true" // Enable compression { //... "Tags": [ "traefik.http.middlewares.test-compress.compress=true" ] } # Enable compression apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-compress spec: compress: {} Configuration Options Field Description Default Required excludedContentTypes List of content types to compare the Content-Type header of the incoming requests and responses before compressing. The responses with content types defined in excludedContentTypes are not compressed. Content types are compared in a case-insensitive, whitespace-ignored manner. The excludedContentTypes and includedContentTypes options are mutually exclusive. "" No defaultEncoding specifies the default encoding if the Accept-Encoding header is not in the request or contains a wildcard ( *). "" No encodings Specifies the list of supported compression encodings. At least one encoding value must be specified, and valid entries are zstd (Zstandard), br (Brotli), and gzip (Gzip). The order of the list also sets the priority, the top entry has the highest priority. gzip, br, zstd No includedContentTypes List of content types to compare the Content-Type header of the responses before compressing. The responses with content types defined in includedContentTypes are compressed. Content types are compared in a case-insensitive, whitespace-ignored manner. The excludedContentTypes and includedContentTypes options are mutually exclusive. "" No minResponseBodyBytes `Minimum amount of bytes a response body must have to be compressed. Responses smaller than the specified values will not be compressed. 1024 No Compression activation The activation of compression, and the compression method choice rely (among other things) on the request's Accept-Encoding header. Responses are compressed when the following criteria are all met: The Accept-Encoding request header contains gzip, *, and/or br, and/or zstd with or without quality values. If the Accept-Encoding request header is absent, the response won't be encoded. When defaultEncoding is configured, the response is encoded even when Accept-Encoding is absent. If it is present, but its value is the empty string, then compression is turned off. The response is not already compressed, that is the Content-Encoding response header is not already set. The response Content-Type header is not one among the excludedContentTypes options, or is one among the includedContentTypes options. The response body is larger than the configured minimum amount of bytes(option minResponseBodyBytes) (default is 1024). Empty Content-Type Header If the Content-Type header is not defined, or empty, the compress middleware will automatically detect a content type. It will also set the Content-Type header according to the detected MIME type. GRPC application Note that application/grpc is never compressed. Traefik ContentType Documentation The contentType middleware sets the Content-Type header value to the media type detected from the response content, when it is not set by the backend. !!! info The `contentType` middleware only applies when Traefik detects the MIME type. If any middleware (such as Headers or Compress) sets the `contentType` header at any point in the chain, the `contentType` middleware has no effect. Configuration Examples # Enable auto-detection http: middlewares: autodetect: contentType: {} # Enable auto-detection [http.middlewares] [http.middlewares.autodetect.contentType] # Enable auto-detection labels: - "traefik.http.middlewares.autodetect.contenttype=true" // Enable auto-detection { // ... "Tags": [ "traefik.http.middlewares.autodetect.contenttype=true" ] } # Enable auto-detection apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: autodetect spec: contentType: {} Traefik DigestAuth Documentation The DigestAuth middleware grants access to services to authorized users only. Configuration Examples # Declaring the user list http: middlewares: test-auth: digestAuth: users: - "test:traefik:a2688e031edb4be6a3797f3882655c05" - "test2:traefik:518845800f9e2bfb1f1f740ec24f074e" # Declaring the user list [http.middlewares] [http.middlewares.test-auth.digestAuth] users = [ "test:traefik:a2688e031edb4be6a3797f3882655c05", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e", ] # Declaring the user list labels: - "traefik.http.middlewares.test-auth.digestauth.users=test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e" // Declaring the user list { //... "Tags" : [ "traefik.http.middlewares.test-auth.digestauth.users=test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e" ] } # Declaring the user list apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-auth spec: digestAuth: secret: userssecret Configuration Options Field Description Default Required users Array of authorized users. Each user must be declared using the name:realm:encoded-password format. The option users supports Kubernetes secrets. (More information here) [] No usersFile Path to an external file that contains the authorized users for the middleware. The file content is a list of name:realm:encoded-password. (More information here) "" No realm Allow customizing the realm for the authentication. "traefik" No headerField Allow defining a header field to store the authenticated user. "" No removeHeader Allow removing the authorization header before forwarding the request to your service. false No Passwords format Use htdigest to generate the passwords. users & usersFile If both users and usersFile are provided, they are merged. The values in users have precedence over the contents of usersFile. Because referencing a file path isn’t feasible on Kubernetes, the users & usersFile field isn’t used in Kubernetes IngressRoute. Instead, use the secret field. Kubernetes Secrets On Kubernetes, you don’t use the users or usersFile fields. Instead, you reference a Kubernetes secret using the secret field in your Middleware resource. This secret can be one of two types: kubernetes.io/basic-auth secret: This secret type contains two keys— username and password—but is generally suited for a smaller number of users. Please note that these keys are not hashed or encrypted in any way, and therefore is less secure than the other method. Opaque secret with a users field: Here, the secret contains a single string field (often called users) where each line represents a user. This approach allows you to store multiple users in one secret. {% include-markdown "includes/traefik-for-business-applications.md" %} Distributed RateLimit !!! info "Traefik Hub Feature" This middleware is available exclusively in Traefik Hub. Learn more about Traefik Hub's advanced features. The Distributed RateLimit middleware ensures that requests are limited over time throughout your cluster and not only on an individual proxy. It is based on a token bucket implementation. Configuration Example Below is an advanced configuration that enables the Distributed RateLimit middleware with Redis backend for cluster-wide rate limiting. # Here, a limit of 100 requests per second is allowed. # In addition, a burst of 200 requests is allowed. apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-distributedratelimit namespace: traefik spec: plugin: distributedRateLimit: burst: 200 limit: 100 period: 1s denyOnError: false responseHeaders: true sourceCriterion: ipStrategy: excludedIPs: - 172.20.176.201 store: redis: endpoints: - my-release-redis-master.default.svc.cluster.local:6379 # Use the field password of the Secret redis in the same namespace password: urn:k8s:secret:redis:password timeout: 500ms apiVersion: v1 kind: Secret metadata: name: redis namespace: traefik stringData: password: mysecret12345678 Rate and Burst The rate is defined by dividing limit by period. For a rate below 1 req/s, define a period larger than a second The middleware is based on a token bucket implementation. In this analogy, the limit and period parameters define the rate at which the bucket refills, and the burst is the size (volume) of the bucket. apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-ratelimit spec: plugin: distributedRateLimit: burst: 100 period: 1m limit: 6 In the example above, the middleware allows up to 100 connections in parallel ( burst). Each connection consume a token, once the 100 tokens are consumed, the other ones are blocked until at least one token is available in the bucket. When the bucket is not full, on token is generated every 10 seconds (6 every 1 minutes ( period / limit)). Configuration Options Field Description Default Required limit Number of requests used to define the rate using the period. 0 means no rate limiting. More information here. 0 No period Period of time used to define the rate. More information here. 1s No burst Maximum number of requests allowed to go through at the very same moment. More information here. 1 No denyOnError Whether to deny requests when the rate limit store (Redis) is unavailable. When false, requests are allowed through if Redis cannot be reached. true No responseHeaders Whether to inject rate limit headers ( X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) into responses. false No store.redis.endpoints Endpoints of the Redis instances to connect to (example: redis.traefik-hub.svc.cluster.local:6379) "" Yes store.redis.username The username Traefik Hub will use to connect to Redis "" No store.redis.password The password Traefik Hub will use to connect to Redis "" No store.redis.database The database Traefik Hub will use to store information. Not available in Redis Cluster mode (only database 0 is supported). 0 No store.redis.timeout Timeout applied to dial, read, and write operations on the Redis connection. "" No store.redis.cluster Enable Redis Cluster mode. Set to {} to enable; omit to disable. Cannot be used together with store.redis.sentinel. - No store.redis.sentinel.masterSet Name of the Redis Sentinel master set. Cannot be used together with store.redis.cluster. "" Yes (when using Sentinel) store.redis.sentinel.username Username for authenticating with the Redis Sentinel. "" No store.redis.sentinel.password Password for authenticating with the Redis Sentinel. "" No store.redis.tls.ca Custom CA bundle "" No store.redis.tls.cert TLS certificate "" No store.redis.tls.key TLS key "" No store.redis.tls.insecureSkipVerify Allow skipping the TLS verification false No sourceCriterion.requestHost Whether to consider the request host as the source. More information about sourceCriterionhere. false No sourceCriterion.requestHeaderName Name of the header used to group incoming requests. More information about sourceCriterionhere. "" No sourceCriterion.ipStrategy.depth Depth position of the IP to select in the X-Forwarded-For header (starting from the right). 0 means no depth. If greater than the total number of IPs in X-Forwarded-For, then the client IP is empty If higher than 0, the excludedIPs options is not evaluated. More information about sourceCriterion, ipStrategy, and depth below. 0 No sourceCriterion.ipStrategy.excludedIPs Allows Traefik to scan the X-Forwarded-For header and select the first IP not in the list. If depth is specified, excludedIPs is ignored. More information about sourceCriterion, ipStrategy, and excludedIPs below. No sourceCriterion The sourceCriterion option defines what criterion is used to group requests as originating from a common source. If several strategies are defined at the same time, an error will be raised. If none are set, the default is to use the request's remote address field (as an ipStrategy). ipStrategy The ipStrategy option defines two parameters that configures how Traefik determines the client IP: depth, and excludedIPs. As a middleware, rate-limiting happens before the actual proxying to the backend takes place. In addition, the previous network hop only gets appended to X-Forwarded-For during the last stages of proxying, that is after it has already passed through rate-limiting. Therefore, during rate-limiting, as the previous network hop is not yet present in X-Forwarded-For, it cannot be found and/or relied upon. sourceCriterion.ipStrategy.depth If depth is set to 2, and the request X-Forwarded-For header is "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" then the "real" client IP is "10.0.0.1" (at depth 4) but the IP used as the criterion is "12.0.0.1" ( depth=2). X-Forwarded-For depth clientIP "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" 1 "13.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" 3 "11.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" 5 "" sourceCriterion.ipStrategy.excludedIPs Contrary to what the name might suggest, this option is not about excluding an IP from the rate limiter, and therefore cannot be used to deactivate rate limiting for some IPs. excludedIPs is meant to address two classes of somewhat distinct use-cases: Distinguish IPs which are behind the same (set of) reverse-proxies so that each of them contributes, independently to the others, to its own rate-limit "bucket" (cf the token bucket). In this case, excludedIPs should be set to match the list of X-Forwarded-For IPs that are to be excluded, in order to find the actual clientIP. Example to use each IP as a distinct source: X-Forwarded-For excludedIPs clientIP "10.0.0.1,11.0.0.1,12.0.0.1" "11.0.0.1,12.0.0.1" "10.0.0.1" "10.0.0.2,11.0.0.1,12.0.0.1" "11.0.0.1,12.0.0.1" "10.0.0.2" Group together a set of IPs (also behind a common set of reverse-proxies) so that they are considered the same source, and all contribute to the same rate-limit bucket. Example to group IPs together as same source: X-Forwarded-For excludedIPs clientIP "10.0.0.1,11.0.0.1,12.0.0.1" "12.0.0.1" "11.0.0.1" "10.0.0.2,11.0.0.1,12.0.0.1" "12.0.0.1" "11.0.0.1" "10.0.0.3,11.0.0.1,12.0.0.1" "12.0.0.1" "11.0.0.1" store A Distributed Rate Limit middleware uses a persistent KV storage to store data. Refer to the redis options to configure the Redis connection. Connection parameters to your Redis server are attached to your Middleware deployment. The following Redis modes are supported: Single instance mode Redis Cluster Redis Sentinel For more information about Redis, we recommend the official Redis documentation. !!! info If you use Redis in single instance mode or Redis Sentinel, you can configure the `database` field. This value won't be taken into account if you use Redis Cluster (only database `0` is available). In this case, a warning is displayed, and the value is ignored. Traefik EncodedCharacters Documentation The EncodedCharacters middleware controls which ambiguous reserved encoded characters are allowed in the request path. When you use this middleware, by default, potentially dangerous encoded characters are rejected for security enhancement. Configuration Examples # Allow encoded slash in the request path. labels: - "traefik.http.middlewares.test-encodedchars.encodedcharacters.allowencodedslash=true" # Allow encoded slash in the request path. apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-encodedchars spec: encodedCharacters: allowEncodedSlash: true # Allow encoded slash in the request path. - "traefik.http.middlewares.test-encodedchars.encodedcharacters.allowencodedslash=true" # Allow encoded slash in the request path. http: middlewares: test-encodedchars: encodedCharacters: allowEncodedSlash: true # Allow encoded slash in the request path. [http.middlewares] [http.middlewares.test-encodedchars.encodedCharacters] allowEncodedSlash = true Configuration Options When you are configuring these options, check if your backend is fully compliant with RFC 3986. This helps avoid split-view situation, where Traefik and your backend interpret the same URL differently. Field Description Default Required allowEncodedSlash Allow encoded slash ( %2F and %2f) in the request path. false No allowEncodedBackSlash Allow encoded backslash ( %5C and %5c) in the request path. false No allowEncodedSemicolon Allow encoded semicolon ( %3B and %3b) in the request path. false No allowEncodedPercent Allow encoded percent ( %25) in the request path. false No allowEncodedQuestionMark Allow encoded question mark ( %3F and %3f) in the request path. false No allowEncodedHash Allow encoded hash ( %23) in the request path. false No Traefik Errors Documentation The errors middleware returns a custom page in lieu of the default, according to configured ranges of HTTP Status codes. Configuration Examples # Dynamic Custom Error Page for 5XX Status Code excluding 502 and 504 http: middlewares: test-errors: errors: status: - "500" - "501" - "503" - "505-599" statusRewrites: "418": 404 "502-504": 500 service: error-handler-service query: "/{status}.html" services: # ... definition of the error-handler-service # Dynamic Custom Error Page for 5XX Status Code excluding 502 and 504 [http.middlewares] [http.middlewares.test-errors.errors] status = ["500","501","503","505-599"] service = "error-handler-service" query = "/{status}.html" [http.middlewares.test-errors.errors.statusRewrites] "418" = 404 "502-504" = 500 [http.services] # ... definition of the error-handler-service # Dynamic Custom Error Page for 5XX Status Code labels: - "traefik.http.middlewares.test-errors.errors.status=500,501,503,505-599" - "traefik.http.middlewares.test-errors.errors.statusRewrites.418=404" - "traefik.http.middlewares.test-errors.errors.statusRewrites.502-504=500" - "traefik.http.middlewares.test-errors.errors.service=error-handler-service" - "traefik.http.middlewares.test-errors.errors.query=/{status}.html" // Dynamic Custom Error Page for 5XX Status Code excluding 502 and 504 { // ... "Tags": [ "traefik.http.middlewares.test-errors.errors.status=500,501,503,505-599", "traefik.http.middlewares.test-errors.errors.statusRewrites.418=404", "traefik.http.middlewares.test-errors.errors.statusRewrites.502-504=500", "traefik.http.middlewares.test-errors.errors.service=error-handler-service", "traefik.http.middlewares.test-errors.errors.query=/{status}.html" ] } apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-errors spec: errors: status: - "500" - "501" - "503" - "505-599" statusRewrites: "418": 404 "502-504": 500 query: /{status}.html service: name: error-handler-service port: 80 Configuration Options Field Description Default Required status Defines which status or range of statuses should result in an error page. The status code ranges are inclusive ( 505-599 will trigger with every code between 505 and 599, 505 and 599 included). You can define either a status code as a number ( 500), as multiple comma-separated numbers ( 500,502), as ranges by separating two codes with a dash ( 505-599), or a combination of the two ( 404,418,505-599). [] No statusRewrites An optional mapping of status codes to be rewritten. More information here. [] No service The service that will serve the new requested error page. More information here. "" Yes query The URL for the error page (hosted by service). More information here "" No errorRequestHeaders Defines the list of original request headers forwarded to the error page service. More information here [] No service and HostHeader By default, the client Host header value is forwarded to the configured error service. To forward the Host value corresponding to the configured error service URL, the passHostHeader option must be set to false. !!!info "Kubernetes" When specifying a service in Kubernetes (e.g., in an IngressRoute), you need to reference the name, namespace, and port of your Kubernetes Service resource. For example, my-service.my-namespace@kubernetescrd (or my-service.my-namespace@kubernetescrd:80) ensures that requests go to the correct service and port. !!! info "ServersTransport (Kubernetes)" To customize how Traefik connects to the error page service (for example, to configure TLS to the backend), set a [`serversTransport`](../../kubernetes/crd/http/serverstransport.md) on the middleware's `service`. The `traefik.ingress.kubernetes.io/service.serverstransport` annotation on the Kubernetes Service is not applied here: it only affects a Service used as an Ingress backend, not one referenced by a middleware. ```yaml apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-errors spec: errors: status: - "500" - "501" service: name: error-handler-service port: 80 serversTransport: mytransport ``` statusRewrites statusRewrites is an optional mapping of status codes to be rewritten. For example, if a service returns a 418, you might want to rewrite it to a 404. You can map individual status codes or even ranges to a different status code. The syntax for ranges follows the same rules as the status option. query There are multiple variables that can be placed in the query option to insert values in the URL. The table below lists all the available variables and their associated values. Variable Value {status} The response status code. {originalStatus} The original response status code, if it has been modified by the statusRewrites option. {url} The escaped request URL. errorRequestHeaders Defines the list of original request headers forwarded to the error page service. By default ( errorRequestHeaders not set), all request headers — including authentication material such as Authorization and Cookie — are forwarded. If the error page service is in a separate trust domain, use this option to restrict which headers cross the service boundary. Set to an explicit list to forward only those headers, or set to an empty list ( errorRequestHeaders: []) to forward no headers. Traefik ForwardAuth Documentation The forwardAuth middleware delegates authentication to an external service. If the service answers with a 2XX code, access is granted, and the original request is performed. Otherwise, the response from the authentication server is returned. Configuration Example # Forward authentication to example.com http: middlewares: test-auth: forwardAuth: address: "https://example.com/auth" # Forward authentication to example.com [http.middlewares] [http.middlewares.test-auth.forwardAuth] address = "https://example.com/auth" # Forward authentication to example.com labels: - "traefik.http.middlewares.test-auth.forwardauth.address=https://example.com/auth" // Forward authentication to example.com { "Tags" : [ "traefik.http.middlewares.test-auth.forwardauth.address=https://example.com/auth" ] } # Forward authentication to example.com apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-auth spec: forwardAuth: address: https://example.com/auth Configuration Options Field Description Default Required address Authentication server address. "" Yes trustForwardHeader Trust all X-Forwarded-* headers. The trustForwardHeader option is deprecated and will be removed in the next major version. More information here - No authResponseHeaders List of headers to copy from the authentication server response and set on forwarded request, replacing any existing conflicting headers. [] No authResponseHeadersRegex Regex to match by the headers to copy from the authentication server response and set on forwarded request, after stripping all headers that match the regex. More information here. "" No authRequestHeaders List of the headers to copy from the request to the authentication server. It allows filtering headers that should not be passed to the authentication server. If not set or empty, then all request headers are passed. [] No addAuthCookiesToResponse List of cookies to copy from the authentication server to the response, replacing any existing conflicting cookie from the forwarded response. Please note that all backend cookies matching the configured list will not be added to the response. [] No forwardBody Sets the forwardBody option to true to send the Body. As body is read inside Traefik before forwarding, this breaks streaming. false No maxBodySize Set the maxBodySize to limit the body size in bytes. If body is bigger than this, it returns a 401 (unauthorized). If left unset, the request body size is unrestricted which can have performance or security implications. More information here. -1 No maxResponseBodySize Set the maxResponseBodySize to limit the response body size from the authentication server in bytes. If the response body exceeds this limit, it returns a 401 (unauthorized). If left unset, the response body size is unrestricted which can have performance or security implications. More information here. - No headerField Defines a header field to store the authenticated user. "" No preserveLocationHeader Defines whether to forward the Location header to the client as is or prefix it with the domain name of the authentication server. false No preserveRequestMethod Defines whether to preserve the original request method while forwarding the request to the authentication server. false No authSigninURL Specifies the URL to redirect to when the authentication server returns 401 Unauthorized. "" No tls.ca Sets the path to the certificate authority used for the secured connection to the authentication server, it defaults to the system bundle. "" No tls.cert Sets the path to the public certificate used for the secure connection to the authentication server. When using this option, setting the key option is required. "" No tls.key Sets the path to the private key used for the secure connection to the authentication server. When using this option, setting the cert option is required. "" No tls.caSecret Defines the secret that contains the certificate authority used for the secured connection to the authentication server, it defaults to the system bundle. This option is only available for the Kubernetes CRD. No tls.certSecret Defines the secret that contains both the private and public certificates used for the secure connection to the authentication server. This option is only available for the Kubernetes CRD. No tls.insecureSkipVerify During TLS connections, if this option is set to true, the authentication server will accept any certificate presented by the server regardless of the host names it covers. false No authResponseHeadersRegex It allows partial matching of the regular expression against the header key. The start of string ( ^) and end of string ( $) anchors should be used to ensure a full match against the header key. Regular expressions and replacements can be tested using online tools such as Go Playground or the Regex101. maxBodySize The maxBodySize option controls the maximum size of request bodies that will be forwarded to the authentication server. ⚠️ Important Security Consideration By default, maxBodySize is not set (value: -1), which means request body size is unlimited. This can have significant security and performance implications: Security Risk: Attackers can send extremely large request bodies, potentially causing DoS attacks or memory exhaustion Performance Impact: Large request bodies consume memory and processing resources, affecting overall system performance Resource Consumption: Unlimited body size can lead to unexpected resource usage patterns Recommended Configuration It is strongly recommended to set an appropriate maxBodySize value for your use case: # For most web applications (1MB limit) maxBodySize: 1048576 # 1MB in bytes # For API endpoints expecting larger payloads (10MB limit) maxBodySize: 10485760 # 10MB in bytes # For file upload authentication (100MB limit) maxBodySize: 104857600 # 100MB in bytes Guidelines for Setting maxBodySize Web Forms: 1-5MB is typically sufficient for most form submissions API Endpoints: Consider your largest expected JSON/XML payload + buffer File Uploads: Set based on your maximum expected file size High-Traffic Services: Use smaller limits to prevent resource exhaustion maxResponseBodySize The maxResponseBodySize option defines the maximum allowed response body size in bytes from the authentication server. If the response body exceeds the configured limit, the request is rejected with a 401 (Unauthorized) status. If left unset, the request body size is unrestricted which can have performance or security implications. !!! warning It is strongly recommended to set this option to a suitable value. Not setting it (or setting it to `-1`) allows unlimited response body sizes which can lead to DoS attacks and memory exhaustion. trustForwardHeader !!! warning `trustForwardHeader` option is deprecated and will be removed in the next major version. Configure the trusted IPs at the [EntryPoint level](../../../install-configuration/entrypoints.md#forwarded-headers) using `forwardedHeaders.trustedIPs`, and set `trustForwardHeader` to `true` on this middleware. With this setup, the EntryPoint is responsible for sanitizing incoming `X-Forwarded-*` headers: it strips any such headers sent by untrusted clients and only preserves those coming from trusted upstream proxies. By the time the ForwardAuth middleware processes the request, all `X-Forwarded-*` headers are guaranteed to be trustworthy, including those intentionally added by other middlewares in the chain — for example, the `X-Forwarded-Prefix` header set by the [StripPrefix](stripprefix.md) middleware. If `trustForwardHeader` is not explicitly set, Traefik will log a warning at startup and use a legacy behavior where some `X-Forwarded-*` headers (e.g. `X-Forwarded-For`, `X-Forwarded-Proto`) are removed but others (e.g. `X-Forwarded-Prefix`) are forwarded untouched. To silence this warning, explicitly set `trustForwardHeader` to `true` or `false`. Set the trustForwardHeader option to true to trust all X-Forwarded-* headers. Forward-Request Headers The following request properties are provided to the forward-auth target endpoint as X-Forwarded- headers. Property Forward-Request Header HTTP Method X-Forwarded-Method Protocol X-Forwarded-Proto Host X-Forwarded-Host Request URI X-Forwarded-Uri Source IP-Address X-Forwarded-For {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik GrpcWeb Documentation The grpcWeb middleware converts gRPC Web requests to HTTP/2 gRPC requests before forwarding them to the backends. !!! tip Please note, that Traefik needs to communicate using gRPC with the backends (h2c or HTTP/2 over TLS). Check out [Exposing gRPC Services](../../../../expose/overview.md#exposing-grpc-services) for more details. Configuration Examples http: middlewares: test-grpcweb: grpcWeb: allowOrigins: - "*" [http.middlewares] [http.middlewares.test-grpcweb.grpcWeb] allowOrigins = ["*"] labels: - "traefik.http.middlewares.test-grpcweb.grpcweb.allowOrigins=*" { //... "Tags" : [ "traefik.http.middlewares.test-grpcweb.grpcWeb.allowOrigins=*" ] } apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-grpcweb spec: grpcWeb: allowOrigins: - "*" Configuration Options Field Description Default Required allowOrigins List of allowed origins. A wildcard origin * can also be configured to match all requests. More information here. [] No allowOrigins More information including how to use the settings can be found at: Mozilla.org w3 IETF Traefik Headers Documentation The Headers middleware manages the headers of requests and responses. By default, the following headers are automatically added when proxying requests: Property HTTP Header Client's IP X-Forwarded-For, X-Real-Ip Host X-Forwarded-Host Port X-Forwarded-Port Protocol X-Forwarded-Proto Proxy Server's Hostname X-Forwarded-Server Configuration Examples Adding Headers to the Request and the Response The following example adds the X-Script-Name header to the proxied request and the X-Custom-Response-Header header to the response http: middlewares: testHeader: headers: customRequestHeaders: X-Script-Name: "test" customResponseHeaders: X-Custom-Response-Header: "value" [http.middlewares] [http.middlewares.testHeader.headers] [http.middlewares.testHeader.headers.customRequestHeaders] X-Script-Name = "test" [http.middlewares.testHeader.headers.customResponseHeaders] X-Custom-Response-Header = "value" labels: - "traefik.http.middlewares.testHeader.headers.customrequestheaders.X-Script-Name=test" - "traefik.http.middlewares.testHeader.headers.customresponseheaders.X-Custom-Response-Header=value" { //... "Tags": [ "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test", "traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header=value" ] } apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-header spec: headers: customRequestHeaders: X-Script-Name: "test" customResponseHeaders: X-Custom-Response-Header: "value" Adding and Removing Headers In the following example, requests are proxied with an extra X-Script-Name header while their X-Custom-Request-Header header gets stripped, and responses are stripped of their X-Custom-Response-Header header. http: middlewares: testHeader: headers: customRequestHeaders: X-Script-Name: "test" # Adds X-Custom-Request-Header: "" # Removes customResponseHeaders: X-Custom-Response-Header: "" # Removes [http.middlewares] [http.middlewares.testHeader.headers] [http.middlewares.testHeader.headers.customRequestHeaders] X-Script-Name = "test" # Adds X-Custom-Request-Header = "" # Removes [http.middlewares.testHeader.headers.customResponseHeaders] X-Custom-Response-Header = "" # Removes labels: - "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test" - "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Custom-Request-Header=" - "traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header=" { "Tags" : [ "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test", "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Custom-Request-Header=", "traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header=" ] } apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-header spec: headers: customRequestHeaders: X-Script-Name: "test" # Adds X-Custom-Request-Header: "" # Removes customResponseHeaders: X-Custom-Response-Header: "" # Removes Using Security Headers Security-related headers (HSTS headers, Browser XSS filter, etc) can be managed similarly to custom headers as shown above. This functionality makes it possible to easily use security features by adding headers. http: middlewares: testHeader: headers: frameDeny: true browserXssFilter: true [http.middlewares] [http.middlewares.testHeader.headers] frameDeny = true browserXssFilter = true labels: - "traefik.http.middlewares.testHeader.headers.framedeny=true" - "traefik.http.middlewares.testHeader.headers.browserxssfilter=true" { "Tags" : [ "traefik.http.middlewares.testheader.headers.framedeny=true", "traefik.http.middlewares.testheader.headers.browserxssfilter=true" ] } apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-header spec: headers: frameDeny: true browserXssFilter: true CORS Headers CORS (Cross-Origin Resource Sharing) headers can be added and configured in a manner similar to the custom headers above. This functionality allows for more advanced security features to quickly be set. If CORS headers are set, then the middleware does not pass preflight requests to any service, instead the response will be generated and sent back to the client directly. Please note that the example below is by no means authoritative or exhaustive, and should not be used as is for production. http: middlewares: testHeader: headers: accessControlAllowMethods: - GET - OPTIONS - PUT accessControlAllowHeaders: - "*" accessControlAllowOriginList: - https://foo.bar.org - https://example.org accessControlMaxAge: 100 addVaryHeader: true [http.middlewares] [http.middlewares.testHeader.headers] accessControlAllowMethods = ["GET", "OPTIONS", "PUT"] accessControlAllowHeaders = [ "*" ] accessControlAllowOriginList = ["https://foo.bar.org","https://example.org"] accessControlMaxAge = 100 addVaryHeader = true labels: - "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT" - "traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=*" - "traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist=https://foo.bar.org,https://example.org" - "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100" - "traefik.http.middlewares.testheader.headers.addvaryheader=true" { "Tags" : [ "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,OPTIONS,PUT", "traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=*", "traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist=https://foo.bar.org,https://example.org", "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100", "traefik.http.middlewares.testheader.headers.addvaryheader=true" ] } apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-header spec: headers: accessControlAllowMethods: - "GET" - "OPTIONS" - "PUT" accessControlAllowHeaders: - "*" accessControlAllowOriginList: - "https://foo.bar.org" - "https://example.org" accessControlMaxAge: 100 addVaryHeader: true Configuration Options !!! warning Custom headers will overwrite existing headers if they have identical names. !!! note "" The detailed documentation for security headers can be found in [unrolled/secure](https://github.com/unrolled/secure#available-options). Field Description Default Required customRequestHeaders Lists the header names and values for requests. [] No customResponseHeaders Lists the header names and values for responses. [] No accessControlAllowCredentials Indicates if the request can include user credentials. false No accessControlAllowHeaders Specifies allowed request header names. [] No accessControlAllowMethods Specifies allowed request methods. [] No accessControlAllowOriginList Specifies allowed origins. More information here [] No accessControlAllowOriginListRegex Allows origins matching regex. More information here [] No accessControlExposeHeaders Specifies which headers are safe to expose to the API of a CORS API specification. [] No accessControlMaxAge Time (in seconds) to cache preflight requests. 0 No addVaryHeader Used in conjunction with accessControlAllowOriginList to determine whether the Vary header should be added or modified to demonstrate that server responses can differ based on the value of the origin header. false No allowedHosts Lists allowed domain names. [] No hostsProxyHeaders Specifies header keys for proxied hostname. [] No sslProxyHeaders Defines a set of header keys with associated values that would indicate a valid HTTPS request. It can be useful when using other proxies (example: "X-Forwarded-Proto": "https"). {} No stsSeconds Max age for Strict-Transport-Security header. - No stsIncludeSubdomains If set to true, the includeSubDomains directive is appended to the Strict-Transport-Security header. false No stsPreload Adds preload flag to STS header. false No forceSTSHeader Adds STS header for HTTP connections. false No frameDeny Set frameDeny to true to add the X-Frame-Options header with the value of DENY. false No customFrameOptionsValue allows the X-Frame-Options header value to be set with a custom value. This overrides the FrameDeny option. "" No contentTypeNosniff Set contentTypeNosniff to true to add the X-Content-Type-Options header with the value nosniff. false No browserXssFilter Set browserXssFilter to true to add the X-XSS-Protection header with the value 1; mode=block. false No customBrowserXSSValue allows the X-XSS-Protection header value to be set with a custom value. This overrides the BrowserXssFilter option. "" No contentSecurityPolicy allows the Content-Security-Policy header value to be set with a custom value. "" No contentSecurityPolicyReportOnly allows the Content-Security-Policy-Report-Only header value to be set with a custom value. "" No publicKey Implements HPKP for certificate pinning. "" No referrerPolicy Controls forwarding of Referer header. "" No permissionsPolicy allows sites to control browser features. "" No isDevelopment Set true when developing to mitigate the unwanted effects of the AllowedHosts, SSL, and STS options. Usually testing takes place using HTTP, not HTTPS, and on localhost, not your production domain. false No accessControlAllowOriginList The accessControlAllowOriginList indicates whether a resource can be shared by returning different values. A wildcard origin * can also be configured, and matches all requests. If this value is set by a backend service, it will be overwritten by Traefik. This value can contain a list of allowed origins. More information including how to use the settings can be found at: Mozilla.org w3 IETF Traefik no longer supports the null value, as it is no longer recommended as a return value. accessControlAllowOriginListRegex The accessControlAllowOriginListRegex option is the counterpart of the accessControlAllowOriginList option with regular expressions instead of origin values. It allows all origins that contain any match of a regular expression in the accessControlAllowOriginList. !!! tip Regular expressions and replacements can be tested using online tools such as [Go Playground](https://play.golang.org/p/mWU9p-wk2ru) or the [Regex101](https://regex101.com/r/58sIgx/2). When defining a regular expression within YAML, any escaped character needs to be escaped twice: `example\.com` needs to be written as `example\\.com`. {% include-markdown "includes/traefik-for-business-applications.md" %} HMAC !!! info "Traefik Hub Feature" This middleware is available exclusively in Traefik Hub. Learn more about Traefik Hub's advanced features. This middleware validates a digital signature computed using the content of an HTTP request and a shared secret that is sent to the proxy using the Authorization or Proxy-Authorization header. It ensures: The identity of the sender (Authentication): If the signature is validated by the proxy, it means that the sender actually owns the shared secret. As a consequence, the sender's identity is considered to be proven. The integrity of the request: As the signature is based on a subset of the HTTP request, it means that if the signature is validated by the proxy, the request used to generate the signature has not been modified between the sender and the proxy. This middleware also allows validating the content integrity using the Digest header. This middleware is based on the HTTP Signature Draft. Configuration Example Below is an advanced configuration that enables the HMAC middleware, sets one secret, ensures that the digest sum of the request body is validated and ensures that the given headers must be included in the computation of the signature of the request. apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: hmac-auth spec: plugin: hmac: keys: - id: secret-key key: secret validateDigest: true enforcedHeaders: - (request-target) - (created) - (expires) - host Configuration Options Field Description Default Required keys A static set of secret keys to be used by HMAC middleware. Yes validateDigest Determines whether the middleware should validate the digest sum of the request body. true No enforcedHeaders A set of headers that must be included in the computation of the signature of the request. No Authentication Mechanism The sender and proxy share a common secret identified by a keyId. How the sender gets the secret and keeps it safe is out of scope of this documentation. Crafting the Authorization Header To authenticate a request, the sender must provide an Authorization or ProxyAuthorization header fulfilling the HMAC authentication scheme. This header carries a set of parameters: Authorization: Hmac keyId="secret-id-1",algorithm="hmac-sha256",headers="(request-target) (created) (expires) host x-example",signature="c29tZXNpZ25hdHVyZQ==",created="1584453022",expires="1584453032" Parameter Description Example keyId Identifier of the key being used by the sender to build the signature keyId="secret-key-1" algorithm Algorithm used to generate the signature. Supported values are hmac-sha1, hmac-sha256, hmac-sha384 and hmac-sha512. algorithm="hmac-sha512" headers List of headers to use in order to build the signature string. Each item must be lowercase. headers="host content-type" signature Digital Signature of the request. See computing the signature. signature="c29tZXNpZ25hdHVyZQ==" created Unix timestamp of the signature creation. created="1574453022" expires Unix timestamp of the signature expiration. expires="1574453022" !!! danger "Time sensitivity" If the created timestamp is in the future or the expires timestamp is in the past, the middleware will refuse the request. This behaviour makes using this middleware sensitive to clock skew between the client and the server. Make sure that your client and your server have their clocks synchronized. Computing the Signature The signature is the base64-encoded value of the result of an HMAC signature algorithm computed with a signature string and the sender's secret key. For example: signature=base64(HMAC(signatureString, secret)) Crafting the Signature String A signed HTTP request needs to be tolerant of some trivial alterations during transmission as it goes through gateways, proxies and other entities. As a consequence, signing the whole request is not an option as a single header modification could result in a not valid signature. To avoid this problem, this middleware builds the signature string from a subset of header values defined by the sender with the headers parameter of the authorization header. To build the signature string, the client must take the values of each header specified by the headers parameter in the order they appear, then apply the following logic to each of them: If the header is a special header, then evaluate its value according to the special headers values section If the header is not a special header, then append the lowercase header name followed with an ASCII colon :, an ASCII space ` ` and the header value. If the header has multiple values then append those values separated by an ASCII comma , and an ASCII space ` ` If value is not the last value then append an ASCII newline \n. The signature string MUST NOT include a trailing ASCII newline !!! warning All headers values are trimmed from their spaces." Special Header Values By design, all the information of an HTTP request is not available through headers. However, it makes sense to secure the request using them. To allow this, the headers parameter accepts special header names that can be used. Value Description Signature String Example (request-target) Obtained by concatenating the lowercase :method, an ASCII space, and the :path pseudo-headers (as specified in HTTP/2). (request-target): get /api/V1/resource?query=foo (created) Value of the authorization header created parameter. (created): 1584453022 (expires) Value of the authorization header expires parameter. (expires): 1584453082 Their evaluated value is obtained by appending the special header name with an ASCII colon : an ASCII space ` ` then the designated value. (created): 1929494939 (request-target): get /foo/bar Signature String Example Here is an example with the authorization header parameters set: headers="(request-target) (created) (expires) host x-example x-emptyheader cache-control" created="1584466921" expires="1584466931" GET /foo HTTP/1.1 Host: example.org X-Example: Example header with some whitespace. X-EmptyHeader: X-NotIncluded: always Cache-Control: max-age=60 Cache-Control: must-revalidate (request-target): get /foo (created): 1584466921 (expires): 1584466931 host: example.org x-example: Example header with some whitespace. x-emptyheader: cache-control: max-age=60, must-revalidate Enforced Headers It is possible to configure the middleware to enforce a minimum set of headers to create the signature string. This means that any request that does not have the enforced headers in its signature is systematically refused. This option also configures the headers list returned when initiating the authentication. It defaults to (request-target) (created) (expires). !!! danger "Always enforce (created) and (expires)" The created and expires header parameters protect against replay attacks. To make sure that their value is not modified during transport, it is highly recommended to always include those parameters values in the signature using the (created) and (expired) special headers value. To do so, it is recommended to **always** configure the middleware to enforce `(created)` and `(expires)`. Initiating the Authentication The authentication can be initiated by the proxy. A 401 Unauthorized response is returned with a WWW-Authenticate header indicating to use the Hmac authentication scheme. WWW-Authenticate: Hmac headers="(request-target) (created) (expires) host x-example" This header indicates that the sender needs to provide an Authorization header that fulfills the Hmac authentication schemes. It also indicates a list of headers that have to be included in the signature using the headers parameter. !!! note "Enforced headers" The list of headers carried in the WWW-Authenticate header is the list of enforced headers indicated in the middleware configuration. Validating Request Body Integrity It is possible to make sure that the body of the incoming request has not been altered during transmission by including the digest header in the signature string. This middleware, by default, validates the digest sum of the body, if there is one. Only SHA-256 and SHA-512 checksums are supported for checksum computation. !!! warning "Potential CPU and memory usage" Validating the digest makes the middleware read the request body and computes a checksum for it. As a consequence it can cause high memory and CPU usage on proxies. To disable this feature and only perform authentication, set the `validateDigest` option to `false` in the middleware configuration. {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik InFlightReq Documentation The inFlightReq middleware proactively prevents services from being overwhelmed with high load. Configuration Examples # Limiting to 10 simultaneous connections http: middlewares: test-inflightreq: inFlightReq: amount: 10 # Limiting to 10 simultaneous connections [http.middlewares] [http.middlewares.test-inflightreq.inFlightReq] amount = 10 labels: - "traefik.http.middlewares.test-inflightreq.inflightreq.amount=10" // Limiting to 10 simultaneous connections { "Tags" : [ "traefik.http.middlewares.test-inflightreq.inflightreq.amount=10" ] } apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-inflightreq spec: inFlightReq: amount: 10 Configuration Options Field Description Default Required amount The amount option defines the maximum amount of allowed simultaneous in-flight request. The middleware responds with HTTP 429 Too Many Requests if there are already amount requests in progress (based on the same sourceCriterion strategy). 0 No sourceCriterion.requestHost Whether to consider the request host as the source. More information about sourceCriterionhere. false No sourceCriterion.requestHeaderName Name of the header used to group incoming requests. More information about sourceCriterionhere. "" No sourceCriterion.ipStrategy.depth Depth position of the IP to select in the X-Forwarded-For header (starting from the right). 0 means no depth. If greater than the total number of IPs in X-Forwarded-For, then the client IP is empty If higher than 0, the excludedIPs options is not evaluated. More information about sourceCriterion, ipStrategy](#ipstrategy), and [depth` below. 0 No sourceCriterion.ipStrategy.excludedIPs Allows Traefik to scan the X-Forwarded-For header and select the first IP not in the list. If depth is specified, excludedIPs is ignored. More information about sourceCriterion, ipStrategy](#ipstrategy), and [excludedIPs` below. No sourceCriterion.ipStrategy.ipv6Subnet If ipv6Subnet is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to. More information about sourceCriterion, ipStrategy.ipv6Subnet, and excludedIPs below. No sourceCriterion The sourceCriterion option defines what criterion is used to group requests as originating from a common source. If several strategies are defined at the same time, an error will be raised. If none are set, the default is to use the requestHost. ipStrategy The ipStrategy option defines three parameters that configures how Traefik determines the client IP: depth, excludedIPs and ipv6Subnet. As a middleware, inFlightReq happens before the actual proxying to the backend takes place. In addition, the previous network hop only gets appended to X-Forwarded-For during the last stages of proxying, that is after it has already passed through the middleware. Therefore, during InFlightReq, as the previous network hop is not yet present in X-Forwarded-For, it cannot be used and/or relied upon. ipStrategy.ipv6Subnet This strategy applies to Depth and RemoteAddr strategy only. If ipv6Subnet is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to. This is useful for grouping IPv6 addresses into subnets to prevent bypassing this middleware by obtaining a new IPv6. ipv6Subnet causes middleware creation to fail if its value is ≤ 0 or > 128. Example of ipv6Subnet If ipv6Subnet is provided, the IP is transformed in the following way. IP ipv6Subnet clientIP "::abcd:1111:2222:3333" 64 "::0:0:0:0" "::abcd:1111:2222:3333" 80 "::abcd:0:0:0:0" "::abcd:1111:2222:3333" 96 "::abcd:1111:0:0:0" Example of Depth & X-Forwarded-For If depth is set to 2, and the request X-Forwarded-For header is "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" then the "real" client IP is "10.0.0.1" (at depth 4) but the IP used as the criterion is "12.0.0.1" ( depth=2). X-Forwarded-For depth clientIP "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" 1 "13.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" 3 "11.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" 5 "" Example of ExcludedIPs & X-Forwarded-For X-Forwarded-For excludedIPs clientIP "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" "12.0.0.1,13.0.0.1" "11.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" "15.0.0.1,13.0.0.1" "12.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" "10.0.0.1,13.0.0.1" "12.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" "15.0.0.1,16.0.0.1" "13.0.0.1" "10.0.0.1,11.0.0.1" "10.0.0.1,11.0.0.1" "" Traefik HTTP Middlewares IPAllowList ipAllowList accepts / refuses requests based on the client IP. Configuration Example # Accepts request from defined IP # and rejects other requests with a 404 rather than a 403 http: middlewares: test-ipallowlist: ipAllowList: sourceRange: - "127.0.0.1/32" - "192.168.1.7" rejectStatusCode: 404 # Accepts request from defined IP # and rejects other requests with a 404 rather than a 403 [http.middlewares] [http.middlewares.test-ipallowlist.ipAllowList] sourceRange = ["127.0.0.1/32", "192.168.1.7"] rejectStatusCode = 404 # Accepts request from defined IP # and rejects other requests with a 404 rather than a 403 labels: - "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7" - "traefik.http.middlewares.test-ipallowlist.ipallowlist.rejectstatuscode=404" // Accepts request from defined IP // and rejects other requests with a 404 rather than a 403 { "Tags" : [ "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7", "traefik.http.middlewares.test-ipallowlist.ipallowlist.rejectstatuscode=404" ] } apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-ipallowlist spec: ipAllowList: sourceRange: - 127.0.0.1/32 - 192.168.1.7 rejectStatusCode: 404 Configuration Options Field Description Default Required sourceRange List of allowed IPs (or ranges of allowed IPs by using CIDR notation). Yes ipStrategy.depth Depth position of the IP to select in the X-Forwarded-For header (starting from the right). 0 means no depth. If greater than the total number of IPs in X-Forwarded-For, then the client IP is empty If higher than 0, the excludedIPs options is not evaluated. More information about ipStrategy, and depth below. 0 No ipStrategy.excludedIPs Allows Traefik to scan the X-Forwarded-For header and select the first IP not in the list. If depth is specified, excludedIPs is ignored. More information about ipStrategy, and excludedIPs below. No ipStrategy.ipv6Subnet If ipv6Subnet is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to. More information about ipStrategy.ipv6Subnet, and excludedIPs below. No rejectStatusCode Defines the HTTP status code used for refused requests. 403 No ipStrategy The ipStrategy option defines two parameters that configures how Traefik determines the client IP: depth, and excludedIPs. If no strategy is set, the default behavior is to match sourceRange against the Remote address found in the request. As a middleware, passlisting happens before the actual proxying to the backend takes place. In addition, the previous network hop only gets appended to X-Forwarded-For during the last stages of proxying, that is after it has already passed through passlisting. Therefore, during passlisting, as the previous network hop is not yet present in X-Forwarded-For, it cannot be matched against sourceRange. ipStrategy.depth The depth option tells Traefik to use the X-Forwarded-For header and take the IP located at the depth position (starting from the right). If depth is greater than the total number of IPs in X-Forwarded-For, then the client IP will be empty. depth is ignored if its value is less than or equal to 0. If ipStrategy.ipv6Subnet is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to. ipStrategy.ipv6Subnet This strategy applies to Depth and RemoteAddr strategy only. If ipv6Subnet is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to. This is useful for grouping IPv6 addresses into subnets to prevent bypassing this middleware by obtaining a new IPv6. Middleware creation fails if ipv6Subnet is ≤ 0 or > 128. Valid range: 1–128. Example of ipv6Subnet If ipv6Subnet is provided, the IP is transformed in the following way. IP ipv6Subnet clientIP "::abcd:1111:2222:3333" 64 "::0:0:0:0" "::abcd:1111:2222:3333" 80 "::abcd:0:0:0:0" "::abcd:1111:2222:3333" 96 "::abcd:1111:0:0:0" Example of Depth & X-Forwarded-For If depth is set to 2, and the request X-Forwarded-For header is "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" then the "real" client IP is "10.0.0.1" (at depth 4) but the IP used as the criterion is "12.0.0.1" ( depth=2). X-Forwarded-For depth clientIP "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" 1 "13.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" 3 "11.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" 5 "" Example of ExcludedIPs & X-Forwarded-For X-Forwarded-For excludedIPs clientIP "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" "12.0.0.1,13.0.0.1" "11.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" "15.0.0.1,13.0.0.1" "12.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" "10.0.0.1,13.0.0.1" "12.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" "15.0.0.1,16.0.0.1" "13.0.0.1" "10.0.0.1,11.0.0.1" "10.0.0.1,11.0.0.1" "" JWT Authentication !!! info "Traefik Hub Feature" This middleware is available exclusively in Traefik Hub. Learn more about Traefik Hub's advanced features. The JWT middleware verifies that a valid JWT token is provided in the Authorization header ( Authorization: Bearer ). If the token can't be passed as an Authorization header, it can be given as form data or as a query parameter. See the tokenKey option for more information. With no specific configuration, a JWT middleware only validates the signature of a JWT and checks the nbf, exp and iat standard claims (if they are present). Custom claim validation can be configured with Custom Claims Validation. Configuration Example apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-jwt spec: plugin: jwt: signingSecret: my-secret forwardHeaders: Group: grp Expires-At: exp claims: Equals(`grp`, `admin`) Configuration Options Field Description Default Required signingSecret Defines the secret used for signing the JWT certificates. It is then used by the middleware to verify incoming requests. At least one of signingSecret, publicKey, jwksFile or jwksUrl options must be set. (More information here) "" No signingSecretBase64Encoded Defines whether the signingSecret is base64-encoded. If set to true, the signingSecret is base64-decoded before being used. false No publicKey Defines the public key used to verify secret signature in incoming requests. In that case, users should sign their token using a private key corresponding to the configured public key. At least one of signingSecret, publicKey, jwksFile or jwksUrl options must be set. "" No jwksFile Defines a set of JWK to be used to verify the signature of JWTs. The option can either be a path to a file mounted on the API Gateway or directly the content of a JWK set file. At least one of signingSecret, publicKey, jwksFile or jwksUrl options must be set. (More information here) "" No jwksUrl Defines the URL of the host serving a JWK set. The keys are cached if the HTTP Cache Control allows for caching. At least one of signingSecret, publicKey, jwksFile or jwksUrl options must be set. (More information here) "" No forwardAuthorization Defines whether the authorization header will be forwarded or stripped from a request after it has been approved by the middleware. false No tokenKey Defines the name of the query and form data parameter used for passing the JWT, for applications that can't pass it in the Authorization header. The middleware always looks in the Authorization header first, even with this option enabled. This option should only be enabled if the JWT cannot be passed as an Authorization header, as it is not recommended by the RFC. "" No claims Defines the claims to validate in order to authorize the request. The claims option can only be used with JWT-formatted token. (More information here) "" No usernameClaim Defines the claim that will be evaluated to populate the clientusername in the access logs. The usernameClaim option can only be used with JWT-formatted token. "" No forwardHeaders Defines the HTTP headers to add to requests and populates them with values extracted from the access token claims returned by the authorization server. Claims to be forwarded that are not found in the JWT result in empty headers. The forwardHeaders option can only be used with JWT-formatted token. {} No clientConfig.tls.ca PEM-encoded certificate bundle or a URN referencing a secret containing the certificate bundle used to establish a TLS connection with the authorization server (More information here) "" No clientConfig.tls.cert PEM-encoded certificate or a URN referencing a secret containing the certificate used to establish a TLS connection with the Vault server (More information here) "" No clientConfig.tls.key PEM-encoded key or a URN referencing a secret containing the key used to establish a TLS connection with the Vault server. (More information here) "" No clientConfig.tls.insecureSkipVerify Disables TLS certificate verification when communicating with the authorization server. Useful for testing purposes but strongly discouraged for production. (More information here) false No clientConfig.timeoutSeconds Defines the time before giving up requests to the authorization server. 5 No clientConfig.maxRetries Defines the number of retries for requests to authorization server that fail. 3 No claims Syntax The following functions are supported in claims: Function Description Example Equals Validates the equality of the value in key with value. Equals(`grp`, `admin`) Prefix Validates the value in key has the prefix of value. Prefix(`referrer`, `http://example.com`) Contains (string) Validates the value in key contains value. Contains(`referrer`, `/foo/`) Contains (array) Validates the key array contains the value. Contains(`areas`, `home`) SplitContains Validates the value in key contains the value once split by the separator. SplitContains(`scope`, ` `, `writer`) OneOf Validates the key array contains one of the values. OneOf(`areas`, `office`, `lab`) All functions can be joined by boolean operands. The supported operands are: Operand Description Example && Compares two functions and returns true only if both evaluate to true. Equals(`grp`, `admin`) && Equals(`active`, `true`) || Compares two functions and returns true if either evaluate to true. Equals(`grp`, `admin`) || Equals(`active`, `true`) ! Returns false if the function is true, otherwise returns true. !Equals(`grp`, `testers`) All examples will return true for the following data structure: { "active": true, "grp": "admin", "scope": "reader writer deploy", "referrer": "http://example.com/foo/bar", "areas": [ "office", "home" ] } Nested Claims Nested claims are supported by using a . between keys. For example: user.name { "active": true, "grp": "admin", "scope": "reader writer deploy", "referrer": "http://example.com/foo/bar", "areas": [ "office", "home" ], "user": { "name": "John Snow", "status": "undead" } } John Snow !!! note "Handling keys that contain a '.'" If the key contains a dot, the dot can be escaped using \. !!! note "Handling a key that contains a ''" If the key contains a \, it needs to be doubled \\. clientConfig Defines the configuration used to connect the API Gateway to a Third Party Software such as an Identity Provider. clientConfig.tls Storing secret values in Kubernetes secrets When configuring the tls.ca, tls.cert, tls.key, it is possible to reference Kubernetes secrets defined in the same namespace as the Middleware. The reference to a Kubernetes secret takes the form of a URN: urn:k8s:secret:[name]:[valueKey] apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-jwt spec: plugin: jwt: clientConfig: tls: ca: "urn:k8s:secret:tls:ca" cert: "urn:k8s:secret:tls:cert" key: "urn:k8s:secret:tls:key" insecureSkipVerify: true apiVersion: v1 kind: Secret metadata: name: tls stringData: ca: |- -----BEGIN CERTIFICATE----- MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3 DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ 98TwDIK/39WEB/V607As+KoYazQG8drorw== -----END CERTIFICATE----- cert: |- -----BEGIN CERTIFICATE----- MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3 DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ 98TwDIK/39WEB/V607As+KoYazQG8drorw== -----END CERTIFICATE----- key: |- -----BEGIN EC PRIVATE KEY----- MHcCAQEEIC8CsJ/B115S+JtR1/l3ZQwKA3XdXt9zLqusF1VXc/KloAoGCCqGSM49 AwEHoUQDQgAEpwUmRIZHFt8CdDHYm1ikScCScd2q6QVYXxJu+G3fQZ78ScGtN7fu KXMnQqVjXVRAr8qUY8yipVKuMCepnPXScQ== -----END EC PRIVATE KEY----- jwksFile JWT Header Key ID If the JWT header contains a kid header, the middleware expects to find a JWK. If a JWK cannot be found, it returns a 401 Unauthorized error. jwksUrl JWT Header Key ID If the JWT header contains a kid header, the middleware expects to find a JWK. If a JWK cannot be found, it returns a 401 Unauthorized error. JWT Issuer Claim If jwksUrl is set to a path and the iss property is missing in the JWT it's trying to verify, the middleware returns a 401 Unauthorized error. signingSecret Storing secret values in Kubernetes secrets When configuring the signingSecret, it is possible to reference a Kubernetes secret defined in the same namespace as the Middleware. The reference to a Kubernetes secret takes the form of a URN: urn:k8s:secret:[name]:[valueKey] {% include-markdown "includes/traefik-for-business-applications.md" %} LDAP Authentication !!! info "Traefik Hub Feature" This middleware is available exclusively in Traefik Hub. Learn more about Traefik Hub's advanced features. The LDAP Authentication middleware secures your applications by delegating the authentication to an external LDAP server. The LDAP middleware will look for user credentials in the Authorization header of each request. Credentials must be encoded with the following format: base64(username:password). Configuration Examples apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-ldap-auth namespace: apps spec: plugin: ldap: url: ldap://ldap.example.org:636 baseDN: dc=example,dc=org apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-ldap-auth namespace: apps spec: plugin: ldap: url: ldap://ldap.example.org:636 baseDN: dc=example,dc=org bindDN: cn=binding_user,dc=example,dc=org bindPassword: "urn:k8s:secret:my-secret:bindpassword" apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-ldap-auth namespace: apps spec: plugin: ldap: url: ldap://ldap.example.org:636 baseDN: dc=example,dc=org searchFilter: (&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s)) forwardUsername: true forwardUsernameHeader: Custom-Username-Header-Name wwwAuthenticateHeader: true wwwAuthenticateHeaderRealm: traefikee Configuration Options Field Description Default Required url LDAP server URL. Either the ldaps or ldap protocol and end with a port (ex: ldaps://ldap.example.org:636). "" Yes startTLS Enable StartTLS request when initializing the connection with the LDAP server. false No certificateAuthority PEM-encoded certificate to use to establish a connection with the LDAP server if the connection uses TLS but that the certificate was signed by a custom Certificate Authority. "" No insecureSkipVerify Allow proceeding and operating even for server TLS connections otherwise considered insecure. false No bindDN Domain name to bind to in order to authenticate to the LDAP server when running on search mode. Leaving this empty with search mode means binds are anonymous, which is rarely expected behavior. Not used when running in bind mode. "" No bindPassword Password for the bindDN used in search mode to authenticate with the LDAP server. More information here "" No connPool Pool of connections to the LDAP server (to minimize the impact on the performance). None No connPool.size Number of connections managed by the pool can be customized with the size property. 10 No connPool.burst Ephemeral connections that are opened when the pool is already full. Once the number of connection exceeds size + burst, a Too Many Connections error is returned. 5 No connPool.ttl Pooled connections are still meant to be short-lived, so they are closed after roughly one minute by default. This behavior can be modified with the ttl property. 60s No baseDN Base domain name that should be used for bind and search queries. "" Yes attribute The attribute used to bind a user. Bind queries use this pattern: =,, where the username is extracted from the request header. cn Yes forwardUsername Forward the username in a specific header, defined using the forwardUsernameHeader option. "" No forwardUsernameHeader Name of the header to put the username in when forwarding it. This is not used if the forwardUsername option is set to false. Username Yes forwardAuthorization Enable to forward the authorization header from the request after it has been approved by the middleware. false Yes searchFilter If not empty, the middleware will run in search mode, filtering search results with the given query. Filter queries can use the %s placeholder that is replaced by the username provided in the Authorization header of the request (for example: (&(objectClass=inetOrgPerson)(gidNumber=500)(uid=%s))). "" No wwwAuthenticateHeader Allow setting a WWW-Authenticate header in the 401 Unauthorized response. See the WWW-Authenticate header documentation for more information. The realm directive of the WWW-Authenticate header can be customized with the wwwAuthenticateHeaderRealm option. false No wwwAuthenticateHeaderRealm Realm name to set in the WWW-Authenticate header. This option is ineffective unless the wwwAuthenticateHeader option is set to true. "" No bindPassword When setting the bindPassword, you can reference a Kubernetes secret from the same namespace as the Middleware using the following URN format: urn:k8s:secret:[secretName]:[key] Bind Mode vs Search Mode If no filter is specified in its configuration, the middleware runs in the default bind mode, meaning it tries to make a bind request to the LDAP server with the credentials provided in the request headers. If the bind succeeds, the middleware forwards the request, otherwise it returns a 401 Unauthorized status code. If a filter query is specified in the middleware configuration, and the Authentication Source referenced has a bindDN and a bindPassword, then the middleware runs in search mode. In this mode, a search query with the given filter is issued to the LDAP server before trying to bind. If result of this search returns only 1 record, it tries to issue a bind request with this record, otherwise it aborts a 401 Unauthorized status code. {% include-markdown "includes/traefik-for-business-applications.md" %} OAuth 2.0 Client Credentials Authentication !!! info "Traefik Hub Feature" This middleware is available exclusively in Traefik Hub. Learn more about Traefik Hub's advanced features. The OAuth 2.0 Client Credentials Authentication middleware allows Traefik Hub to secure routes using the OAuth 2.0 Client Credentials flow as described in the RFC 6749. Access tokens can be cached using an external KV store. The OAuth Client Credentials Authentication middleware allows using Redis (or Sentinel) as persistent KV store to authorization access tokens while they are valid. This reduces latency and the number of calls made to the authorization server. Configuration Example apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-client-creds spec: plugin: oAuthClientCredentials: url: https://tenant.auth0.com/oauth/token clientID: urn:k8s:my-secret:my-secret:clientID clientSecret: urn:k8s:my-secret:my-secret:clientSecret audience: https://api.example.com forwardHeaders: Group: grp Expires-At: exp claims: Equals(`grp`, `admin`) apiVersion: v1 kind: Secret type: Opaque metadata: name: my-secret stringData: clientID: my-oauth-client-name clientSecret: mypasswd Configuration Options Field Description Default Required audience Defines the audience configured in your authorization server. The audience value is the base address of the resource being accessed, for example: https://api.example.com. "" Yes claims Defines the claims to validate in order to authorize the request. The claims option can only be used with JWT-formatted token. (More information here) "" No clientConfig.tls.ca PEM-encoded certificate bundle or a URN referencing a secret containing the certificate bundle used to establish a TLS connection with the authorization server (More information here) "" No clientConfig.tls.cert PEM-encoded certificate or a URN referencing a secret containing the certificate used to establish a TLS connection with the Vault server (More information here) "" No clientConfig.tls.key PEM-encoded key or a URN referencing a secret containing the key used to establish a TLS connection with the Vault server. (More information here) "" No clientConfig.tls.insecureSkipVerify Disables TLS certificate verification when communicating with the authorization server. Useful for testing purposes but strongly discouraged for production. (More information here) false No clientConfig.timeoutSeconds Defines the time before giving up requests to the authorization server. 5 No clientConfig.maxRetries Defines the number of retries for requests to authorization server that fail. 3 No clientID Defines the unique client identifier for an account on the OpenID Connect provider, must be set when the clientSecret option is set. More information here. "" Yes clientSecret Defines the unique client secret for an account on the OpenID Connect provider, must be set when the clientID option is set. More information here. "" Yes forwardHeaders Defines the HTTP headers to add to requests and populates them with values extracted from the access token claims returned by the authorization server. Claims to be forwarded that are not found in the JWT result in empty headers. The forwardHeaders option can only be used with JWT-formatted token. [] No store.keyPrefix Defines the prefix of the key for the entries that store the sessions. "" No store.secret Defines the encryption secret used to store access tokens in Redis. Must be 16, 24, or 32 characters long. Required when store is configured. "" Yes (if store is configured) store.redis.endpoints Endpoints of the Redis instances to connect to (example: redis.traefik-hub.svc.cluster.local:6379) "" Yes store.redis.username The username Traefik Hub will use to connect to Redis "" No store.redis.password The password Traefik Hub will use to connect to Redis "" No store.redis.database The database Traefik Hub will use to sore information (default: 0) 0 No store.redis.cluster Enable Redis Cluster mode. Set to {} to enable; omit to disable. - No store.redis.tls.ca Custom CA bundle "" No store.redis.tls.cert TLS certificate "" No store.redis.tls.key TLS "" No store.redis.tls.insecureSkipVerify Allow skipping the TLS verification false No store.redis.sentinel.masterSet Name of the set of main nodes to use for main selection. Required when using Sentinel. "" Yes (when using Sentinel) store.redis.sentinel.username Username to use for sentinel authentication (can be different from username) "" No store.redis.sentinel.password Password to use for sentinel authentication (can be different from password) "" No url Defines the authorization server URL (for example: https://tenant.auth0.com/oauth/token). "" Yes usernameClaim Defines the claim that will be evaluated to populate the clientusername in the access logs. The usernameClaim option can only be used with JWT-formatted token. "" No Storing secret values in Kubernetes secrets It is possible to reference Kubernetes secrets defined in the same namespace as the Middleware. The reference to a Kubernetes secret takes the form of a URN: urn:k8s:secret:[name]:[valueKey] claims Syntax The following functions are supported in claims: Function Description Example Equals Validates the equality of the value in key with value. Equals(`grp`, `admin`) Prefix Validates the value in key has the prefix of value. Prefix(`referrer`, `http://example.com`) Contains (string) Validates the value in key contains value. Contains(`referrer`, `/foo/`) Contains (array) Validates the key array contains the value. Contains(`areas`, `home`) SplitContains Validates the value in key contains the value once split by the separator. SplitContains(`scope`, ` `, `writer`) OneOf Validates the key array contains one of the values. OneOf(`areas`, `office`, `lab`) All functions can be joined by boolean operands. The supported operands are: Operand Description Example && Compares two functions and returns true only if both evaluate to true. Equals(`grp`, `admin`) && Equals(`active`, `true`) || Compares two functions and returns true if either evaluate to true. Equals(`grp`, `admin`) || Equals(`active`, `true`) ! Returns false if the function is true, otherwise returns true. !Equals(`grp`, `testers`) All examples will return true for the following data structure: { "active": true, "grp": "admin", "scope": "reader writer deploy", "referrer": "http://example.com/foo/bar", "areas": [ "office", "home" ] } Nested Claims Nested claims are supported by using a . between keys. For example: user.name { "active": true, "grp": "admin", "scope": "reader writer deploy", "referrer": "http://example.com/foo/bar", "areas": [ "office", "home" ], "user": { "name": "John Snow", "status": "undead" } } John Snow !!! note "Handling keys that contain a '.'" If the key contains a dot, the dot can be escaped using \. !!! note "Handling a key that contains a ''" If the key contains a \, it needs to be doubled \\. clientConfig Defines the configuration used to connect the API Gateway to a Third Party Software such as an Identity Provider. clientConfig.tls Storing secret values in Kubernetes secrets When configuring the tls.ca, tls.cert, tls.key, it is possible to reference Kubernetes secrets defined in the same namespace as the Middleware. The reference to a Kubernetes secret takes the form of a URN: urn:k8s:secret:[name]:[valueKey] apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-client-creds spec: plugin: oAuthClientCredentials: clientConfig: tls: ca: "urn:k8s:secret:tls:ca" cert: "urn:k8s:secret:tls:cert" key: "urn:k8s:secret:tls:key" insecureSkipVerify: true apiVersion: v1 kind: Secret metadata: name: tls stringData: ca: |- -----BEGIN CERTIFICATE----- MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3 DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ 98TwDIK/39WEB/V607As+KoYazQG8drorw== -----END CERTIFICATE----- cert: |- -----BEGIN CERTIFICATE----- MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3 DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ 98TwDIK/39WEB/V607As+KoYazQG8drorw== -----END CERTIFICATE----- key: |- -----BEGIN EC PRIVATE KEY----- MHcCAQEEIC8CsJ/B115S+JtR1/l3ZQwKA3XdXt9zLqusF1VXc/KloAoGCCqGSM49 AwEHoUQDQgAEpwUmRIZHFt8CdDHYm1ikScCScd2q6QVYXxJu+G3fQZ78ScGtN7fu KXMnQqVjXVRAr8qUY8yipVKuMCepnPXScQ== -----END EC PRIVATE KEY----- store.redis Connection parameters to your Redis server are attached to your Middleware deployment. The following Redis modes are supported: Single instance mode Redis Cluster Redis Sentinel !!! info If you use Redis in single instance mode or Redis Sentinel, you can configure the `database` field. This value won't be taken into account if you use Redis Cluster (only database `0` is available). In this case, a warning is displayed, and the value is ignored. For more information about Redis, we recommend the official Redis documentation. {% include-markdown "includes/traefik-for-business-applications.md" %} OAuth 2.0 Token Introspection Authentication !!! info "Traefik Hub Feature" This middleware is available exclusively in Traefik Hub. Learn more about Traefik Hub's advanced features. OAuth 2.0 Token Introspection allows Traefik Hub to retrieve metadata about an access token from an OAuth 2.0 server with the Token Introspection extension. The metadata can be used to restrict the access to applications. For more information please refer to the RFC. Configuration Example apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-oauth-intro spec: plugin: oAuthIntrospection: tokenSource: header: Authorization headerAuthScheme: Bearer clientConfig: url: "https://YOUR-KEYCLOAK-ADDRESS/realms/YOUR-REALM/protocol/openid-connect/token/introspect" headers: Authorization: Basic ZXhhbXBsZTpleGFtcGxl # echo -n "$CLIENT_ID:$CLIENT_SECRET" | base64 tokenTypeHint: access_token forwardHeaders: Group: grp Expires-At: exp claims: Equals(`grp`, `admin`) Configuration Options Field Description Default Required claims Defines the claims to validate in order to authorize the request. The claims option can only be used with JWT-formatted token. (More information here) "" No clientConfig.url Defines the introspection endpoint URL. It must include the scheme and path. "" Yes clientConfig.headers Defines the headers to send in every introspection request. Values can be plain strings or a valid Go template. Currently, a variable of type Request corresponding to the request being introspected is accessible in templates. "" No clientConfig.tokenTypeHint Defines the type of token being introspected, sent as a hint to the introspection server. Please refer to the official documentation for more details. "" No clientConfig.tls.ca PEM-encoded certificate bundle or a URN referencing a secret containing the certificate bundle used to establish a TLS connection with the authorization server (More information here) "" No clientConfig.tls.cert PEM-encoded certificate or a URN referencing a secret containing the certificate used to establish a TLS connection with the authorization server. (More information here) "" No clientConfig.tls.key PEM-encoded key or a URN referencing a secret containing the key used to establish a TLS connection with the authorization server. (More information here) "" No clientConfig.tls.insecureSkipVerify Disables TLS certificate verification when communicating with the authorization server. Useful for testing purposes but strongly discouraged for production. (More information here) false No clientConfig.timeoutSeconds Defines the time before giving up requests to the authorization server. 5 No clientConfig.maxRetries Defines the number of retries for requests to authorization server that fail. 3 No forwardAuthorization Defines whether the authorization header will be forwarded or stripped from a request after it has been approved by the middleware. false No forwardHeaders Defines the HTTP headers to add to requests and populates them with values extracted from the access token claims returned by the authorization server. Claims to be forwarded that are not found in the JWT result in empty headers. The forwardHeaders option can only be used with JWT-formatted token. [] No tokenSource.header Defines the header name containing the secret sent by the client. At least one tokenSourceoption must be set. "" No tokenSource.headerAuthScheme Defines the scheme when using Authorization as header name. Check out the Authorization header documentation. At least one tokenSourceoption must be set. "" No tokenSource.query Defines the query parameter name containing the secret sent by the client. At least one tokenSourceoption must be set. "" No tokenSource.cookie Defines the cookie name containing the secret sent by the client. At least one tokenSourceoption must be set. "" No usernameClaim Defines the claim that will be evaluated to populate the clientusername in the access logs. The usernameClaim option can only be used with JWT-formatted token. "" No claims Syntax The following functions are supported in claims: Function Description Example Equals Validates the equality of the value in key with value. Equals(`grp`, `admin`) Prefix Validates the value in key has the prefix of value. Prefix(`referrer`, `http://example.com`) Contains (string) Validates the value in key contains value. Contains(`referrer`, `/foo/`) Contains (array) Validates the key array contains the value. Contains(`areas`, `home`) SplitContains Validates the value in key contains the value once split by the separator. SplitContains(`scope`, ` `, `writer`) OneOf Validates the key array contains one of the values. OneOf(`areas`, `office`, `lab`) All functions can be joined by boolean operands. The supported operands are: Operand Description Example && Compares two functions and returns true only if both evaluate to true. Equals(`grp`, `admin`) && Equals(`active`, `true`) || Compares two functions and returns true if either evaluate to true. Equals(`grp`, `admin`) || Equals(`active`, `true`) ! Returns false if the function is true, otherwise returns true. !Equals(`grp`, `testers`) All examples will return true for the following data structure: { "active": true, "grp": "admin", "scope": "reader writer deploy", "referrer": "http://example.com/foo/bar", "areas": [ "office", "home" ] } Nested Claims Nested claims are supported by using a . between keys. For example: user.name { "active": true, "grp": "admin", "scope": "reader writer deploy", "referrer": "http://example.com/foo/bar", "areas": [ "office", "home" ], "user" { "name": "John Snow", "status": "undead" } } John Snow !!! note "Handling keys that contain a '.'" If the key contains a dot, the dot can be escaped using \. !!! note "Handling a key that contains a ''" If the key contains a \, it needs to be doubled \\. clientConfig Defines the configuration used to connect the API Gateway to a Third Party Software such as an Identity Provider. clientConfig.tls Storing secret values in Kubernetes secrets When configuring the tls.ca, tls.cert, tls.key, it is possible to reference Kubernetes secrets defined in the same namespace as the Middleware. The reference to a Kubernetes secret takes the form of a URN: urn:k8s:secret:[name]:[valueKey] apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-oauth-intro spec: plugin: oAuthIntrospection: clientConfig: tls: ca: "urn:k8s:secret:tls:ca" cert: "urn:k8s:secret:tls:cert" key: "urn:k8s:secret:tls:key" insecureSkipVerify: true apiVersion: v1 kind: Secret metadata: name: tls stringData: ca: |- -----BEGIN CERTIFICATE----- MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3 DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ 98TwDIK/39WEB/V607As+KoYazQG8drorw== -----END CERTIFICATE----- cert: |- -----BEGIN CERTIFICATE----- MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3 DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ 98TwDIK/39WEB/V607As+KoYazQG8drorw== -----END CERTIFICATE----- key: |- -----BEGIN EC PRIVATE KEY----- MHcCAQEEIC8CsJ/B115S+JtR1/l3ZQwKA3XdXt9zLqusF1VXc/KloAoGCCqGSM49 AwEHoUQDQgAEpwUmRIZHFt8CdDHYm1ikScCScd2q6QVYXxJu+G3fQZ78ScGtN7fu KXMnQqVjXVRAr8qUY8yipVKuMCepnPXScQ== -----END EC PRIVATE KEY----- {% include-markdown "includes/traefik-for-business-applications.md" %} OpenID Connect Authentication !!! info "Traefik Hub Feature" This middleware is available exclusively in Traefik Hub. Learn more about Traefik Hub's advanced features. The OIDC Authentication middleware secures your applications by delegating the authentication to an external provider Configuration Example apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-oidc namespace: whoami spec: plugin: oidc: issuer: "https://tenant.auth0.com/realms/myrealm" redirectUrl: "/callback" clientId: "urn:k8s:secret:my-secret:clientId" clientSecret: "urn:k8s:secret:my-secret:clientSecret" session: name: customsessioncookiename sliding: false refresh: false expiry: 10 sameSite: none httpOnly: false secure: true stateCookie: name: customstatecookiename maxAge: 10 sameSite: none httpOnly: true secure: true forwardHeaders: Group: grp Expires-At: exp claims: Equals(`grp`, `admin`) csrf: {} apiVersion: v1 kind: Secret metadata: name: my-secret stringData: clientID: my-oidc-client-name clientSecret: mysecret Configuration Options Field Description Default Required issuer Defines the URL to the OpenID Connect provider (for example, https://accounts.google.com). It should point to the server which provides the OpenID Connect configuration. "" Yes trustedIssuer Defines a trusted issuer URL to validate against in addition to the one discovered from the OpenID Connect provider. "" No disableIssuerCheck Disables the issuer validation check during token verification. false No redirectUrl Defines the URL used by the OpenID Connect provider to redirect back to the middleware once the authorization is complete. (More information here) "" Yes clientId Defines the unique client identifier for an account on the OpenID Connect provider, must be set when the clientSecret option is set. (More information here) "" Yes clientSecret Defines the unique client secret for an account on the OpenID Connect provider, must be set when the clientId option is set. (More information here) "" Yes claims Defines the claims to validate in order to authorize the request. The claims option can only be used with JWT-formatted token. (More information here) "" No usernameClaim Defines the claim that will be evaluated to populate the clientusername in the access logs. The usernameClaim option can only be used with JWT-formatted token. "" No forwardHeaders Defines the HTTP headers to add to requests and populates them with values extracted from the access token claims returned by the authorization server. Claims to be forwarded that are not found in the JWT result in empty headers. The forwardHeaders option can only be used with JWT-formatted token. [] No clientConfig.tls.ca PEM-encoded certificate bundle or a URN referencing a secret containing the certificate bundle used to establish a TLS connection with the authorization server (More information here) "" No clientConfig.tls.cert PEM-encoded certificate or a URN referencing a secret containing the certificate used to establish a TLS connection with the Vault server (More information here) "" No clientConfig.tls.key PEM-encoded key or a URN referencing a secret containing the key used to establish a TLS connection with the Vault server. (More information here) "" No clientConfig.tls.insecureSkipVerify Disables TLS certificate verification when communicating with the authorization server. Useful for testing purposes but strongly discouraged for production. (More information here) "" No clientConfig.timeoutSeconds Defines the time before giving up requests to the authorization server. 5 No clientConfig.maxRetries Defines the number of retries for requests to authorization server that fail. 3 No pkce Defines the Proof Key for Code Exchange as described in RFC 7636. false No discoveryParams A map of arbitrary query parameters to be added to the openid-configuration well-known URI during the discovery mechanism. "" No scopes The scopes to request. Must include openid. openid No authParams A map of the arbitrary query parameters to be passed to the Authentication Provider. When a prompt key is set to an empty string in the AuthParams,the prompt parameter is not added to the OAuth2 authorization URL Which means the user won't be prompted for consent. "" No disableLogin Disables redirections to the authentication provider This can be useful for protecting APIs where redirecting to a login page is undesirable. false No loginUrl Defines the URL used to start authorization when needed. All other requests that are not already authorized will return a 401 Unauthorized. When left empty, all requests can start authorization. It can be a path ( /login for example), a host and a path ( example.com/login) or a complete URL ( https://example.com/login). Only http and https schemes are supported. "" No logoutUrl Defines the URL on which the session should be deleted in order to log users out. It can be a path ( /logout for example), a host and a path ( example.com/logout) or a complete URL ( https://example.com/logout). Only http and https schemes are supported. "" No postLoginRedirectUrl If set and used in conjunction with loginUrl, the middleware will redirect to this URL after successful login. It can be a path ( /after/login for example), a host and a path ( example.com/after/login) or a complete URL ( https://example.com/after/login). Only http and https schemes are supported. "" No postLogoutRedirectUrl If set and used in conjunction with logoutUrl, the middleware will redirect to this URL after logout. It can be a path ( /after/logout for example), a host and a path ( example.com/after/logout) or a complete URL ( https://example.com/after/logout). Only http and https schemes are supported. "" No backchannelLogoutUrl Defines the URL called by the OIDC provider when a user logs out (see https://openid.net/specs/openid-connect-rpinitiated-1_0.html#OpenID.BackChannel). It can be a path ( /backchannel-logout for example), a host and a path ( example.com/backchannel-logout) or a complete URL ( https://example.com/backchannel-logout). Only http and https schemes are supported. This feature is currently in an experimental state and has been tested exclusively with the Keycloak OIDC provider. "" No backchannelLogoutSessionsRequired This specifies whether the OIDC provider includes the sid (session ID) Claim in the Logout Token to identify the user session (see https://openid.net/specs/openid-connect-backchannel-1_0.html#BCRegistration). If omitted, the default value is false. This feature is currently in an experimental state and has been tested exclusively with the Keycloak OIDC provider. false No stateCookie.name Defines the name of the state cookie. " MIDDLEWARE_NAME-state" No stateCookie.path Defines the URL path that must exist in the requested URL in order to send the Cookie header. The %x2F ('/') character is considered a directory separator, and subdirectories will match as well. For example, if stateCookie.path is set to /docs, these paths will match: /docs, /docs/web/, /docs/web/http. "/" No stateCookie.domain Defines the hosts that are allowed to receive the cookie. If specified, then subdomains are always included. For example, if it is set to example.com, then cookies are included on subdomains like api.example.com. "" No stateCookie.maxAge Defines the number of seconds after which the state cookie should expire. A zero or negative number will expire the cookie immediately. 600 No stateCookie.sameSite Informsbrowsers how they should handle the state cookie on cross-site requests. Setting it to lax or strict can provide some protection against cross-site request forgery attacks (CSRF). More information here. lax No stateCookie.httpOnly Forbids JavaScript from accessing the cookie. For example, through the Document.cookie property, the XMLHttpRequest API, or the Request API. This mitigates attacks against cross-site scripting (XSS). true No stateCookie.secure Defines whether the state cookie is only sent to the server when a request is made with the https scheme. false No session.name The name of the session cookie. " MIDDLEWARE_NAME-session" No session.path Defines the URL path that must exist in the requested URL in order to send the Cookie header. The %x2F ('/'') character is considered a directory separator, and subdirectories will match as well. For example, if stateCookie.path is set to /docs, these paths will match: /docs, /docs/web/, /docs/web/http. "/" No session.domain Specifies the hosts that are allowed to receive the cookie. If specified, then subdomains are always included. If specified, then subdomains are always included. For example, if it is set to example.com, then cookies are included on subdomains like api.example.com. "" No session.expiry Number of seconds after which the session should expire. A zero or negative number is prohibited. 86400 (24h) No session.sliding Forces the middleware to renew the session cookie each time an authenticated request is received. true No session.refresh Enables the access token refresh when it expires. true No session.sameSite Inform browsers how they should handle the session cookie on cross-site requests. Setting it to lax or strict can provide some protection against cross-site request forgery attacks (CSRF). More information here. lax No session.httpOnly Forbids JavaScript from accessing the cookie. For example, through the Document.cookie property, the XMLHttpRequest API, or the Request API. This mitigates attacks against cross-site scripting (XSS). true No session.secure Defines whether the session cookie is only sent to the server when a request is made with the https scheme. false No session.store.redis.endpoints Endpoints of the Redis instances to connect to (example: redis.traefik-hub.svc.cluster.local:6379) "" Yes session.store.redis.username The username Traefik Hub will use to connect to Redis "" No session.store.redis.password The password Traefik Hub will use to connect to Redis "" No session.store.redis.database The database Traefik Hub will use to sore information (default: 0) "" No session.store.redis.cluster Enable Redis Cluster "" No session.store.redis.tls.caBundle Custom CA bundle "" No session.store.redis.tls.cert TLS certificate "" No session.store.redis.tls.key TLS key "" No session.store.redis.tls.insecureSkipVerify Allow skipping the TLS verification "" No session.store.redis.sentinel.masterSet Name of the set of main nodes to use for main selection. Required when using Sentinel. "" No session.store.redis.sentinel.username Username to use for sentinel authentication (can be different from username) "" No session.store.redis.sentinel.password Password to use for sentinel authentication (can be different from password) "" No session.store.keyPrefix Defines the prefix of the key for the entries that store the sessions. "" No csrf When enabled, a CSRF cookie, named hub-csrf-token, is bound to the OIDC session to protect service from CSRF attacks. It is based on the Signed Double Submit Cookie implementation as defined by the OWASP Foundation. Moreinformation here. "" No csrf.secure Defines whether the CSRF cookie is only sent to the server when a request is made with the https scheme. false No csrf.headerName Defines the name of the header used to send the CSRF token value received previously in the CSRF cookie. Hub-Csrf-Token No redirectUrl Add specific rule on the IngressRoute The URL informs the OpenID Connect provider how to return to the middleware. If the router rule is accepting all paths on a domain, no extra work is needed. If the router rule is specific about the paths allowed, the path set in this option should be included. apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: whoami spec: entryPoints: - web - websecure routes: # Rules to match the loginUrl and redirectUrl can be added into # your current router. - match: Path(`/myapi`) || Path(`/login`) || Path(`/callback`) kind: Rule middlewares: - name: test-oidc This URL will not be passed to the upstream application, but rather handled by the middleware itself. The chosen URL should therefore not conflict with any URLs needed by the upstream application. This URL sometimes needs to be set in the OpenID Connect Provider's configuration as well (like for Google Accounts for example). It can be the absolute URL, relative to the protocol (inherits the request protocol), or relative to the domain (inherits the request domain and protocol). See the following examples. Inherit the Protocol and Domain from the Request and Uses the Redirecturl’s Path Request URL RedirectURL Result http://expl.co /cback http://expl.co/cback Inherit the Protocol from the Request and Uses the Redirecturl’s Domain and Path Request URL RedirectURL Result https://scur.co expl.co/cback https://expl.co/cback Replace the Request URL with the Redirect URL since It Is an Absolute URL Request URL RedirectURL Result https://scur.co http://expl.co/cback http://expl.co/cback !!! note "Supported Schemes" Only `http` and `https` schemes are supported. apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-oidc spec: plugin: oidc: issuer: "https://tenant.auth0.com/realms/myrealm" redirectUrl: "/callback" clientId: my-oidc-client-name clientSecret: mysecret clientId, clientSecret Storing secret values in Kubernetes secrets When configuring the clientId and the clientSecret, it is possible to reference Kubernetes secrets defined in the same namespace as the Middleware. The reference to a Kubernetes secret takes the form of a URN: urn:k8s:secret:[name]:[valueKey] claims Syntax The following functions are supported in claims: Function Description Example Equals Validates the equality of the value in key with value. Equals(`grp`, `admin`) Prefix Validates the value in key has the prefix of value. Prefix(`referrer`, `http://example.com`) Contains (string) Validates the value in key contains value. Contains(`referrer`, `/foo/`) Contains (array) Validates the key array contains the value. Contains(`areas`, `home`) SplitContains Validates the value in key contains the value once split by the separator. SplitContains(`scope`, ` `, `writer`) OneOf Validates the key array contains one of the values. OneOf(`areas`, `office`, `lab`) All functions can be joined by boolean operands. The supported operands are: Operand Description Example && Compares two functions and returns true only if both evaluate to true. Equals(`grp`, `admin`) && Equals(`active`, `true`) || Compares two functions and returns true if either evaluate to true. Equals(`grp`, `admin`) || Equals(`active`, `true`) ! Returns false if the function is true, otherwise returns true. !Equals(`grp`, `testers`) All examples will return true for the following data structure: { "active": true, "grp": "admin", "scope": "reader writer deploy", "referrer": "http://example.com/foo/bar", "areas": [ "office", "home" ] } Nested Claims Nested claims are supported by using a . between keys. For example: user.name { "active": true, "grp": "admin", "scope": "reader writer deploy", "referrer": "http://example.com/foo/bar", "areas": [ "office", "home" ], "user" { "name": "John Snow", "status": "undead" } } John Snow !!! note "Handling keys that contain a '.'" If the key contains a dot, the dot can be escaped using \. !!! note "Handling a key that contains a ''" If the key contains a \, it needs to be doubled \\. !!! note "Access Token and ID Token claims" The first argument of the function, which represents the key to look for in the token claims, can be prefixed to specify which of the two kinds of token is inspected. Possible prefix values are `id_token.` and `access_token.`. If no prefix is specified, it defaults to the ID token. | Example | Description | | ----------------------------------------- | ------------------------------------------------------------------------------ | | Equals(\`id_token.grp\`, \`admin\`) | Checks if the value of claim `grp` in the ID token is `admin`. | | Prefix(\`access_token.referrer\`, \`http://example.com\`) | Checks if the value of claim `referrer` in the access token is prefixed by `http://example.com\`.| | OneOf(\`areas\`, \`office\`, \`lab\`) | Checks if the value of claim `areas` in the ID token is `office` or `labs`. | clientConfig Defines the configuration used to connect the API Gateway to a Third Party Software such as an Identity Provider. clientConfig.tls Storing secret values in Kubernetes secrets When configuring the tls.ca, tls.cert, tls.key, it is possible to reference Kubernetes secrets defined in the same namespace as the Middleware. The reference to a Kubernetes secret takes the form of a URN: urn:k8s:secret:[name]:[valueKey] apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-oidc spec: plugin: oidc: clientConfig: tls: ca: "urn:k8s:secret:tls:ca" cert: "urn:k8s:secret:tls:cert" key: "urn:k8s:secret:tls:key" insecureSkipVerify: true apiVersion: v1 kind: Secret metadata: name: tls stringData: ca: |- -----BEGIN CERTIFICATE----- MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3 DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ 98TwDIK/39WEB/V607As+KoYazQG8drorw== -----END CERTIFICATE----- cert: |- -----BEGIN CERTIFICATE----- MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3 DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ 98TwDIK/39WEB/V607As+KoYazQG8drorw== -----END CERTIFICATE----- key: |- -----BEGIN EC PRIVATE KEY----- MHcCAQEEIC8CsJ/B115S+JtR1/l3ZQwKA3XdXt9zLqusF1VXc/KloAoGCCqGSM49 AwEHoUQDQgAEpwUmRIZHFt8CdDHYm1ikScCScd2q6QVYXxJu+G3fQZ78ScGtN7fu KXMnQqVjXVRAr8qUY8yipVKuMCepnPXScQ== -----END EC PRIVATE KEY----- sameSite - Accepted values none: Thebrowser will send cookies with both cross-site requests and same-site requests. strict: Thebrowser will only send cookies for same-site requests (requests originating from the site that set the cookie). If the request originated from a different URL than the URL of the current location, none of the cookies tagged with the strict attribute will be included. lax: Same-site cookies are withheld on cross-site subrequests, such as calls to load images or frames, but will be sent when a user navigates to the URL from an external site; for example, by following a link. session.store An OpenID Connect Authentication middleware can use a persistent KV storage to store the HTTP sessions data instead of keeping all the state in cookies. It avoids cookies growing inconveniently large, which can lead to latency issues. Refer to the redis options to configure the Redis connection. Connection parameters to your Redis server are attached to your Middleware deployment. The following Redis modes are supported: Single instance mode Redis Cluster Redis Sentinel !!! info If you use Redis in single instance mode or Redis Sentinel, you can configure the `database` field. This value won't be taken into account if you use Redis Cluster (only database `0` is available). In this case, a warning is displayed, and the value is ignored. For more information about Redis, we recommend the official Redis documentation. apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-oidc spec: plugin: oidc: issuer: "https://tenant.auth0.com/realms/myrealm" redirectUrl: "/callback" clientId: my-oidc-client-name clientSecret: mysecret session: store: redis: endpoints: - redis-master.traefik-hub.svc.cluster.local:6379 password: "urn:k8s:secret:oidc:redisPass" apiVersion: v1 kind: Secret metadata: name: oidc stringData: redisPass: mysecret12345678 csrf CSRF Internal Behavior When the OIDC session is expired, the corresponding CSRF cookie is deleted. This means that a new CSRF token will be generated and sent to the client whenever the session is refreshed or recreated. When a request is sent and uses a non-safe method (see RFC7231#section-4.2.1), the CSRF token value (extracted from the cookie) have to be sent to the server in the header configured with the headerName option. {% include-markdown "includes/traefik-for-business-applications.md" %} Open Policy Agent !!! info "Traefik Hub Feature" This middleware is available exclusively in Traefik Hub. Learn more about Traefik Hub's advanced features. Traefik Hub comes with an Open Policy Agent middleware that allows you to restrict access to your services. It also allows you to enrich request headers with data extracted from policies. The OPA middleware works as an OPA agent. !!! note "OPA Version" This middleware uses [OPA v1.x](https://www.openpolicyagent.org/) with Rego v0-compatible syntax. Policies written in Rego v0 style (e.g. `allow { ... }` without the `if` keyword) are fully supported. Configuration Example apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: opa-allow-jwt-claim namespace: apps spec: plugin: opa: policy: | package example.policies allow { [_, encoded] := split(input.headers.Authorization, " ") [header, payload, signature] = io.jwt.decode(encoded) payload["email"] == "bibi@example.com" } forwardHeaders: Group: data.package.grp apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: opa-deny-json namespace: apps spec: plugin: opa: policy: | package example.policies default allow = false json_content { input.headers["Accept"] == "application/json" } allow { not json_content } allow: data.example.policies.allow Configuration Options Field Description Default Required policy Path or the content of a policy file. "" No (one of policy or bundlePath must be set) bundlePath The bundlePath option should contain the path to an OPA bundle. "" No (one of policy or bundlePath must be set) allow The allow option sets the expression to evaluate that determines if the request should be authorized. "" No (one of allow or forwardHeaders must be set) forwardHeaders The forwardHeaders option sets the HTTP headers to add to requests and populates them with the result of the given expression. {} No (one of allow or forwardHeaders must be set) {% include-markdown "includes/traefik-for-business-applications.md" %} HTTP Middleware Overview Attached to routers or services, pieces of middleware are a means of tweaking the requests before they are sent to your backend servers (or before the answer is sent to the clients). Middlewares can be attached at two levels: Router-level: Applied to all requests matching the router's rule, before forwarding to the service. Service-level: Applied to all requests handled by the service, regardless of which router forwards the request. See service middlewares. When both are configured, router middlewares execute first, followed by service middlewares. There are several available middlewares in Traefik, some can modify the request, the headers, some are in charge of redirections, some add authentication, and so on. Middlewares that use the same protocol can be combined into chains to fit every scenario. !!! warning "Provider Namespace" Be aware of the concept of Providers Namespace described in the [Configuration Discovery](../../../install-configuration/providers/overview.md#provider-namespace) section. It also applies to Middlewares. Available HTTP Middlewares Middleware Purpose Area AddPrefix Adds a Path Prefix Path Modifier BasicAuth Adds Basic Authentication Security, Authentication Buffering Buffers the request/response Request Lifecycle Chain Combines multiple pieces of middleware Misc CircuitBreaker Prevents calling unhealthy services Request Lifecycle Compress Compresses the response Content Modifier ContentType Handles Content-Type auto-detection Misc DigestAuth Adds Digest Authentication Security, Authentication EncodedCharacters Defines allowed reserved encoded characters in the request path Security, Request Lifecycle Errors Defines custom error pages Request Lifecycle ForwardAuth Delegates Authentication Security, Authentication GrpcWeb Converts gRPC Web requests to HTTP/2 gRPC requests. Request Headers Adds / Updates headers Security IPAllowList Limits the allowed client IPs Security, Request lifecycle InFlightReq Limits the number of simultaneous connections Security, Request lifecycle PassTLSClientCert Adds Client Certificates in a Header Security RateLimit Limits the call frequency Security, Request lifecycle RedirectScheme Redirects based on scheme Request lifecycle RedirectRegex Redirects based on regex Request lifecycle ReplacePath Changes the path of the request Path Modifier ReplacePathRegex Changes the path of the request Path Modifier Retry Automatically retries in case of error Request lifecycle StripPrefix Changes the path of the request Path Modifier StripPrefixRegex Changes the path of the request Path Modifier Tap Sends a copy of the requests and responses to Traefik services Observability, Audit Community Middlewares Please take a look at the community-contributed plugins in the plugin catalog. {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik PassTLSClientCert Documentation The passTLSClientCert middleware adds the selected data from the passed client TLS certificate to a header. Configuration Examples Pass the pem in the X-Forwarded-Tls-Client-Cert header: # Pass the pem in the `X-Forwarded-Tls-Client-Cert` header. http: middlewares: test-passtlsclientcert: passTLSClientCert: pem: true # Pass the pem in the `X-Forwarded-Tls-Client-Cert` header. [http.middlewares] [http.middlewares.test-passtlsclientcert.passTLSClientCert] pem = true # Pass the pem in the `X-Forwarded-Tls-Client-Cert` header. labels: - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.pem=true" // Pass the pem in the `X-Forwarded-Tls-Client-Cert` header { "Tags": [ "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.pem=true" ] } apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-passtlsclientcert spec: passTLSClientCert: pem: true ??? example "Pass the pem in the X-Forwarded-Tls-Client-Cert header" ```yaml tab="Structured (YAML)" # Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header http: middlewares: test-passtlsclientcert: passTLSClientCert: info: notAfter: true notBefore: true sans: true subject: country: true province: true locality: true organization: true organizationalUnit: true commonName: true serialNumber: true domainComponent: true issuer: country: true province: true locality: true organization: true commonName: true serialNumber: true domainComponent: true ``` ```toml tab="Structured (TOML)" # Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header [http.middlewares] [http.middlewares.test-passtlsclientcert.passTLSClientCert] [http.middlewares.test-passtlsclientcert.passTLSClientCert.info] notAfter = true notBefore = true sans = true [http.middlewares.test-passtlsclientcert.passTLSClientCert.info.subject] country = true province = true locality = true organization = true organizationalUnit = true commonName = true serialNumber = true domainComponent = true [http.middlewares.test-passtlsclientcert.passTLSClientCert.info.issuer] country = true province = true locality = true organization = true commonName = true serialNumber = true domainComponent = true ``` ```yaml tab="Labels" # Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header labels: - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notafter=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notbefore=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.sans=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.serialnumber=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.commonname=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.country=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.domaincomponent=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.locality=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organization=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organizationalunit=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.province=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.serialnumber=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.commonname=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.country=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.domaincomponent=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.locality=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.organization=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.province=true" - "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.serialnumber=true" ``` ```json tab="Tags" // Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header { //... "Tags" : [ "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notafter=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notbefore=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.sans=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.commonname=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.country=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.domaincomponent=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.locality=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organization=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organizationalunit=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.province=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.serialnumber=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.commonname=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.country=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.domaincomponent=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.locality=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.organization=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.province=true", "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.serialnumber=true" ] } ``` ```yaml tab="Kubernetes" # Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-passtlsclientcert spec: passTLSClientCert: info: notAfter: true notBefore: true sans: true subject: country: true province: true locality: true organization: true organizationalUnit: true commonName: true serialNumber: true domainComponent: true issuer: country: true province: true locality: true organization: true commonName: true serialNumber: true domainComponent: true ``` General Information passTLSClientCert can add two headers to the request: X-Forwarded-Tls-Client-Cert that contains the pem. X-Forwarded-Tls-Client-Cert-Info that contains all the selected certificate information in an escaped string. !!! info - `X-Forwarded-Tls-Client-Cert-Info` header value is a string that has been escaped in order to be a valid URL query. - These options only work accordingly to the MutualTLS configuration. i.e, only the certificates that match the `clientAuth.clientAuthType` policy are passed. Configuration Options Field Description Default Required pem Fills the X-Forwarded-Tls-Client-Cert header with the certificate information. More information here. false No info.serialNumber Add the Serial Number of the certificate. More information about info here. false No info.notAfter Add the Not After information from the Validity part. More information about info here. false No info.notBefore Add the Not Before information from the Validity part. More information about info here. false No info.sans Add the Subject Alternative Name information from the Subject Alternative Name part. More information about info here. false No info.subject The info.subject selects the specific client certificate subject details you want to add to the X-Forwarded-Tls-Client-Cert-Info header. More information about info here. false No info.subject.country Add the country information into the subject. The data is taken from the subject part with the C key. More information about info here. false No info.subject.province Add the province information into the subject. The data is taken from the subject part with the ST key. More information about info here. false No info.subject.locality Add the locality information into the subject. The data is taken from the subject part with the L key. More information about info here. false No info.subject.organization Add the organization information into the subject. The data is taken from the subject part with the O key. More information about info here. false No info.subject.organizationalUnit Add the organizationalUnit information into the subject. The data is taken from the subject part with the OU key. More information about info here. false No info.subject.commonName Add the commonName information into the subject. The data is taken from the subject part with the CN key. false No info.subject.serialNumber Add the serialNumber information into the subject. The data is taken from the subject part with the SN key. false No info.subject.domainComponent Add the domainComponent information into the subject. The data is taken from the subject part with the DC key. More information about info here. false No info.issuer The info.issuer selects the specific client certificate issuer details you want to add to the X-Forwarded-Tls-Client-Cert-Info header. More information about info here. false No info.issuer.country Add the country information into the issuer. The data is taken from the issuer part with the C key. More information about info here. false No info.issuer.province Add the province information into the issuer. The data is taken from the issuer part with the ST key. More information about info here. false No info.issuer.locality Add the locality information into the issuer. The data is taken from the issuer part with the L key. More information about info here. false No info.issuer.organization Add the organization information into the issuer. The data is taken from the issuer part with the O key. More information about info here. false No info.issuer.commonName Add the commonName information into the issuer. The data is taken from the issuer part with the CN key. More information about info here. false No info.issuer.serialNumber Add the serialNumber information into the issuer. The data is taken from the issuer part with the SN key. More information about info here. false No info.issuer.domainComponent Add the domainComponent information into the issuer. The data is taken from the issuer part with the DC key. More information about info here. false No pem Data Format The delimiters and \n will be removed. If there are more than one certificate, they are separated by a " ,". Header size The X-Forwarded-Tls-Client-Cert header value could exceed the web server header size limit The header size limit of web servers is commonly between 4kb and 8kb. If that turns out to be a problem, and if reconfiguring the server to allow larger headers is not an option, one can alleviate the problem by selecting only the interesting parts of the cert, through the use of the info options described below. (And by setting pem to false). info The info option selects the specific client certificate details you want to add to the X-Forwarded-Tls-Client-Cert-Info header. Data Format The value of the header is an escaped concatenation of all the selected certificate details. Unless specified otherwise, all the header values examples are shown unescaped, for readability. If there are more than one certificate, they are separated by a ,. The following example shows such a concatenation, when all the available fields are selected: Subject="DC=org,DC=cheese,C=FR,C=US,ST=Cheese org state,ST=Cheese com state,L=TOULOUSE,L=LYON,O=Cheese,O=Cheese 2,CN=*.example.com";Issuer="DC=org,DC=cheese,C=FR,C=US,ST=Signing State,ST=Signing State 2,L=TOULOUSE,L=LYON,O=Cheese,O=Cheese 2,CN=Simple Signing CA 2";SerialNumber="1";NB="1747282426";NA="1778818426";SAN="*.example.org,*.example.net,*.example.com,test@example.org,test@example.net,10.0.1.0,10.0.1.2" Traefik RateLimit Documentation The rateLimit middleware ensures that services will receive a fair amount of requests, and allows you to define what fair is. It is based on a token bucket implementation. In this analogy, the average and period parameters define the rate at which the bucket refills, and the burst is the size (volume) of the bucket Rate and Burst The rate is defined by dividing average by period. For a rate below 1 req/s, define a period larger than a second Configuration Example # Here, an average of 100 requests per second is allowed. # In addition, a burst of 200 requests is allowed. # Redis distributed rate limiting is configured with all available options. http: middlewares: test-ratelimit: rateLimit: average: 100 period: 1s burst: 200 redis: endpoints: - "redis-primary.example.com:6379" - "redis-replica.example.com:6379" username: "ratelimit-user" password: "secure-password" db: 2 poolSize: 50 minIdleConns: 10 maxActiveConns: 200 readTimeout: 3s writeTimeout: 3s dialTimeout: 5s tls: ca: "/etc/ssl/redis-ca.crt" cert: "/etc/ssl/redis-client.crt" key: "/etc/ssl/redis-client.key" insecureSkipVerify: false # Here, an average of 100 requests per second is allowed. # In addition, a burst of 200 requests is allowed. # Redis distributed rate limiting is configured with all available options. [http.middlewares] [http.middlewares.test-ratelimit.rateLimit] average = 100 period = "1s" burst = 200 [http.middlewares.test-ratelimit.rateLimit.redis] endpoints = ["redis-primary.example.com:6379", "redis-replica.example.com:6379"] username = "ratelimit-user" password = "secure-password" db = 2 poolSize = 50 minIdleConns = 10 maxActiveConns = 200 readTimeout = "3s" writeTimeout = "3s" dialTimeout = "5s" [http.middlewares.test-ratelimit.rateLimit.redis.tls] ca = "/etc/ssl/redis-ca.crt" cert = "/etc/ssl/redis-client.crt" key = "/etc/ssl/redis-client.key" insecureSkipVerify = false # Here, an average of 100 requests per second is allowed. # In addition, a burst of 200 requests is allowed. # Redis distributed rate limiting is configured with all available options. labels: - "traefik.http.middlewares.test-ratelimit.ratelimit.average=100" - "traefik.http.middlewares.test-ratelimit.ratelimit.period=1s" - "traefik.http.middlewares.test-ratelimit.ratelimit.burst=200" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.endpoints=redis-primary.example.com:6379,redis-replica.example.com:6379" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.username=ratelimit-user" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.password=secure-password" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.db=2" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.poolSize=50" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.minIdleConns=10" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.maxActiveConns=200" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.readTimeout=3s" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.writeTimeout=3s" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.dialTimeout=5s" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.tls.ca=/etc/ssl/redis-ca.crt" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.tls.cert=/etc/ssl/redis-client.crt" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.tls.key=/etc/ssl/redis-client.key" - "traefik.http.middlewares.test-ratelimit.ratelimit.redis.tls.insecureSkipVerify=false" // Here, an average of 100 requests per second is allowed. // In addition, a burst of 200 requests is allowed. // Redis distributed rate limiting is configured with all available options. { "Tags": [ "traefik.http.middlewares.test-ratelimit.ratelimit.average=100", "traefik.http.middlewares.test-ratelimit.ratelimit.period=1s", "traefik.http.middlewares.test-ratelimit.ratelimit.burst=200", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.endpoints=redis-primary.example.com:6379,redis-replica.example.com:6379", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.username=ratelimit-user", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.password=secure-password", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.db=2", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.poolSize=50", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.minIdleConns=10", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.maxActiveConns=200", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.readTimeout=3s", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.writeTimeout=3s", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.dialTimeout=5s", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.tls.ca=/etc/ssl/redis-ca.crt", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.tls.cert=/etc/ssl/redis-client.crt", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.tls.key=/etc/ssl/redis-client.key", "traefik.http.middlewares.test-ratelimit.ratelimit.redis.tls.insecureSkipVerify=false" ] } # Here, an average of 100 requests per second is allowed. # In addition, a burst of 200 requests is allowed. # Redis distributed rate limiting is configured with all available options. apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-ratelimit spec: rateLimit: average: 100 period: 1s burst: 200 redis: endpoints: - "redis-primary.example.com:6379" - "redis-replica.example.com:6379" secret: redis-credentials db: 2 poolSize: 50 minIdleConns: 10 maxActiveConns: 200 readTimeout: 3s writeTimeout: 3s dialTimeout: 5s tls: caSecret: redis-ca certSecret: redis-client-cert insecureSkipVerify: false --- apiVersion: v1 kind: Secret metadata: name: redis-credentials namespace: default data: username: cmF0ZWxpbWl0LXVzZXI= # base64 encoded "ratelimit-user" password: c2VjdXJlLXBhc3N3b3Jk # base64 encoded "secure-password" --- apiVersion: v1 kind: Secret metadata: name: redis-ca namespace: default data: tls.ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t... --- apiVersion: v1 kind: Secret metadata: name: redis-client-cert namespace: default data: tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t... tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0t... Configuration Options Field Description Default Required average Number of requests used to define the rate using the period. 0 means no rate limiting. More information here. 0 No period Period of time used to define the rate. More information here. 1s No burst Maximum number of requests allowed to go through at the very same moment. More information here. 1 No sourceCriterion.requestHost Whether to consider the request host as the source. More information about sourceCriterionhere. false No sourceCriterion.requestHeaderName Name of the header used to group incoming requests. More information about sourceCriterionhere. "" No sourceCriterion.ipStrategy.depth Depth position of the IP to select in the X-Forwarded-For header (starting from the right). 0 means no depth. If greater than the total number of IPs in X-Forwarded-For, then the client IP is empty If higher than 0, the excludedIPs options is not evaluated. More information about sourceCriterion, ipStrategy, and depth below. 0 No sourceCriterion.ipStrategy.excludedIPs Allows scanning the X-Forwarded-For header and select the first IP not in the list. If depth is specified, excludedIPs is ignored. More information about sourceCriterion, ipStrategy, and excludedIPs below. No sourceCriterion.ipStrategy.ipv6Subnet If ipv6Subnet is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to. More information about sourceCriterion, ipStrategy.ipv6Subnet below. No redis The redis configuration enables distributed rate limiting by using Redis to store rate limit tokens across multiple Traefik instances. This allows you to enforce consistent rate limits across a cluster of Traefik proxies. When Redis is not configured, Traefik uses in-memory storage for rate limiting, which works only for the individual Traefik instance. No redis.endpoints List of Redis server endpoints for distributed rate limiting. You can specify multiple endpoints for Redis cluster or high availability setups. "localhost:6379" No redis.username Username for Redis authentication. "" No redis.password Password for Redis authentication. In Kubernetes, these can be provided via secrets. "" No redis.db Redis database number to select. 0 No redis.poolSize Defines the base number of socket connections in the pool. If set to 0, it defaults to 10 connections per CPU core as reported by runtime.GOMAXPROCS. If there are not enough connections in the pool, new connections will be allocated beyond poolSize, up to maxActiveConns. 0 No redis.minIdleConns Minimum number of idle connections to maintain in the pool. This is useful when establishing new connections is slow. A value of 0 means idle connections are not automatically closed. 0 No redis.maxActiveConns Maximum number of connections the pool can allocate at any given time. A value of 0 means no limit. 0 No redis.readTimeout Timeout for socket reads. If reached, commands will fail with a timeout instead of blocking. Zero means no timeout. 3s No redis.writeTimeout Timeout for socket writes. If reached, commands will fail with a timeout instead of blocking. Zero means no timeout. 3s No redis.dialTimeout Timeout for establishing new connections. Zero means no timeout. 5s No redis.tls.ca Path to the certificate authority used for the secure connection to Redis, it defaults to the system bundle. "" No redis.tls.cert Path to the public certificate used for the secure connection to Redis. When this option is set, the key option is required. "" No redis.tls.key Path to the private key used for the secure connection to Redis. When this option is set, the cert option is required. "" No redis.tls.insecureSkipVerify If insecureSkipVerify is true, the TLS connection to Redis accepts any certificate presented by the server regardless of the hostnames it covers. false No sourceCriterion The sourceCriterion option defines what criterion is used to group requests as originating from a common source. If several strategies are defined at the same time, an error will be raised. If none are set, the default is to use the request's remote address field (as an ipStrategy). ipStrategy The ipStrategy option defines three parameters that configures how Traefik determines the client IP: depth, excludedIPs and ipv6Subnet. As a middleware, rate-limiting happens before the actual proxying to the backend takes place. In addition, the previous network hop only gets appended to X-Forwarded-For during the last stages of proxying, that is after it has already passed through rate-limiting. Therefore, during rate-limiting, as the previous network hop is not yet present in X-Forwarded-For, it cannot be found and/or relied upon. sourceCriterion.ipStrategy.ipv6Subnet This strategy applies to Depth and RemoteAddr strategy only. If ipv6Subnet is provided and the selected IP is IPv6, the IP is transformed into the first IP of the subnet it belongs to. This is useful for grouping IPv6 addresses into subnets to prevent bypassing this middleware by obtaining a new IPv6. ipv6Subnet is ignored if its value is outside of 0-128 interval Example of ipv6Subnet If ipv6Subnet is provided, the IP is transformed in the following way. IP ipv6Subnet clientIP "::abcd:1111:2222:3333" 64 "::0:0:0:0" "::abcd:1111:2222:3333" 80 "::abcd:0:0:0:0" "::abcd:1111:2222:3333" 96 "::abcd:1111:0:0:0" sourceCriterion.ipStrategy.depth If depth is set to 2, and the request X-Forwarded-For header is "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" then the "real" client IP is "10.0.0.1" (at depth 4) but the IP used as the criterion is "12.0.0.1" ( depth=2). X-Forwarded-For depth clientIP "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" 1 "13.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" 3 "11.0.0.1" "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" 5 "" sourceCriterion.ipStrategy.excludedIPs Contrary to what the name might suggest, this option is not about excluding an IP from the rate limiter, and therefore cannot be used to deactivate rate limiting for some IPs. excludedIPs is meant to address two classes of somewhat distinct use-cases: Distinguish IPs which are behind the same (set of) reverse-proxies so that each of them contributes, independently to the others, to its own rate-limit "bucket" (cf the token bucket). In this case, excludedIPs should be set to match the list of X-Forwarded-For IPs that are to be excluded, in order to find the actual clientIP. Example to use each IP as a distinct source: X-Forwarded-For excludedIPs clientIP "10.0.0.1,11.0.0.1,12.0.0.1" "11.0.0.1,12.0.0.1" "10.0.0.1" "10.0.0.2,11.0.0.1,12.0.0.1" "11.0.0.1,12.0.0.1" "10.0.0.2" Group together a set of IPs (also behind a common set of reverse-proxies) so that they are considered the same source, and all contribute to the same rate-limit bucket. Example to group IPs together as same source: X-Forwarded-For excludedIPs clientIP "10.0.0.1,11.0.0.1,12.0.0.1" "12.0.0.1" "11.0.0.1" "10.0.0.2,11.0.0.1,12.0.0.1" "12.0.0.1" "11.0.0.1" "10.0.0.3,11.0.0.1,12.0.0.1" "12.0.0.1" "11.0.0.1" Traefik RedirectRegex Documentation The RedirectRegex redirects a request using regex matching and replacement. Configuration Examples # Redirect with domain replacement http: middlewares: test-redirectregex: redirectRegex: regex: "^http://localhost/(.*)" replacement: "http://mydomain/${1}" # Redirect with domain replacement [http.middlewares] [http.middlewares.test-redirectregex.redirectRegex] regex = "^http://localhost/(.*)" replacement = "http://mydomain/${1}" # Redirect with domain replacement # Note: all dollar signs need to be doubled for escaping. labels: - "traefik.http.middlewares.test-redirectregex.redirectregex.regex=^http://localhost/(.*)" - "traefik.http.middlewares.test-redirectregex.redirectregex.replacement=http://mydomain/$${1}" // Redirect with domain replacement // Note: all dollar signs need to be doubled for escaping. { // ... "Tags" : [ "traefik.http.middlewares.test-redirectregex.redirectregex.regex=^http://localhost/(.*)" "traefik.http.middlewares.test-redirectregex.redirectregex.replacement=http://mydomain/$${1}" ] } # Redirect with domain replacement apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-redirectregex spec: redirectRegex: regex: ^http://localhost/(.*) replacement: http://mydomain/${1} Configuration Options Field Description Default Required regex The regex option is the regular expression to match and capture elements from the request URL. "" Yes permanent Enable a permanent redirection. false No replacement The replacement option defines how to modify the URL to have the new target URL.. $1x is equivalent to ${1x}, not ${1}x (see Regexp.Expand), so use ${1} syntax. "" No regex The regex option is the regular expression to match and capture elements from the request URL. !!! tip Regular expressions and replacements can be tested using online tools such as [Go Playground](https://play.golang.org/p/mWU9p-wk2ru) or the [Regex101](https://regex101.com/r/58sIgx/2). When defining a regular expression within YAML, any escaped character needs to be escaped twice: `example\.com` needs to be written as `example\\.com`. replacement The replacement option defines how to modify the URL to have the new target URL. !!! warning Care should be taken when defining replacement expand variables: `$1x` is equivalent to `${1x}`, not `${1}x` (see [Regexp.Expand](https://golang.org/pkg/regexp/#Regexp.Expand)), so use `${1}` syntax. {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik RedirectScheme Documentation The RedirectScheme middleware redirects the request if the request scheme is different from the configured scheme. !!! warning "When behind another reverse-proxy" When there is at least one other reverse-proxy between the client and Traefik, the other reverse-proxy (i.e. the last hop) needs to be a [trusted](../../../install-configuration/entrypoints.md#configuration-options) one. Otherwise, Traefik would clean up the `X-Forwarded` headers coming from this last hop, and as the RedirectScheme middleware relies on them to determine the scheme used, it would not function as intended. Configuration Examples # Redirect to https http: middlewares: test-redirectscheme: redirectScheme: scheme: https permanent: true # Redirect to https [http.middlewares] [http.middlewares.test-redirectscheme.redirectScheme] scheme = "https" permanent = true # Redirect to https labels: - "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https" - "traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true" // Redirect to https { // ... "Tags": [ "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https", "traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true" ] } # Redirect to https apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-redirectscheme spec: redirectScheme: scheme: https permanent: true Configuration Options Field Description Default Required scheme Scheme of the new URL. "" Yes permanent Enable a permanent redirection. false No port Port of the new URL. Set a string, not a numeric value. "" No Traefik ReplacePath Documentation The replacePath middleware will: Replace the actual path with the specified one. Store the original path in a X-Replaced-Path header Configuration Examples # Replace the path with /foo http: middlewares: test-replacepath: replacePath: path: "/foo" # Replace the path with /foo [http.middlewares] [http.middlewares.test-replacepath.replacePath] path = "/foo" # Replace the path with /foo labels: - "traefik.http.middlewares.test-replacepath.replacepath.path=/foo" // Replace the path with /foo { // ... "Tags" : [ "traefik.http.middlewares.test-replacepath.replacepath.path=/foo" ] } # Replace the path with /foo apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-replacepath spec: replacePath: path: "/foo" Configuration Options Field Description path The path option defines the path to use as replacement in the request URL. Traefik ReplacePathRegex Documentation The replacePathRegex middleware will: Replace the matching path with the specified one. Store the original path in an X-Replaced-Path header Configuration Examples # Replace path with regex http: middlewares: test-replacepathregex: replacePathRegex: regex: "^/foo/(.*)" replacement: "/bar/$1" # Replace path with regex [http.middlewares] [http.middlewares.test-replacepathregex.replacePathRegex] regex = "^/foo/(.*)" replacement = "/bar/$1" # Replace path with regex apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-replacepathregex spec: replacePathRegex: regex: "^/foo/(.*)" replacement: "/bar/$1" # Replace path with regex labels: - "traefik.http.middlewares.test-replacepathregex.replacepathregex.regex=^/foo/(.*)" - "traefik.http.middlewares.test-replacepathregex.replacepathregex.replacement=/bar/$$1" # Replace path with regex - "traefik.http.middlewares.test-replacepathregex.replacepathregex.regex=^/foo/(.*)" - "traefik.http.middlewares.test-replacepathregex.replacepathregex.replacement=/bar/$1" Configuration Options Field Description Default Required regex Regular expression to match and capture the path from the request URL. Yes replacement Replacement path format, which can include captured variables. $1x is equivalent to ${1x}, not ${1}x (see Regexp.Expand), so use ${1} syntax. No !!! tip Regular expressions and replacements can be tested using online tools such as [Go Playground](https://play.golang.org/p/mWU9p-wk2ru) or the [Regex101](https://regex101.com/r/58sIgx/2). When defining a regular expression within YAML, any escaped character needs to be escaped twice: `example\.com` needs to be written as `example\\.com`. Traefik HTTP Retry Documentation The retry middleware retries requests a given number of times to a backend server if that server does not reply. As soon as the server answers, the middleware stops retrying, regardless of the response status. The Retry middleware has an optional configuration to enable an exponential backoff. Configuration Examples # Retry 4 times with exponential backoff http: middlewares: test-retry: retry: attempts: 4 initialInterval: 100ms timeout: 60s maxRequestBodyBytes: 1024 status: - "400" - "500-599" disableRetryOnNetworkError: true retryNonIdempotentMethod: true # Retry 4 times with exponential backoff [http.middlewares] [http.middlewares.test-retry.retry] attempts = 4 initialInterval = "100ms" timeout = "60s" maxRequestBodyBytes = 1024 status = ["400","500-599"] disableRetryOnNetworkError = true retryNonIdempotentMethod = true # Retry 4 times with exponential backoff labels: - "traefik.http.middlewares.test-retry.retry.attempts=4" - "traefik.http.middlewares.test-retry.retry.initialinterval=100ms" - "traefik.http.middlewares.test-retry.retry.timeout=60s" - "traefik.http.middlewares.test-retry.retry.maxrequestbodybytes=1024" - "traefik.http.middlewares.test-retry.retry.status=400,500-599" - "traefik.http.middlewares.test-retry.retry.disableretryonnetworkerror=true" - "traefik.http.middlewares.test-retry.retry.retrynonidempotentmethod=true" // Retry 4 times with exponential backoff { // ... "Tags" : [ "traefik.http.middlewares.test-retry.retry.attempts=4", "traefik.http.middlewares.test-retry.retry.initialinterval=100ms", "traefik.http.middlewares.test-retry.retry.timeout=60s", "traefik.http.middlewares.test-retry.retry.maxrequestbodybytes=1024", "traefik.http.middlewares.test-retry.retry.status=400,500-599", "traefik.http.middlewares.test-retry.retry.disableretryonnetworkerror=true", "traefik.http.middlewares.test-retry.retry.retrynonidempotentmethod=true" ] } # Retry 4 times with exponential backoff apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-retry spec: retry: attempts: 4 initialInterval: 100ms timeout: 60s maxRequestBodyBytes: 1024 status: - "400" - "500-599" disableRetryOnNetworkError: true retryNonIdempotentMethod: true Configuration Options Field Description Default Required attempts number of times the request should be retried. Yes initialInterval First wait time in the exponential backoff series. The maximum interval is calculated as twice the initialInterval. If unspecified, requests will be retried immediately. Defined in seconds or as a valid duration format, see time.ParseDuration. 0 No timeout How much time the middleware is allowed to retry the request. Defined in seconds or as a valid duration format, see time.ParseDuration. 0 No maxRequestBodyBytes Defines the maximum size for the request body. More information here. 2MB No status Defines the range of HTTP status codes to retry on. More information here. [] No disableRetryOnNetworkError This option disables the retry if an error occurs when transmitting the request to the server. More information here. false No retryNonIdempotentMethod Activates the retry for non-idempotent methods ( POST, LOCK, PATCH) false No maxRequestBodyBytes The maxRequestBodyBytes option controls the maximum size of request bodies that will be sent to the server. ⚠️ Important Security Consideration When maxRequestBodyBytes is set to -1, it means there is no limit for request body size. This can have significant security and performance implications: Security Risk: Attackers can send extremely large request bodies, potentially causing DoS attacks or memory exhaustion Performance Impact: Large request bodies consume memory and processing resources, affecting overall system performance Resource Consumption: Unlimited body size can lead to unexpected resource usage patterns Recommended Configuration It is strongly recommended to set an appropriate maxRequestBodyBytes value for your use case: # For most web applications (1MB limit) maxRequestBodyBytes: 1048576 # 1MB in bytes # For API endpoints expecting larger payloads (10MB limit) maxRequestBodyBytes: 10485760 # 10MB in bytes # For file upload authentication (100MB limit) maxRequestBodyBytes: 104857600 # 100MB in bytes Guidelines for Setting maxRequestBodyBytes Web Forms: 1-5MB is typically sufficient for most form submissions API Endpoints: Consider your largest expected JSON/XML payload + buffer File Uploads: Set based on your maximum expected file size High-Traffic Services: Use smaller limits to prevent resource exhaustion disableRetryOnNetworkError and status The disableRetryOnNetworkError option disables the retry if an error occurs when transmitting the request to the server, at the TCP layer. However, if you want to retry only for specific HTTP status codes, you can configure the status option with the relevant status codes to retry on. If disableRetryOnNetworkError is set to true, you must define the status option. Otherwise, the middleware will raise a configuration error. Traefik StripPrefix Documentation The stripPrefix middleware strips the matching path prefix and stores it in an X-Forwarded-Prefix header. !!! tip Use a `StripPrefix` middleware if your backend listens on the root path (`/`) but should be exposed on a specific prefix. Configuration Examples # Strip prefix /foobar and /fiibar http: middlewares: test-stripprefix: stripPrefix: prefixes: - "/foobar" - "/fiibar" # Strip prefix /foobar and /fiibar [http.middlewares] [http.middlewares.test-stripprefix.stripPrefix] prefixes = ["/foobar", "/fiibar"] # Strip prefix /foobar and /fiibar labels: - "traefik.http.middlewares.test-stripprefix.stripprefix.prefixes=/foobar,/fiibar" // Strip prefix /foobar and /fiibar { "Tags" : [ "traefik.http.middlewares.test-stripprefix.stripprefix.prefixes=/foobar,/fiibar" ] } # Strip prefix /foobar and /fiibar apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-stripprefix spec: stripPrefix: prefixes: - /foobar - /fiibar Configuration Options Field Description Default Required prefixes List of prefixes to strip from the request URL. If your backend is serving assets (for example, images or JavaScript files), it can use the X-Forwarded-Prefix header to construct relative URLs. [] No {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik StripPrefixRegex Documentation The stripPrefixRegex middleware strips the matching path prefix and stores it in an X-Forwarded-Prefix header. !!! tip Use a `stripPrefixRegex` middleware if your backend listens on the root path (`/`) but should be exposed on a specific prefix. Configuration Example http: middlewares: test-stripprefixregex: stripPrefixRegex: regex: - "/foo/[a-z0-9]+/[0-9]+/" [http.middlewares] [http.middlewares.test-stripprefixregex.stripPrefixRegex] regex = ["/foo/[a-z0-9]+/[0-9]+/"] labels: - "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=/foo/[a-z0-9]+/[0-9]+/" { //.. "Tags" : [ "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=/foo/[a-z0-9]+/[0-9]+/" ] } - apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-stripprefixregex spec: stripPrefixRegex: regex: - "/foo/[a-z0-9]+/[0-9]+/" Configuration Options Field Description Default Required regex List of regular expressions to match the path prefix from the request URL. For instance, /products also matches /products/shoes and /products/shirts. More information here. No regex If your backend is serving assets (for example, images or JavaScript files), it can use the X-Forwarded-Prefix header to construct relative URLs. Using the previous example, the backend should return /products/shoes/image.png (and not /images.png, which Traefik would likely not be able to associate with the same backend). !!! tip Regular expressions and replacements can be tested using online tools such as [Go Playground](https://play.golang.org/p/mWU9p-wk2ru) or the [Regex101](https://regex101.com/r/58sIgx/2). When defining a regular expression within YAML, any escaped character needs to be escaped twice: `example\.com` needs to be written as `example\\.com`. Traefik Tap Documentation The tap middleware sends a copy of the requests and responses going through it to Traefik services, as JSON records. Because the destinations are ordinary Traefik services, they benefit from load balancing, health checks, retries and serversTransport options like any other service, and they can be anything reachable over HTTP: a message queue gateway, an audit store, or a sidecar of your own. Requests and responses are sent as two separate records, each to its own service, so that both streams can be consumed and scaled independently. Set only one of the two to capture a single side. !!! warning "Sensitive data" Records carry the headers as they go through Traefik, `Authorization` and `Cookie` included, and the bodies too once `recordBody` is enabled. Restrict what is captured with `recordBody` and `maxRecordBodySize`, and treat the tap services and their storage as holding production secrets. !!! info "Difference with the Mirroring service" The [Mirroring](../../../../reference/routing-configuration/http/load-balancing/service.md) service replays requests to another service, and the replayed requests are handled as real traffic. The `tap` middleware sends a description of the exchange, response included, and never replays anything. !!! tip "Position in the middleware chain" The records describe the request and the response as they are at the position of the `tap` middleware in the chain. - Placed first, it records the request as received from the client, and the response as sent to the client. - Placed last, it records the request as sent to the backend, and the response as received from the backend. To get both, use two `tap` middlewares, one first and one last in the chain. Their records can be matched with the `traceId`, or with a correlation header listed in `requestHeaders`. Configuration Examples http: middlewares: test-tap: tap: request: service: audit-requests path: /records/requests recordBody: true maxRecordBodySize: 4096 rejectOnRecordError: true timeout: 5s response: service: audit-responses path: /records/responses recordBody: true maxRecordBodySize: 4096 requestHeaders: - X-Request-Id rejectOnRecordError: false timeout: 5s [http.middlewares] [http.middlewares.test-tap.tap] [http.middlewares.test-tap.tap.request] service = "audit-requests" path = "/records/requests" recordBody = true maxRecordBodySize = 4096 rejectOnRecordError = true timeout = "5s" [http.middlewares.test-tap.tap.response] service = "audit-responses" path = "/records/responses" recordBody = true maxRecordBodySize = 4096 requestHeaders = ["X-Request-Id"] rejectOnRecordError = false timeout = "5s" labels: - "traefik.http.middlewares.test-tap.tap.request.service=audit-requests" - "traefik.http.middlewares.test-tap.tap.request.path=/records/requests" - "traefik.http.middlewares.test-tap.tap.request.recordBody=true" - "traefik.http.middlewares.test-tap.tap.request.maxRecordBodySize=4096" - "traefik.http.middlewares.test-tap.tap.request.rejectOnRecordError=true" - "traefik.http.middlewares.test-tap.tap.request.timeout=5s" - "traefik.http.middlewares.test-tap.tap.response.service=audit-responses" - "traefik.http.middlewares.test-tap.tap.response.path=/records/responses" - "traefik.http.middlewares.test-tap.tap.response.recordBody=true" - "traefik.http.middlewares.test-tap.tap.response.maxRecordBodySize=4096" - "traefik.http.middlewares.test-tap.tap.response.requestHeaders=X-Request-Id" - "traefik.http.middlewares.test-tap.tap.response.rejectOnRecordError=false" - "traefik.http.middlewares.test-tap.tap.response.timeout=5s" { //... "Tags" : [ "traefik.http.middlewares.test-tap.tap.request.service=audit-requests", "traefik.http.middlewares.test-tap.tap.request.path=/records/requests", "traefik.http.middlewares.test-tap.tap.request.recordBody=true", "traefik.http.middlewares.test-tap.tap.request.maxRecordBodySize=4096", "traefik.http.middlewares.test-tap.tap.request.rejectOnRecordError=true", "traefik.http.middlewares.test-tap.tap.request.timeout=5s", "traefik.http.middlewares.test-tap.tap.response.service=audit-responses", "traefik.http.middlewares.test-tap.tap.response.path=/records/responses", "traefik.http.middlewares.test-tap.tap.response.recordBody=true", "traefik.http.middlewares.test-tap.tap.response.maxRecordBodySize=4096", "traefik.http.middlewares.test-tap.tap.response.requestHeaders=X-Request-Id", "traefik.http.middlewares.test-tap.tap.response.rejectOnRecordError=false", "traefik.http.middlewares.test-tap.tap.response.timeout=5s" ] } apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-tap spec: tap: request: service: name: audit-requests port: 80 path: /records/requests recordBody: true maxRecordBodySize: 4096 rejectOnRecordError: true timeout: 5s response: service: name: audit-responses port: 80 path: /records/responses recordBody: true maxRecordBodySize: 4096 requestHeaders: - X-Request-Id rejectOnRecordError: false timeout: 5s Configuration Options Field Description Default Required request Where and how the request records are sent. When omitted, requests are not recorded. More information here. No response Where and how the response records are sent. When omitted, responses are not recorded. More information here. No At least one of request and response must be set. request Field Description Default Required service Name of the service the records are sent to. Yes path Path of the requests sending the records to the service. / No recordBody Whether the body is part of the records. false No maxRecordBodySize Maximum number of body bytes in a record, and held in memory. More information here. With recordBody rejectOnRecordError Rejects the request with a 500 when the record cannot be sent. More information here. false No timeout Maximum duration allowed to send a record. A value of 0 means no limit. 10s No response Field Description Default Required service Name of the service the records are sent to. Yes path Path of the requests sending the records to the service. / No recordBody Whether the body is part of the records. false No maxRecordBodySize Maximum number of body bytes in a record, and held in memory. More information here. With recordBody requestHeaders Request headers described in the records, along with the request line. More information here. No rejectOnRecordError Rejects the request with a 500 when the record cannot be sent. More information here. false No timeout Maximum duration allowed to send a record. A value of 0 means no limit. 10s No rejectOnRecordError When the record cannot be sent: With false, the error is logged, and the request is served. With true, the request is rejected with a 500 Internal Server Error. With true, the record is sent first: the request record before the request reaches the backend, and the response record before the response reaches the client. Nothing is served unrecorded. The request and response settings are independent. On response, true also means: The response is held until its record is complete, then the rest of it is streamed. The record is complete once the status is known, or with recordBody, once the first maxRecordBodySize bytes of the body are captured, or the response ends. WebSocket upgrades are served as usual, and their record is sent as with false. Informational responses, such as 103 Early Hints, are dropped. In both cases, records are sent inline, within timeout: the time taken by the tap service adds to the latency of every request. Keep timeout short, and the tap service close to Traefik. requestHeaders A response record describes the response alone, which is enough to store it, but not to tell which exchange it belongs to without fetching the matching request record. requestHeaders adds a request object to the response records, holding the request line and the listed headers, and nothing else: the body of a request is never part of a response record. It is typically used to carry a correlation identifier set by a middleware standing before the tap in the chain. Headers absent from the request are absent from the record. The option does not exist on the request records, which already describe the whole request. maxRecordBodySize maxRecordBodySize is the maximum number of body bytes in a record. A larger body is cut in the record, which sets bodyTruncated to true. The backend and the client still get the whole body. It also bounds the memory used for the body: only the recorded bytes are held, and the rest of the body is streamed. It has no default, as no limit fits every route, and must be set with recordBody. A value of -1 means no limit, and holds the whole body in memory. Records A record is sent as a POST request to the configured service and path, with a JSON body: { "id": "9f8b1c8a3d4e5f60718293a4b5c6d7e8", "kind": "response", "time": "2026-08-28T14:02:11.123456789Z", "traceId": "4bf92f3577b34da6a3ce929d0e0e4736", "response": { "status": 201, "headers": { "Content-Type": ["application/json"] }, "body": "eyJpZCI6MX0=", "duration": 14234000 } } Field Description id Identifier of the exchange. The request record and the response record of the same exchange share it. kind Either request or response. time Time at which the request was received. traceId Trace the request belongs to, when tracing is enabled. request Method, URL, host, protocol, remote address, headers and body. Set on request records, and on response records when requestHeaders is set. response Status, headers, body, and duration in nanoseconds. The duration ends with the response, or when the record is sent with rejectOnRecordError. Set on response records. Bodies are part of the records only when recordBody is enabled. They are base64-encoded, as they are not necessarily valid UTF-8, and carry a bodyTruncated flag when they exceed maxRecordBodySize. The same information is also carried by two headers, so that a service handling both kinds of records can dispatch them without parsing the payload: Header Description X-Tap-Id The record id. X-Tap-Record The record kind. A tap service is expected to answer with a status below 400. Anything else is treated as a failure to record. Coraza Web Application Firewall !!! info "Traefik Hub Feature" This middleware is available exclusively in Traefik Hub. Learn more about Traefik Hub's advanced features. The Coraza WAF middleware in Traefik Hub API Gateway provides web application firewall capabilities. The native middleware in Hub API Gateway provides at least 23 times more performance compared to the WASM-based Coraza plugin available with the open-source Traefik Proxy. To learn how to write rules, please visit Coraza documentation and OWASP CRS documentation. !!! warning Starting with Traefik Hub v3.11.0, Coraza needs to have read/write permissions to `/tmp`. This is related to [this upstream PR](https://github.com/corazawaf/coraza/pull/1030). Configuration Examples apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: waf spec: plugin: coraza: directives: - SecRuleEngine On - SecRule REQUEST_URI "@streq /admin" "id:101,phase:1,t:lowercase,log,deny" apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: wafcrs namespace: apps spec: plugin: coraza: crsEnabled: true directives: - SecDefaultAction "phase:1,log,auditlog,deny,status:403" - SecDefaultAction "phase:2,log,auditlog,deny,status:403" - SecAction "id:900110, phase:1, pass, t:none, nolog, setvar:tx.inbound_anomaly_score_threshold=5, setvar:tx.outbound_anomaly_score_threshold=4" - SecAction "id:900200, phase:1, pass, t:none, nolog, setvar:'tx.allowed_methods=GET'" - Include @owasp_crs/REQUEST-911-METHOD-ENFORCEMENT.conf - Include @owasp_crs/REQUEST-949-BLOCKING-EVALUATION.conf Configuration Options Field Description Default Required directives List of WAF rules to enforce. Yes crsEnabled Enable CRS rulesets. Once the ruleset is enabled, it can be used in the middleware. false False {% include-markdown "includes/traefik-for-business-applications.md" %} Multi-Layer Routing Hierarchical Router Relationships for Advanced Routing Scenarios. Overview Multi-layer routing enables you to create hierarchical relationships between routers, where parent routers can process requests through middleware before child routers make final routing decisions. This feature allows middleware at the parent level to modify requests (adding headers, performing authentication, etc.) that influence how child routers evaluate their rules and route traffic to services. Multi-layer routing is particularly useful for progressive request enrichment, where each layer adds context to the request, enabling increasingly specific routing decisions: Authentication-Based Routing: Parent router authenticates requests and adds user context (roles, permissions) as headers, child routers route based on these headers Staged Middleware Application: Apply common middleware (rate limiting, CORS) at parent level (for a given domain/path), but specific middleware at child level !!! info "Provider Support" Multi-layer routing is supported by the following providers: - **File provider** (YAML, TOML, JSON) - **KV stores** (Consul, etcd, Redis, ZooKeeper) - **Kubernetes CRD** (IngressRoute) Multi-layer routing is not available for other providers (Docker, Kubernetes Ingress, Gateway API, etc.). How It Works Request → EntryPoint → Parent Router → Middleware → Child Router A → Service A ↓ → Child Router B → Service B Modify Request (e.g., add headers) Request arrives at an entrypoint Parent router matches based on its rule (e.g., Host(`example.com`)) Parent middleware executes, potentially modifying the request One child router matches based on its rule (which may use modified request attributes) Request is forwarded to the matching child router's service Building a Router Hierarchy Root Routers Have no parentRefs (top of the hierarchy) Can have tls, observability, and entryPoints configuration Can be either parent routers (with children) or standalone routers (with service) Can have models applied (non-root routers cannot have models) Intermediate Routers Reference their parent router(s) via parentRefs Have one or more child routers Must not have a service defined Must not have entryPoints, tls, or observability configuration Leaf Routers Reference their parent router(s) via parentRefs Must have a service defined Must not have entryPoints, tls, or observability configuration Configuration Example ??? example "Authentication-Based Routing" ```yaml tab="File (YAML)" ## Dynamic configuration http: routers: # Parent router with authentication api-parent: rule: "PathPrefix(`/api`)" middlewares: - auth-middleware entryPoints: - websecure tls: {} # Note: No service defined - this is a parent router # Child router for admin users api-admin: rule: "HeaderRegexp(`X-User-Role`, `admin`)" service: admin-service parentRefs: - api-parent # Child router for regular users api-user: rule: "HeaderRegexp(`X-User-Role`, `user`)" service: user-service parentRefs: - api-parent middlewares: auth-middleware: forwardAuth: address: "http://auth-service:8080/auth" authResponseHeaders: - X-User-Role - X-User-Name services: admin-service: loadBalancer: servers: - url: "http://admin-backend:8080" user-service: loadBalancer: servers: - url: "http://user-backend:8080" ``` ```toml tab="File (TOML)" ## Dynamic configuration [http.routers] # Parent router with authentication [http.routers.api-parent] rule = "PathPrefix(`/api`)" middlewares = ["auth-middleware"] entryPoints = ["websecure"] [http.routers.api-parent.tls] # Note: No service defined - this is a parent router # Child router for admin users [http.routers.api-admin] rule = "HeaderRegexp(`X-User-Role`, `admin`)" service = "admin-service" parentRefs = ["api-parent"] # Child router for regular users [http.routers.api-user] rule = "HeaderRegexp(`X-User-Role`, `user`)" service = "user-service" parentRefs = ["api-parent"] [http.middlewares] [http.middlewares.auth-middleware.forwardAuth] address = "http://auth-service:8080/auth" authResponseHeaders = ["X-User-Role", "X-User-Name"] [http.services] [http.services.admin-service.loadBalancer] [[http.services.admin-service.loadBalancer.servers]] url = "http://admin-backend:8080" [http.services.user-service.loadBalancer] [[http.services.user-service.loadBalancer.servers]] url = "http://user-backend:8080" ``` ```txt tab="KV (Consul/etcd/Redis/ZK)" | Key | Value | |------------------------------------------------------------------------|---------------------------------| | `traefik/http/routers/api-parent/rule` | `PathPrefix(\`/api\`)` | | `traefik/http/routers/api-parent/middlewares/0` | `auth-middleware` | | `traefik/http/routers/api-parent/entrypoints/0` | `websecure` | | `traefik/http/routers/api-parent/tls` | `true` | | `traefik/http/routers/api-admin/rule` | `HeaderRegexp(\`X-User-Role\`, \`admin\`)` | | `traefik/http/routers/api-admin/service` | `admin-service` | | `traefik/http/routers/api-admin/parentrefs/0` | `api-parent` | | `traefik/http/routers/api-user/rule` | `HeaderRegexp(\`X-User-Role\`, \`user\`)` | | `traefik/http/routers/api-user/service` | `user-service` | | `traefik/http/routers/api-user/parentrefs/0` | `api-parent` | | `traefik/http/middlewares/auth-middleware/forwardauth/address` | `http://auth-service:8080/auth` | | `traefik/http/middlewares/auth-middleware/forwardauth/authresponseheaders/0` | `X-User-Role` | | `traefik/http/middlewares/auth-middleware/forwardauth/authresponseheaders/1` | `X-User-Name` | | `traefik/http/services/admin-service/loadbalancer/servers/0/url` | `http://admin-backend:8080` | | `traefik/http/services/user-service/loadbalancer/servers/0/url` | `http://user-backend:8080` | ``` **How it works:** 1. Request to `/api/endpoint` matches `api-parent` router 2. `auth-middleware` (ForwardAuth) validates the request and adds `X-User-Role` header 3. Modified request is evaluated by child routers 4. If `X-User-Role: admin`, `api-admin` router matches and forwards to `admin-service` 5. If `X-User-Role: user`, `api-user` router matches and forwards to `user-service` {% include-markdown "includes/traefik-for-business-applications.md" %} Per-Router Observability Traefik's observability features include logs, access logs, metrics, and tracing. You can configure these options globally or at more specific levels, such as per router or per entry point. By default, the router observability configuration is inherited from the attached EntryPoints and can be configured with the observability options. However, a router defining its own observability configuration will opt-out from these defaults. !!! info To enable router-level observability, you must first enable access-logs, tracing, and metrics. When metrics layers are not enabled with the `addEntryPointsLabels`, `addRoutersLabels` and/or `addServicesLabels` options, enabling metrics for a router will not enable them. !!! warning "AddInternals option" By default, and for any type of signal (access-logs, metrics and tracing), Traefik disables observability for internal resources. The observability options described below cannot interfere with the `AddInternals` ones, and will be ignored. For instance, if a router exposes the `api@internal` service and `metrics.AddInternals` is false, it will never produces metrics, even if the router observability configuration enables metrics. Configuration Example http: routers: my-router: rule: "Path(`/foo`)" service: service-foo observability: metrics: false accessLogs: false tracing: false traceVerbosity: detailed [http.routers.my-router] rule = "Path(`/foo`)" service = "service-foo" [http.routers.my-router.observability] metrics = false accessLogs = false tracing = false traceVerbosity = "detailed" labels: - "traefik.http.routers.my-router.rule=Path(`/foo`)" - "traefik.http.routers.my-router.service=service-foo" - "traefik.http.routers.my-router.observability.metrics=false" - "traefik.http.routers.my-router.observability.accessLogs=false" - "traefik.http.routers.my-router.observability.tracing=false" - "traefik.http.routers.my-router.observability.traceVerbosity=detailed" { // ... "Tags": [ "traefik.http.routers.my-router.rule=Path(`/foo`)", "traefik.http.routers.my-router.service=service-foo", "traefik.http.routers.my-router.observability.metrics=false", "traefik.http.routers.my-router.observability.accessLogs=false", "traefik.http.routers.my-router.observability.tracing=false", "traefik.http.routers.my-router.observability.traceVerbosity=detailed" ] } Configuration Options Field Description Default Required accessLogs The accessLogs option controls whether the router will produce access-logs. true No metrics The metrics option controls whether the router will produce metrics. true No tracing The tracing option controls whether the router will produce traces. true No traceVerbosity The traceVerbosity option controls the tracing verbosity level for the router. Possible values: minimal (default), detailed. If not set, the value is inherited from the entryPoint. minimal No traceVerbosity observability.traceVerbosity defines the tracing verbosity level for the router. Possible values are: minimal: produces a single server span and one client span for each request processed by a router. detailed: enables the creation of additional spans for each middleware executed for each request processed by a router. Traefik HTTP Routers Documentation An HTTP router is in charge of connecting incoming requests to the services that can handle them. Routers analyze incoming requests based on rules, and when a match is found, forward the request through any configured middlewares to the appropriate service. Configuration Example http: routers: my-router: entryPoints: - "web" - "websecure" rule: "Host(`example.com`) && Path(`/api`)" priority: 10 middlewares: - "auth" - "ratelimit" tls: certResolver: "letsencrypt" options: "modern" domains: - main: "example.com" sans: - "www.example.com" observability: metrics: true accessLogs: true tracing: true respondingTimeouts: readTimeout: "30s" writeTimeout: "30s" parentRefs: - "parent-router-1" - "parent-router-2" service: my-service [http.routers] [http.routers.my-router] entryPoints = ["web", "websecure"] rule = "Host(`example.com`) && Path(`/api`)" priority = 10 middlewares = ["auth", "ratelimit"] service = "my-service" parentRefs = ["parent-router-1", "parent-router-2"] [http.routers.my-router.tls] certResolver = "letsencrypt" options = "modern" [[http.routers.my-router.tls.domains]] main = "example.com" sans = ["www.example.com"] [http.routers.my-router.observability] metrics = true accessLogs = true tracing = true [http.routers.my-router.respondingTimeouts] readTimeout = "30s" writeTimeout = "30s" labels: - "traefik.http.routers.my-router.entrypoints=web,websecure" - "traefik.http.routers.my-router.rule=Host(`example.com`) && Path(`/api`)" - "traefik.http.routers.my-router.priority=10" - "traefik.http.routers.my-router.middlewares=auth,ratelimit" - "traefik.http.routers.my-router.service=my-service" - "traefik.http.routers.my-router.tls.certresolver=letsencrypt" - "traefik.http.routers.my-router.tls.options=modern" - "traefik.http.routers.my-router.tls.domains[0].main=example.com" - "traefik.http.routers.my-router.tls.domains[0].sans=www.example.com" - "traefik.http.routers.my-router.observability.metrics=true" - "traefik.http.routers.my-router.observability.accessLogs=true" - "traefik.http.routers.my-router.observability.tracing=true" - "traefik.http.routers.my-router.respondingtimeouts.readtimeout=30s" - "traefik.http.routers.my-router.respondingtimeouts.writetimeout=30s" { "Tags": [ "traefik.http.routers.my-router.entrypoints=web,websecure", "traefik.http.routers.my-router.rule=Host(`example.com`) && Path(`/api`)", "traefik.http.routers.my-router.priority=10", "traefik.http.routers.my-router.middlewares=auth,ratelimit", "traefik.http.routers.my-router.service=my-service", "traefik.http.routers.my-router.tls.certresolver=letsencrypt", "traefik.http.routers.my-router.tls.options=modern", "traefik.http.routers.my-router.tls.domains[0].main=example.com", "traefik.http.routers.my-router.tls.domains[0].sans=www.example.com", "traefik.http.routers.my-router.observability.metrics=true", "traefik.http.routers.my-router.observability.accessLogs=true", "traefik.http.routers.my-router.observability.tracing=true", "traefik.http.routers.my-router.respondingtimeouts.readtimeout=30s", "traefik.http.routers.my-router.respondingtimeouts.writetimeout=30s", ] } Configuration Options Field Description Default Required entryPoints The list of entry points to which the router is attached. If not specified, HTTP routers are attached to all entry points. All entry points No rule Rules are a set of matchers configured with values, that determine if a particular request matches specific criteria. If the rule is verified, the router becomes active, calls middlewares, and then forwards the request to the service. See Rules & Priority for details. Yes priority To avoid path overlap, routes are sorted, by default, in descending order using rules length. The priority is directly equal to the length of the rule, and so the longest length has the highest priority. A value of 0 for the priority is ignored. Negative values are supported. See Rules & Priority for details. Rule length No middlewares The list of middlewares that are applied to the router. Middlewares are applied in the order they are declared. See Middlewares overview for available middlewares. No tls TLS configuration for the router. When specified, the router will only handle HTTPS requests. No tls.certResolver The name of the certificate resolver to use for automatic certificate generation. See Certificate Resolver for details. No tls.options The name of the TLS options to use for configuring TLS parameters (cipher suites, min/max TLS version, client authentication, etc.). They are mapped to the host names of the router rule, and not to the router itself, so all the routers serving the same host name on the same entry point must reference the same TLS options. See TLS Options for detailed configuration, and Conflicting TLS Options for the consequences of not doing so. default No tls.domains List of domains and Subject Alternative Names (SANs) for explicit certificate domain specification. When using ACME certificate resolvers, domains are automatically extracted from router rules, making this option optional. No observability Observability configuration for the router. Allows fine-grained control over access logs, metrics, and tracing per router. See Observability for details. Inherited from entry points No observability.traceVerbosity Defines the verbosity level of tracing for this router. Accepted values are minimal and detailed. minimal No respondingTimeouts Overrides the entry point respondingTimeouts for the requests matched by the router. Both timeouts count from when the router receives the request, and each one replaces the entry point one, whether longer or shorter. An unset timeout leaves the entry point one in force. Only one router per branch of a multi-layer routing tree can define respondingTimeouts, otherwise the router is disabled with an error. No respondingTimeouts.readTimeout Maximum duration for reading the request body. 0 means no timeout. It must not be longer than writeTimeout, otherwise the router is disabled with an error. A value longer than the entry point readTimeout weakens its protection against slow clients (Slowloris) for the whole entry point, so set it only on the routes that need it. Entry point readTimeout No respondingTimeouts.writeTimeout Maximum duration for handling the request: the router middlewares, the backend processing (including retries), and the response write. 0 means no timeout. If it expires before the response has started, the client receives a 504 Gateway Timeout; afterwards, the connection is closed. It does not apply to protocol upgrades (WebSocket, ...), but applies to streaming responses (SSE, gRPC streaming, ...): leave it unset or set it to 0 on such routers. Entry point writeTimeout No parentRefs References to parent router names for multi-layer routing. When specified, this router becomes a child router that processes requests after parent routers have applied their middlewares. See Multi-Layer Routing for details. No service The name of the service that will handle the matched requests. Services can be load balancer services, weighted round robin, mirroring, or failover services. See Service for details. Yes Router Naming The character @ is not authorized in the router name In provider-specific configurations (Docker, Kubernetes), router names are often auto-generated based on service names and rules {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik HTTP Routers Rules & Priority Documentation An HTTP router is in charge of connecting incoming requests to the services that can handle them. Traefik allows you to define your matching rules and prioritize the routes. Rules Rules are a set of matchers configured with values, that determine if a particular request matches a specific criteria. If the rule is verified, the router becomes active, calls middlewares, and then forwards the request to the service. To set the value of a rule, use backticks ` or escaped double-quotes \". Single quotes ' are not accepted since the values are Go's String Literals. Matchers that accept a regular expression ( regexp) use the Go flavored syntax. The usual AND ( &&) and OR ( ||) logical operators can be used, with the expected precedence rules, as well as parentheses to express complex rules. The NOT ( !) operator allows you to invert the matcher. The table below lists all the available matchers: Matcher Description Header(`key`, `value`) Matches requests containing a header named key set to value. HeaderRegexp(`key`, `regexp`) Matches requests containing a header named key matching regexp. Host(`domain`) Matches requests host set to domain. Supports wildcard subdomain matching (e.g. *.example.com, **.example.com). HostRegexp(`regexp`) Matches requests host matching regexp. Method(`method`) Matches requests method set to method. Path(`path`) Matches requests path set to path. PathPrefix(`prefix`) Matches requests path prefix set to prefix. PathRegexp(`regexp`) Matches request path using regexp. Query(`key`, `value`) Matches requests query parameters named key set to value. QueryRegexp(`key`, `regexp`) Matches requests query parameters named key matching regexp. ClientIP(`ip`) Matches requests client IP using ip. It accepts IPv4, IPv6 and CIDR formats. Header and HeaderRegexp The Header and HeaderRegexp matchers allow matching requests that contain specific header. Behavior Rule Match requests with a Content-Type header set to application/yaml. Header(`Content-Type`, `application/yaml`) Match requests with a Content-Type header set to either application/json or application/yaml. ```HeaderRegexp( Content-Type, `^application/(json Match headers case-insensitively. ```HeaderRegexp( Content-Type, `(?i)^application/(json Host and HostRegexp The Host and HostRegexp matchers allow matching requests that are targeted to a given host. These matchers do not support non-ASCII characters, use punycode encoded values (rfc 3492) to match such domains. If no Host is set in the request URL (for example, it's an IP address), these matchers will look at the Host header. These matchers will match the request's host in lowercase. !!! info "Wildcard subdomain matching" The `Host` matcher supports a wildcard prefix to match the subdomains of a domain. It should be preferred over the `HostRegexp` matcher as it allows attaching a TLS option and is more efficient. A single wildcard matches exactly one subdomain label, a double wildcard one or more: `*.example.com` matches `foo.example.com` but not `foo.bar.example.com`, while `**.example.com` matches both. Neither matches `example.com` itself. This is only available with the **v3 rule syntax** (the default). !!! info "Exception: a bare wildcard matches every request" As an exception to the rules above, a bare `*` is not treated as a subdomain wildcard but as a catch-all: ``Host(`*`)`` matches every request regardless of its host, including requests with no host at all. This mirrors the behaviour of the TCP [``HostSNI(`*`)``](../../tcp/routing/rules-and-priority.md#hostsni-and-hostsniregexp) matcher, so both stay consistent. Behavior Rule Match requests with Host set to example.com. Host(`example.com`) Match every request regardless of its host (see the exception above). Host(`*`) Match requests sent to any subdomain of example.com. Host(`**.example.com`) Match requests with Host set to either example.com or example.org. ```HostRegexp(`^example.(com Match Host case-insensitively. ```HostRegexp(`(?i)^example.(com Method The Method matchers allows matching requests sent based on their HTTP method (also known as request verb). Behavior Rule Match OPTIONS requests. Method(`OPTIONS`) Path, PathPrefix, and PathRegexp These matchers allow matching requests based on their URL path. For exact matches, use Path and its prefixed alternative PathPrefix, for regexp matches, use PathRegexp. Path are always starting with a /, except for PathRegexp. Behavior Rule Match /products but neither /products/shoes nor /products/. Path(`/products`) Match /products as well as everything under /products, such as /products/shoes, /products/ but also /products-for-sale. PathPrefix(`/products`) Match both /products/shoes and /products/socks with and ID like /products/shoes/31. ```PathRegexp(`^/products/(shoes Match requests with a path ending in either .jpeg, .jpg or .png. ```PathRegexp(`.(jpeg Match /products as well as everything under /products, such as /products/shoes, /products/ but also /products-for-sale, case-insensitively. PathRegexp(`(?i)^/products`) Query and QueryRegexp The Query and QueryRegexp matchers allow matching requests based on query parameters. Behavior Rule Match requests with a mobile query parameter set to true, such as in /search?mobile=true. Query(`mobile`, `true`) Match requests with a query parameter mobile that has no value, such as in /search?mobile. Query(`mobile`) Match requests with a mobile query parameter set to either true or yes. ```QueryRegexp( mobile, `^(true Match requests with a mobile query parameter set to any value (including the empty value). QueryRegexp(`mobile`, `^.*$`) Match query parameters case-insensitively. ```QueryRegexp( mobile, `(?i)^(true ClientIP The ClientIP matcher allows matching requests sent from the given client IP. It only matches the request client IP and does not use the X-Forwarded-For header for matching. Behavior Rule Match requests coming from a given IP (IPv4). ClientIP(`10.76.105.11`) Match requests coming from a given IP (IPv6). ClientIP(`::1`) Match requests coming from a given subnet (IPv4). ClientIP(`192.168.1.0/24`) Match requests coming from a given subnet (IPv6). ClientIP(`fe80::/10`) RuleSyntax !!! warning RuleSyntax option is deprecated and will be removed in the next major version. Please do not use this field and rewrite the router rules to use the v3 syntax. In Traefik v3 a new rule syntax has been introduced (migration guide). The ruleSyntax option allows configuring the rule syntax to be used for parsing the rule on a per-router basis. This allows having heterogeneous router configurations and eases migration. The default value of the ruleSyntax option is inherited from the core.defaultRuleSyntax option in the install configuration (formerly known as static configuration). By default, the core.defaultRuleSyntax static option is v3, meaning that the default rule syntax is also v3 Configuration Example The configuration below uses the File Provider (Structured) to configure the ruleSyntax to allow Router-v2 to use v2 syntax, while for Router-v3 it is configured to use v3 syntax. ## Dynamic configuration http: routers: Router-v3: rule: HostRegexp(`[a-z]+\\.traefik\\.com`) ruleSyntax: v3 Router-v2: rule: HostRegexp(`{subdomain:[a-z]+}.traefik.com`) ruleSyntax: v2 ## Dynamic configuration [http.routers] [http.routers.Router-v3] rule = "HostRegexp(`[a-z]+\\.traefik\\.com`)" ruleSyntax = "v3" [http.routers.Router-v2] rule = "HostRegexp(`{subdomain:[a-z]+}.traefik.com`)" ruleSyntax = "v2" labels: - "traefik.http.routers.Router-v3.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)" - "traefik.http.routers.Router-v3.ruleSyntax=v3" - "traefik.http.routers.Router-v2.rule=HostRegexp(`{subdomain:[a-z]+}.traefik.com`)" - "traefik.http.routers.Router-v2.ruleSyntax=v2" { // ... "Tags": [ "traefik.http.routers.Router-v3.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)", "traefik.http.routers.Router-v3.ruleSyntax=v3" "traefik.http.routers.Router-v2.rule=HostRegexp(`{subdomain:[a-z]+}.traefik.com`)", "traefik.http.routers.Router-v2.ruleSyntax=v2" ] }, Priority Calculation ??? info "How default priorities are computed" ```yaml tab="Structured (YAML)" http: routers: Router-1: rule: "HostRegexp(`[a-z]+\.traefik\.com`)" # ... Router-2: rule: "Host(`foobar.traefik.com`)" # ... ``` ```toml tab="Structured (TOML)" [http.routers] [http.routers.Router-1] rule = "HostRegexp(`[a-z]+\\.traefik\\.com`)" # ... [http.routers.Router-2] rule = "Host(`foobar.traefik.com`)" # ... ``` ```yaml tab="Labels" labels: - "traefik.http.routers.Router-1.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)" - "traefik.http.routers.Router-2.rule=Host(`foobar.traefik.com`)" ``` ```json tab="Tags" { // ... "Tags": [ "traefik.http.routers.Router-1.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)", "traefik.http.routers.Router-2.rule=Host(`foobar.traefik.com`)" ] } ``` In this case, all requests with host `foobar.traefik.com` will be routed through `Router-1` instead of `Router-2`. | Name | Rule | Priority | |----------|------------------------------------------|----------| | Router-1 | ```HostRegexp(`[a-z]+\.traefik\.com`)``` | 34 | | Router-2 | ```Host(`foobar.traefik.com`)``` | 26 | The previous table shows that `Router-1` has a higher priority than `Router-2`. To solve this issue, the priority must be set. To avoid path overlap, routes are sorted, by default, in descending order using rules length. The priority is directly equal to the length of the rule, and so the longest length has the highest priority. The stars of a double wildcard host do not count toward this length, so that it always ranks below the single wildcard and the exact hosts it covers: Host(`foo.example.com`) has a priority of 23, Host(`*.example.com`) of 21, and Host(`**.example.com`) of 20. A value of 0 for the priority is ignored: priority: 0 means that the default rules length sorting is used. Negative priority values are supported. Traefik reserves a range of priorities for its internal routers, the maximum user-defined router priority value is: (MaxInt32 - 1000) = 2147482647 for 32-bit platforms, (MaxInt64 - 1000) = 9223372036854774807 for 64-bit platforms. !!! info "Providers Precedence" When two routes from **different providers** share the same numeric priority, Traefik uses the [`providers.precedence`](../../../install-configuration/providers/overview.md#providers-precedence) install configuration option to determine which route takes precedence. The provider listed first in `precedence` wins the tie. Example ## Dynamic configuration http: routers: Router-1: rule: "HostRegexp(`[a-z]+\\.traefik\\.com`)" entryPoints: - "web" service: service-1 priority: 1 Router-2: rule: "Host(`foobar.traefik.com`)" entryPoints: - "web" priority: 2 service: service-2 ## Dynamic configuration [http.routers] [http.routers.Router-1] rule = "HostRegexp(`[a-z]+\\.traefik\\.com`)" entryPoints = ["web"] service = "service-1" priority = 1 [http.routers.Router-2] rule = "Host(`foobar.traefik.com`)" entryPoints = ["web"] priority = 2 service = "service-2" labels: - "traefik.http.routers.Router-1.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)" - "traefik.http.routers.Router-1.entryPoints=web" - "traefik.http.routers.Router-1.service=service-1" - "traefik.http.routers.Router-1.priority=1" - "traefik.http.routers.Router-2.rule=Host(`foobar.traefik.com`)" - "traefik.http.routers.Router-2.entryPoints=web" - "traefik.http.routers.Router-2.service=service-2" - "traefik.http.routers.Router-2.priority=2" { // ... "Tags": [ "traefik.http.routers.Router-1.rule=HostRegexp(`[a-z]+\\.traefik\\.com`)", "traefik.http.routers.Router-1.entryPoints=web", "traefik.http.routers.Router-1.service=service-1", "traefik.http.routers.Router-1.priority=1" "traefik.http.routers.Router-2.rule=Host(`foobar.traefik.com`)", "traefik.http.routers.Router-2.entryPoints=web", "traefik.http.routers.Router-2.service=service-2", "traefik.http.routers.Router-2.priority=2" ] } In the example above, the priority is configured to allow Router-2 to handle requests with the foobar.traefik.com host. Traefik HTTP TLS Documentation When an HTTP router is configured to handle HTTPS traffic, include a tls field in its definition. This field tells Traefik that the router should process only TLS requests and ignore non-TLS traffic. By default, an HTTP router with a TLS field will terminate the TLS connections, meaning that it will send decrypted data to the services. The TLS configuration provides several options for fine-tuning the TLS behavior, including automatic certificate generation, custom TLS options, and explicit domain specification. !!! warning "Router TLS replaces entrypoint TLS" Entrypoint `http.tls` settings apply only when a router does **not** define its own `tls` section. Defining a router `tls` section — even empty, or with any field such as `certResolver`, `options`, or `domains` — means Traefik does **not** merge that configuration with the entrypoint defaults for that router. The router TLS configuration replaces the entrypoint TLS configuration entirely. For example, with entrypoint TLS options configured: ```yaml entryPoints: websecure: address: :443 http: tls: options: modern-tls@file ``` and a router that only sets a certificate resolver: ```yaml http: routers: sample: rule: Host(`example.com`) service: sample tls: certResolver: letsencrypt ``` the entrypoint `options` (`modern-tls@file`) are **not** applied to `sample`. To keep both, set them together on the entrypoint, or set both `options` and `certResolver` on the router. Configuration Example http: routers: my-https-router: rule: "Host(`example.com`) && Path(`/api`)" service: "my-http-service" tls: certResolver: "letsencrypt" options: "modern-tls" domains: - main: "example.com" sans: - "www.example.com" - "api.example.com" [http.routers.my-https-router] rule = "Host(`example.com`) && Path(`/api`)" service = "my-http-service" [http.routers.my-https-router.tls] certResolver = "letsencrypt" options = "modern-tls" [[http.routers.my-https-router.tls.domains]] main = "example.com" sans = ["www.example.com", "api.example.com"] labels: - "traefik.http.routers.my-https-router.rule=Host(`example.com`) && Path(`/api`)" - "traefik.http.routers.my-https-router.service=my-http-service" - "traefik.http.routers.my-https-router.tls=true" - "traefik.http.routers.my-https-router.tls.certresolver=letsencrypt" - "traefik.http.routers.my-https-router.tls.options=modern-tls" - "traefik.http.routers.my-https-router.tls.domains[0].main=example.com" - "traefik.http.routers.my-https-router.tls.domains[0].sans=www.example.com,api.example.com" { "Tags": [ "traefik.http.routers.my-https-router.rule=Host(`example.com`) && Path(`/api`)", "traefik.http.routers.my-https-router.service=my-http-service", "traefik.http.routers.my-https-router.tls=true", "traefik.http.routers.my-https-router.tls.certresolver=letsencrypt", "traefik.http.routers.my-https-router.tls.options=modern-tls", "traefik.http.routers.my-https-router.tls.domains[0].main=example.com", "traefik.http.routers.my-https-router.tls.domains[0].sans=www.example.com,api.example.com" ] } Configuration Options Field Description Default Required options The name of the TLS options to use for configuring TLS parameters (cipher suites, min/max TLS version, client authentication, etc.). See TLS Options for detailed configuration. "" (resolves to default at runtime) No certResolver The name of the certificate resolver to use for automatic certificate generation via ACME providers (such as Let's Encrypt). See the Certificate Resolver section for more details. "" No domains List of domains and Subject Alternative Names (SANs) for explicit certificate domain specification. See the Custom Domains section for more details. [] No Certificate Resolver The tls.certResolver option allows you to specify a certificate resolver for automatic certificate generation via ACME providers (such as Let's Encrypt). When a certificate resolver is configured for a router, Traefik will automatically obtain and manage TLS certificates for the domains specified in the router's rule (in the Host matcher) or in the tls.domains configuration (with tls.domains taking precedence). !!! important "Prerequisites" - Certificate resolvers must be defined in the [static configuration](../../../install-configuration/tls/certificate-resolvers/acme.md) - The router must have `tls` enabled - An ACME challenge type must be configured for the certificate resolver Custom Domains When using ACME certificate resolvers, domains are automatically extracted from router rules, but the tls.domains option allows you to explicitly specify the domains and Subject Alternative Names (SANs) for which certificates should be generated. This provides fine-grained control over certificate generation and takes precedence over domains automatically extracted from router rules. Every domain must have A/AAAA records pointing to Traefik. {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik TLS Certificates Documentation !!! info When a router has to handle HTTPS traffic, it should be specified with a tls field of the router definition. Certificates Definition Automated See the Let's Encrypt page. User defined To add / remove TLS certificates, even when Traefik is already running, their definition can be added to the dynamic configuration, in the [[tls.certificates]] section: tls: certificates: - certFile: /path/to/domain.cert keyFile: /path/to/domain.key - certFile: /path/to/other-domain.cert keyFile: /path/to/other-domain.key [[tls.certificates]] certFile = "/path/to/domain.cert" keyFile = "/path/to/domain.key" [[tls.certificates]] certFile = "/path/to/other-domain.cert" keyFile = "/path/to/other-domain.key" !!! important "Restriction" In the above example, we've used the [file provider](../../../install-configuration/providers/others/file.md) to handle these definitions. It is the only available method to configure the certificates (as well as the options and the stores). However, in [Kubernetes](../../../install-configuration/providers/kubernetes/kubernetes-crd.md), the certificates can and must be provided by [secrets](https://kubernetes.io/docs/concepts/configuration/secret/). Certificate selection (SNI) Traefik selects the certificate to present during the TLS handshake, based on the Server Name Indication (SNI) sent by the client. However, HTTP router rules (e.g., Host()) are evaluated after TLS has been established, so they do not influence certificate selection. Strict SNI Checking By default, if the client does not send SNI, or if no certificate matches the requested server name, Traefik falls back to the default certificate from the TLS store (if configured). To reject connections without SNI (or with an unknown server name) instead of falling back to the default certificate, enable sniStrict in TLS Options. Certificates Stores In Traefik, certificates are grouped together in certificates stores. !!! important "Restriction" Any store definition other than the default one (named `default`) will be ignored, and there is therefore only one globally available TLS store. !!! important "TLSStore in Kubernetes" With the [TLSStore resource](../../kubernetes/crd/tls/tlsstore.md), the store named `default` applies to every entry point, whatever the namespace it is defined in. The [`defaultTLSResourcesNamespace`](../../../install-configuration/providers/kubernetes/kubernetes-crd.md#defaulttlsresourcesnamespace) provider option restricts the namespace this cluster-wide store can be defined in. In the tls.certificates section, a list of stores can then be specified to indicate where the certificates should be stored: tls: certificates: - certFile: /path/to/domain.cert keyFile: /path/to/domain.key stores: - default # Note that since no store is defined, # the certificate below will be stored in the `default` store. - certFile: /path/to/other-domain.cert keyFile: /path/to/other-domain.key [[tls.certificates]] certFile = "/path/to/domain.cert" keyFile = "/path/to/domain.key" stores = ["default"] [[tls.certificates]] # Note that since no store is defined, # the certificate below will be stored in the `default` store. certFile = "/path/to/other-domain.cert" keyFile = "/path/to/other-domain.key" !!! important "Restriction" The `stores` list will actually be ignored and automatically set to `["default"]`. !!! tip "Per provider examples" - [Docker: Enable TLS](../../../../expose/docker/basic.md#enable-tls) - [Swarm: Enable TLS](../../../../expose/swarm/basic.md#enable-tls) - [Kubernetes: Enable TLS](../../../../expose/kubernetes/basic.md#enable-tls) Default Certificate Traefik can use a default certificate for connections without a SNI, or without a matching domain. This default certificate should be defined in a TLS store: tls: stores: default: defaultCertificate: certFile: path/to/cert.crt keyFile: path/to/cert.key [tls.stores] [tls.stores.default] [tls.stores.default.defaultCertificate] certFile = "path/to/cert.crt" keyFile = "path/to/cert.key" If no defaultCertificate is provided, Traefik will use the generated one. ACME Default Certificate You can configure Traefik to use an ACME provider (like Let's Encrypt) to generate the default certificate. The configuration to resolve the default certificate should be defined in a TLS store: !!! important "Precedence with the defaultGeneratedCert option" The `defaultGeneratedCert` definition takes precedence over the ACME default certificate configuration. tls: stores: default: defaultGeneratedCert: resolver: myresolver domain: main: example.org sans: - foo.example.org - bar.example.org [tls.stores] [tls.stores.default.defaultGeneratedCert] resolver = "myresolver" [tls.stores.default.defaultGeneratedCert.domain] main = "example.org" sans = ["foo.example.org", "bar.example.org"] labels: - "traefik.tls.stores.default.defaultgeneratedcert.resolver=myresolver" - "traefik.tls.stores.default.defaultgeneratedcert.domain.main=example.org" - "traefik.tls.stores.default.defaultgeneratedcert.domain.sans=foo.example.org, bar.example.org" { "Name": "default", "Tags": [ "traefik.tls.stores.default.defaultgeneratedcert.resolver=myresolver", "traefik.tls.stores.default.defaultgeneratedcert.domain.main=example.org", "traefik.tls.stores.default.defaultgeneratedcert.domain.sans=foo.example.org, bar.example.org" ] } {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik TLS Options Documentation The TLS options allow one to configure some parameters of the TLS connection. !!! important "'default' TLS Option" The `default` option is special. When no tls options are specified in a tls router, the `default` option is used. When specifying the `default` option explicitly, make sure not to specify provider namespace as the `default` option does not have one. Conversely, for cross-provider references, for example, when referencing the file provider from a docker label, you must specify the provider namespace, for example: `traefik.http.routers.myrouter.tls.options=myoptions@file` !!! important "Providers" TLS options are not supported by label or tag-based providers. However, you can define them when using a [KV provider](../../other-providers/kv.md). !!! important "TLSOption in Kubernetes" With the [TLSOption resource](../../kubernetes/crd/tls/tlsoption.md), the option named `default` applies to every router that does not reference a TLSOption explicitly, whatever the namespace it is defined in. The [`defaultTLSResourcesNamespace`](../../../install-configuration/providers/kubernetes/kubernetes-crd.md#defaulttlsresourcesnamespace) provider option restricts the namespace this cluster-wide default can be defined in. Server Name Association The TLS options are configured on a router, but they are applied during the TLS handshake, that is to say before the routing occurs, when the server name (SNI) is the only information available. A TLS options reference is therefore always mapped to the host names found in the Host part of the router rule, and neither to the router nor to its rule. There could also be several Host parts in a rule, in which case the TLS options reference is mapped to as many host names. In the case of domain fronting, if the TLS options associated with the Host header and the SNI are different, Traefik responds with a 421 Misdirected Request status code. Conflicting TLS Options Since a TLS options reference is mapped to a host name, a conflict occurs when a configuration introduces a situation where the same host name, on the same entry point, is matched with two different TLS options references, such as in the example below: # Dynamic configuration http: routers: routerfoo: rule: "Host(`example.com`) && Path(`/foo`)" tls: options: foo routerbar: rule: "Host(`example.com`) && Path(`/bar`)" tls: options: bar # Dynamic configuration [http.routers] [http.routers.routerfoo] rule = "Host(`example.com`) && Path(`/foo`)" [http.routers.routerfoo.tls] options = "foo" [http.routers.routerbar] rule = "Host(`example.com`) && Path(`/bar`)" [http.routers.routerbar.tls] options = "bar" If that happens, both mappings are discarded, and the host name ( example.com in this example) gets associated with the default TLS options instead. The conflict detection is not limited to a single provider: routers coming from different providers, for example a router defined with a container label and another one defined with the file provider, conflict with each other as soon as they serve the same host name on the same entry point. !!! important "Default TLS Options" The `default` TLS options are the fallback of the conflict resolution, and should therefore not be less secure than the options they can replace. A router relying on a mutual TLS authentication (`clientAuth`), for example, no longer enforces it if a conflict on its host name falls back to `default` TLS options that do not require it. The surest way to avoid this is to have all the routers serving the same host name, on the same entry point, reference the same TLS options. Strict TLS Options The core.strictTLSOptions install configuration option disables the fallback to the default TLS options. When it is enabled, the routers involved in the conflict are marked in error and are not built at all, and the host name is no longer mapped to any TLS options. !!! warning "Disabled routers" Enabling `strictTLSOptions` fails closed: a conflict disables all the routers serving the conflicting host name on the concerned entry point, until the conflict is resolved. ## Install configuration core: strictTLSOptions: true ## Install configuration [core] strictTLSOptions = true ## Install configuration --core.strictTLSOptions=true Minimum TLS Version # Dynamic configuration tls: options: default: minVersion: VersionTLS12 mintls13: minVersion: VersionTLS13 # Dynamic configuration [tls.options] [tls.options.default] minVersion = "VersionTLS12" [tls.options.mintls13] minVersion = "VersionTLS13" Maximum TLS Version We discourage the use of this setting to disable TLS1.3. The recommended approach is to update the clients to support TLS1.3. # Dynamic configuration tls: options: default: maxVersion: VersionTLS13 maxtls12: maxVersion: VersionTLS12 # Dynamic configuration [tls.options] [tls.options.default] maxVersion = "VersionTLS13" [tls.options.maxtls12] maxVersion = "VersionTLS12" Cipher Suites See cipherSuites for more information. # Dynamic configuration tls: options: default: cipherSuites: - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 # Dynamic configuration [tls.options] [tls.options.default] cipherSuites = [ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" ] !!! important "TLS 1.3" Cipher suites defined for TLS 1.2 and below cannot be used in TLS 1.3, and vice versa. () With TLS 1.3, the cipher suites are not configurable (all supported cipher suites are safe in this case). Curve Preferences This option allows setting the preferred elliptic curves. The names of the curves defined by crypto (e.g. CurveP521) and the RFC defined names (e. g. secp521r1) can be used. See CurveID for more information. # Dynamic configuration tls: options: default: curvePreferences: - CurveP521 - CurveP384 # Dynamic configuration [tls.options] [tls.options.default] curvePreferences = ["CurveP521", "CurveP384"] Strict SNI Checking With strict SNI checking enabled, Traefik won't allow connections from clients that do not specify a server_name extension or don't match any of the configured certificates. The default certificate is irrelevant on that matter. # Dynamic configuration tls: options: default: sniStrict: true # Dynamic configuration [tls.options] [tls.options.default] sniStrict = true ALPN Protocols Optional, Default="h2, http/1.1, acme-tls/1" This option allows specifying the list of supported application level protocols for the TLS handshake, in order of preference. If the client supports ALPN, the selected protocol will be one from this list, and the connection will fail if there is no mutually supported protocol. # Dynamic configuration tls: options: default: alpnProtocols: - http/1.1 - h2 # Dynamic configuration [tls.options] [tls.options.default] alpnProtocols = ["http/1.1", "h2"] Client Authentication (mTLS) Traefik supports mutual authentication, through the clientAuth section. For authentication policies that require verification of the client certificate, the certificate authority for the certificates should be set in clientAuth.caFiles. In Kubernetes environment, CA certificate can be set in clientAuth.secretNames. See TLSOption resource for more details. The clientAuth.clientAuthType option governs the behaviour as follows: Option Operation NoClientCert Disregards any client certificate. RequestClientCert Asks for a certificate but proceeds anyway if none is provided. RequireAnyClientCert Requires a certificate but does not verify if it is signed by a CA listed in clientAuth.caFiles or in clientAuth.secretNames. VerifyClientCertIfGiven If a certificate is provided, verifies if it is signed by a CA listed in clientAuth.caFiles or in clientAuth.secretNames. Otherwise proceeds without any certificate. RequireAndVerifyClientCert requires a certificate, which must be signed by a CA listed in clientAuth.caFiles or in clientAuth.secretNames. # Dynamic configuration tls: options: default: clientAuth: # in PEM format. each file can contain multiple CAs. caFiles: - tests/clientca1.crt - tests/clientca2.crt clientAuthType: RequireAndVerifyClientCert # Dynamic configuration [tls.options] [tls.options.default] [tls.options.default.clientAuth] # in PEM format. each file can contain multiple CAs. caFiles = ["tests/clientca1.crt", "tests/clientca2.crt"] clientAuthType = "RequireAndVerifyClientCert" Disable Session Tickets Optional, Default="false" When set to true, Traefik disables the use of session tickets, forcing every client to perform a full TLS handshake instead of resuming sessions. # routing configuration tls: options: default: disableSessionTickets: true # routing configuration [tls.options] [tls.options.default] disableSessionTickets = true apiVersion: traefik.io/v1alpha1 kind: TLSOption metadata: name: default namespace: default spec: disableSessionTickets: true {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik & Kubernetes with Gateway API When using the Kubernetes Gateway API provider, Traefik leverages the Gateway API Custom Resource Definitions (CRDs) to obtain its routing configuration. For detailed information on the Gateway API concepts and resources, refer to the official documentation. The Kubernetes Gateway API provider supports version v1.6.3 of the specification. It fully supports all HTTPRoute core and some extended features, like BackendTLSPolicy, GRPCRoute, ListenerSet, and TLSRoute resources from the Standard channel, as well as TCPRoute from the Experimental channel. For more details, check out the conformance report. Deploying a Gateway A Gateway is a core resource in the Gateway API specification that defines the entry point for traffic into a Kubernetes cluster. It is linked to a GatewayClass, which specifies the controller responsible for managing and handling the traffic, ensuring that it is directed to the appropriate Kubernetes backend services. The GatewayClass is a cluster-scoped resource typically defined by the infrastructure provider. The following GatewayClass defines that gateways attached to it must be managed by the Traefik controller. --- apiVersion: gateway.networking.k8s.io/v1 kind: GatewayClass metadata: name: traefik spec: controllerName: traefik.io/gateway-controller Next, the following Gateway manifest configures the running Traefik controller to handle the incoming traffic. !!! info "Listener ports" Please note that `Gateway` listener ports must match the configured [EntryPoint ports](../../install-configuration/entrypoints.md) of the Traefik deployment. In case they do not match, an `ERROR` message is logged, and the resource status is updated accordingly. --- apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: traefik namespace: default spec: gatewayClassName: traefik # Only Routes from the same namespace are allowed. listeners: - name: http protocol: HTTP port: 80 allowedRoutes: namespaces: from: Same - name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: - name: secret-tls namespace: default allowedRoutes: namespaces: from: Same - name: tcp protocol: TCP port: 3000 allowedRoutes: namespaces: from: Same - name: tls protocol: TLS port: 3443 tls: mode: Terminate certificateRefs: - name: secret-tls namespace: default allowedRoutes: namespaces: from: Same --- apiVersion: v1 kind: Secret metadata: name: secret-tls namespace: default type: kubernetes.io/tls data: # Self-signed certificate for the whoami.localhost domain. tls.crt: | LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZWakNDQXo2Z0F3SUJBZ0lVZUUrZG94aTUrMTBMVi9DaUdTMkt2Q1dJR1dZd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1JERUxNQWtHQTFVRUJoTUNSbEl4RFRBTEJnTlZCQWNNQkV4NWIyNHhGVEFUQmdOVkJBb01ERlJ5WVdWbQphV3NnVEdGaWN6RVBNQTBHQTFVRUF3d0dWMmh2WVcxcE1DQVhEVEkwTURjeE1ERTFNRGt3TjFvWUR6SXhNalF3Ck5qRTJNVFV3T1RBM1dqQkVNUXN3Q1FZRFZRUUdFd0pHVWpFTk1Bc0dBMVVFQnd3RVRIbHZiakVWTUJNR0ExVUUKQ2d3TVZISmhaV1pwYXlCTVlXSnpNUTh3RFFZRFZRUUREQVpYYUc5aGJXa3dnZ0lpTUEwR0NTcUdTSWIzRFFFQgpBUVVBQTRJQ0R3QXdnZ0lLQW9JQ0FRQ1pNNm1WNUJkV2V0QzZtdnp0YVBobFNjZ0ljbnd6Z3NsOEFxendEMk05ClJWVkZwRUxBbTh2OTNlRWtMZEY2ZnNkY0FhUXQxWlFDSFdYby9mTHBRNVVrUHh1djZNUCt2NG1KMHY4ZEtGWjcKUjcwaTVud1lCMkVlVkw2RUNZaWlxNmZ6VEtsa3F6U0QvNW93elN3L3pqa0dUYTBJdy92SDlhc0g3NEhqM1d0QQo3RythenZjaVlhQTZxK1dWYlZxNlBIanF6em9obEFuMkh1ano2aERqYWllc3ZMbHdBL0IvcmhEc0FLaCtpMHI4CkFKUTFqM0JiTGJuYkJyWmZqYnBJUjNhYVh5amkwK3RQWENnVTkzQmU5dm1LZTZTY0dSNy82T25tYmtTc0xjZFcKaFpVNzcrL2c4WllsZGhwS01nczc4ekJYUlh4bHlzSThHRUtqU1hud3k5WmZNT2RJNEpBTWNtT0lOaVlBY21abgpJTUJIa0xacFl3aUl0eFdseXVJcWxoZFpkSHNrTFdNSjBSTHUxRmhTMnBFV0NOZTM3VDBiOWhtNFg0OXJ1QWJ6Ckl1M01xSmczcXFIdGRMNGRkZ1JZRHNjMXd0cDJrR2dBZGxDaXJIclF6K1l4MEJNT1ZsZEczaG1SUUh5ZHEySHIKWW0xeEFDNWpMZ3FvaVZhY09wd0xKY21PcGsrZWVNQkNZNVo0ekNYN1hXeXdhVmNtMnN2aGlPMThCZFIraDloWQpiMkRNZDFCendDbE95endQcUlvQy9uNGRURG96Ry9GT3NySzgvNEZ4dzY2Q1ZmM3E4MzBNUHdSd2xDSzFDQjdGCjNQK3lKWkpPelRuK05QZ2dGQW9NaGZUYXBQWTFhUGlWajBzVG9vQjBaOGNFV1RkTnJxQU5tUGs5aDNoQjJwbjgKSndJREFRQUJvejR3UERBYkJnTlZIUkVFRkRBU2doQjNhRzloYldrdWJHOWpZV3hvYjNOME1CMEdBMVVkRGdRVwpCQlNGSjF4N01xdG9zQ3UwQmFWbEs1U054K2djampBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQWdFQVdCOVc1eWkzClRpTWpmSThhSCtMZW1wZjc4clhyeWJ6UXJvSXdEazhqQXhnc3Nrc2V2ZEtIaXJIZGJMZ0RoS2krbkJLeEQ5S2QKNWM4RS9VL1VHWUhxaUowTVUzYkpoeTVNM3oyaklKd1hFa3FuVVhRd0dBNzVyU0QxWVBkOTlWeVpuNEJVRlEwdwpCT3loOU5DS3Z3ZTgycUVlOWZmeU5iem5JUEMrNS9pekhaYlNQMEpwRzdtNFQ5TXljdHV1OTlsaVhmSVlCMU1PCkRFRUdpamxhZ3JvdTliVlpsNmovR2xCaVZpU0JVQXhaRlNqdFErV2RFODJaZlFRUFVWdXQrUEY0SEl0N1dmYlgKaUpZbjRsMytJSVczNStvbUZ5QjR5WUJNdU9SVWRsZ3V5N1ZieEU5OTdPdHYzTnpDOGJYcGtaQVM0TkVzQVVFdwpJZ3lOcTFCdExsb3dZdjZXY05HbkJ5RE1NRUMzdUYzNEcxQkJCTzFDRHUrYXBVdW5NbVhUWmU5WlkrbXh4U2Z2CnBZclhHTHBoT2t4ZitQalpMbEpqQVFlcTNxblMvWWtLQmtYQi9zb282ZVVLTTlybyt5RTVMbnFrV20wZXpQWmwKc2Z5NGpqZ0lJUHlUMHhhZ0YyWExzUSs0M3N4aDRYTEhmc3Z3Zis2QnJVK2trTnoydmc2M3duLzJDQUNVVms3bgphSDdwZzZyZGt4T2pOTDJjUGd6ZzhWaExXbkVYYjhhUVJlVjY1WnlRc0xta21oOXBlSFRpYXBUb2xWa0d6TDIwCm9pdExZc3ZUcnhUR2NRd3Jpd3FaT1I3WjEvVEJLVnVoYnp0emxlRjFHRk9LdE52UmNSREVBeWVlbnJDRzRRMmgKMnFNNFh1RFFKcjJrR095OEV0dnlYTitENkNZUkg0ck5vZUk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K tls.key: | LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUpRUUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQ1Nzd2dna25BZ0VBQW9JQ0FRQ1pNNm1WNUJkV2V0QzYKbXZ6dGFQaGxTY2dJY253emdzbDhBcXp3RDJNOVJWVkZwRUxBbTh2OTNlRWtMZEY2ZnNkY0FhUXQxWlFDSFdYbwovZkxwUTVVa1B4dXY2TVArdjRtSjB2OGRLRlo3UjcwaTVud1lCMkVlVkw2RUNZaWlxNmZ6VEtsa3F6U0QvNW93CnpTdy96amtHVGEwSXcvdkg5YXNINzRIajNXdEE3RythenZjaVlhQTZxK1dWYlZxNlBIanF6em9obEFuMkh1anoKNmhEamFpZXN2TGx3QS9CL3JoRHNBS2graTByOEFKUTFqM0JiTGJuYkJyWmZqYnBJUjNhYVh5amkwK3RQWENnVQo5M0JlOXZtS2U2U2NHUjcvNk9ubWJrU3NMY2RXaFpVNzcrL2c4WllsZGhwS01nczc4ekJYUlh4bHlzSThHRUtqClNYbnd5OVpmTU9kSTRKQU1jbU9JTmlZQWNtWm5JTUJIa0xacFl3aUl0eFdseXVJcWxoZFpkSHNrTFdNSjBSTHUKMUZoUzJwRVdDTmUzN1QwYjlobTRYNDlydUFiekl1M01xSmczcXFIdGRMNGRkZ1JZRHNjMXd0cDJrR2dBZGxDaQpySHJReitZeDBCTU9WbGRHM2htUlFIeWRxMkhyWW0xeEFDNWpMZ3FvaVZhY09wd0xKY21PcGsrZWVNQkNZNVo0CnpDWDdYV3l3YVZjbTJzdmhpTzE4QmRSK2g5aFliMkRNZDFCendDbE95endQcUlvQy9uNGRURG96Ry9GT3NySzgKLzRGeHc2NkNWZjNxODMwTVB3UndsQ0sxQ0I3RjNQK3lKWkpPelRuK05QZ2dGQW9NaGZUYXBQWTFhUGlWajBzVApvb0IwWjhjRVdUZE5ycUFObVBrOWgzaEIycG44SndJREFRQUJBb0lDQUVCa2dKRXA3ODAvamVBQktQSTR2cjhFCkJmblc5UEZKdFpwVUhaQkJSM3NIVzFJTU9xcHVVWTJBNXhLbjEzWmZOemdxMEhFYlpqeUZVc0pkaXU0VW8razYKUlU3b3pRaVVSU0VTK0h1dTZycWlhcEx5d1pIditCZ2hrbm80NzU4Lyt6VytNU3pJOFNmU0ZXTVJ1ZG1QdWxRMQo3ZGJUV1U2d3FaU0tUTlFUeXZMYzdnUHBuZUpybWtkTzNRNnppZ0RoVGdtVDFHRXNzZ3NxN3NzbXhMWnhkZithCnkyNlRtVkJ4UDFlUzV6OVpHTWxYRFBSK044RjdOTFVrMng3S21WT3NCZVBZdjN5bmlpNHZGQUhNQndWRFZadXAKWUlUajRpMjZIaVhtanlLM2t5T0F2anNWSElRMXh1QTBCZFROdC84WXRtYllJL005QitydVg0UDJiRFNUMktRKwo4TlN2Uk9wbVppcnBHZkY3bExMSGpJUjlTMFhCWDd6VDRoWnBRWnpqK3NEWnhDM2Y3TGIwRFlKYkp0TmlDYTQxCmNpTjhNUlNldzNneHZ0RVk0RzdnN3hjbkJNdjdNT3RwQTE3d2gvMHdLd0h0amYzSWh2TmIzdkZwT0k5d1FqSzYKSlRQMng4bENJV0tyalpObVN0UksreHJTN3hTOUZVdnBhSVlyclRLQkZWSmcyMURCYWI1L3hqRlBlQWxXejczSwpvVkhsa0hLdXNMSjZLczZzcXo0ZG9mbzg3dkFsUFJzTXRkZ1ZnZFIzNXhLTGtEWXNIbGxML3Z5dE9oSkNieXB5CkJqQm1TR0RMdzBDdWplaHVtU2czYjdSUGVTNk5rbHNqUEIrMVpzRjhpVGdCcjMyM1hvTmNha2dhWWVYQlg4NFAKaE1WZHUxWk1rbXJZMWhXTzEydnhBb0lCQVFEWU5Vb2xCMkhsdWlDcVFqdmU4UFNhV0YxRmhwNUlOMGJIZEppeApIdkhqMkplVHJ6V1pUZFlIdFNJR2RzalhTOTBESXo2bXJhMW9YZXFRYlgrODVlOUFQQkZnRTJmNU5uTzBCSVVJCk5hMXRiVGpIOUhjRGRzQmJKUkZwYnk1ODZUb3lhdFY3bS9zcjVpQUZlZFMyenFOTm1XUmZOdllZS2xselZoSEUKdUd4ZjZxMHJTWktVQUhja2s1bU5Yais3WFhZaTgyemErVEE3ZjBDVm5OamR3OXFpd3B2aTJKTFB2SnA0bWt6KwpyMEN1RW9yV2NhMUdTL2hTVWdXemw3NzhQdlRpZFI2RW4zMDB2ZlIyTE84aG1xRjhVL3Bpb2UrTDVjSllRNnNKCk1YMngrYThzWFFpZ3dwdG02aUNxQ2FuS3ExN3NUZS9RTmQ1czdwb3ZOaHVKOHd3dEFvSUJBUUMxWmM5ZktPUFgKVzZSN1VoaHRRcmhIc3htQnRIQ1BuNWRLbjN5MElNNWRBaEFSdFZDV1U0M0hOTHpCNW1LbjU2dnZrSVNFaXdBbAoxTGhuY2I3YXQ2cHpTSlZtMm5oTDhjeUZrdGQrNzVyL1FHNFlpNnZQbHNBODV5ZXZpZDhZcWswaHdaZXExY05xCmxETUN3NWsrV0drckM2VW5jZXNIc2FWbDJTUGdZV1c1L3I1NnVxUnBsaVFka1EyZmlEYWRyblVueU8ycHg3bFMKVG1HemZaNmtzTWh2MlZFR1NPRm05aUo0dWlPb0xyZVhoU1RQRmxTdjdZUTZSWWtSaGgwT0tqdXM5bXZacEIxWApjcytYN0UyVTNlM0RZelpCR0NFdmxxaFNWTFRScjdIN21pMWxUMEozR0RzbDdiUk9xOE50WVdQa3hhSlNCUnQ5Ck9TcTlkTm9CcGRvakFvSUJBQ2lQdnN3NW1WVW0yUS80QXhGdE5RWnJ3M3ZTcUlrMXpaS0h2a21rVzQ3NlNGMk4KaGttdmY1TE1tWWlLNmx6eHY1SGlIOVBYUzJ3RUNvaHo4bjMyeVM3TTFobW5LbDlucHNkRC9jMHZmTXpGcTl4ZgpjYUIxdTlxZGxxbW9FUm1nQzZuL3Z2TkVyUmRzUWQrbEhwSDVMRXZYbGl3Q3ZLS0Y5MmdhNHBSOFlPQ1J2MUVhCnFXUVl2a0ZmYTNSSkZUM0taK3BncnJCYUJZRnoreUxXWFIwbHJEUFN2TG9QRldQaHB6MHUvWGplV2cwT0wzdlIKc2NjNVkybldOM21jNDFpaFd3SE5KUitPYUVmbnh5QVFpQUJPNlRMUThtMWtvZk1sOUpMb2h3TGZoUXhKb21KNQpSYkFiTWxwWlhDMXFTSzliL1IvcDh5NmxuSWZsTDRuaDVjSzRsVFVDZ2dFQUpSSHVSQU1tTksrTXVJcjVaUEs2Cm1DUjR0UEg4QXMzWmJDMlZuWFlLMWlVQ3hhdXBFVjkzM05yaExEcjV0Rmg2NFpWR0Q1UWNicDYvSkp5eEpSOWQKblB1YlZJNlhBT1lrSnJQd2lBZE5SSmFWS1R6NTJvMXpNYjhIZEM4WHdZR2tDNTcxY0xzSW1YSTV6bm5NaWxvaworK0FBVzBSRGhLb0FKQVV3K0x6T3ZpamFJbGljR3R2TSs2SFdCK0VkVURJRHpTS1p0eFdTd01nMTNTbHh6elExCmNlNFdTZE9CQkxxT0p0L2JRNVp3ZkcyQUxUWGlEcVhhWE5JekJickRtMDUwTFkrYVVMcmlLQ25WVkxXODBReGQKZDQyQjIrR2pmb2NxVk5Ec3R1RlIzUm9QNXVGQXN2Zm50b09TVW5WMWxaZk9nMFVFUEFEQk1tRUpZL2hLU1FYcwp3d0tDQVFBNWQya2hFQ1c1V3QrMzRYWnl1b3NFTjZ4UDExbC96VDRBZjhGSWtQLzlkb0JXRnBhc28zbG1NcXZHCmhPeFErbnZBSjFhNzhZRjA4N3p1UC9DZkQ0UElOUTV4YzZHMDNQdG5JOVNVT0dpMDB4Zlg5MU5NMHBHYWJqb0QKZ0RqVzJxSkJDaVB5N0RIR1RlZkU5eUNUbkhrY1NBbWllVGc3aGFyeEZPOUREZTJKbzhKQXV2SHI1aGVxazVIcgpLYlgzTy9vNUMwcWVnYW1rWVRLcHZzV2VFdXhkY2l5LzFQd3NnV3BuV1JPWllQNENrSkJweEx1bDNVamVSY3dkCnRhcjBJYU52WlV2NFd4U0JZdWVHMDFyYUd2SDZtTTcyTEExR3MrMytwTnZwUVo3bGo2S09tcFlhQUlhemVxY2MKTjJjT2R5U1RqZmQ5OFlNVFAxbmIyK3N1Yy91VAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg== Multiple TLS Certificates Traefik supports multiple secret certificateRefs per Gateway listener. If one of the certificates is invalid or cannot be loaded, the listener will be considered invalid and will not be able to serve traffic until the issue is resolved. For example, the following Gateway listener references two different certificates: --- apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: multi-cert-gateway namespace: default spec: gatewayClassName: traefik listeners: - name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: - name: example-com-tls - name: example-org-tls allowedRoutes: namespaces: from: Same Backend Client Certificate The tls.backend.clientCertificateRef field on a Gateway ( spec.tls.backend, a sibling of spec.listeners) sets the client certificate that Traefik presents to backends that require mutual TLS (mTLS), as defined by GEP-3155. Traefik presents the certificate to the backends selected by a BackendTLSPolicy, for HTTPRoute and GRPCRoute routes. Backends without a BackendTLSPolicy are not affected, because the field does not enable TLS by itself. The listeners of a ListenerSet use the certificate of their parent Gateway. The reference must point to a core Secret that contains the tls.crt and tls.key entries. A Secret in another namespace requires a ReferenceGrant in that namespace. --- apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: mtls-gateway namespace: default spec: gatewayClassName: traefik tls: backend: # Presented to every backend selected by a BackendTLSPolicy. clientCertificateRef: name: backend-client-tls # Set namespace only for a Secret in another namespace, which requires a ReferenceGrant. # namespace: certs listeners: - name: http protocol: HTTP port: 80 allowedRoutes: namespaces: from: Same ListenerSets Traefik supports ListenerSet resources, which attach additional listeners to an existing Gateway. !!! info "Listener ports" Please note that `ListenerSet` listener ports must match the configured [EntryPoint ports](../../install-configuration/entrypoints.md) of the Traefik deployment, just like `Gateway` listeners. !!! warning "Shared TLS certificate store" Traefik keeps all TLS certificates, from `Gateway` listeners and from every `ListenerSet` listener, in a single global certificate store. During the TLS handshake, the certificate is selected by matching the SNI against the SANs of **all** certificates in that store; the selection is **not** scoped to the listener, port, or EntryPoint that received the connection. A certificate attached to a `ListenerSet` listener can therefore be served for a connection destined to another listener, including the parent `Gateway`'s own listeners, when its SANs match the requested SNI. Because a `ListenerSet` may reference a `Secret` in its own namespace without a `ReferenceGrant`, any namespace admitted through `allowedListeners` can introduce certificates that compete in SNI selection on all TLS EntryPoints. Treat `allowedListeners` as a trust boundary, and only allow ListenerSets from namespaces you trust with TLS termination for the hostnames served by this Gateway. Frontend Client Certificate Validation The tls.frontend field on a Gateway ( spec.tls.frontend, a sibling of spec.listeners) allows requiring a client certificate (mTLS) for incoming connections, as defined by GEP-91. Validation can be set for all HTTPS listeners on the Gateway via default, and optionally overridden per port via perPort. The CA certificate used to validate client certificates is provided through caCertificateRefs, with a single reference to a ConfigMap containing a ca.crt key, as defined by the core support of the specification. Other kinds of resources and multiple references are not supported, and leave the listener not accepted. The mode field controls how a missing or invalid client certificate is handled: AllowValidOnly (default): the connection is rejected unless the client presents a certificate signed by one of the referenced CAs. AllowInsecureFallback: the client certificate is requested but connections without one, or with an invalid one, are still accepted. --- apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: mtls-gateway namespace: default spec: gatewayClassName: traefik tls: frontend: # Applies to every HTTPS listener, unless overridden by a perPort entry below. default: validation: caCertificateRefs: - name: client-ca kind: ConfigMap # Overrides the default validation for listeners bound to port 8443. perPort: - port: 8443 tls: validation: mode: AllowInsecureFallback caCertificateRefs: - name: other-client-ca kind: ConfigMap listeners: - name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: - name: secret-tls allowedRoutes: namespaces: from: Same - name: https-relaxed protocol: HTTPS port: 8443 tls: mode: Terminate certificateRefs: - name: secret-tls allowedRoutes: namespaces: from: Same !!! info "Insecure fallback" When any listener uses `AllowInsecureFallback`, Traefik sets the `InsecureFrontendValidationMode` condition to `True` on the `Gateway` status to make the reduced security guarantee visible. !!! warning "Gateways sharing an entry point" `Gateway` resources with HTTPS listeners on the same port must declare the same validation, or none. Otherwise, the oldest `Gateway` keeps the port, and the HTTPS listeners of the newer ones on that port are reported as `Conflicted` with the `FrontendValidationConflict` reason. Exposing a Route Once a Gateway is deployed (see Deploying a Gateway) HTTPRoute, TCPRoute, and/or TLSRoute resources must be deployed to forward some traffic to Kubernetes backend services. !!! info "Attaching to Gateways" As demonstrated in the following examples, a Route resource must be configured with `ParentRefs` that reference the parent `Gateway` it should be associated with. HTTP/HTTPS The HTTPRoute is a core resource in the Gateway API specification, designed to define how HTTP traffic should be routed within a Kubernetes cluster. It allows the specification of routing rules that direct HTTP requests to the appropriate Kubernetes backend services. For more details on the resource and concepts, check out the Kubernetes Gateway API documentation. For example, the following manifests configure a whoami backend and its corresponding HTTPRoute, reachable through the deployed Gateway at the http://whoami.localhost address. --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami-http namespace: default spec: parentRefs: - name: traefik sectionName: http kind: Gateway hostnames: - whoami.localhost rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: whoami namespace: default port: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: whoami namespace: default spec: selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami --- apiVersion: v1 kind: Service metadata: name: whoami namespace: default spec: selector: app: whoami ports: - port: 80 To secure the connection with HTTPS and redirect non-secure request to the secure endpoint, we will update the above HTTPRoute manifest to add a RequestRedirect filter, and add a new HTTPRoute which binds to the https Listener and forward the traffic to the whoami backend. --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami-http namespace: default spec: parentRefs: - name: traefik sectionName: http kind: Gateway hostnames: - whoami.localhost rules: - filters: - type: RequestRedirect requestRedirect: scheme: https --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami-https namespace: default spec: parentRefs: - name: traefik sectionName: https kind: Gateway hostnames: - whoami.localhost rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: whoami namespace: default port: 80 Once everything is deployed, sending a GET request to the HTTP and HTTPS endpoints should return the following responses: ??? success "Response" ```shell $ curl -I http://whoami.localhost HTTP/1.1 302 Found Location: https://whoami.localhost/ Date: Thu, 11 Jul 2024 15:11:31 GMT Content-Length: 5 $ curl -k https://whoami.localhost Hostname: whoami-697f8c6cbc-2krl7 IP: 127.0.0.1 IP: ::1 IP: 10.42.1.5 IP: fe80::60ed:22ff:fe10:3ced RemoteAddr: 10.42.2.4:44682 GET / HTTP/1.1 Host: whoami.localhost User-Agent: curl/7.87.1-DEV Accept: */* Accept-Encoding: gzip X-Forwarded-For: 10.42.1.0 X-Forwarded-Host: whoami.localhost X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Forwarded-Server: traefik-6b66d45748-ns8mt X-Real-Ip: 10.42.1.0 ``` Using Traefik middleware as HTTPRoute filter An HTTP filter is an HTTPRoute component which enables the modification of HTTP requests and responses as they traverse the routing infrastructure. There are three types of filters: Core: Mandatory filters for every Gateway controller, such as RequestHeaderModifier and RequestRedirect. Extended: Optional filters for Gateway controllers, such as ResponseHeaderModifier and RequestMirror. ExtensionRef: Additional filters provided by the Gateway controller. In Traefik, these are the HTTP middlewares supported through the Middleware CRD. !!! info "Supported Filter Types" Traefik supports the following route-level filter types: - `RequestHeaderModifier`: Add, set, or remove HTTP request headers before forwarding to the backend. - `ResponseHeaderModifier`: Add, set, or remove HTTP response headers. - `RequestRedirect`: Redirect the request to a different URL. - `URLRewrite`: Rewrite the request URL path and/or hostname. - `CORS`: Configure Cross-Origin Resource Sharing (CORS) response headers. - `RequestMirror`: Send a copy of the requests to another backend, ignoring its responses. - `ExtensionRef`: Reference a Traefik [Middleware](../kubernetes/crd/http/middleware.md) resource. !!! info "ExtensionRef Filters" To use Traefik middlewares as `ExtensionRef` filters, the Kubernetes CRD provider must be enabled in the static configuration, as detailed in the [documentation](../../install-configuration/providers/kubernetes/kubernetes-crd.md). For example, the following manifests configure an HTTPRoute using the Traefik AddPrefix middleware, reachable through the deployed Gateway at the http://whoami.localhost address: --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami-http namespace: default spec: parentRefs: - name: traefik sectionName: http kind: Gateway hostnames: - whoami.localhost rules: - backendRefs: - name: whoami namespace: default port: 80 filters: - type: ExtensionRef extensionRef: group: traefik.io kind: Middleware name: add-prefix --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: add-prefix namespace: default spec: addPrefix: prefix: /prefix --- apiVersion: apps/v1 kind: Deployment metadata: name: whoami namespace: default spec: selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami --- apiVersion: v1 kind: Service metadata: name: whoami namespace: default spec: selector: app: whoami ports: - port: 80 Once everything is deployed, sending a GET request should return the following response: ??? success "Response" ```shell $ curl http://whoami.localhost Hostname: whoami-697f8c6cbc-kw954 IP: 127.0.0.1 IP: ::1 IP: 10.42.2.6 IP: fe80::a460:ecff:feb6:3a56 RemoteAddr: 10.42.2.4:54758 GET /prefix/ HTTP/1.1 Host: whoami.localhost User-Agent: curl/7.87.1-DEV Accept: */* Accept-Encoding: gzip X-Forwarded-For: 10.42.2.1 X-Forwarded-Host: whoami.localhost X-Forwarded-Port: 80 X-Forwarded-Proto: http X-Forwarded-Server: traefik-6b66d45748-ns8mt X-Real-Ip: 10.42.2.1 ``` Backend-Level Filters In addition to route-level filters, the Gateway API also supports applying filters directly to individual backends through the backendRefs[].filters field. This allows request modifications to be applied to specific backends, enabling the HTTPRouteBackendRequestHeaderModification extended feature. !!! info "Supported Filter Types" Backend-level filters support the same filter types as route-level filters: - `RequestHeaderModifier`: Add, set, or remove HTTP request headers before forwarding to the backend. - `ResponseHeaderModifier`: Add, set, or remove HTTP response headers. - `RequestRedirect`: Redirect the request to a different URL. - `URLRewrite`: Rewrite the request URL path and/or hostname. - `CORS`: Configure Cross-Origin Resource Sharing (CORS) response headers. - `RequestMirror`: Send a copy of the requests to another backend, ignoring its responses. - `ExtensionRef`: Reference a Traefik [Middleware](../kubernetes/crd/http/middleware.md) resource. !!! info "Middlewares Execution Order" When both route-level and backend-level filters are configured, route-level filters are applied first, followed by backend-level filters. For more information on service-level middlewares, see service middlewares. ??? example "Using RequestHeaderModifier on a Backend" ```yaml tab="HTTPRoute" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami-http namespace: default spec: parentRefs: - name: traefik sectionName: http kind: Gateway hostnames: - whoami.localhost rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: whoami namespace: default port: 80 filters: - type: RequestHeaderModifier requestHeaderModifier: set: - name: X-Backend-Header value: "backend-filter" ``` ??? example "Using ExtensionRef (Traefik Middleware) on a Backend" ```yaml tab="HTTPRoute" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami-http namespace: default spec: parentRefs: - name: traefik sectionName: http kind: Gateway hostnames: - whoami.localhost rules: - backendRefs: - name: whoami namespace: default port: 80 filters: - type: ExtensionRef extensionRef: group: traefik.io kind: Middleware name: add-prefix ``` ```yaml tab="AddPrefix Middleware" --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: add-prefix namespace: default spec: addPrefix: prefix: /api ``` GRPC The GRPCRoute is an extended resource in the Gateway API specification, designed to define how GRPC traffic should be routed within a Kubernetes cluster. It allows the specification of routing rules that direct GRPC requests to the appropriate Kubernetes backend services. For more details on the resource and concepts, check out the Kubernetes Gateway API documentation. For example, the following manifests configure an echo backend and its corresponding GRPCRoute, reachable through the deployed Gateway at the echo.localhost:80 address. --- apiVersion: gateway.networking.k8s.io/v1 kind: GRPCRoute metadata: name: echo namespace: default spec: parentRefs: - name: traefik sectionName: http kind: Gateway hostnames: - echo.localhost rules: - matches: - method: type: Exact service: grpc.reflection.v1alpha.ServerReflection - method: type: Exact service: gateway_api_conformance.echo_basic.grpcecho.GrpcEcho method: Echo backendRefs: - name: echo namespace: default port: 3000 --- apiVersion: apps/v1 kind: Deployment metadata: name: echo namespace: default spec: selector: matchLabels: app: echo template: metadata: labels: app: echo spec: containers: - name: echo-basic image: gcr.io/k8s-staging-gateway-api/echo-basic env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: GRPC_ECHO_SERVER value: "1" --- apiVersion: v1 kind: Service metadata: name: echo namespace: default spec: selector: app: echo ports: - port: 3000 Once everything is deployed, sending a GRPC request to the HTTP endpoint should return the following response: ??? success "Response" ```shell $ grpcurl -plaintext echo.localhost:80 gateway_api_conformance.echo_basic.grpcecho.GrpcEcho/Echo { "assertions": { "fullyQualifiedMethod": "/gateway_api_conformance.echo_basic.grpcecho.GrpcEcho/Echo", "headers": [ { "key": "x-real-ip", "value": "10.42.2.0" }, { "key": "x-forwarded-server", "value": "traefik-74b4cf85d8-nkqqf" }, { "key": "x-forwarded-port", "value": "80" }, { "key": "x-forwarded-for", "value": "10.42.2.0" }, { "key": "grpc-accept-encoding", "value": "gzip" }, { "key": "user-agent", "value": "grpcurl/1.9.1 grpc-go/1.61.0" }, { "key": "content-type", "value": "application/grpc" }, { "key": "x-forwarded-host", "value": "echo.localhost:80" }, { "key": ":authority", "value": "echo.localhost:80" }, { "key": "accept-encoding", "value": "gzip" }, { "key": "x-forwarded-proto", "value": "http" } ], "authority": "echo.localhost:80", "context": { "namespace": "default", "pod": "echo-78f76675cf-9k7rf" } } } ``` TCP The TCPRoute is a resource in the Gateway API specification designed to define how TCP traffic should be routed within a Kubernetes cluster. For more details on the resource and concepts, check out the Kubernetes Gateway API documentation. For example, the following manifests configure a whoami backend and its corresponding TCPRoute, reachable through the deployed Gateway at the localhost:3000 address. --- apiVersion: gateway.networking.k8s.io/v1 kind: TCPRoute metadata: name: whoami-tcp namespace: default spec: parentRefs: - name: traefik sectionName: tcp kind: Gateway rules: - backendRefs: - name: whoamitcp namespace: default port: 3000 --- apiVersion: apps/v1 kind: Deployment metadata: name: whoamitcp namespace: default spec: selector: matchLabels: app: whoamitcp template: metadata: labels: app: whoamitcp spec: containers: - name: whoami image: traefik/whoamitcp args: - --port=:3000 --- apiVersion: v1 kind: Service metadata: name: whoamitcp namespace: default spec: selector: app: whoamitcp ports: - port: 3000 Once everything is deployed, sending the WHO command should return the following response: ??? success "Response" ```shell $ nc localhost 3000 WHO Hostname: whoamitcp-85d644bfc-ktzv4 IP: 127.0.0.1 IP: ::1 IP: 10.42.1.4 IP: fe80::b89e:85ff:fec2:7d21 ``` TLS The TLSRoute is a resource in the Gateway API specification designed to define how TLS (Transport Layer Security) traffic should be routed within a Kubernetes cluster. It specifies routing rules for TLS connections, directing them to appropriate backend services based on the SNI (Server Name Indication) of the incoming connection. For more details on the resource and concepts, check out the Kubernetes Gateway API documentation. For example, the following manifests configure a whoami backend and its corresponding TLSRoute, reachable through the deployed Gateway at the localhost:3443 address via a secure connection with the whoami.localhost SNI. --- apiVersion: gateway.networking.k8s.io/v1 kind: TLSRoute metadata: name: whoami-tls namespace: default spec: parentRefs: - name: traefik sectionName: tls kind: Gateway hostnames: - whoami.localhost rules: - backendRefs: - name: whoamitcp namespace: default port: 3000 --- apiVersion: apps/v1 kind: Deployment metadata: name: whoamitcp namespace: default spec: selector: matchLabels: app: whoamitcp template: metadata: labels: app: whoamitcp spec: containers: - name: whoami image: traefik/whoamitcp args: - --port=:3000 --- apiVersion: v1 kind: Service metadata: name: whoamitcp namespace: default spec: selector: app: whoamitcp ports: - port: 3000 Once everything is deployed, sending the WHO command should return the following response: ??? success "Response" ```shell $ openssl s_client -quiet -connect localhost:3443 -servername whoami.localhost Connecting to ::1 depth=0 C=FR, L=Lyon, O=Traefik Labs, CN=Whoami verify error:num=18:self-signed certificate verify return:1 depth=0 C=FR, L=Lyon, O=Traefik Labs, CN=Whoami verify return:1 WHO Hostname: whoamitcp-85d644bfc-hnmdz IP: 127.0.0.1 IP: ::1 IP: 10.42.2.4 IP: fe80::d873:20ff:fef5:be86 ``` Native Load Balancing By default, Traefik sends the traffic directly to the pod IPs and reuses the established connections to the backends for performance purposes. It is possible to override this behavior and configure Traefik to send the traffic to the service IP. The Kubernetes service itself does the load balancing to the pods. It can be done with the annotation traefik.io/service.nativelb on the backend Service. By default, NativeLB is false. !!! info "Default value" Note that it is possible to override the default value by using the option [`nativeLBByDefault`](../../install-configuration/providers/kubernetes/kubernetes-gateway.md) at the provider level. apiVersion: v1 kind: Service metadata: name: myservice namespace: default annotations: traefik.io/service.nativelb: "true" spec: ports: - name: web port: 80 {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik & Ingresses with NGINX Annotations Enable seamless migration from NGINX Ingress Controller to Traefik with NGINX annotation compatibility. {: .subtitle } !!! warning "NGINX Ingress Controller Retirement" The Kubernetes NGINX Ingress Controller project has announced its retirement in **March 2026** and will no longer receive updates or security patches. Traefik provides a migration path by supporting NGINX annotations, allowing you to transition your workloads without rewriting all your Ingress configurations. **→ See the [NGINX to Traefik Migration Guide](../../../migrate/nginx-to-traefik.md) for step-by-step instructions.** For more information about the NGINX Ingress Controller retirement, see the [official Kubernetes blog announcement](https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement). Ingress Discovery This provider discovers all Ingresses in the cluster by default, which may lead to duplicated routers if you are also using the standard Kubernetes Ingress provider. Best Practices: Use IngressClass to specify which Ingresses should be handled by this provider Configure watchNamespace to limit discovery to a single namespace Use watchNamespaceSelector to target Ingresses based on namespace labels Routing Configuration This provider watches for incoming Ingress events and automatically translates NGINX annotations into Traefik's dynamic configuration, creating the corresponding routers, services, middlewares, and other components needed to handle your traffic. !!! warning "ConfigMap Configuration and Default Behaviors" Routing annotations take precedence over provider-level defaults, but they don't control all behaviors that NGINX Ingress Controller's ConfigMap configuration would handle globally. Important differences in default behaviors: - **Request buffering**: NGINX enables `proxy-request-buffering` by default, while Traefik requires explicit opt-in via the provider's `proxyRequestBuffering` option. - **Legacy scheme headers**: If your applications depend on `X-Forwarded-Scheme` or `X-Scheme`, enable `entryPoints..forwardedHeaders.addXForwardedSchemeHeaders=true` on the relevant entrypoints. To ensure consistent behavior during migration, review and configure Traefik's provider-level options to match your current NGINX ConfigMap settings. See the [provider configuration options](../../install-configuration/providers/kubernetes/kubernetes-ingress-nginx.md) for available settings. Configuration Example ??? example "Configuring Kubernetes Ingress NGINX Controller" ```yaml tab="RBAC" --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: traefik-ingress-controller rules: - apiGroups: - "" resources: - namespaces verbs: - get - apiGroups: - "" resources: - configmaps - pods - secrets - endpoints verbs: - get - list - watch - apiGroups: - "" resources: - services verbs: - get - list - watch - apiGroups: - networking.k8s.io resources: - ingresses verbs: - get - list - watch - apiGroups: - networking.k8s.io resources: - ingresses/status verbs: - update - apiGroups: - networking.k8s.io resources: - ingressclasses verbs: - get - list - watch - apiGroups: - "" resources: - events verbs: - create - patch - apiGroups: - discovery.k8s.io resources: - endpointslices verbs: - list - watch - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: traefik-ingress-controller roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: traefik-ingress-controller subjects: - kind: ServiceAccount name: traefik-ingress-controller namespace: default ``` ```yaml tab="Traefik" --- apiVersion: v1 kind: ServiceAccount metadata: name: traefik-ingress-controller --- apiVersion: apps/v1 kind: Deployment metadata: name: traefik labels: app: traefik spec: replicas: 1 selector: matchLabels: app: traefik template: metadata: labels: app: traefik spec: serviceAccountName: traefik-ingress-controller containers: - name: traefik image: traefik:v3.8 args: - --entryPoints.web.address=:80 - --providers.kubernetesingressnginx ports: - name: web containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: traefik spec: type: LoadBalancer selector: app: traefik ports: - name: web port: 80 targetPort: 80 ``` ```yaml tab="Whoami" --- apiVersion: apps/v1 kind: Deployment metadata: name: whoami labels: app: whoami spec: replicas: 2 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: whoami spec: selector: app: whoami ports: - name: http port: 80 ``` ```yaml tab="Ingress" --- apiVersion: networking.k8s.io/v1 kind: IngressClass metadata: name: nginx spec: controller: k8s.io/ingress-nginx --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myingress spec: ingressClassName: nginx rules: - host: whoami.localhost http: paths: - path: /bar pathType: Exact backend: service: name: whoami port: number: 80 - path: /foo pathType: Exact backend: service: name: whoami port: number: 80 ``` Annotations Support This section lists all known NGINX Ingress annotations. The following annotations are organized by category for easier navigation. Authentication Annotation Limitations / Notes nginx.ingress.kubernetes.io/auth-type nginx.ingress.kubernetes.io/auth-secret nginx.ingress.kubernetes.io/auth-secret-type nginx.ingress.kubernetes.io/auth-realm nginx.ingress.kubernetes.io/auth-url Only URL and response headers copy supported. Forward auth behaves differently than NGINX. When combined on the same Ingress with rewrite-target (or a rewrite directive in configuration-snippet/ auth-snippet), the X-Forwarded-Uri header sent to the auth service reflects the rewritten path, not the original client request path. It supports minimal variable interpolation by using the following NGINX variables: $scheme, $host, $http_*, $hostname, $request_uri, $request_method, $query_string, $args, $arg_*, $remote_addr, $uri, $document_uri, $server_name, $server_port, $content_type, $content_length, $cookie_*, $is_args, $best_http_host, $escaped_request_uri, $proxy_add_x_forwarded_for. nginx.ingress.kubernetes.io/auth-signin Redirects to signin URL on 401 response. It supports minimal variable interpolation by using the following NGINX variables: $scheme, $host, $http_*, $hostname, $request_uri, $request_method, $query_string, $args, $arg_*, $remote_addr, $uri, $document_uri, $server_name, $server_port, $content_type, $content_length, $cookie_*, $is_args, $best_http_host, $escaped_request_uri, $proxy_add_x_forwarded_for. Like ingress-nginx, Traefik automatically appends rd=$scheme://$best_http_host$escaped_request_uri so the auth service can redirect back after sign-in; pass an empty rd to disable it. On routes without a Host matcher, the request's Host header feeds the interpolation and can be abused for open redirects. Scoping routers with a Host rule is strongly recommended when relying on this behavior. nginx.ingress.kubernetes.io/auth-snippet Supported directives: proxy_method, more_set_headers, proxy_set_header, more_set_input_headers, set, if, return code [text]. It supports minimal variable interpolation by using the following NGINX variables: $scheme, $host, $http_*, $hostname, $request_uri, $request_method, $query_string, $args, $arg_*, $remote_addr, $uri, $document_uri, $server_name, $server_port, $content_type, $content_length, $cookie_*, $is_args, $best_http_host, $escaped_request_uri, $proxy_add_x_forwarded_for. nginx.ingress.kubernetes.io/auth-method This annotation uses the proxy_method directive in Nginx. Thus, it can't be defined on an ingress that already have an auth-snippet annotation with the proxy_method directive. nginx.ingress.kubernetes.io/auth-response-headers nginx.ingress.kubernetes.io/enable-global-auth SSL/TLS Annotation Limitations / Notes nginx.ingress.kubernetes.io/ssl-redirect Cannot opt-out per route if enabled globally. nginx.ingress.kubernetes.io/force-ssl-redirect Cannot opt-out per route if enabled globally. nginx.ingress.kubernetes.io/ssl-passthrough Some differences in SNI/default backend handling. nginx.ingress.kubernetes.io/proxy-ssl-server-name nginx.ingress.kubernetes.io/proxy-ssl-name nginx.ingress.kubernetes.io/proxy-ssl-verify nginx.ingress.kubernetes.io/proxy-ssl-secret nginx.ingress.kubernetes.io/auth-tls-secret When validation fails, the rejection happens during the TLS handshake rather than returning a 400 Bad Request. nginx.ingress.kubernetes.io/auth-tls-verify-client When validation fails, the rejection happens during the TLS handshake rather than returning a 400 Bad Request. nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream nginx.ingress.kubernetes.io/auth-tls-verify-depth Go has no configurable depth limit. It will accept any valid chain regardless of how many intermediates it contains. Session Affinity Annotation Limitations / Notes nginx.ingress.kubernetes.io/affinity nginx.ingress.kubernetes.io/affinity-mode Only persistent mode supported; balanced not supported. nginx.ingress.kubernetes.io/affinity-canary-behavior Only the sticky behavior is supported; legacy behavior is not supported. nginx.ingress.kubernetes.io/session-cookie-name nginx.ingress.kubernetes.io/session-cookie-secure nginx.ingress.kubernetes.io/session-cookie-path nginx.ingress.kubernetes.io/session-cookie-domain nginx.ingress.kubernetes.io/session-cookie-samesite nginx.ingress.kubernetes.io/session-cookie-max-age nginx.ingress.kubernetes.io/session-cookie-expires Load Balancing & Backend Annotation Limitations / Notes nginx.ingress.kubernetes.io/load-balance Not implemented; silently ignored. nginx.ingress.kubernetes.io/backend-protocol FCGI and AUTO_HTTP not supported. nginx.ingress.kubernetes.io/service-upstream nginx.ingress.kubernetes.io/upstream-hash-by It supports minimal variable interpolation by using the following NGINX variables: $scheme, $host, $http_*, $hostname, $request_uri, $request_method, $query_string, $args, $arg_*, $remote_addr, $uri, $document_uri, $server_name, $server_port, $content_type, $content_length, $cookie_*, $is_args, $best_http_host, $escaped_request_uri, $proxy_add_x_forwarded_for. nginx.ingress.kubernetes.io/upstream-vhost Supports NGINX variable interpolation. Request-time variables ( $scheme, $host, $http_*, $hostname, $request_uri, $request_method, $query_string, $args, $arg_*, $remote_addr, $uri, $document_uri, $server_name, $server_port, $content_type, $content_length, $cookie_*, $is_args, $best_http_host, $escaped_request_uri, $proxy_add_x_forwarded_for) and the provider-resolved per-location variables ( $namespace, $ingress_name, $service_name, $service_port, $location_path) are supported. The NGINX-internal variable $proxy_upstream_name is not available. nginx.ingress.kubernetes.io/custom-headers Header whitelisting, similar to global-allowed-response-headers NGINX config is not supported. nginx.ingress.kubernetes.io/default-backend Specifies a fallback service within the same namespace as the Ingress resource used to handle requests when the primary backend service has no active endpoints. If the specified service exposes multiple ports, the first port will receive the traffic. nginx.ingress.kubernetes.io/proxy-http-version Controls HTTP protocol version for backend communication. Supported value: "1.1" (disables HTTP/2 to backend). Value "1.0" is not supported and will log a warning. nginx.ingress.kubernetes.io/canary nginx.ingress.kubernetes.io/canary-by-header nginx.ingress.kubernetes.io/canary-by-header-value nginx.ingress.kubernetes.io/canary-by-header-pattern nginx.ingress.kubernetes.io/canary-by-cookie nginx.ingress.kubernetes.io/canary-weight nginx.ingress.kubernetes.io/canary-weight-total nginx.ingress.kubernetes.io/x-forwarded-prefix CORS Annotation Limitations / Notes nginx.ingress.kubernetes.io/enable-cors Partial support. nginx.ingress.kubernetes.io/cors-allow-credentials nginx.ingress.kubernetes.io/cors-allow-headers nginx.ingress.kubernetes.io/cors-allow-methods nginx.ingress.kubernetes.io/cors-allow-origin Single-level wildcard origins are supported in the protocol://*.domain[:port] form, where * matches exactly one DNS label. Wildcards in any other position are ignored, as with ingress-nginx. nginx.ingress.kubernetes.io/cors-expose-headers nginx.ingress.kubernetes.io/cors-max-age Routing Annotation Limitations / Notes nginx.ingress.kubernetes.io/app-root nginx.ingress.kubernetes.io/from-to-www-redirect Doesn't support wildcard hosts. nginx.ingress.kubernetes.io/use-regex nginx.ingress.kubernetes.io/rewrite-target When combined with auth-url/ auth-snippet on the same Ingress, downstream middlewares (including the ForwardAuth request) see the rewritten path, not the original request path. nginx.ingress.kubernetes.io/permanent-redirect Defaults to a 301 Moved Permanently status code. nginx.ingress.kubernetes.io/permanent-redirect-code Only valid 3XX HTTP Status Codes are accepted. nginx.ingress.kubernetes.io/temporal-redirect Takes precedence over the permanent-redirect annotation. Defaults to a 302 Found status code. nginx.ingress.kubernetes.io/temporal-redirect-code Only valid 3XX HTTP Status Codes are accepted. nginx.ingress.kubernetes.io/custom-http-errors Specifies a comma-separated list of HTTP status codes that should be intercepted and served by an error page backend. When any of these status codes occur, the request is forwarded to the global default backend, or to the backend defined by the default-backend annotation if specified. nginx.ingress.kubernetes.io/server-alias Ignored if the alias conflicts with an existing Ingress Host rule. Ingress Host rules always take precedence. nginx.ingress.kubernetes.io/server-snippet Supported directives: add_header, location, proxy_method, more_set_headers, proxy_set_header, more_set_input_headers, set, if, return code [text]. It supports minimal variable interpolation by using the following NGINX variables: $scheme, $host, $http_*, $hostname, $request_uri, $request_method, $query_string, $args, $arg_*, $remote_addr, $uri, $document_uri, $server_name, $server_port, $content_type, $content_length, $cookie_*, $is_args, $best_http_host, $escaped_request_uri, $proxy_add_x_forwarded_for. nginx.ingress.kubernetes.io/configuration-snippet Supported directives: add_header, proxy_method, more_set_headers, proxy_set_header, more_set_input_headers, set, rewrite, if, return code [text]. It supports minimal variable interpolation by using the following NGINX variables: $scheme, $host, $http_*, $hostname, $request_uri, $request_method, $query_string, $args, $arg_*, $remote_addr, $uri, $document_uri, $server_name, $server_port, $content_type, $content_length, $cookie_*, $is_args, $best_http_host, $escaped_request_uri, $proxy_add_x_forwarded_for. IP Whitelist !!! info "Client IP Strategy" By default, the client IP is determined from the remote address of the incoming request. When Traefik is behind a reverse proxy, the actual client IP is often found in the `X-Forwarded-For` header instead. This can be configured globally using the provider option [`ipAllowListStrategy`](../../../install-configuration/providers/kubernetes/kubernetes-ingress-nginx/#opt-providers-kubernetesIngressNGINX-ipAllowListStrategy). Annotation Limitations / Notes nginx.ingress.kubernetes.io/whitelist-source-range nginx.ingress.kubernetes.io/allowlist-source-range Rate Limiting Annotation Limitations / Notes nginx.ingress.kubernetes.io/limit-rps Exceeding the limit returns 429 Too Many Requests instead of NGINX's default 503 Service Unavailable. nginx.ingress.kubernetes.io/limit-rpm Exceeding the limit returns 429 Too Many Requests instead of NGINX's default 503 Service Unavailable. nginx.ingress.kubernetes.io/limit-burst-multiplier Default to a multiplier of 5 if the configured value is less than 1. Exceeding the limit returns 429 Too Many Requests instead of NGINX's default 503 Service Unavailable. nginx.ingress.kubernetes.io/limit-connections Exceeding the limit returns 429 Too Many Requests instead of NGINX's default 503 Service Unavailable. The concurrent connection limit is evaluated per client IP address. Values less than or equal to 0 are safely ignored. nginx.ingress.kubernetes.io/limit-allowlist Comma-separated list of IPs and CIDR ranges exempted from limit-rps, limit-rpm and limit-connections. Each router of the Ingress path gets a companion router matching those client IPs, without the limit middlewares: the exempted traffic is reported under that router name in the metrics. Client IPs are matched on the connection remote address, as NGINX does with geo $remote_addr. The companion router takes the priority of the router it exempts plus one, so the exemption does not affect the other routers of the host. nginx.ingress.kubernetes.io/limit-whitelist Legacy alias for limit-allowlist, which takes precedence when both are set. Buffering Annotation Limitations / Notes nginx.ingress.kubernetes.io/proxy-request-buffering nginx.ingress.kubernetes.io/proxy-body-size nginx.ingress.kubernetes.io/client-body-buffer-size nginx.ingress.kubernetes.io/proxy-buffering nginx.ingress.kubernetes.io/proxy-buffer-size nginx.ingress.kubernetes.io/proxy-buffers-number With Traefik, proxy-buffers-number is actually used to compute the size of a single buffer (size * number). nginx.ingress.kubernetes.io/proxy-max-temp-file-size Observability Annotation Limitations / Notes nginx.ingress.kubernetes.io/enable-access-log Access logs must first be enabled in the install configuration (globally or per entrypoint) for this annotation to take effect. When access logs are enabled, this annotation allows opting out specific Ingresses by setting it to "false". Conversely, when access logs are disabled on an entrypoint, setting this annotation to "true" allows opting in specific Ingresses. Timeout Annotation Limitations / Notes nginx.ingress.kubernetes.io/proxy-connect-timeout Timeout can be defined globally at the provider level using the proxyConnectTimeout option. nginx.ingress.kubernetes.io/proxy-send-timeout Timeout can be defined globally at the provider level using the proxySendTimeout option. nginx.ingress.kubernetes.io/proxy-read-timeout Timeout can be defined globally at the provider level using the proxyReadTimeout option. Retry Annotation Limitations / Notes nginx.ingress.kubernetes.io/proxy-next-upstream Unlike NGINX, Traefik does not guarantee that retries are sent to a different server. There is no difference between error and timeout, both are treated as TCP level failure. This configuration can be defined globally at the provider level using the proxyNextUpstream option. nginx.ingress.kubernetes.io/proxy-next-upstream-tries Unlimited retry (0) will be capped to the number of available servers to avoid infinite retries. The value can be defined globally at the provider level using the proxyNextUpstreamTries option. nginx.ingress.kubernetes.io/proxy-next-upstream-timeout The timeout can be defined globally at the provider level using the proxyNextUpstreamTimeout option. Limitations Caveats and Key Behavioral Differences Authentication: Forward auth behaves differently and session caching is not supported. NGINX supports sub-request based auth, while Traefik forwards the original request. Session Affinity: Only persistent mode is supported. Leader Election: Not supported; no cluster mode with leader election. Load Balancing: Only round_robin is supported; EWMA and IP hash are not supported. CORS: NGINX responds with all configured headers unconditionally; Traefik handles headers differently between pre-flight and regular requests. TLS/Backend Protocols: AUTO_HTTP, FCGI and some TLS options are not supported in Traefik. Path Handling: Traefik preserves trailing slashes by default; NGINX removes them unless configured otherwise. Retry: NGINX guarantee that the next retry will be passed to the next server, while on Traefik there is a possibility that the retry would be passed to the same server. Rate Limiting: NGINX uses the Leaky Bucket algorithm, where requests are queued and drained at a fixed rate. Once the queue (burst) is full, excess requests are rejected immediately with 503. Traefik uses the Token Bucket algorithm, where the bucket starts full at burst tokens, each request consumes one token, and tokens refill at the limit-rps rate. When the bucket is empty, the request is either delayed until more tokens are available or rejected with 429 if the delay would be too long. In practice, Traefik is slightly more lenient under bursty load, as it smooths out burst traffic rather than dropping it, but the steady-state throughput cap is similar. Unsupported Annotations !!! question "Want to Add Support for More Annotations?" You can help extend support in two ways: - [**Open a PR**](../../../contributing/submitting-pull-requests.md) with the new annotation support. - **Reach out** to the [Traefik Labs support team](https://info.traefik.io/request-commercial-support?cta=doc). All contributions and suggestions are welcome — let's build this together! Annotation Notes nginx.ingress.kubernetes.io/auth-tls-error-page nginx.ingress.kubernetes.io/auth-tls-match-cn nginx.ingress.kubernetes.io/auth-cache-key nginx.ingress.kubernetes.io/auth-cache-duration nginx.ingress.kubernetes.io/auth-keepalive nginx.ingress.kubernetes.io/auth-keepalive-share-vars nginx.ingress.kubernetes.io/auth-keepalive-requests nginx.ingress.kubernetes.io/auth-keepalive-timeout nginx.ingress.kubernetes.io/auth-proxy-set-headers nginx.ingress.kubernetes.io/disable-proxy-intercept-errors nginx.ingress.kubernetes.io/limit-rate-after nginx.ingress.kubernetes.io/limit-rate nginx.ingress.kubernetes.io/global-rate-limit nginx.ingress.kubernetes.io/global-rate-limit-window nginx.ingress.kubernetes.io/global-rate-limit-key nginx.ingress.kubernetes.io/global-rate-limit-ignored-cidrs nginx.ingress.kubernetes.io/preserve-trailing-slash Traefik preserves trailing slash by default. nginx.ingress.kubernetes.io/proxy-cookie-domain nginx.ingress.kubernetes.io/proxy-cookie-path nginx.ingress.kubernetes.io/proxy-redirect-from nginx.ingress.kubernetes.io/proxy-redirect-to nginx.ingress.kubernetes.io/proxy-ssl-ciphers nginx.ingress.kubernetes.io/proxy-ssl-verify-depth nginx.ingress.kubernetes.io/proxy-ssl-protocols nginx.ingress.kubernetes.io/enable-rewrite-log nginx.ingress.kubernetes.io/satisfy nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none nginx.ingress.kubernetes.io/session-cookie-change-on-failure nginx.ingress.kubernetes.io/ssl-ciphers nginx.ingress.kubernetes.io/ssl-prefer-server-ciphers nginx.ingress.kubernetes.io/connection-proxy-header nginx.ingress.kubernetes.io/enable-opentracing nginx.ingress.kubernetes.io/opentracing-trust-incoming-span nginx.ingress.kubernetes.io/enable-opentelemetry nginx.ingress.kubernetes.io/opentelemetry-trust-incoming-span nginx.ingress.kubernetes.io/enable-modsecurity nginx.ingress.kubernetes.io/enable-owasp-core-rules nginx.ingress.kubernetes.io/modsecurity-transaction-id nginx.ingress.kubernetes.io/modsecurity-snippet nginx.ingress.kubernetes.io/mirror-request-body nginx.ingress.kubernetes.io/mirror-target nginx.ingress.kubernetes.io/mirror-host nginx.ingress.kubernetes.io/denylist-source-range nginx.ingress.kubernetes.io/stream-snippet Global Configuration Traefik does not expose all global configuration options to control default behaviors for Ingresses in the same way NGINX does. Some behaviors that are globally configurable in NGINX (such as default SSL redirect, rate limiting, or affinity) are currently not supported and cannot be overridden per-Ingress as in NGINX. These limitations are noted in the annotation tables below where applicable. Traefik & Kubernetes with Ingress Routing Configuration The Kubernetes Ingress provider watches for incoming ingresses events, such as the example below, and derives the corresponding dynamic configuration from it, which in turn will create the resulting routers, services, handlers, etc. Configuration Example apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myingress annotations: traefik.ingress.kubernetes.io/router.entrypoints: web spec: rules: - host: example.com http: paths: - path: /bar pathType: Exact backend: service: name: whoami port: number: 80 - path: /foo pathType: Exact backend: service: name: whoami port: number: 80 Annotations !!! warning "Referencing resources in annotations" In an annotation, when referencing a resource defined by another provider, the [provider namespace syntax](../../install-configuration/providers/overview.md#provider-namespace) must be used. When [`safeNaming`](../../install-configuration/providers/kubernetes/kubernetes-crd.md#safenaming) is enabled, a namespaced `@kubernetescrd` reference must be of form `namespace_name@kubernetescrd` instead of `namespace-name@kubernetescrd`, using the same `_` separator as the other names generated by the provider. On Ingress Annotation Description Value traefik.ingress.kubernetes.io/router.entrypoints See entry points for more information. ep1,ep2 traefik.ingress.kubernetes.io/router.middlewares See middlewares overview for more information. auth@file,default-prefix@kubernetescrd traefik.ingress.kubernetes.io/router.priority See priority for more information. "42" traefik.ingress.kubernetes.io/router.rulesyntax See rule syntax for more information. Deprecated: RuleSyntax option is deprecated and will be removed in the next major version. Please do not use this field and rewrite the router rules to use the v3 syntax. "v2" traefik.ingress.kubernetes.io/router.pathmatcher Overrides the default router rule type used for a path. Only path-related matcher name should be specified: Path, PathPrefix or PathRegexp. Default: PathPrefix Path traefik.ingress.kubernetes.io/router.tls Enables TLS for the router. "true" traefik.ingress.kubernetes.io/router.tls.certresolver Specifies the certificate resolver to use for TLS certificates. myresolver traefik.ingress.kubernetes.io/router.tls.domains.n.main Defines the main domain for TLS certificate (where n is the domain index). example.org traefik.ingress.kubernetes.io/router.tls.domains.n.sans Defines the Subject Alternative Names (SANs) for TLS certificate (where n is the domain index). test.example.org,dev.example.org traefik.ingress.kubernetes.io/router.tls.options See TLS options for more information. The TLS options are mapped to the host names of the Ingress rules, and not to the Ingress itself, so an Ingress serving a host name already served with different TLS options, in any namespace, makes them conflict. See Conflicting TLS Options for more information. foobar@file traefik.ingress.kubernetes.io/router.observability.accesslogs Controls whether the router produces access logs. See observability for more information. true traefik.ingress.kubernetes.io/router.observability.metrics Controls whether the router produces metrics. See observability for more information. true traefik.ingress.kubernetes.io/router.observability.tracing Controls whether the router produces traces. See observability for more information. true traefik.ingress.kubernetes.io/router.observability.traceVerbosity Defines the verbosity level of tracing for the router. Valid values: minimal, detailed. Default: minimal. See observability for more information. detailed traefik.ingress.kubernetes.io/router.respondingtimeouts.readtimeout Defines the maximum duration for reading the request body on the router. 0 means no timeout. When unset, the entry point readTimeout applies. See readTimeout for more information. 10s traefik.ingress.kubernetes.io/router.respondingtimeouts.writetimeout Defines the maximum duration for handling the request on the router: the router middlewares, the backend processing (including retries), and the response write. 0 means no timeout. When unset, the entry point writeTimeout applies. See writeTimeout for more information. 10s On Service Annotation Description Value traefik.ingress.kubernetes.io/service.nativelb Controls, when creating the load-balancer, whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. To put it more plainly, setting nativelb to true ensures Traefik routes traffic to the Kubernetes Service (using your cluster's networking such as kube-proxy, Cilium, Calico, etc.) and load balancing is handled by Kubernetes itself. If nativelb is set to false, Traefik routes traffic directly to the pods and makes load balancing decisions internally. By default, Traefik reuses the established connections to the backends for performance purposes regardless of the nativelb configuration. However, connection reuse combined with nativelb: true can cause uneven load balancing. If this is unacceptable, you can disable connection reuse by setting maxIdleConnsPerHost to -1. Default: false "true" traefik.ingress.kubernetes.io/service.nodeportlb Controls, when creating the load-balancer, whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. Default: false "true" traefik.ingress.kubernetes.io/service.serversscheme Overrides the default scheme. h2c traefik.ingress.kubernetes.io/service.serverstransport See ServersTransport for more information. foobar@file traefik.ingress.kubernetes.io/service.passhostheader Controls whether to forward the Host header to the backend. "true" traefik.ingress.kubernetes.io/service.sticky.cookie Enables sticky sessions using cookies. See sticky sessions for more information. "true" traefik.ingress.kubernetes.io/service.sticky.cookie.name Defines the cookie name for sticky sessions. See sticky sessions for more information. foobar traefik.ingress.kubernetes.io/service.sticky.cookie.secure Sets the Secure flag on the sticky session cookie. See sticky sessions for more information. "true" traefik.ingress.kubernetes.io/service.sticky.cookie.samesite Sets the SameSite attribute on the sticky session cookie. See sticky sessions for more information. "none" traefik.ingress.kubernetes.io/service.sticky.cookie.domain Sets the Domain attribute on the sticky session cookie, defining the host to which the cookie will be sent. See sticky sessions for more information. "foo.com" traefik.ingress.kubernetes.io/service.sticky.cookie.httponly Sets the HttpOnly flag on the sticky session cookie. See sticky sessions for more information. "true" traefik.ingress.kubernetes.io/service.sticky.cookie.maxage Sets the Max-Age attribute (in seconds) on the sticky session cookie. See sticky sessions for more information. 42 traefik.ingress.kubernetes.io/service.sticky.cookie.path Sets the Path attribute on the sticky session cookie, defining the path that must exist in the requested URL. See sticky sessions for more information. /foobar !!! note "Service annotations and middlewares" These `service` annotations configure a Kubernetes Service only when it is used as a backend of the Ingress. They are not applied to a Service that is referenced by a middleware, such as the [ErrorPages](../http/middlewares/errorpages.md) middleware: the middleware's service is configured from the middleware definition, which does not read annotations set on Kubernetes Services. To set the `serversTransport` in that case, declare it in the middleware definition instead. ??? info " traefik.ingress.kubernetes.io/service.middlewares" See [service middlewares](../http/load-balancing/service.md#middlewares) for more information. ```yaml traefik.ingress.kubernetes.io/service.middlewares: auth@file,prefix@kubernetescrd ``` TLS Enabling TLS via HTTP Options on Entrypoint TLS can be enabled through the HTTP options of an Entrypoint: # Static configuration --entryPoints.websecure.address=:443 --entryPoints.websecure.http.tls # Static configuration entryPoints: websecure: address: ':443' http: tls: {} # Static configuration [entryPoints.websecure] address = ":443" [entryPoints.websecure.http.tls] This way, any Ingress attached to this Entrypoint will have TLS termination by default. ??? example "Configuring Kubernetes Ingress Controller with TLS on Entrypoint" ```yaml tab="RBAC" --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: traefik-ingress-controller rules: - apiGroups: - "" resources: - services - secrets verbs: - get - list - watch - apiGroups: - discovery.k8s.io resources: - endpointslices verbs: - get - list - watch - apiGroups: - extensions - networking.k8s.io resources: - ingresses - ingressclasses verbs: - get - list - watch - apiGroups: - extensions - networking.k8s.io resources: - ingresses/status verbs: - update --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: traefik-ingress-controller roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: traefik-ingress-controller subjects: - kind: ServiceAccount name: traefik-ingress-controller namespace: default ``` ```yaml tab="Ingress" apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myingress annotations: traefik.ingress.kubernetes.io/router.entrypoints: websecure spec: rules: - host: example.com http: paths: - path: /bar pathType: Exact backend: service: name: whoami port: number: 80 - path: /foo pathType: Exact backend: service: name: whoami port: number: 80 ``` ```yaml tab="Traefik" apiVersion: v1 kind: ServiceAccount metadata: name: traefik-ingress-controller --- apiVersion: apps/v1 kind: Deployment metadata: name: traefik labels: app: traefik spec: replicas: 1 selector: matchLabels: app: traefik template: metadata: labels: app: traefik spec: serviceAccountName: traefik-ingress-controller containers: - name: traefik image: traefik:v3.8 args: - --entryPoints.websecure.address=:443 - --entryPoints.websecure.http.tls - --providers.kubernetesingress ports: - name: websecure containerPort: 443 --- apiVersion: v1 kind: Service metadata: name: traefik spec: type: LoadBalancer selector: app: traefik ports: - protocol: TCP port: 443 name: websecure targetPort: 443 ``` ```yaml tab="Whoami" apiVersion: apps/v1 kind: Deployment metadata: name: whoami labels: app: traefiklabs name: whoami spec: replicas: 2 selector: matchLabels: app: traefiklabs task: whoami template: metadata: labels: app: traefiklabs task: whoami spec: containers: - name: whoami image: traefik/whoami ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: whoami spec: ports: - name: http port: 80 selector: app: traefiklabs task: whoami ``` Enabling TLS via Annotations To enable TLS on the underlying router created from an Ingress, one should configure it through annotations: traefik.ingress.kubernetes.io/router.tls: "true" For more options, please refer to the available annotations. ??? example "Configuring Kubernetes Ingress Controller with TLS" ```yaml tab="Ingress" apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myingress annotations: traefik.ingress.kubernetes.io/router.entrypoints: websecure traefik.ingress.kubernetes.io/router.tls: "true" spec: rules: - host: example.com http: paths: - path: /bar pathType: Exact backend: service: name: whoami port: number: 80 - path: /foo pathType: Exact backend: service: name: whoami port: number: 80 ``` Certificates Management ??? example "Using a secret" ```yaml tab="Ingress" apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: foo namespace: production spec: rules: - host: example.net http: paths: - path: /bar pathType: Exact backend: service: name: service1 port: number: 80 # Only selects which certificate(s) should be loaded from the secret, in order to terminate TLS. # Doesn't enable TLS for that ingress (hence for the underlying router). # Please see the TLS annotations on ingress made for that purpose. tls: - secretName: supersecret ``` ```yaml tab="Secret" apiVersion: v1 kind: Secret metadata: name: supersecret data: tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0= ``` TLS certificates can be managed in Secrets objects. !!! info Only TLS certificates provided by users can be stored in Kubernetes Secrets. [Let's Encrypt](../../install-configuration/tls/certificate-resolvers/acme.md) certificates cannot be managed in Kubernetes Secrets yet. Communication Between Traefik and Pods !!! info "Routing directly to Kubernetes services" To route directly to the Kubernetes service, one can use the `traefik.ingress.kubernetes.io/service.nativelb` annotation on the Kubernetes service. It controls, when creating the load-balancer, whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. One alternative is to use an `ExternalName` service to forward requests to the Kubernetes service through DNS. To do so, one must allow external name services. Traefik automatically requests endpoint information based on the service provided in the ingress spec. Although Traefik will connect directly to the endpoints (pods), it still checks the service port to see if TLS communication is required. There are 3 ways to configure Traefik to use HTTPS to communicate with pods: If the service port defined in the ingress spec is 443 (note that you can still use targetPort to use a different port on your pod). If the service port defined in the ingress spec has a name that starts with https (such as https-api, https-web or just https). If the service spec includes the annotation traefik.ingress.kubernetes.io/service.serversscheme: https. If either of those configuration options exist, then the backend communication protocol is assumed to be TLS, and will connect via TLS automatically. !!! info Please note that by enabling TLS communication between traefik and your pods, you will have to have trusted certificates that have the proper trust chain and IP subject name. If this is not an option, you may need to skip TLS certificate verification. See the [`insecureSkipVerify` TLSOption](../kubernetes/crd/tls/tlsoption.md) setting for more details. Global Default Backend Ingresses Ingresses can be created that look like the following: apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: cheese spec: defaultBackend: service: name: stilton port: number: 80 This ingress follows the Global Default Backend property of ingresses. This will allow users to create a "default router" that will match all unmatched requests. !!! info Due to Traefik's use of priorities, you may have to set this ingress priority lower than other ingresses in your environment, to avoid this global ingress from satisfying requests that could match other ingresses. To do this, use the `traefik.ingress.kubernetes.io/router.priority` annotation (as seen in [Annotations on Ingress](#on-ingress)) on your ingresses accordingly. {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik & Knative When using the Knative provider, Traefik leverages Knative's Custom Resource Definitions (CRDs) to obtain its routing configuration. For detailed information on Knative concepts and resources, refer to the official documentation. The Knative provider supports versions v1.19.0 and v1.20.0 of the specification. Deploying a Knative Service A Service is a core resource in the Knative specification that defines the entry point for traffic into a Knative application. It is linked to a Ingress, which specifies the Knative networking controller responsible for managing and handling the traffic, ensuring that it is directed to the appropriate Knative backend services. The following Service manifest configures the running Traefik controller to handle the incoming traffic. --- apiVersion: serving.knative.dev/v1 kind: Service metadata: name: helloworld-go namespace: default spec: template: spec: containers: - image: gcr.io/knative-samples/helloworld-go env: - name: TARGET value: "Go Sample v1" Once everything is deployed, sending a GET request to the HTTP endpoint should return the following response: $ curl http://helloworld-go.default.example.com Hello Go Sample v1! !!! Note The `example.com` domain is the public domain configured when deploying the Traefik controller. Check out [the install configuration](../../install-configuration/providers/kubernetes/knative.md) for more details. Tag based routing To add tag-based routing with percentage in Knative, you can define the traffic section in your Service manifest to include different revisions with specific tags and percentages. Here is an example: apiVersion: serving.knative.dev/v1 kind: Service metadata: name: helloworld-go namespace: default spec: template: spec: containers: - image: gcr.io/knative-samples/helloworld-go env: - name: TARGET value: "Go Sample v2" traffic: - tag: v1 revisionName: helloworld-go-00001 percent: 50 - tag: v2 revisionName: helloworld-go-00002 percent: 50 In this example: The traffic section specifies two revisions ( helloworld-go-00001 and helloworld-go-00002) with tags v1 and v2, each receiving 50% of the traffic. The tag field allows you to route traffic to specific revisions using the tag. You can access the tagged revisions using these URLs: http://v1-helloworld-go.default.example.com http://v2-helloworld-go.default.example.com Use the default URL to access percentage-based routing: http://helloworld-go.default.example.com HTTP/HTTPS Check out the Knative documentation for HTTP/HTTPS configuration. {% include-markdown "includes/traefik-for-business-applications.md" %} Kubernetes IngressRoute IngressRoute is the CRD implementation of a Traefik HTTP router. Before creating IngressRoute objects, you need to apply the Traefik Kubernetes CRDs such as Definitions and RBAC to your Kubernetes cluster. This registers the IngressRoute kind and other Traefik-specific resources. Configuration Example You can declare an IngressRoute as detailed below: apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test-name namespace: apps spec: ingressClassName: traefik-lb entryPoints: - web parentRefs: - name: parent-gateway namespace: default # Optional - defaults to same namespace routes: - kind: Rule # Rule on the Host match: Host(`test.example.com`) # Attach a middleware middlewares: - name: middleware1 namespace: apps # Enable Router observability observability: accessLogs: true metrics: true tracing: true # Override the entry point timeouts respondingTimeouts: readTimeout: 30s writeTimeout: 30s # Set a priority priority: 10 services: # Target a Kubernetes Support - kind: Service name: foo namespace: apps # Customize the connection between Traefik and the backend passHostHeader: true port: 80 responseForwarding: flushInterval: 1ms scheme: https sticky: cookie: httpOnly: true name: cookie secure: true strategy: wrr weight: 10 tls: # Generate a TLS certificate using a certificate resolver certResolver: foo domains: - main: example.net sans: - a.example.net - b.example.net # Customize the TLS options options: name: opt namespace: apps # Add a TLS certificate from a Kubernetes Secret secretName: supersecret Configuration Options Field Description Default Required ingressClassName Defines the IngressClass cluster resource to use. It replaces the deprecated kubernetes.io/ingress.class annotation. The spec field takes precedence over the annotation. No entryPoints List of entry points names. If not specified, HTTP routers will accept requests from all EntryPoints in the list of default EntryPoints. No parentRefs List of references to parent IngressRoute resources for multi-layer routing. When specified, this IngressRoute's routers become children of the referenced parent IngressRoute's routers. See Multi-Layer Routing section for details. No parentRefs[n].name Name of the referenced parent IngressRoute resource. Yes parentRefs[n].namespace Namespace of the referenced parent IngressRoute resource. If not specified, defaults to the same namespace as the child IngressRoute. Cross-namespace references require allowCrossNamespace provider option to be enabled. No routes List of routes. Yes routes[n].kind Kind of router matching, only Rule is allowed yet. "Rule" No routes[n].match Defines the rule corresponding to an underlying router. Yes routes[n].priority Defines the priority to disambiguate rules of the same length, for route matching. If not set, the priority is directly equal to the length of the rule, and so the longest length has the highest priority. A value of 0 for the priority is ignored, the default rules length sorting is used. Negative values are supported. 0 No routes[n].middlewares List of middlewares to attach to the IngressRoute. More information here. "" No routes[n]. middlewares[m]. name Middleware name. The character @ is not authorized. More information here. Yes routes[n]. middlewares[m]. namespace Middleware namespace. Can be empty if the middleware belongs to the same namespace as the IngressRoute. More information here. No routes[n]. observability. accessLogs Defines whether the route will produce access-logs. See here for more information. false No routes[n]. observability. metrics Defines whether the route will produce metrics. See here for more information. false No routes[n]. observability. tracing Defines whether the route will produce traces. See here for more information. false No routes[n]. observability. traceVerbosity Defines the verbosity level of the tracing for this route. Valid values are minimal and detailed. See here for more information. minimal No routes[n]. respondingTimeouts. readTimeout Defines the maximum duration for reading the request body on the route. 0 means no timeout. When unset, the entry point readTimeout applies. See readTimeout for more information. No routes[n]. respondingTimeouts. writeTimeout Defines the maximum duration for handling the request on the route: the router middlewares, the backend processing (including retries), and the response write. 0 means no timeout. When unset, the entry point writeTimeout applies. See writeTimeout for more information. No tls TLS configuration. Can be an empty value( {}): A self signed is generated in such a case (or the default certificate is used if it is defined.) No routes[n]. services List of any combination of TraefikService and Kubernetes service. Exhaustive list of option in the Service documentation. No tls.secretName Secret name used to store the certificate (in the same namespace as the IngressRoute) "" No tls. options.name Name of the TLSOption to use. More information here. "" No tls. options.namespace Namespace of the TLSOption to use. "" No tls.certResolver Name of the Certificate Resolver to use to generate automatic TLS certificates. "" No tls.domains List of domains to serve using the certificates generates (one tls.domain= one certificate). More information in the dedicated section. No tls. domains[n].main Main domain name "" Yes tls. domains[n].sans List of alternative domains (SANs) No Middleware You can attach a list of middlewares to each HTTP router. The middlewares will take effect only if the rule matches, and before forwarding the request to the service. Middlewares are applied in the same order as their declaration in router. In Kubernetes, the option middleware allow you to attach a middleware using its name and namespace (the namespace can be omitted when the Middleware is in the same namespace as the IngressRoute) ??? example "IngressRoute attached to a few middlewares" ```yaml apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: my-app namespace: apps spec: entryPoints: - websecure routes: - match: Host(`example.com`) kind: Rule middlewares: # same namespace as the IngressRoute - name: middleware01 # default namespace - name: middleware02 namespace: apps # Other namespace - name: middleware03 namespace: other-ns services: - name: whoami port: 80 ``` ??? abstract "routes.services.kind" As the field `name` can reference different types of objects, use the field `kind` to avoid any ambiguity. The field `kind` allows the following values: - `Service` (default value): to reference a [Kubernetes Service](https://kubernetes.io/docs/concepts/services-networking/service/) - `TraefikService`: to reference an object [`TraefikService`](../http/traefikservice.md) TLS Options The options field enables fine-grained control of the TLS parameters. It refers to a TLSOption and will be applied only if a Host rule is defined. Server Name Association A TLS options reference is always mapped to the host name found in the Host part of the rule, but neither to a router nor a router rule. There could also be several Host parts in a rule. In such a case the TLS options reference would be mapped to as many host names. A TLS option is picked from the mapping mentioned above and based on the server name provided during the TLS handshake, and it all happens before routing actually occurs. In the case of domain fronting, if the TLS options associated with the Host Header and the SNI are different then Traefik will respond with a status code 421. Conflicting TLS Options Since a TLS options reference is mapped to a host name, if a configuration introduces a situation where the same host name (from a Host rule) gets matched with two TLS options references, a conflict occurs, such as in the example below. The conflict detection is not scoped to a namespace: an IngressRoute defined in any namespace, and even a router coming from another provider, conflicts with this one as soon as it serves the same host name on the same entry point. ??? example ```yaml tab="IngressRoute01" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: IngressRoute01 namespace: apps spec: entryPoints: - foo routes: - match: Host(`example.net`) kind: Rule tls: options: foo ... ``` ```yaml tab="IngressRoute02" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: IngressRoute02 namespace: apps spec: entryPoints: - foo routes: - match: Host(`example.net`) kind: Rule tls: options: bar ... ``` If that happens, both mappings are discarded, and the host name ( example.net in the example) for these routers gets associated with the default TLS options instead. !!! important "Default TLS Options" The `default` TLS options are the fallback of the conflict resolution, and should therefore not be less secure than the options they can replace. See [Conflicting TLS Options](../../../http/tls/tls-options.md#conflicting-tls-options) for more information. Multi-Layer Routing with IngressRoutes Multi-layer routing allows creating hierarchical relationships between IngressRoutes, where parent IngressRoutes can apply middleware before child IngressRoutes make routing decisions. This is particularly useful for authentication-based routing, where a parent IngressRoute authenticates requests and adds context (e.g., user roles as headers), and child IngressRoutes route based on that context. When a child IngressRoute references a parent IngressRoute with multiple routes, all parent routers then become parents of all child routers. !!! info "Comprehensive Multi-Layer Routing Documentation" For detailed information about multi-layer routing concepts, validation rules, and use cases, see the dedicated [Multi-Layer Routing](../../../../routing-configuration/http/routing/multi-layer-routing.md) page. Configuration Requirements Root IngressRoutes Have no parentRefs (top of the hierarchy) Can have entryPoints, tls, and observability configuration Can be either parent IngressRoutes (with children) or standalone IngressRoutes (with service) Intermediate IngressRoutes Reference their parent IngressRoute(s) via parentRefs Have one or more child IngressRoutes Must not have a service defined Must not have entryPoints, tls, or observability configuration Leaf IngressRoutes Reference their parent IngressRoute(s) via parentRefs Must have a service defined Must not have entryPoints, tls, or observability configuration !!! warning "Cross-Namespace References" Cross-namespace parent references require the `allowCrossNamespace` provider option to be enabled. If disabled, child IngressRoute creation will be skipped with an error logged. Example: Authentication-Based Routing ??? example "Parent IngressRoute with ForwardAuth and Child IngressRoutes" ```yaml tab="Parent IngressRoute" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: api-parent namespace: default spec: entryPoints: - websecure tls: certResolver: letsencrypt routes: # Parent route with authentication - no services - match: Host(`api.example.com`) && PathPrefix(`/api`) kind: Rule middlewares: - name: auth-middleware namespace: default --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: auth-middleware namespace: default spec: forwardAuth: address: "http://auth-service.default.svc.cluster.local:8080/auth" authResponseHeaders: - X-User-Role - X-User-Name ``` ```yaml tab="Child IngressRoutes" # Child IngressRoute for admin users apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: api-admin namespace: default spec: parentRefs: - name: api-parent namespace: default # Optional - defaults to same namespace routes: - match: HeadersRegexp(`X-User-Role`, `admin`) kind: Rule services: - name: admin-service port: 80 --- # Child IngressRoute for regular users apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: api-user namespace: default spec: parentRefs: - name: api-parent routes: - match: HeadersRegexp(`X-User-Role`, `user`) kind: Rule services: - name: user-service port: 80 ``` ```yaml tab="Services" apiVersion: v1 kind: Service metadata: name: auth-service namespace: default spec: ports: - port: 8080 selector: app: auth-service --- apiVersion: v1 kind: Service metadata: name: admin-service namespace: default spec: ports: - port: 80 selector: app: admin-backend --- apiVersion: v1 kind: Service metadata: name: user-service namespace: default spec: ports: - port: 80 selector: app: user-backend ``` **How it works:** 1. Request to `https://api.example.com/api/endpoint` matches the parent router 2. `auth-middleware` (ForwardAuth) validates the request with `auth-service` 3. `auth-service` returns 200 OK with `X-User-Role` header (e.g., `admin` or `user`) 4. Child routers evaluate rules against the modified request (with `X-User-Role` header) 5. Request is routed to `admin-service` or `user-service` based on the role Traefik Kubernetes Middleware Documentation Middleware is the CRD implementation of a Traefik middleware. Before creating Middleware objects, you need to apply the Traefik Kubernetes CRDs to your Kubernetes cluster. This registers the Middleware kind and other Traefik-specific resources. !!! tip "Cross-provider namespace" As Kubernetes also has its own notion of namespace, one should not confuse the Kubernetes namespace of a resource (in the reference to the middleware) with the provider namespace, when the definition of the middleware comes from another provider. In this context, specifying a namespace when referring to the resource does not make any sense, and will be ignored. Additionally, when you want to reference a Middleware from the CRD Provider, you have to append the namespace of the resource in the resource-name as Traefik appends the namespace internally automatically. !!! note "Cross-Namespace References" In the example below, the middleware is defined in the foo namespace while being referenced from an IngressRoute in another namespace. To enable such cross-namespace references, the allowCrossNamespace option must be enabled in the Traefik Kubernetes CRD provider configuration. If you prefer to avoid this requirement, you can define and reference the Middleware within the same namespace. Configuration Example apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: stripprefix namespace: foo spec: stripPrefix: prefixes: - /stripit apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: ingressroutebar spec: entryPoints: - web routes: - match: Host(`example.com`) && PathPrefix(`/stripit`) kind: Rule services: - name: whoami port: 80 middlewares: - name: stripprefix namespace: foo For more information about the available middlewares, navigate to the dedicated middlewares overview section. Referencing a Secret or a ConfigMap in a plugin configuration A value inside spec.plugin can be a reference to a Kubernetes object instead of a literal. Traefik resolves it while building the dynamic configuration, at any depth, in strings, lists and maps. Reference Reads urn:k8s:secret:[name]:[key] the key of that Secret urn:k8s:configmap:[name]:[key] the key of that ConfigMap, from data or binaryData Both are read from the namespace of the Middleware itself. A reference has no namespace, so a Middleware cannot read a Secret or a ConfigMap from another namespace. Use a Secret for a credential, and a ConfigMap for a value that is not one and is too long to sit in the manifest, such as a block of text the plugin hands to its clients. The two references are not shown the same way in the API, the dashboard and the support dump: A Secret reference stays in the routing configuration, and Traefik reads its value only when it builds the middleware, so the value is never shown. A ConfigMap reference is replaced with its value in the routing configuration, so the value is shown. !!! warning "Unresolved references" If the referenced object does not exist, does not carry the key, or if the reference is malformed, the whole Middleware is invalid and is left out of the routing configuration. Routers referencing it are not served. apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: my-plugin namespace: foo spec: plugin: myplugin: token: urn:k8s:secret:my-plugin-credentials:token instructions: urn:k8s:configmap:my-plugin-instructions:text apiVersion: v1 kind: Secret metadata: name: my-plugin-credentials namespace: foo data: token: dG9rZW4= apiVersion: v1 kind: ConfigMap metadata: name: my-plugin-instructions namespace: foo data: text: |- Any text the plugin needs and a manifest should not carry. Kubernetes serversTransport A ServersTransport allows you to configure the connection between Traefik and the HTTP servers in Kubernetes. Before creating ServersTransport objects, you need to apply the Traefik Kubernetes CRDs to your Kubernetes cluster. This registers the ServersTransport kind and other Traefik-specific resources. It can be applied on a service using: The option services.serverstransport on a IngressRoute (if the service is a Kubernetes Service) The option serverstransport on a TraefikService (if the service is a Kubernetes Service) !!! note "Reference a ServersTransport CRD from another namespace" The value must be of form `namespace-name@kubernetescrd`, and the `allowCrossNamespace` option must be enabled at the provider level. When [`safeNaming`](../../../../install-configuration/providers/kubernetes/kubernetes-crd.md#safenaming) is enabled, the value becomes `namespace_name@kubernetescrd`, using the same `_` separator as the other names generated by the provider. Configuration Example apiVersion: traefik.io/v1alpha1 kind: ServersTransport metadata: name: mytransport namespace: default spec: serverName: example.org insecureSkipVerify: true apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: testroute namespace: default spec: entryPoints: - web routes: - match: Host(`example.com`) kind: Rule services: - name: whoami port: 80 serversTransport: mytransport Configuration Options Field Description Default Required serverstransport. serverName Defines the server name that will be used for SNI. No serverstransport. insecureSkipVerify Controls whether the server's certificate chain and host name is verified. false No serverstransport. rootCAs Set of root certificate authorities to use when verifying server certificates. No serverstransport. certificatesSecrets Certificates to present to the server for mTLS. No serverstransport. maxIdleConnsPerHost Maximum idle (keep-alive) connections to keep per-host. 0 No serverstransport. disableHTTP2 Disables HTTP/2 for connections with servers. false No serverstransport. peerCertSANs Defines the SANs (Subject Alternative Names) used to match against SANs during the peer certificate verification. [] No serverstransport. peerCertSANs[].type Defines the SAN type ( URI or DNSName) to match against the peer certificate's Subject Alternative Names. "" No serverstransport. peerCertSANs[].value Defines the SAN value to match against the peer certificate's Subject Alternative Names. "" No serverstransport. forwardingTimeouts.dialTimeout Amount of time to wait until a connection to a server can be established. Zero means no timeout. 30s No serverstransport. forwardingTimeouts.responseHeaderTimeout Amount of time to wait for a server's response headers after fully writing the request (including its body, if any). Zero means no timeout 0s No serverstransport. forwardingTimeouts.readTimeout Defines a timeout for reading a response from the proxied server. The timeout between two successive read operations. The connection is closed if nothing is transmitted within this time. Zero means no timeout 0s No serverstransport. forwardingTimeouts.writeTimeout Defines a timeout for transmitting a request to the proxied server. The timeout between two successive write operations. The connection is closed if nothing is transmitted within this time. Zero means no timeout 0s No serverstransport. forwardingTimeouts.idleConnTimeout Maximum amount of time an idle (keep-alive) connection will remain idle before closing itself. Zero means no timeout. 90s No serverstransport. forwardingTimeouts.readIdleTimeout Timeout after which a health check using a ping frame will be carried out if no frame is received on the HTTP/2 connection. Zero means no timeout. 0s No serverstransport. forwardingTimeouts.pingTimeout Timeout after which the HTTP/2 connection will be closed if a response to a ping is not received. Zero means no timeout. 0s No serverstransport. spiffe.ids Allow SPIFFE IDs. This takes precedence over the SPIFFE TrustDomain. No serverstransport. spiffe.trustDomain Allow SPIFFE trust domain. "" No serverstransport. cipherSuites Defines the cipher suites to use when contacting backend servers. [] No serverstransport. minVersion Defines the minimum TLS version to use when contacting backend servers. "" No serverstransport. maxVersion Defines the maximum TLS version to use when contacting backend servers. "" No !!! note "CA Secret" The CA secret must contain a base64 encoded certificate under either a tls.ca or a ca.crt key. Kubernetes Service Service is the implementation of a Traefik HTTP service. There is no dedicated CRD, a Service is part of: IngressRoute TraefikService Note that, before creating IngressRoute or TraefikService objects, you need to apply the Traefik Kubernetes CRDs to your Kubernetes cluster. This registers the Traefik-specific resources. Configuration Example You can declare a Service either as part of an IngressRoute or a TraefikService as detailed below: apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test-name namespace: apps spec: entryPoints: - web routes: - kind: Rule # Rule on the Host match: Host(`test.example.com`) services: # Target a Kubernetes Service - kind: Service name: foo namespace: apps # Customize the connection between Traefik and the backend passHostHeader: true port: 80 responseForwarding: flushInterval: 1ms scheme: https sticky: cookie: httpOnly: true name: cookie secure: true strategy: wrr # Attach middlewares to this service middlewares: - name: my-middleware namespace: apps apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: wrr1 namespace: apps spec: weighted: services: # Target a Kubernetes Service - kind: Service name: foo namespace: apps # Customize the connection between Traefik and the backend passHostHeader: true port: 80 responseForwarding: flushInterval: 1ms scheme: https sticky: cookie: httpOnly: true name: cookie secure: true strategy: wrr Configuration Options Field Description Default Required kind Kind of the service targeted. Two values allowed: - Service: Kubernetes Service TraefikService: Traefik Service. More information here. "Service" No name Service name. The character @ is not authorized. More information here. Yes namespace Service namespace. Can be empty if the service belongs to the same namespace as the IngressRoute. More information here. No port Service port (number or port name). Evaluated only if the kind is Service. No responseForwarding. flushInterval Interval, in milliseconds, in between flushes to the client while copying the response body. A negative value means to flush immediately after each write to the client. This configuration is ignored when a response is a streaming response; for such responses, writes are flushed to the client immediately. Evaluated only if the kind is Service. 100ms No scheme Scheme to use for the request to the upstream Kubernetes Service. Evaluated only if the kind is Service. "http" "https" if port is 443 or contains the string https. No serversTransport Name of ServersTransport resource to use to configure the transport between Traefik and your servers. Evaluated only if the kind is Service. "" No passHostHeader Forward client Host header to server. Evaluated only if the kind is Service. true No healthCheck.scheme Server URL scheme for the health check endpoint. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "" No healthCheck.mode Health check mode. If defined to grpc, will use the gRPC health check protocol to probe the server. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "http" No healthCheck.path Server URL path for the health check endpoint. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "" No healthCheck.interval Frequency of the health check calls for healthy targets. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "30s" No healthCheck.unhealthyInterval Frequency of the health check calls for unhealthy targets. When not defined, it defaults to the interval value. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "30s" No healthCheck.method HTTP method for the health check endpoint. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "GET" No healthCheck.status Expected HTTP status code of the response to the health check request. Only for Kubernetes service of type ExternalName. If not set, expect a status between 200 and 399. Evaluated only if the kind is Service. No healthCheck.port URL port for the health check endpoint. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. No healthCheck.timeout Maximum duration to wait before considering the server unhealthy. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "5s" No healthCheck.hostname Value in the Host header of the health check request. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "" No healthCheck. followRedirect Follow the redirections during the healtchcheck. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. true No healthCheck.headers Map of header to send to the health check endpoint Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName). No sticky. cookie.name Name of the cookie used for the stickiness. When sticky sessions are enabled, a Set-Cookie header is set on the initial response to let the client know which server handles the first response. On subsequent requests, to keep the session alive with the same server, the client should send the cookie with the value set. If the server specified in the cookie becomes unhealthy, the request will be forwarded to a new server (and the cookie will keep track of the new server). Evaluated only if the kind is Service. "" No sticky. cookie.httpOnly Prevents client-side APIs, such as JavaScript, from accessing the cookie. Evaluated only if the kind is Service. false No sticky. cookie.secure Allow the cookie can only be transmitted over an encrypted connection (i.e. HTTPS). Evaluated only if the kind is Service. false No sticky. cookie.sameSite SameSite policy Allowed values: - none - lax strict Evaluated only if the kind is Service. "" No sticky. cookie.maxAge Number of seconds until the cookie expires. Negative number, the cookie expires immediately. 0, the cookie never expires. Evaluated only if the kind is Service. 0 No sticky. cookie.path Path that must exist in the requested URL for the browser to send the Cookie header. When not provided the cookie will be sent on every request to the domain. Evaluated only if the kind is Service. "/" No sticky. cookie.domain Host to which the cookie will be sent. Evaluated only if the kind is Service. "" No strategy Strategy defines the load balancing strategy between the servers. Supported values are: wrr (Weighed round-robin), p2c (Power of two choices), hrw (Highest Random Weight), and leasttime (Least-Time). Evaluated only if the kind is Service. "wrr" No nativeLB Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik. Evaluated only if the kind is Service. false No nodePortLB Use the nodePort IP address when the service type is NodePort. It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. Evaluated only if the kind is Service. false No middlewares List of references to Middleware resources to apply to the service. The middlewares will take effect for all requests handled by the service, regardless of which router forwards the request. Evaluated only if the kind is Service. More information here. No middlewares[n].name Middleware name. The character @ is not authorized. Yes middlewares[n].namespace Middleware namespace. Can be empty if the middleware belongs to the same namespace as the IngressRoute. No ExternalName Service Traefik backends creation needs a port to be set, however Kubernetes ExternalName Service could be defined without any port. Accordingly, Traefik supports defining a port in two ways: only on IngressRoute service on both sides, you'll be warned if the ports don't match, and the IngressRoute service port is used Thus, in case of two sides port definition, Traefik expects a match between ports. === "Ports defined on Resource" ```yaml tab="IngressRoute" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test.route namespace: apps spec: entryPoints: - foo routes: - match: Host(`example.net`) kind: Rule services: - name: external-svc port: 80 ``` ```yaml tab="Service ExternalName" apiVersion: v1 kind: Service metadata: name: external-svc namespace: apps spec: externalName: external.domain type: ExternalName ``` === "Port defined on the Service" ```yaml tab="IngressRoute" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test.route namespace: apps spec: entryPoints: - foo routes: - match: Host(`example.net`) kind: Rule services: - name: external-svc ``` ```yaml tab="Service ExternalName" apiVersion: v1 kind: Service metadata: name: external-svc namespace: apps spec: externalName: external.domain type: ExternalName ports: - port: 80 ``` === "Port defined on both sides" ```yaml tab="IngressRoute" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test.route namespace: apps spec: entryPoints: - foo routes: - match: Host(`example.net`) kind: Rule services: - name: external-svc port: 80 ``` ```yaml tab="Service ExternalName" apiVersion: v1 kind: Service metadata: name: external-svc namespace: apps spec: externalName: external.domain type: ExternalName ports: - port: 80 ``` Port Definition Traefik backends creation needs a port to be set, however Kubernetes ExternalName Service could be defined without any port. Accordingly, Traefik supports defining a port in two ways: only on IngressRoute service on both sides, you'll be warned if the ports don't match, and the IngressRoute service port is used Thus, in case of two sides port definition, Traefik expects a match between ports. ??? example ```yaml tab="IngressRoute" --- apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test.route namespace: default spec: entryPoints: - foo routes: - match: Host(`example.net`) kind: Rule services: - name: external-svc port: 80 --- apiVersion: v1 kind: Service metadata: name: external-svc namespace: default spec: externalName: external.domain type: ExternalName ``` ```yaml tab="ExternalName Service" --- apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test.route namespace: default spec: entryPoints: - foo routes: - match: Host(`example.net`) kind: Rule services: - name: external-svc --- apiVersion: v1 kind: Service metadata: name: external-svc namespace: default spec: externalName: external.domain type: ExternalName ports: - port: 80 ``` ```yaml tab="Both sides" --- apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test.route namespace: default spec: entryPoints: - foo routes: - match: Host(`example.net`) kind: Rule services: - name: external-svc port: 80 --- apiVersion: v1 kind: Service metadata: name: external-svc namespace: default spec: externalName: external.domain type: ExternalName ports: - port: 80 ``` Load Balancing You can declare and use Kubernetes Service load balancing as detailed below: apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: ingressroutebar namespace: default spec: entryPoints: - web routes: - match: Host(`example.com`) && PathPrefix(`/foo`) kind: Rule services: - name: svc1 namespace: default - name: svc2 namespace: default apiVersion: v1 kind: Service metadata: name: svc1 namespace: default spec: ports: - name: http port: 80 selector: app: traefiklabs task: app1 --- apiVersion: v1 kind: Service metadata: name: svc2 namespace: default spec: ports: - name: http port: 80 selector: app: traefiklabs task: app2 !!! important "Kubernetes Service Native Load-Balancing" To avoid creating the server load-balancer with the pod IPs and use Kubernetes Service clusterIP directly, one should set the service `NativeLB` option to true. Please note that, by default, Traefik reuses the established connections to the backends for performance purposes. This can prevent the requests load balancing between the replicas from behaving as one would expect when the option is set. By default, `NativeLB` is false. ??? example "Example" ```yaml --- apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test.route namespace: default spec: entryPoints: - foo routes: - match: Host(`example.net`) kind: Rule services: - name: svc port: 80 # Here, nativeLB instructs to build the server load-balancer with the Kubernetes Service clusterIP only. nativeLB: true --- apiVersion: v1 kind: Service metadata: name: svc namespace: default spec: type: ClusterIP ... ``` Middlewares You can attach a list of middlewares to each service. The middlewares will take effect for all requests handled by the service, regardless of which router forwards the request. For more information on service-level middlewares, see service middlewares. ??? example "Attaching Middlewares to a Service" ```yaml tab="IngressRoute" apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test-name namespace: default spec: entryPoints: - web routes: - kind: Rule match: Host(`example.com`) services: - kind: Service name: whoami port: 80 middlewares: - name: add-header namespace: default ``` ```yaml tab="Middleware" apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: add-header namespace: default spec: headers: customRequestHeaders: X-Custom-Header: "service-middleware" ``` ```yaml tab="Whoami Service" apiVersion: v1 kind: Service metadata: name: whoami namespace: default spec: ports: - port: 80 selector: app: whoami ``` Configuring Backend Protocol There are 3 ways to configure the backend protocol for communication between Traefik and your pods: Setting the scheme explicitly (http/https/h2c) Configuring the name of the kubernetes service port to start with https (https) Setting the kubernetes service port to use port 443 (https) If you do not configure the above, Traefik will assume an http connection. Traefik Kubernetes Services Documentation A TraefikService is a custom resource that sits on top of the Kubernetes Services. It enables advanced load-balancing features such as a Weighted Round Robin load balancing, a Highest Random Weight load balancing, a Mirroring, or a Failover between your Kubernetes Services. Services configure how to reach the actual endpoints that will eventually handle incoming requests. In Traefik, the target service can be either a standard Kubernetes service—which exposes a pod—or a TraefikService. The latter allows you to combine advanced load-balancing options like: Weighted Round Robin load balancing. Highest Random Weight load balancing. Mirroring. Failover. Weighted Round Robin The WRR is able to load balance the requests between multiple services based on weights. The WRR TraefikService allows you to load balance the traffic between Kubernetes Services and other instances of TraefikService (another WRR service -, or a mirroring service). Configuration Example apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test-name namespace: apps spec: entryPoints: - websecure routes: - match: Host(`example.com`) && PathPrefix(`/foo`) kind: Rule services: # Set a WRR TraefikService - name: wrr1 namespace: apps kind: TraefikService tls: # Add a TLS certificate from a Kubernetes Secret secretName: supersecret apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: wrr1 namespace: apps spec: weighted: services: # Kubernetes Service - name: svc1 namespace: apps port: 80 weight: 1 # Second level WRR service - name: wrr2 namespace: apps kind: TraefikService weight: 1 # Mirroring service # The service is described in the Mirroring example - name: mirror1 namespace: apps kind: TraefikService weight: 1 apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: wrr2 namespace: apps spec: weighted: services: # Kubernetes Service - name: svc2 namespace: apps port: 80 weight: 1 # Kubernetes Service - name: svc3 namespace: apps port: 80 weight: 1 apiVersion: v1 kind: Service metadata: name: svc1 namespace: apps spec: ports: - name: http port: 80 selector: app: traefiklabs task: app1 --- apiVersion: v1 kind: Service metadata: name: svc2 namespace: apps spec: ports: - name: http port: 80 selector: app: traefiklabs task: app2 --- apiVersion: v1 kind: Service metadata: name: svc3 namespace: apps spec: ports: - name: http port: 80 selector: app: traefiklabs task: app3 apiVersion: v1 kind: Secret metadata: name: supersecret namespace: apps data: tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0= Configuration Options Field Description Default Required services List of any combination of TraefikService and Kubernetes service. . Exhaustive list of option in the Service documentation. No services[m].weight Service weight. "" No sticky. cookie.name Name of the cookie used for the stickiness at the WRR service level. When sticky sessions are enabled, a Set-Cookie header is set on the initial response to let the client know which server handles the first response. On subsequent requests, to keep the session alive with the same server, the client should send the cookie with the value set. If the server pecified in the cookie becomes unhealthy, the request will be forwarded to a new server (and the cookie will keep track of the new server). More information about WRR stickiness here Abbreviation of a sha1 (ex: _1d52e). No sticky. cookie.httpOnly Allow the cookie used for the stickiness at the WRR service level to be accessed by client-side APIs, such as JavaScript. More information about WRR stickiness here false No sticky. cookie.secure Allow the cookie used for the stickiness at the WRR service level to be only transmitted over an encrypted connection (i.e. HTTPS). More information about WRR stickiness here false No sticky. cookie.sameSite SameSite policy for the cookie used for the stickiness at the WRR service level. Allowed values: - none - lax - strict - None - Lax - Strict More information about WRR stickiness here "" No sticky. cookie.maxAge Number of seconds until the cookie used for the stickiness at the WRR service level expires. Negative number, the cookie expires immediately. 0, the cookie never expires. 0 No Stickiness on multiple levels When chaining or mixing load-balancers (e.g. a load-balancer of servers is one of the "children" of a load-balancer of services), for stickiness to work all the way, the option needs to be specified at all required levels. Which means the client needs to send a cookie with as many key/value pairs as there are sticky levels. Sticky sessions, for stickiness to work all the way, must be specified at each load-balancing level. For instance, in the example below, there is a first level of load-balancing because there is a (Weighted Round Robin) load-balancing of the two whoami services, and there is a second level because each whoami service is a replicaset and is thus handled as a load-balancer of servers. apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: ingressroutebar namespace: apps spec: entryPoints: - web routes: - match: Host(`example.com`) && PathPrefix(`/foo`) kind: Rule services: - name: wrr1 namespace: apps kind: TraefikService apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: wrr1 namespace: apps spec: weighted: services: - name: whoami1 kind: Service port: 80 weight: 1 # Stickiness level2 (on the Kubernetes service) sticky: cookie: name: lvl2 - name: whoami2 kind: Service weight: 1 port: 80 # Stickiness level2 (on the Kubernetes service) sticky: cookie: name: lvl2 # Stickiness level2 (on the WRR service) sticky: cookie: name: lvl1 In the example above, to keep a session open with the same server, the client would then need to specify the two levels within the cookie for each request, e.g. with curl: # Assuming `10.42.0.6` is the IP address of one of the replicas (a pod then) of the `whoami1` service. curl -H Host:example.com -b "lvl1=default-whoami1-80; lvl2=http://10.42.0.6:80" http://localhost:8000/foo Highest Random Weight The HRW (Highest Random Weight) load balancer uses consistent hashing to ensure that requests from the same client IP are always routed to the same service. Unlike weighted round-robin which distributes requests based on weights, HRW provides consistent routing based on the client's remote address. This is particularly useful for maintaining session affinity without requiring sticky cookies, as clients will consistently reach the same backend service based on their IP address. Configuration Example apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test-hrw namespace: apps spec: entryPoints: - websecure routes: - match: Host(`example.com`) && PathPrefix(`/app`) kind: Rule services: # Set an HRW TraefikService - name: hrw1 namespace: apps kind: TraefikService tls: secretName: supersecret apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: hrw1 namespace: apps spec: highestRandomWeight: services: # Kubernetes Service with weight 10 - name: svc1 namespace: apps port: 80 weight: 10 # Kubernetes Service with weight 20 - name: svc2 namespace: apps port: 80 weight: 20 # Another TraefikService - name: wrr1 namespace: apps kind: TraefikService weight: 15 apiVersion: v1 kind: Service metadata: name: svc1 namespace: apps spec: ports: - name: http port: 80 selector: app: traefiklabs task: app1 --- apiVersion: v1 kind: Service metadata: name: svc2 namespace: apps spec: ports: - name: http port: 80 selector: app: traefiklabs task: app2 Configuration Options Field Description Default Required services List of any combination of TraefikService and Kubernetes service. Each service must have a weight assigned. Yes services[m]. kind Kind of the service targeted. Two values allowed: - Service: Kubernetes Service - TraefikService: Traefik Service. "" No services[m]. name Service name. The character @ is not authorized. "" Yes services[m]. namespace Service namespace. "" No services[m]. port Service port (number or port name). Evaluated only if the kind is Service. "" No services[m]. weight Service weight used in the HRW algorithm. Higher weights increase the probability of selection for a given client IP. 1 No services[m]. responseForwarding. flushInterval Interval, in milliseconds, in between flushes to the client while copying the response body. A negative value means to flush immediately after each write to the client. This configuration is ignored when a response is a streaming response; for such responses, writes are flushed to the client immediately. Evaluated only if the kind is Service. 100ms No services[m]. scheme Scheme to use for the request to the upstream Kubernetes Service. Evaluated only if the kind is Service. "http" "https" if port is 443 or contains the string https. No services[m]. serversTransport Name of ServersTransport resource to use to configure the transport between Traefik and your servers. Evaluated only if the kind is Service. "" No services[m]. passHostHeader Forward client Host header to server. Evaluated only if the kind is Service. true No services[m]. healthCheck.scheme Server URL scheme for the health check endpoint. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "" No services[m]. healthCheck.mode Health check mode. If defined to grpc, will use the gRPC health check protocol to probe the server. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "http" No services[m]. healthCheck.path Server URL path for the health check endpoint. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "" No services[m]. healthCheck.interval Frequency of the health check calls for healthy targets. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "30s" No services[m]. healthCheck.unhealthyInterval Frequency of the health check calls for unhealthy targets. When not defined, it defaults to the interval value. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "30s" No services[m]. healthCheck.method HTTP method for the health check endpoint. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "GET" No services[m]. healthCheck.status Expected HTTP status code of the response to the health check request. Only for Kubernetes service of type ExternalName. If not set, expect a status between 200 and 399. Evaluated only if the kind is Service. No services[m]. healthCheck.port URL port for the health check endpoint. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. No services[m]. healthCheck.timeout Maximum duration to wait before considering the server unhealthy. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "5s" No services[m]. healthCheck.hostname Value in the Host header of the health check request. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. "" No services[m]. healthCheck. followRedirect Follow the redirections during the healtchcheck. Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. true No services[m]. healthCheck.headers Map of header to send to the health check endpoint Evaluated only if the kind is Service. Only for Kubernetes service of type ExternalName. No services[m]. sticky. cookie.name Name of the cookie used for the stickiness. Evaluated only if the kind is Service. Abbreviation of a sha1 (ex: _1d52e). No services[m]. sticky. cookie.httpOnly Allow the cookie can be accessed by client-side APIs, such as JavaScript. Evaluated only if the kind is Service. false No services[m]. sticky. cookie.secure Allow the cookie can only be transmitted over an encrypted connection (i.e. HTTPS). Evaluated only if the kind is Service. false No services[m]. sticky. cookie.sameSite SameSite policy. Allowed values (case-insensitive): - none - lax - strict - None - Lax - Strict Evaluated only if the kind is Service. "" No services[m]. sticky. cookie.maxAge Number of seconds until the cookie expires. Negative number, the cookie expires immediately. 0, the cookie never expires. Evaluated only if the kind is Service. 0 No services[m]. strategy Load balancing strategy between the servers. Supported values: wrr, p2c, hrw, leasttime. Evaluated only if the kind is Service. "wrr" No services[m]. nativeLB Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik. To put it more plainly, setting nativeLB to true makes Traefik route traffic to the Kubernetes Service (using your cluster's networking such as kube-proxy, Cilium, Calico, etc.) and load balancing is handled by Kubernetes itself. When set to false, Traefik routes traffic directly to the pods and makes load balancing decisions internally. By default, Traefik reuses the established connections to the backends for performance purposes regardless of the nativeLB configuration. However, connection reuse combined with nativeLB: true can cause uneven load balancing; if this is unacceptable, you can disable connection reuse by setting maxIdleConnsPerHost to -1. Evaluated only if the kind is Service. false No services[m]. nodePortLB Use the nodePort IP address when the service type is NodePort. It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. Evaluated only if the kind is Service. false No How HRW Works The Highest Random Weight algorithm combines consistent hashing with weighted load balancing: Consistent Hashing: For each incoming request, the client's remote address is hashed to ensure consistent routing. Weighted Selection: Each service is assigned a random value based on both the hash of the client IP and the service's weight. Highest Selection: The service with the highest calculated value receives the request. This approach provides several benefits: Session Affinity: Clients consistently reach the same backend service Weighted Distribution: Services with higher weights are more likely to be selected No State Required: Unlike sticky cookies, no client-side or server-side state is needed Fault Tolerance: If a service becomes unavailable, requests are redistributed consistently among remaining services Mirroring The mirroring is able to mirror requests sent to a service to other services. A mirroring service allows you to send the trafiic to many services together: The main service receives 100% of the traffic, The mirror services receive a percentage of the traffic. For example, to upgrade the version of your application. You can set the service that targets current version as the main service, and the service of the new version a mirror service. Thus you can start testing the behavior of the new version keeping the current version reachable. The mirroring TraefikService allows you to reference Kubernetes Services and other instances of TraefikService (another WRR service -, or a mirroring service). Please note that by default the whole request is buffered in memory while it is being mirrored. See the maxBodySize option in the example below for how to modify this behavior, or the streamBody option to stream the body to the mirrors instead of buffering it. Configuration Example apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: ingressroutebar namespace: default spec: entryPoints: - web routes: - match: Host(`example.com`) && PathPrefix(`/foo`) kind: Rule services: - name: mirror1 namespace: default kind: TraefikService # Mirroring from a k8s Service apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: mirror1 namespace: default spec: mirroring: name: svc1 # svc1 receives 100% of the traffic port: 80 mirrorBody: true # Default: true maxBodySize: 1048576 mirrors: - name: svc2 # svc2 receives a copy of 20% of this traffic port: 80 percent: 20 - name: svc3 # svc3 receives a copy of 15% of this traffic kind: TraefikService percent: 15 # Mirroring from a Traefik Service apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: mirror1 namespace: default spec: mirroring: name: wrr1 # wrr1 receives 100% of the traffic kind: TraefikService mirrors: - name: svc2 # svc2 receives a copy of 20% of this traffic port: 80 percent: 20 - name: svc3 # svc3 receives a copy of 10% of this traffic kind: TraefikService percent: 10 apiVersion: v1 kind: Service metadata: name: svc1 namespace: default spec: ports: - name: http port: 80 selector: app: traefiklabs task: app1 --- apiVersion: v1 kind: Service metadata: name: svc2 namespace: default spec: ports: - name: http port: 80 selector: app: traefiklabs task: app2 Configuration Options Main Service Options The main service properties are set as the option root level. The main service provides the same options as a Service. The exhaustive list of the service options is described in the Service documentation. The mirror main service dedicated option are described below. Field Description Default Required mirrorBody Defines whether the request body should be mirrored. true No maxBodySize Maximum size allowed for the body of the request. If the body is larger, the request is not mirrored. -1 means unlimited size. -1 No streamBody Defines whether the request body is streamed to the mirrors while the main service reads it, instead of being buffered in memory. A mirror falling more than 1 MiB behind the main service is aborted. It has no effect when mirrorBody is false, and cannot be used with maxBodySize. false No mirrors List of mirrored services to target. It can be any combination of TraefikService and Kubernetes service. Exhaustive list of option in the Service documentation. Yes Mirrored Services Options The mirrored services properties are set in the mirrors list. A mirrored service provides the same options as a Service. The exhaustive list of the service options is described in the Service documentation. The mirrorerd service dedicated option are described below. Field Description Default Required mirrors[m].percent Traffic percentage to route to the service. 0 No Failover The failover service forwards all requests to a fallback service when the main service responds with specific HTTP status codes defined in the errors configuration. !!! Failover on Heathcheck Status HealthCheck on a Failover service can be defined currently only with the [File provider](../../../../install-configuration/providers/others/file.md). Configuration Examples apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: test-name namespace: apps spec: entryPoints: - websecure routes: - match: Host(`example.com`) && PathPrefix(`/foo`) kind: Rule services: # Set a Failover TraefikService - name: failover1 namespace: apps kind: TraefikService apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: failover1 namespace: apps spec: failover: service: name: svc1 port: 80 fallback: name: svc2 port: 80 errors: status: - "500-503" - "429" apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: failover1 namespace: apps spec: failover: service: name: wrr1 kind: TraefikService fallback: name: wrr2 kind: TraefikService errors: status: - "500-503" apiVersion: traefik.io/v1alpha1 kind: TraefikService metadata: name: failover1 namespace: apps spec: failover: service: name: svc1 port: 80 fallback: name: svc2 port: 80 errors: status: - "500-503" - "429" maxRequestBodyBytes: 1048576 apiVersion: v1 kind: Service metadata: name: svc1 namespace: apps spec: ports: - name: http port: 80 selector: app: traefiklabs task: app1 --- apiVersion: v1 kind: Service metadata: name: svc2 namespace: apps spec: ports: - name: http port: 80 selector: app: traefiklabs task: app2 Configuration Options Main Service and Fallback Options The service and fallback fields each define a target service using the same options as a Service. The exhaustive list of the service options is described in the Service documentation. Failover Dedicated Options Field Description Default Required service Main service to forward requests to. Provides the same options as a Service. Yes fallback Fallback service to use when the main service returns matching error status codes. Provides the same options as a Service. Yes errors.status List of HTTP status code ranges for which the fallback service should be used. Each entry can be a single code (e.g. "429") or a range (e.g. "500-503"). No errors. maxRequestBodyBytes Maximum size allowed for the body of the request. If the body is larger, the request is not replayed to the fallback service. -1 means unlimited size. -1 No Kubernetes IngressRouteTCP IngressRouteTCP is the CRD implementation of a Traefik TCP router. Before creating IngressRouteTCP objects, you need to apply the Traefik Kubernetes CRDs to your Kubernetes cluster. This registers the IngressRouteTCP kind and other Traefik-specific resources. !!! note "General" If both HTTP routers and TCP routers are connected to the same EntryPoint, the TCP routers will apply before the HTTP routers. If no matching route is found for the TCP routers, then the HTTP routers will take over. Configuration Example You can declare an IngressRouteTCP as detailed below: apiVersion: traefik.io/v1alpha1 kind: IngressRouteTCP metadata: name: ingressroutetcpfoo namespace: apps spec: ingressClassName: traefik-lb entryPoints: - footcp routes: - match: HostSNI(`*`) priority: 10 middlewares: - name: middleware1 namespace: default services: - name: foo port: 8080 weight: 10 serversTransport: transport nativeLB: true nodePortLB: true tls: secretName: supersecret options: name: opt namespace: default certResolver: foo domains: - main: example.net sans: - a.example.net - b.example.net passthrough: false Configuration Options Field Description Default Required ingressClassName Defines the IngressClass cluster resource to use. It replaces the deprecated kubernetes.io/ingress.class annotation. The spec field takes precedence over the annotation. No entryPoints List of entrypoints names. No routes List of routes. Yes routes[n].match Defines the rule of the underlying router. Yes routes[n].priority Defines the priority to disambiguate rules of the same length, for route matching. No routes[n].middlewares[n].name Defines the MiddlewareTCP name. Yes routes[n].middlewares[n].namespace Defines the MiddlewareTCP namespace. "" No routes[n].services List of Kubernetes service definitions. No routes[n].services[n].name Defines the name of a Kubernetes service. Yes routes[n].services[n].namespace Defines the namespace of the referenced Kubernetes service. "" No routes[n].services[n].port Defines the port of a Kubernetes service. This can be a reference to a named port. Yes routes[n].services[n].weight Defines the weight to apply to the server load balancing. 1 No routes[n].services[n].proxyProtocol Defines the PROXY protocol configuration. No routes[n].services[n].proxyProtocol.version Defines the PROXY protocol version. No routes[n].services[n].serversTransport Defines the ServersTransportTCP. The ServersTransport namespace is assumed to be the Kubernetes service namespace. No routes[n].services[n].tls Determines whether to use TLS when dialing with the backend. false No routes[n].services[n].nativeLB Controls, when creating the load-balancer, whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. See here for more information. false No routes[n].services[n].nodePortLB Controls, when creating the load-balancer, whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. false No tls Defines TLS certificate configuration. No tls.secretName Defines the secret name used to store the certificate (in the IngressRoute namespace). "" No tls.options Defines the reference to a TLSOption. "" No tls.options.name Defines the TLSOption name. "" No tls.options.namespace Defines the TLSOption namespace. "" No tls.store Defines the reference to a TLSStore. Note that only the default TLSStore can be used. No tls.certResolver Defines the reference to a CertResolver. "" No tls.domains List of domains. "" No tls.domains[n].main Defines the main domain name. "" No tls.domains[n].sans List of SANs (alternative domains). "" No tls.passthrough If true, delegates the TLS termination to the backend. false No ExternalName Service Traefik connect to a backend with a domain and a port. However, Kubernetes ExternalName Service can be defined without any port. Accordingly, Traefik supports defining a port in two ways: only on IngressRouteTCP service on both sides, you'll be warned if the ports don't match, and the IngressRouteTCP service port is used Thus, in case of two sides port definition, Traefik expects a match between ports. === "Ports defined on Resource" ```yaml tab="IngressRouteTCP" apiVersion: traefik.io/v1alpha1 kind: IngressRouteTCP metadata: name: test.route namespace: apps spec: entryPoints: - foo routes: - match: Host(`example.net`) services: - name: external-svc port: 80 ``` ```yaml tab="Service ExternalName" apiVersion: v1 kind: Service metadata: name: external-svc namespace: apps spec: externalName: external.domain type: ExternalName ``` === "Port defined on the Service" ```yaml tab="IngressRouteTCP" apiVersion: traefik.io/v1alpha1 kind: IngressRouteTCP metadata: name: test.route namespace: apps spec: entryPoints: - foo routes: - match: Host(`example.net`) services: - name: external-svc ``` ```yaml tab="Service ExternalName" apiVersion: v1 kind: Service metadata: name: external-svc namespace: apps spec: externalName: external.domain type: ExternalName ports: - port: 80 ``` === "Port defined on both sides" ```yaml tab="IngressRouteTCP" apiVersion: traefik.io/v1alpha1 kind: IngressRouteTCP metadata: name: test.route namespace: apps spec: entryPoints: - foo routes: - match: Host(`example.net`) services: - name: external-svc port: 80 ``` ```yaml tab="Service ExternalName" apiVersion: v1 kind: Service metadata: name: external-svc namespace: apps spec: externalName: external.domain type: ExternalName ports: - port: 80 ``` NativeLB To avoid creating the server load-balancer with the pods IPs and use Kubernetes Service clusterIP directly, one should set the NativeLB option to true. By default, NativeLB is false. apiVersion: traefik.io/v1alpha1 kind: IngressRouteTCP metadata: name: test.route namespace: default spec: entryPoints: - foo routes: - match: HostSNI(`*`) services: - name: svc port: 80 # Here, nativeLB instructs to build the servers load balancer with the Kubernetes Service clusterIP only. nativeLB: true apiVersion: v1 kind: Service metadata: name: svc namespace: default spec: type: ClusterIP ... Kubernetes MiddlewareTCP MiddlewareTCP is the CRD implementation of a Traefik TCP middleware. Before creating MiddlewareTCP objects, you need to apply the Traefik Kubernetes CRDs to your Kubernetes cluster. This registers the MiddlewareTCP kind and other Traefik-specific resources. !!! tip "Cross-provider namespace" As Kubernetes also has its own notion of namespace, one should not confuse the kubernetes namespace of a resource (in the reference to the middleware) with the provider namespace, when the definition of the middleware comes from another provider. In this context, specifying a namespace when referring to the resource does not make any sense, and will be ignored. Additionally, when you want to reference a Middleware from the CRD Provider, you have to append the namespace of the resource in the resource-name as Traefik appends the namespace internally automatically. Configuration Example apiVersion: traefik.io/v1alpha1 kind: MiddlewareTCP metadata: name: ipallowlist spec: ipAllowList: sourceRange: - 127.0.0.1/32 - 192.168.1.7 apiVersion: traefik.io/v1alpha1 kind: IngressRouteTCP metadata: name: ingressroutebar spec: entryPoints: - web routes: - match: HostSNI(`example.com`) kind: Rule services: - name: whoami port: 80 middlewares: - name: ipallowlist namespace: foo More information about available TCP middlewares in the dedicated middlewares section. serverstransporttcp title : 'ServersTransportTCP' description : 'Understand the service routing configuration for the Kubernetes ServerTransportTCP & Traefik CRD' ServersTransportTCP is the CRD implementation of ServersTransportTCP. Before creating ServersTransportTCP objects, you need to apply the Traefik Kubernetes CRDs to your Kubernetes cluster. This registers the ServersTransportTCP kind and other Traefik-specific resources. !!! tip "Default serversTransportTCP" If no serversTransportTCP is specified, the default@internal will be used. The default@internal serversTransportTCP is created from the install configuration (formerly known as static configuration). !!! note "ServersTransport reference" By default, the referenced ServersTransportTCP CRD must be defined in the same Kubernetes service namespace. To reference a `ServersTransportTCP` CRD from another namespace, the value must be of form `namespace-name@kubernetescrd`, and the `allowCrossNamespace` option must be enabled. If the `ServersTransportTCP` CRD is defined in another provider the cross-provider format `name@provider` should be used. When [`safeNaming`](../../../../install-configuration/providers/kubernetes/kubernetes-crd.md#safenaming) is enabled, the cross-namespace value becomes `namespace_name@kubernetescrd`, using the same `_` separator as the other names generated by the provider. Configuration Example apiVersion: traefik.io/v1alpha1 kind: ServersTransportTCP metadata: name: mytransport namespace: default spec: proxyProtocol: version: 2 terminationDelay: 100ms tls: serverName: example.org insecureSkipVerify: true Configuration Options Field Description Default Required dialTimeout The amount of time to wait until a connection to a server can be established. If zero, no timeout exists. 30s No dialKeepAlive The interval between keep-alive probes for an active network connection. If this option is set to zero, keep-alive probes are sent with a default value (currently 15 seconds), if supported by the protocol and operating system. Network protocols or operating systems that do not support keep-alives ignore this field. If negative, keep-alive probes are turned off. 15s No proxyProtocol Defines the Proxy Protocol configuration. An empty proxyProtocol section enables Proxy Protocol version 2. No proxyProtocol.version Traefik supports PROXY Protocol version 1 and 2 on TCP Services. No terminationDelay Defines the delay to wait before fully terminating the connection, after one connected peer has closed its writing capability. 100ms No tls.serverName ServerName used to contact the server. "" No tls.insecureSkipVerify Controls whether the server's certificate chain and host name is verified. false No tls.peerCertSANs Defines the SANs (Subject Alternative Names) used to match against SANs during the peer certificate verification. [] No tls.peerCertSANs[].type Defines the SAN type ( URI or DNSName) to match against the peer certificate's Subject Alternative Names. "" No tls.peerCertSANs[].value Defines the SAN value to match against the peer certificate's Subject Alternative Names. "" No tls.rootCAs Defines a list of CA certificate Secrets or ConfigMaps used to validate server certificates. Each entry can reference either a Secret ( secret) or a ConfigMap ( configMap) by name. The referenced resource must contain a certificate under either a tls.ca or a ca.crt key. No tls.rootCAsSecrets Deprecated: use tls.rootCAs instead. Defines the set of root certificate authorities to use when verifying server certificates. The CA secret must contain a base64 encoded certificate under either a tls.ca or a ca.crt key. "" No tls.certificatesSecrets Certificates to present to the server for mTLS. "" No spiffe Configures SPIFFE options. "" No spiffe.ids Defines the allowed SPIFFE IDs. This takes precedence over the SPIFFE trustDomain. "" No spiffe.trustDomain Defines the allowed SPIFFE trust domain. "" No TLSOption The TLS options allow you to configure some parameters of the TLS connection in Traefik. Before creating TLSOption objects or referencing TLS options in the IngressRoute / IngressRouteTCP objects, you need to apply the Traefik Kubernetes CRDs to your Kubernetes cluster. !!! tip "References and namespaces" If the optional namespace attribute is not set, the configuration will be applied with the namespace of the IngressRoute/ IngressRouteTCP. Additionally, when the definition of the TLS option is from another provider, the cross-provider [syntax](../../../../install-configuration/providers/overview.md#provider-namespace) (`middlewarename@provider`) should be used to refer to the TLS option. Specifying a namespace attribute in this case would not make any sense, and will be ignored. !!! important "TLSOption in Kubernetes" When using the `TLSOption` resource in Kubernetes, one might setup a default set of options that, if not explicitly overwritten, should apply to all ingresses. To achieve that, you'll have to create a `TLSOption` resource with the name `default`. There may exist only one `TLSOption` with the name `default` (across all namespaces) - otherwise they will be dropped. To explicitly use a different `TLSOption` (and using the Kubernetes Ingress resources) you'll have to add an annotation to the Ingress in the following form: `traefik.ingress.kubernetes.io/router.tls.options: -@kubernetescrd` This `default` TLSOption carries the TLS enforcement policy (client authentication, TLS versions, cipher suites, SNI strictness) of every router that does not reference a TLSOption explicitly. The [`defaultTLSResourcesNamespace`](../../../../install-configuration/providers/kubernetes/kubernetes-crd.md#defaulttlsresourcesnamespace) provider option restricts the namespace this cluster-wide default can be defined in. When [`safeNaming`](../../../../install-configuration/providers/kubernetes/kubernetes-crd.md#safenaming) is enabled, the annotation value becomes `_@kubernetescrd`, using the same `_` separator as the other names generated by the provider. Configuration Example apiVersion: traefik.io/v1alpha1 kind: TLSOption metadata: name: mytlsoption namespace: default spec: minVersion: VersionTLS12 sniStrict: true cipherSuites: - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - TLS_RSA_WITH_AES_256_GCM_SHA384 clientAuth: secretNames: - secret-ca1 - secret-ca2 clientAuthType: VerifyClientCertIfGiven Configuration Options Field Description Default Required minVersion Minimum TLS version that is acceptable. "VersionTLS12" No maxVersion Maximum TLS version that is acceptable. We do not recommend setting this option to disable TLS 1.3. No cipherSuites List of supported cipher suites for TLS versions up to TLS 1.2. Cipher suites defined for TLS 1.2 and below cannot be used in TLS 1.3, and vice versa. With TLS 1.3, the cipher suites are not configurable (all supported cipher suites are safe in this case). No curvePreferences List of the elliptic curves references that will be used in an ECDHE handshake. Use curves names from crypto or the RFC. See CurveID for more information. No clientAuth.secretNames Client Authentication (mTLS) option. List of names of the referenced Kubernetes Secrets (in TLSOption namespace). The secret must contain a certificate under either a tls.ca or a ca.crt key. No clientAuth.clientAuthType Client Authentication (mTLS) option. Client authentication type to apply. Available values here. No sniStrict Allow rejecting connections from clients connections that do not specify a server_name extension. The default certificate is never served is the option is enabled. false No alpnProtocols List of supported application level protocols for the TLS handshake, in order of preference. If the client supports ALPN, the selected protocol will be one from this list, and the connection will fail if there is no mutually supported protocol. "h2, http/1.1, acme-tls/1" No disableSessionTickets Allow disabling the use of session tickets, forcing every client to perform a full TLS handshake instead of resuming sessions. false No Client Authentication (mTLS) The clientAuth.clientAuthType option governs the behavior as follows: NoClientCert: disregards any client certificate. RequestClientCert: asks for a certificate but proceeds anyway if none is provided. RequireAnyClientCert: requires a certificate but does not verify if it is signed by a CA listed in clientAuth.caFiles or in clientAuth.secretNames. VerifyClientCertIfGiven: if a certificate is provided, verifies if it is signed by a CA listed in clientAuth.caFiles or in clientAuth.secretNames. Otherwise proceeds without any certificate. RequireAndVerifyClientCert: requires a certificate, which must be signed by a CA listed in clientAuth.caFiles or in clientAuth.secretNames. !!! note "CA Secret" The CA secret must contain a base64 encoded certificate under either a tls.ca or a ca.crt key. Default TLS Option When no TLS options are specified in an IngressRoute/ IngressRouteTCP, the default option is used. The default behavior is summed up in the table below: Configuration Behavior No default TLS Option Default internal set of TLS Options by default. One default TLS Option Custom TLS Options applied by default. Many default TLS Option Error log + Default internal set of TLS Options by default. TLSStore In Traefik, certificates are grouped together in certificates stores. TLSStore is the CRD implementation of a Traefik TLS Store. Before creating TLSStore objects, you need to apply the Traefik Kubernetes CRDs to your Kubernetes cluster. !!! Tip "Default TLS Store" Traefik currently only uses the TLS Store named "default". This default TLSStore should be in a namespace discoverable by Traefik. Since it is used by default on IngressRoute and IngressRouteTCP objects, there never is a need to actually reference it. This means that you cannot have two stores that are named default in different Kubernetes namespaces. As a consequence, with respect to TLS stores, the only change that makes sense (and only if needed) is to configure the default TLSStore. The defaultTLSResourcesNamespace provider option restricts the namespace this cluster-wide store can be defined in. Configuration Example apiVersion: traefik.io/v1alpha1 kind: TLSStore metadata: name: default spec: defaultCertificate: secretName: supersecret Configuration Options Field Description Required certificates[n].secretName List of Kubernetes Secrets, each of them holding a key/certificate pair to add to the store. No defaultCertificate.secretName Name of the Kubernetes Secret served for connections without a SNI, or without a matching domain. If no default certificate is provided, Traefik will use the generated one. Do not use if the option defaultGeneratedCert is set. No defaultGeneratedCert.resolver Name of the ACME resolver to use to generate the default certificate. Do not use if the option defaultCertificate is set. No defaultGeneratedCert.domain.main Main domain used to generate the default certificate. Do not use if the option defaultCertificate is set. No defaultGeneratedCert.domain.sans List of Subject Alternative Name used to generate the default certificate. Do not use if the option defaultCertificate is set. No !!! note "DefaultCertificate vs DefaultGeneratedCert" If both defaultCertificate and defaultGeneratedCert are set, the TLS certificate contained in defaultCertificate.secretName is served. The ACME default certificate is not generated. IngressRouteUDP IngressRouteUDP is the CRD implementation of a Traefik UDP router. Before creating IngressRouteUDP objects, you need to apply the Traefik Kubernetes CRDs to your Kubernetes cluster. This registers the IngressRouteUDP kind and other Traefik-specific resources. Configuration Example apiVersion: traefik.io/v1alpha1 kind: IngressRouteUDP metadata: name: ingressrouteudpfoo namespace: apps spec: ingressClassName: traefik-lb entryPoints: - fooudp # The entry point where Traefik listens for incoming traffic. routes: - services: - name: foo # The name of the Kubernetes Service to route to. port: 8080 weight: 10 nativeLB: true # Enables native load balancing between pods. Configuration Options Field Description Default Required ingressClassName Defines the IngressClass cluster resource to use. It replaces the deprecated kubernetes.io/ingress.class annotation. The spec field takes precedence over the annotation. No entryPoints List of entrypoints names. No routes List of routes. Yes routes[n].services List of Kubernetes service definitions. See here for ExternalName Service setup. No routes[n].services[n].name Defines the name of a Kubernetes service. Yes routes[n].services[n].port Defines the port of a Kubernetes service. This can be a reference to a named port. Yes routes[n].services[n].weight Defines the weight to apply to the server load balancing. 1 No routes[n].services[n].nativeLB Controls, when creating the load-balancer, whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. false No routes[n].services[n].nodePortLB Controls, when creating the load-balancer, whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes. See here for more information. false No ExternalName Service Traefik backends creation needs a port to be set, however Kubernetes ExternalName Service could be defined without any port. Accordingly, Traefik supports defining a port in two ways: only on IngressRouteUDP service on both sides, you'll be warned if the ports don't match, and the IngressRouteUDP service port is used Thus, in case of two sides port definition, Traefik expects a match between ports. === "Ports defined on Resource" ```yaml tab="IngressRouteUDP" apiVersion: traefik.io/v1alpha1 kind: IngressRouteUDP metadata: name: test.route namespace: apps spec: entryPoints: - foo routes: - services: - name: external-svc port: 80 ``` ```yaml tab="Service ExternalName" apiVersion: v1 kind: Service metadata: name: external-svc namespace: apps spec: externalName: external.domain type: ExternalName ``` === "Port defined on the Service" ```yaml tab="IngressRouteUDP" apiVersion: traefik.io/v1alpha1 kind: IngressRouteUDP metadata: name: test.route namespace: apps spec: entryPoints: - foo routes: - services: - name: external-svc ``` ```yaml tab="Service ExternalName" apiVersion: v1 kind: Service metadata: name: external-svc namespace: apps spec: externalName: external.domain type: ExternalName ports: - port: 80 ``` === "Port defined on both sides" ```yaml tab="IngressRouteUDP" apiVersion: traefik.io/v1alpha1 kind: IngressRouteUDP metadata: name: test.route namespace: apps spec: entryPoints: - foo routes: - services: - name: external-svc port: 80 ``` ```yaml tab="Service ExternalName" apiVersion: v1 kind: Service metadata: name: external-svc namespace: apps spec: externalName: external.domain type: ExternalName ports: - port: 80 ``` NativeLB To avoid creating the server load-balancer with the pods IPs and use Kubernetes Service clusterIP directly, one should set the NativeLB option to true. By default, NativeLB is false. apiVersion: traefik.io/v1alpha1 kind: IngressRouteUDP metadata: name: test.route namespace: default spec: entryPoints: - foo routes: - services: - name: svc port: 80 # Here, nativeLB instructs to build the servers load balancer with the Kubernetes Service clusterIP only. nativeLB: true apiVersion: v1 kind: Service metadata: name: svc namespace: default spec: type: ClusterIP ... Traefik & Consul Catalog One of the best feature of Traefik is to delegate the routing configuration to the application level. With Consul Catalog, Traefik can leverage tags attached to a service to generate routing rules. !!! warning "Tags & sensitive data" We recommend to *not* use tags to store sensitive data (certificates, credentials, etc). Instead, we recommend to store sensitive data in a safer storage (secrets, file, etc). Configuration Examples ??? example "Configuring Consul Catalog & Deploying / Exposing one Service" Enabling the consul catalog provider ```yaml tab="Structured (YAML)" providers: consulCatalog: {} ``` ```toml tab="Structured (TOML)" [providers.consulCatalog] ``` ```bash tab="CLI" --providers.consulcatalog=true ``` Attaching tags to services (when registering a service in Consul) ```bash consul services register -name=my-service -tag="traefik.http.routers.my-service.rule=Host(`example.com`)" ``` Or using a service definition file: ```json { "service": { "name": "my-service", "tags": [ "traefik.http.routers.my-service.rule=Host(`example.com`)" ] } } ``` ??? example "Specify a Custom Port for the Container" Forward requests for `http://example.com` to `http://:12345`: ```json { "service": { "name": "my-service", "tags": [ "traefik.http.routers.my-service.rule=Host(`example.com`)", "traefik.http.routers.my-service.service=my-service", "traefik.http.services.my-service.loadbalancer.server.port=12345" ] } } ``` !!! important "Traefik Connecting to the Wrong Port: `HTTP/502 Gateway Error`" By default, Traefik uses the first exposed port of a container. Setting the tag `traefik.http.services.xxx.loadbalancer.server.port` overrides that behavior. ??? example "Specifying more than one router and service per container" Forwarding requests to more than one port on a container requires referencing the service loadbalancer port definition using the service parameter on the router. In this example, requests are forwarded for `http://example-a.com` to `http://:8000` in addition to `http://example-b.com` forwarding to `http://:9000`: ```json { "service": { "name": "my-service", "tags": [ "traefik.http.routers.www-router.rule=Host(`example-a.com`)", "traefik.http.routers.www-router.service=www-service", "traefik.http.services.www-service.loadbalancer.server.port=8000", "traefik.http.routers.admin-router.rule=Host(`example-b.com`)", "traefik.http.routers.admin-router.service=admin-service", "traefik.http.services.admin-service.loadbalancer.server.port=9000" ] } } ``` Configuration Options !!! info "tags" Tags are case-insensitive. !!! tip "TLS Default Generated Certificates" To learn how to configure Traefik default generated certificate, refer to the [TLS Certificates](../http/tls/tls-certificates.md#acme-default-certificate) page. General Traefik creates, for each consul Catalog service, a corresponding service and router. The Service automatically gets a server per instance in this consul Catalog service, and the router gets a default rule attached to it, based on the service name. Routers To update the configuration of the Router automatically attached to the service, add tags starting with traefik.http.routers.{name-of-your-choice}. and followed by the option you want to change. For example, to change the rule, you could add the tag traefik.http.routers.my-service.rule=Host(`example.com`). Configuration Options Label Description Value traefik.http.routers..rule See rule for more information. Host(`example.com`) traefik.http.routers..ruleSyntax See ruleSyntax for more information. RuleSyntax option is deprecated and will be removed in the next major version. Please do not use this field and rewrite the router rules to use the v3 syntax. v3 traefik.http.routers..priority See priority for more information. 42 traefik.http.routers..entrypoints See entry points for more information. web,websecure traefik.http.routers..middlewares See middlewares overview for more information. auth,prefix,cb traefik.http.routers..service See service for more information. myservice traefik.http.routers..tls See tls for more information. true traefik.http.routers..tls.certresolver See certResolver for more information. myresolver traefik.http.routers..tls.domains[n].main See domains for more information. example.org traefik.http.routers..tls.domains[n].sans See domains for more information. test.example.org,dev.example.org traefik.http.routers..tls.options See TLS Options for more information, and Conflicting TLS Options when several routers serve the same host name. foobar traefik.http.routers..observability.accesslogs The accessLogs option controls whether the router will produce access-logs. true traefik.http.routers..observability.metrics The metrics option controls whether the router will produce metrics. true traefik.http.routers..observability.tracing The tracing option controls whether the router will produce traces. true Services To update the configuration of the Service automatically attached to the service, add tags starting with traefik.http.services.{name-of-your-choice}., followed by the option you want to change. For example, to change the passHostHeader behavior, you'd add the tag traefik.http.services.{name-of-your-choice}.loadbalancer.passhostheader=false. Configuration Options Label Description Value traefik.http.services..loadbalancer.server.port Registers a port. Useful when the service exposes multiples ports. 8080 traefik.http.services..loadbalancer.server.scheme Overrides the default scheme. http traefik.http.services..loadbalancer.server.weight Overrides the default weight. 42 traefik.http.services..loadbalancer.serverstransport Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one. See serverstransport for more information. foobar@file traefik.http.services..loadbalancer.passhostheader true traefik.http.services..loadbalancer.healthcheck.headers. See health check for more information. foobar traefik.http.services..loadbalancer.healthcheck.hostname See health check for more information. example.org traefik.http.services..loadbalancer.healthcheck.interval See health check for more information. 10 traefik.http.services..loadbalancer.healthcheck.unhealthyinterval See health check for more information. 10 traefik.http.services..loadbalancer.healthcheck.path See health check for more information. /foo traefik.http.services..loadbalancer.healthcheck.method See health check for more information. foobar traefik.http.services..loadbalancer.healthcheck.status See health check for more information. 42 traefik.http.services..loadbalancer.healthcheck.port See health check for more information. 42 traefik.http.services..loadbalancer.healthcheck.scheme See health check for more information. http traefik.http.services..loadbalancer.healthcheck.timeout See health check for more information. 10 traefik.http.services..loadbalancer.healthcheck.followredirects See health check for more information. true traefik.http.services..loadbalancer.sticky.cookie true traefik.http.services..loadbalancer.sticky.cookie.httponly true traefik.http.services..loadbalancer.sticky.cookie.name foobar traefik.http.services..loadbalancer.sticky.cookie.path /foobar traefik.http.services..loadbalancer.sticky.cookie.secure true traefik.http.services..loadbalancer.sticky.cookie.samesite none traefik.http.services..loadbalancer.sticky.cookie.maxage 42 traefik.http.services..loadbalancer.responseforwarding.flushinterval 10 Middleware You can declare pieces of middleware using tags starting with traefik.http.middlewares.{name-of-your-choice}., followed by the middleware type/options. For example, to declare a middleware redirectscheme named my-redirect, you'd write traefik.http.middlewares.my-redirect.redirectscheme.scheme: https. More information about available middlewares in the dedicated middlewares section. ??? example "Declaring and Referencing a Middleware" ```yaml # ... # Declaring a middleware traefik.http.middlewares.my-redirect.redirectscheme.scheme=https # Referencing a middleware traefik.http.routers.my-service.middlewares=my-redirect ``` !!! warning "Conflicts in Declaration" If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared. TCP You can declare TCP Routers, Middlewares and/or Services using tags. ??? example "Declaring TCP Routers and Services" ```yaml traefik.tcp.routers.my-router.rule=HostSNI(`example.com`) traefik.tcp.routers.my-router.tls=true traefik.tcp.services.my-service.loadbalancer.server.port=4123 ``` !!! warning "TCP and HTTP" If you declare a TCP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no TCP Router/Service is defined). You can declare both a TCP Router/Service and an HTTP Router/Service for the same consul service (but you have to do so manually). TCP Routers Configuration Options Label Description Value traefik.tcp.routers..entrypoints See entry points for more information. ep1,ep2 traefik.tcp.routers..rule See rule for more information. HostSNI(`example.com`) traefik.tcp.routers..ruleSyntax configure the rule syntax to be used for parsing the rule on a per-router basis. RuleSyntax option is deprecated and will be removed in the next major version. Please do not use this field and rewrite the router rules to use the v3 syntax. v3 traefik.tcp.routers..priority See priority for more information. 42 traefik.tcp.routers..service See service for more information. myservice traefik.tcp.routers..tls See TLS for more information. true traefik.tcp.routers..tls.certresolver See certResolver for more information. myresolver traefik.tcp.routers..tls.domains[n].main See TLS for more information. example.org traefik.tcp.routers..tls.domains[n].sans See TLS for more information. test.example.org,dev.example.org traefik.tcp.routers..tls.options See TLS for more information. mysoptions traefik.tcp.routers..tls.passthrough See Passthrough for more information. true TCP Services Configuration Options Label Description Value traefik.tcp.services..loadbalancer.server.port Registers a port of the application. 423 traefik.tcp.services..loadbalancer.server.tls Determines whether to use TLS when dialing with the backend. true traefik.tcp.services..loadbalancer.serverstransport Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one. See serverstransport for more information. foobar@file TCP Middleware You can declare pieces of middleware using tags starting with traefik.tcp.middlewares.{name-of-your-choice}., followed by the middleware type/options. For example, to declare a middleware InFlightConn named test-inflightconn, you'd write traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10. More information about available middlewares in the dedicated middlewares section. ??? example "Declaring and Referencing a Middleware" ```yaml # ... # Declaring a middleware traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10 # Referencing a middleware traefik.tcp.routers.my-service.middlewares=test-inflightconn ``` !!! warning "Conflicts in Declaration" If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared. UDP You can declare UDP Routers and/or Services using tags. ??? example "Declaring UDP Routers and Services" ```yaml traefik.udp.routers.my-router.entrypoints=udp traefik.udp.services.my-service.loadbalancer.server.port=4123 ``` !!! warning "UDP and HTTP" If you declare a UDP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no UDP Router/Service is defined). You can declare both a UDP Router/Service and an HTTP Router/Service for the same consul service (but you have to do so manually). UDP Routers Configuration Options Label Description Value traefik.udp.routers..entrypoints See entry points for more information. ep1,ep2 traefik.udp.routers..service See service for more information. myservice UDP Services Configuration Options Label Description Value traefik.udp.services..loadbalancer.server.port Registers a port of the application. 423 Specific Provider Options Label Description Value traefik.enable You can tell Traefik to consider (or not) the service by setting traefik.enable to true or false. This option overrides the value of exposedByDefault. true traefik.consulcatalog.connect You can tell Traefik to consider (or not) the service as a Connect capable one by setting traefik.consulcatalog.connect to true or false. This option overrides the value of connectByDefault. true traefik.consulcatalog.canary When ConsulCatalog, in the context of a Nomad orchestrator, is a provider (of service registration) for Traefik, one might have the need to distinguish within Traefik between a Canary instance of a service, or a production one. For example if one does not want them to be part of the same load-balancer. Therefore, this option, which is meant to be provided as one of the values of the canary_tags field in the Nomad service stanza, allows Traefik to identify that the associated instance is a canary one. true Port Lookup Traefik is capable of detecting the port to use, by following the default consul Catalog flow. That means, if you just expose lets say port :1337 on the consul Catalog ui, traefik will pick up this port and use it. Traefik & Docker One of the best feature of Traefik is to delegate the routing configuration to the application level. With Docker, Traefik can leverage labels attached to a container to generate routing rules. !!! warning "Labels & sensitive data" We recommend to *not* use labels to store sensitive data (certificates, credentials, etc). Instead, we recommend to store sensitive data in a safer storage (secrets, file, etc). Configuration Examples ??? example "Configuring Docker & Deploying / Exposing one Service" Enabling the docker provider ```yaml tab="Structured (YAML)" providers: docker: {} ``` ```toml tab="Structured (TOML)" [providers.docker] ``` ```bash tab="CLI" --providers.docker=true ``` Attaching labels to containers (in your docker compose file) ```yaml services: my-container: # ... labels: - traefik.http.routers.my-container.rule=Host(`example.com`) ``` ??? example "Specify a Custom Port for the Container" Forward requests for `http://example.com` to `http://:12345`: ```yaml services: my-container: # ... labels: - traefik.http.routers.my-container.rule=Host(`example.com`) # Tell Traefik to use the port 12345 to connect to `my-container` - traefik.http.services.my-service.loadbalancer.server.port=12345 ``` !!! important "Traefik Connecting to the Wrong Port: `HTTP/502 Gateway Error`" By default, Traefik uses the first exposed port of a container. Setting the label `traefik.http.services.xxx.loadbalancer.server.port` overrides that behavior. ??? example "Specifying more than one router and service per container" Forwarding requests to more than one port on a container requires referencing the service loadbalancer port definition using the service parameter on the router. In this example, requests are forwarded for `http://example-a.com` to `http://:8000` in addition to `http://example-b.com` forwarding to `http://:9000`: ```yaml services: my-container: # ... labels: - traefik.http.routers.www-router.rule=Host(`example-a.com`) - traefik.http.routers.www-router.service=www-service - traefik.http.services.www-service.loadbalancer.server.port=8000 - traefik.http.routers.admin-router.rule=Host(`example-b.com`) - traefik.http.routers.admin-router.service=admin-service - traefik.http.services.admin-service.loadbalancer.server.port=9000 ``` Configuration Options !!! info "Labels" - Labels are case-insensitive. !!! tip "TLS Default Generated Certificates" To learn how to configure Traefik default generated certificate, refer to the [TLS Certificates](../http/tls/tls-certificates.md#acme-default-certificate) page. General Traefik creates, for each container, a corresponding service and router. The Service automatically gets a server per instance of the container, and the router automatically gets a rule defined by defaultRule (if no rule for it was defined in labels). Service definition {% include-markdown "includes/service-by-label.md" %} ??? example "Automatic assignment with one Service" With labels in a compose file ```yaml labels: - "traefik.http.routers.myproxy.rule=Host(`example.net`)" # service myservice gets automatically assigned to router myproxy - "traefik.http.services.myservice.loadbalancer.server.port=80" ``` ??? example "Automatic service creation with one Router" With labels in a compose file ```yaml labels: # no service specified or defined and yet one gets automatically created # and assigned to router myproxy. - "traefik.http.routers.myproxy.rule=Host(`example.net`)" ``` ??? example "Explicit definition with one Service" With labels in a compose file ```yaml labels: - traefik.http.routers.www-router.rule=Host(`example-a.com`) # Explicit link between the router and the service - traefik.http.routers.www-router.service=www-service - traefik.http.services.www-service.loadbalancer.server.port=8000 ``` Routers To update the configuration of the Router automatically attached to the container, add labels starting with traefik.http.routers.. and followed by the option you want to change. For example, to change the rule, you could add the label traefik.http.routers.my-container.rule=Host(`example.com`). !!! warning "The character @ is not authorized in the router name ." Configuration Options Label Description Value traefik.http.routers..rule See rule for more information. Host(`example.com`) traefik.http.routers..ruleSyntax See ruleSyntax for more information. RuleSyntax option is deprecated and will be removed in the next major version. Please do not use this field and rewrite the router rules to use the v3 syntax. v3 traefik.http.routers..entrypoints See entry points for more information. ep1,ep2 traefik.http.routers..middlewares See middlewares overview for more information. auth,prefix,cb traefik.http.routers..service See service for more information. myservice traefik.http.routers..tls See tls for more information. true traefik.http.routers..tls.certresolver See certResolver for more information. myresolver traefik.http.routers..tls.domains[n].main See domains for more information. example.org traefik.http.routers..tls.domains[n].sans See domains for more information. test.example.org,dev.example.org traefik.http.routers..tls.options See TLS Options for more information, and Conflicting TLS Options when several routers serve the same host name. foobar traefik.http.routers..observability.accesslogs The accessLogs option controls whether the router will produce access-logs. true traefik.http.routers..observability.metrics The metrics option controls whether the router will produce metrics. true traefik.http.routers..observability.tracing The tracing option controls whether the router will produce traces. true traefik.http.routers..priority See priority for more information. 42 Services To update the configuration of the Service automatically attached to the container, add labels starting with traefik.http.services.., followed by the option you want to change. For example, to change the passHostHeader behavior, you'd add the label traefik.http.services..loadbalancer.passhostheader=false. !!! warning "The character @ is not authorized in the service name ." Configuration Options Label Description Value traefik.http.services..loadbalancer.server.port Registers a port. Useful when the container exposes multiples ports. 8080 traefik.http.services..loadbalancer.server.scheme Overrides the default scheme. http traefik.http.services..loadbalancer.server.url Defines the service URL. This option cannot be used in combination with port or scheme definition. http://foobar:8080 traefik.http.services..loadbalancer.serverstransport Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one. See serverstransport for more information. foobar@file traefik.http.services..loadbalancer.passhostheader true traefik.http.services..loadbalancer.healthcheck.headers. See health check for more information. foobar traefik.http.services..loadbalancer.healthcheck.hostname See health check for more information. example.org traefik.http.services..loadbalancer.healthcheck.interval See health check for more information. 10s traefik.http.services..loadbalancer.healthcheck.unhealthyinterval See health check for more information. 10s traefik.http.services..loadbalancer.healthcheck.path See health check for more information. /foo traefik.http.services..loadbalancer.healthcheck.method See health check for more information. foobar traefik.http.services..loadbalancer.healthcheck.status See health check for more information. 42 traefik.http.services..loadbalancer.healthcheck.port See health check for more information. 42 traefik.http.services..loadbalancer.healthcheck.scheme See health check for more information. http traefik.http.services..loadbalancer.healthcheck.timeout See health check for more information. 10s traefik.http.services..loadbalancer.healthcheck.followredirects See health check for more information. true traefik.http.services..loadbalancer.sticky.cookie true traefik.http.services..loadbalancer.sticky.cookie.httponly true traefik.http.services..loadbalancer.sticky.cookie.name foobar traefik.http.services..loadbalancer.sticky.cookie.path /foobar traefik.http.services..loadbalancer.sticky.cookie.secure true traefik.http.services..loadbalancer.sticky.cookie.samesite none traefik.http.services..loadbalancer.sticky.cookie.maxage 42 traefik.http.services..loadbalancer.responseforwarding.flushinterval 10 Middleware You can declare pieces of middleware using labels starting with traefik.http.middlewares.., followed by the middleware type/options. For example, to declare a middleware redirectscheme named my-redirect, you'd write traefik.http.middlewares.my-redirect.redirectscheme.scheme=https. More information about available middlewares in the dedicated middlewares section. !!! warning "The character @ is not authorized in the middleware name." ??? example "Declaring and Referencing a Middleware" ```yaml services: my-container: # ... labels: # Declaring a middleware - traefik.http.middlewares.my-redirect.redirectscheme.scheme=https # Referencing a middleware - traefik.http.routers.my-container.middlewares=my-redirect ``` !!! warning "Conflicts in Declaration" If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared. TCP You can declare TCP Routers and/or Services using labels. ??? example "Declaring TCP Routers with one Service" ```yaml services: my-container: # ... labels: - "traefik.tcp.routers.my-router.rule=HostSNI(`example.com`)" - "traefik.tcp.routers.my-router.tls=true" - "traefik.tcp.services.my-service.loadbalancer.server.port=4123" ``` !!! warning "TCP and HTTP" If you declare a TCP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no TCP Router/Service is defined). You can declare both a TCP Router/Service and an HTTP Router/Service for the same container (but you have to do so manually). TCP Routers Configuration Options Label Description Value traefik.tcp.routers..entrypoints See entry points for more information. ep1,ep2 traefik.tcp.routers..rule See rule for more information. HostSNI(`example.com`) traefik.tcp.routers..ruleSyntax configure the rule syntax to be used for parsing the rule on a per-router basis. RuleSyntax option is deprecated and will be removed in the next major version. Please do not use this field and rewrite the router rules to use the v3 syntax. v3 traefik.tcp.routers..service See service for more information. myservice traefik.tcp.routers..tls See TLS for more information. true traefik.tcp.routers..tls.certresolver See certResolver for more information. myresolver traefik.tcp.routers..tls.domains[n].main See TLS for more information. example.org traefik.tcp.routers..tls.domains[n].sans See TLS for more information. test.example.org,dev.example.org traefik.tcp.routers..tls.options See TLS for more information. mysoptions traefik.tcp.routers..tls.passthrough See Passthrough for more information. true traefik.tcp.routers..priority See priority for more information. 42 TCP Services Configuration Options Label Description Value traefik.tcp.services..loadbalancer.server.port Registers a port of the application. 423 traefik.tcp.services..loadbalancer.server.tls Determines whether to use TLS when dialing with the backend. true traefik.tcp.services..loadbalancer.serverstransport Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one. See serverstransport for more information. foobar@file TCP Middleware You can declare pieces of middleware using tags starting with traefik.tcp.middlewares.{name-of-your-choice}., followed by the middleware type/options. For example, to declare a middleware InFlightConn named test-inflightconn, you'd write traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10. More information about available middlewares in the dedicated middlewares section. ??? example "Declaring and Referencing a Middleware" ```yaml # ... # Declaring a middleware traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10 # Referencing a middleware traefik.tcp.routers.my-service.middlewares=test-inflightconn ``` !!! warning "Conflicts in Declaration" If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared. UDP You can declare UDP Routers and/or Services using labels. ??? example "Declaring UDP Routers with one Service" ```yaml services: my-container: # ... labels: - "traefik.udp.routers.my-router.entrypoints=udp" - "traefik.udp.services.my-service.loadbalancer.server.port=4123" ``` !!! warning "UDP and HTTP" If you declare a UDP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no UDP Router/Service is defined). You can declare both a UDP Router/Service and an HTTP Router/Service for the same container (but you have to do so manually). UDP Routers Configuration Options Label Description Value traefik.udp.routers..entrypoints See entry points for more information. ep1,ep2 traefik.udp.routers..service See service for more information. myservice UDP Services Configuration Options Label Description Value traefik.udp.services..loadbalancer.server.port Registers a port of the application. 423 Specific Provider Options Label Description Value traefik.enable You can tell Traefik to consider (or not) the container by setting traefik.enable to true or false. This option overrides the value of exposedByDefault. true traefik.docker.allownonrunning By default, Traefik only considers containers in "running" state. This option controls whether containers that are not in "running" state (e.g., stopped, paused, exited) should still be visible to Traefik for service discovery. When this label is set to true, Traefik will: - Keep the router and service configuration even when the container is not running - Create services with empty backend server lists - Return 503 Service Unavailable for requests to stopped containers (instead of 404 Not Found) - Execute the full middleware chain, allowing middlewares to intercept requests As the traefik.docker.allownonrunning enables the discovery of all containers exposing this option disregarding their state, if multiple stopped containers expose the same router but their configurations diverge, then the routers will be dropped. true traefik.docker.network Overrides the default docker network to use for connections to the container. If a container is linked to several networks, be sure to set the proper network name (you can check this with docker inspect ), otherwise it will randomly pick one (depending on how docker is returning them). When deploying a stack from a compose file stack, the networks defined are prefixed with stack. mynetwork Traefik & ECS One of the best feature of Traefik is to delegate the routing configuration to the application level. With ECS, Traefik can leverage labels attached to a container to generate routing rules. !!! warning "Labels & sensitive data" We recommend to *not* use labels to store sensitive data (certificates, credentials, etc). Instead, we recommend to store sensitive data in a safer storage (secrets, file, etc). Configuration Examples ??? example "Configuring ECS & Deploying / Exposing one Service" Enabling the ECS provider ```yaml tab="Structured (YAML)" providers: ecs: {} ``` ```toml tab="Structured (TOML)" [providers.ecs] ``` ```bash tab="CLI" --providers.ecs=true ``` Attaching labels to containers (in your ECS task definition) ```json { "family": "my-service", "containerDefinitions": [ { "name": "my-container", "image": "my-image:latest", "labels": { "traefik.http.routers.my-container.rule": "Host(`example.com`)" } } ] } ``` ??? example "Specify a Custom Port for the Container" Forward requests for `http://example.com` to `http://:12345`: ```json { "family": "my-service", "containerDefinitions": [ { "name": "my-container", "image": "my-image:latest", "labels": { "traefik.http.routers.my-container.rule": "Host(`example.com`)", "traefik.http.routers.my-container.service": "my-service", "traefik.http.services.my-service.loadbalancer.server.port": "12345" } } ] } ``` !!! important "Traefik Connecting to the Wrong Port: `HTTP/502 Gateway Error`" By default, Traefik uses the first exposed port of a container. Setting the label `traefik.http.services.xxx.loadbalancer.server.port` overrides that behavior. ??? example "Specifying more than one router and service per container" Forwarding requests to more than one port on a container requires referencing the service loadbalancer port definition using the service parameter on the router. In this example, requests are forwarded for `http://example-a.com` to `http://:8000` in addition to `http://example-b.com` forwarding to `http://:9000`: ```json { "family": "my-service", "containerDefinitions": [ { "name": "my-container", "image": "my-image:latest", "labels": { "traefik.http.routers.www-router.rule": "Host(`example-a.com`)", "traefik.http.routers.www-router.service": "www-service", "traefik.http.services.www-service.loadbalancer.server.port": "8000", "traefik.http.routers.admin-router.rule": "Host(`example-b.com`)", "traefik.http.routers.admin-router.service": "admin-service", "traefik.http.services.admin-service.loadbalancer.server.port": "9000" } } ] } ``` Configuration Options !!! info "labels" Labels are case-insensitive. !!! tip "TLS Default Generated Certificates" To learn how to configure Traefik default generated certificate, refer to the [TLS Certificates](../http/tls/tls-certificates.md#acme-default-certificate) page. General Traefik creates, for each elastic service, a corresponding service and router. The Service automatically gets a server per elastic container, and the router gets a default rule attached to it, based on the service name. Routers To update the configuration of the Router automatically attached to the service, add labels starting with traefik.routers.{name-of-your-choice}. and followed by the option you want to change. For example, to change the rule, you could add the label traefik.http.routers.my-service.rule=Host(`example.com`). !!! warning "The character @ is not authorized in the router name ." Configuration Options Label Description Value traefik.http.routers..rule See rule for more information. Host(`example.com`) traefik.http.routers..ruleSyntax See ruleSyntax for more information. RuleSyntax option is deprecated and will be removed in the next major version. Please do not use this field and rewrite the router rules to use the v3 syntax. v3 traefik.http.routers..entrypoints See entry points for more information. web,websecure traefik.http.routers..middlewares See middlewares overview for more information. auth,prefix,cb traefik.http.routers..service See service for more information. myservice traefik.http.routers..tls See tls for more information. true traefik.http.routers..tls.certresolver See certResolver for more information. myresolver traefik.http.routers..tls.domains[n].main See domains for more information. example.org traefik.http.routers..tls.domains[n].sans See domains for more information. test.example.org,dev.example.org traefik.http.routers..tls.options See TLS Options for more information, and Conflicting TLS Options when several routers serve the same host name. foobar traefik.http.routers..observability.accesslogs The accessLogs option controls whether the router will produce access-logs. true traefik.http.routers..observability.metrics The metrics option controls whether the router will produce metrics. true traefik.http.routers..observability.tracing The tracing option controls whether the router will produce traces. true traefik.http.routers..priority See priority for more information. 42 Services To update the configuration of the Service automatically attached to the service, add labels starting with traefik.http.services.{name-of-your-choice}., followed by the option you want to change. For example, to change the passHostHeader behavior, you'd add the label traefik.http.services.{name-of-your-choice}.loadbalancer.passhostheader=false. !!! warning "The character @ is not authorized in the service name ." Configuration Options Label Description Value traefik.http.services..loadbalancer.server.port Registers a port. Useful when the service exposes multiples ports. 8080 traefik.http.services..loadbalancer.server.scheme Overrides the default scheme. http traefik.http.services..loadbalancer.serverstransport Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one. See serverstransport for more information. foobar@file traefik.http.services..loadbalancer.passhostheader true traefik.http.services..loadbalancer.healthcheck.headers. See health check for more information. foobar traefik.http.services..loadbalancer.healthcheck.hostname See health check for more information. example.org traefik.http.services..loadbalancer.healthcheck.interval See health check for more information. 10 traefik.http.services..loadbalancer.healthcheck.unhealthyinterval See health check for more information. 10 traefik.http.services..loadbalancer.healthcheck.path See health check for more information. /foo traefik.http.services..loadbalancer.healthcheck.method See health check for more information. foobar traefik.http.services..loadbalancer.healthcheck.status See health check for more information. 42 traefik.http.services..loadbalancer.healthcheck.port See health check for more information. 42 traefik.http.services..loadbalancer.healthcheck.scheme See health check for more information. http traefik.http.services..loadbalancer.healthcheck.timeout See health check for more information. 10 traefik.http.services..loadbalancer.healthcheck.followredirects See health check for more information. true traefik.http.services..loadbalancer.sticky.cookie true traefik.http.services..loadbalancer.sticky.cookie.httponly true traefik.http.services..loadbalancer.sticky.cookie.name foobar traefik.http.services..loadbalancer.sticky.cookie.path /foobar traefik.http.services..loadbalancer.sticky.cookie.secure true traefik.http.services..loadbalancer.sticky.cookie.samesite none traefik.http.services..loadbalancer.sticky.cookie.maxage 42 traefik.http.services..loadbalancer.responseforwarding.flushinterval FlushInterval specifies the flush interval to flush to the client while copying the response body. 10 Middleware You can declare pieces of middleware using labels starting with traefik.http.middlewares.{name-of-your-choice}., followed by the middleware type/options. For example, to declare a middleware redirectscheme named my-redirect, you'd write traefik.http.middlewares.my-redirect.redirectscheme.scheme: https. More information about available middlewares in the dedicated middlewares section. !!! warning "The character @ is not authorized in the middleware name." ??? example "Declaring and Referencing a Middleware" ```yaml # ... # Declaring a middleware traefik.http.middlewares.my-redirect.redirectscheme.scheme=https # Referencing a middleware traefik.http.routers.my-service.middlewares=my-redirect ``` !!! warning "Conflicts in Declaration" If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared. TCP You can declare TCP Routers and/or Services using labels. ??? example "Declaring TCP Routers and Services" ```yaml traefik.tcp.routers.my-router.rule=HostSNI(`example.com`) traefik.tcp.routers.my-router.tls=true traefik.tcp.services.my-service.loadbalancer.server.port=4123 ``` !!! warning "TCP and HTTP" If you declare a TCP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no TCP Router/Service is defined). You can declare both a TCP Router/Service and an HTTP Router/Service for the same elastic service (but you have to do so manually). TCP Routers Configuration Options Label Description Value traefik.tcp.routers..entrypoints See entry points for more information. ep1,ep2 traefik.tcp.routers..rule See rule for more information. HostSNI(`example.com`) traefik.tcp.routers..ruleSyntax configure the rule syntax to be used for parsing the rule on a per-router basis. RuleSyntax option is deprecated and will be removed in the next major version. Please do not use this field and rewrite the router rules to use the v3 syntax. v3 traefik.tcp.routers..service See service for more information. myservice traefik.tcp.routers..tls See TLS for more information. true traefik.tcp.routers..tls.certresolver See certResolver for more information. myresolver traefik.tcp.routers..tls.domains[n].main See TLS for more information. example.org traefik.tcp.routers..tls.domains[n].sans See TLS for more information. test.example.org,dev.example.org traefik.tcp.routers..tls.options See TLS for more information. mysoptions traefik.tcp.routers..tls.passthrough See Passthrough for more information. true traefik.tcp.routers..priority See priority for more information. 42 TCP Services Configuration Options Label Description Value traefik.tcp.services..loadbalancer.server.port Registers a port of the application. 423 traefik.tcp.services..loadbalancer.server.tls Determines whether to use TLS when dialing with the backend. true traefik.tcp.services..loadbalancer.serverstransport Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one. See serverstransport for more information. foobar@file UDP You can declare UDP Routers and/or Services using tags. ??? example "Declaring UDP Routers and Services" ```yaml traefik.udp.routers.my-router.entrypoints=udp traefik.udp.services.my-service.loadbalancer.server.port=4123 ``` !!! warning "UDP and HTTP" If you declare a UDP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no UDP Router/Service is defined). You can declare both a UDP Router/Service and an HTTP Router/Service for the same elastic service (but you have to do so manually). TCP Middleware You can declare pieces of middleware using tags starting with traefik.tcp.middlewares.{name-of-your-choice}., followed by the middleware type/options. For example, to declare a middleware InFlightConn named test-inflightconn, you'd write traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10. More information about available middlewares in the dedicated middlewares section. ??? example "Declaring and Referencing a Middleware" ```yaml # ... # Declaring a middleware traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10 # Referencing a middleware traefik.tcp.routers.my-service.middlewares=test-inflightconn ``` !!! warning "Conflicts in Declaration" If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared. UDP Routers Configuration Options Label Description Value traefik.udp.routers..entrypoints See entry points for more information. ep1,ep2 traefik.udp.routers..service See service for more information. myservice UDP Services Configuration Options Label Description Value traefik.udp.services..loadbalancer.server.port Registers a port of the application. 423 Specific Provider Options Configuration Options Label Description Value traefik.enable You can tell Traefik to consider (or not) the ECS service by setting traefik.enable to true or false. This option overrides the value of exposedByDefault. true Traefik File Routing Configuration The file provider lets you define routing configuration in YAML or TOML. Use it to declare routers, services, middlewares, TCP and UDP routing, and TLS options that Traefik should load from a file or a directory. To configure the file provider itself, see the File provider install configuration page. Configuration Examples ??? example "Configuring the File Provider and Exposing One HTTP Service" Enabling the file provider: ```yaml tab="Structured (YAML)" providers: file: filename: /etc/traefik/dynamic.yml ``` ```toml tab="Structured (TOML)" [providers.file] filename = "/etc/traefik/dynamic.toml" ``` ```bash tab="CLI" --providers.file.filename=/etc/traefik/dynamic.yml ``` Declaring the dynamic HTTP configuration: ```yaml tab="Structured (YAML)" http: routers: app: rule: Host(`example.com`) entryPoints: - websecure service: app tls: {} services: app: loadBalancer: servers: - url: http://127.0.0.1:8080 ``` ```toml tab="Structured (TOML)" [http.routers.app] rule = "Host(`example.com`)" entryPoints = ["websecure"] service = "app" [http.routers.app.tls] [http.services.app.loadBalancer] [[http.services.app.loadBalancer.servers]] url = "http://127.0.0.1:8080" ``` ??? example "Specifying More Than One Router and Service" Define each router and explicitly attach it to the service that should handle matching requests. ```yaml tab="Structured (YAML)" http: routers: app: rule: Host(`example-a.com`) service: app admin: rule: Host(`example-b.com`) service: admin services: app: loadBalancer: servers: - url: http://127.0.0.1:8000 admin: loadBalancer: servers: - url: http://127.0.0.1:9000 ``` ```toml tab="Structured (TOML)" [http.routers.app] rule = "Host(`example-a.com`)" service = "app" [http.routers.admin] rule = "Host(`example-b.com`)" service = "admin" [http.services.app.loadBalancer] [[http.services.app.loadBalancer.servers]] url = "http://127.0.0.1:8000" [http.services.admin.loadBalancer] [[http.services.admin.loadBalancer.servers]] url = "http://127.0.0.1:9000" ``` ??? example "Declaring and Referencing Middlewares" Middlewares declared by the file provider can be used by routers from the file provider or by routers from other providers. When another provider references them, use the `@file` provider suffix. ```yaml tab="Structured (YAML)" http: routers: app: rule: Host(`secure.example.com`) entryPoints: - websecure middlewares: - secure-headers service: app tls: options: modern middlewares: secure-headers: headers: stsSeconds: 31536000 forceSTSHeader: true services: app: loadBalancer: servers: - url: http://127.0.0.1:8080 tls: options: modern: minVersion: VersionTLS12 sniStrict: true ``` ```toml tab="Structured (TOML)" [http.routers.app] rule = "Host(`secure.example.com`)" entryPoints = ["websecure"] middlewares = ["secure-headers"] service = "app" [http.routers.app.tls] options = "modern" [http.middlewares.secure-headers.headers] stsSeconds = 31536000 forceSTSHeader = true [http.services.app.loadBalancer] [[http.services.app.loadBalancer.servers]] url = "http://127.0.0.1:8080" [tls.options.modern] minVersion = "VersionTLS12" sniStrict = true ``` ??? example "Loading Multiple Dynamic Configuration Files" Configure the file provider with a directory when you want to split dynamic configuration across multiple files. ```yaml tab="Structured (YAML)" providers: file: directory: /etc/traefik/dynamic watch: true ``` ```toml tab="Structured (TOML)" [providers.file] directory = "/etc/traefik/dynamic" watch = true ``` ```bash tab="CLI" --providers.file.directory=/etc/traefik/dynamic --providers.file.watch=true ``` Example `/etc/traefik/dynamic/http.yml`: ```yaml http: routers: app: rule: Host(`example.com`) service: app services: app: loadBalancer: servers: - url: http://127.0.0.1:8080 ``` Example `/etc/traefik/dynamic/tls.yml`: ```yaml tls: certificates: - certFile: /certs/example.crt keyFile: /certs/example.key ``` Configuration Options General The file provider does not discover services automatically. Define every router, service, middleware, and TLS resource explicitly in the routing configuration file. When another provider references a resource declared by the file provider, append the @file provider suffix. For example, a Docker label can reference a file-provider middleware with secure-headers@file. The examples below use YAML-style field paths. In TOML, use the equivalent table and array syntax, such as [http.routers.] and [[http.services..loadBalancer.servers]]. HTTP Routers Define HTTP routers under http.routers.. !!! warning "The character @ is not authorized in the router name ." Field Description Value http.routers..rule See rule for more information. Host(`example.com`) http.routers..ruleSyntax See ruleSyntax for more information. RuleSyntax is deprecated and will be removed in the next major version. v3 http.routers..entryPoints[n] See entry points for more information. websecure http.routers..middlewares[n] See middlewares overview for more information. secure-headers http.routers..service See service for more information. app http.routers..parentRefs[n] See multi-layer routing for more information. parent-router@file http.routers..tls See TLS for more information. {} http.routers..tls.certResolver See certResolver for more information. myresolver http.routers..tls.domains[n].main See domains for more information. example.org http.routers..tls.domains[n].sans[n] See domains for more information. www.example.org http.routers..tls.options See TLS options for more information. modern http.routers..observability.accessLogs Enables or disables access logs for the router. true http.routers..observability.metrics Enables or disables metrics for the router. true http.routers..observability.tracing Enables or disables tracing for the router. true http.routers..observability.traceVerbosity See trace verbosity for more information. minimal http.routers..priority See priority for more information. 42 Services Define HTTP services under http.services.. !!! warning "The character @ is not authorized in the service name ." Field Description Value http.services..loadBalancer.servers[n].url See servers for more information. http://127.0.0.1:8080 http.services..loadBalancer.servers[n].weight See servers for more information. 1 http.services..loadBalancer.servers[n].preservePath See servers for more information. true http.services..loadBalancer.strategy See load balancing strategies for more information. wrr http.services..loadBalancer.passHostHeader See service load balancer for more information. true http.services..loadBalancer.healthCheck.* See health check for more information. path: /health http.services..loadBalancer.passiveHealthCheck.* See passive health check for more information. maxFailedAttempts: 3 http.services..loadBalancer.sticky.cookie.* See sticky sessions for more information. name: app-cookie http.services..loadBalancer.responseForwarding.flushInterval See service load balancer for more information. 100ms http.services..loadBalancer.serversTransport See ServersTransport for more information. secure-transport http.services..weighted.services[n].name See weighted round robin for more information. app-v1 http.services..weighted.services[n].weight See weighted round robin for more information. 3 http.services..weighted.sticky.cookie.* See sticky sessions for more information. name: app-cookie http.services..weighted.healthCheck See weighted service health check for more information. {} http.services..highestRandomWeight.services[n].name See highest random weight for more information. app-v1 http.services..highestRandomWeight.services[n].weight See highest random weight for more information. 3 http.services..highestRandomWeight.healthCheck See highest random weight for more information. {} http.services..mirroring.service See mirroring for more information. app-main http.services..mirroring.mirrorBody See mirroring for more information. true http.services..mirroring.maxBodySize See mirroring for more information. 1048576 http.services..mirroring.streamBody See mirroring for more information. false http.services..mirroring.mirrors[n].name See mirroring for more information. app-shadow http.services..mirroring.mirrors[n].percent See mirroring for more information. 10 http.services..mirroring.healthCheck See mirroring for more information. {} http.services..failover.service See failover for more information. app-main http.services..failover.fallback See failover for more information. app-backup http.services..failover.healthCheck See failover for more information. {} Middlewares Define HTTP middlewares under http.middlewares.. For example, to declare an AddPrefix middleware named add-api, set http.middlewares.add-api.addPrefix.prefix=/api. More information about available middlewares can be found in the dedicated middlewares section. !!! warning "The character @ is not authorized in the middleware name ." !!! warning "Conflicts in Declaration" If you declare multiple middlewares with the same name but different parameters, the middleware fails to be declared. Field Description Value http.middlewares... With middleware_type the middleware type, such as addPrefix or headers, and middleware_option the option to set. prefix: /api ServersTransports Define HTTP ServersTransports under http.serversTransports.. Field Description Value http.serversTransports..* See ServersTransport for more information. serverName: example.org TCP You can declare TCP routers, services, middlewares, and ServersTransports with the file provider. TCP Routers Define TCP routers under tcp.routers.. !!! warning "The character @ is not authorized in the router name ." Field Description Value tcp.routers..entryPoints[n] See entry points for more information. websecure tcp.routers..rule See rule for more information. HostSNI(`example.com`) tcp.routers..ruleSyntax Configures the rule syntax to use for parsing the rule on a per-router basis. RuleSyntax is deprecated and will be removed in the next major version. v3 tcp.routers..middlewares[n] See TCP middlewares overview for more information. ip-allowlist tcp.routers..service See service for more information. tcp-app tcp.routers..tls See TLS for more information. {} tcp.routers..tls.certResolver See certResolver for more information. myresolver tcp.routers..tls.domains[n].main See TLS for more information. example.org tcp.routers..tls.domains[n].sans[n] See TLS for more information. www.example.org tcp.routers..tls.options See TLS for more information. modern tcp.routers..tls.passthrough See Passthrough for more information. true tcp.routers..priority See priority for more information. 42 TCP Services Define TCP services under tcp.services.. !!! warning "The character @ is not authorized in the service name ." Field Description Value tcp.services..loadBalancer.servers[n].address See servers load balancer for more information. 127.0.0.1:9000 tcp.services..loadBalancer.servers[n].tls Determines whether to use TLS when dialing the backend server. true tcp.services..loadBalancer.serversTransport See TCP ServersTransport for more information. secure-tcp tcp.services..loadBalancer.proxyProtocol.version Enables Proxy Protocol for backend connections. 2 tcp.services..loadBalancer.terminationDelay Defines the delay before terminating connections. 100 tcp.services..loadBalancer.healthCheck.* See TCP service health check for more information. interval: 10s tcp.services..weighted.services[n].name See weighted round robin for more information. tcp-v1 tcp.services..weighted.services[n].weight See weighted round robin for more information. 3 tcp.services..weighted.healthCheck See weighted round robin for more information. {} TCP Middlewares Define TCP middlewares under tcp.middlewares.. For example, to declare an InFlightConn middleware named limit, set tcp.middlewares.limit.inFlightConn.amount=10. More information about available middlewares is available in the dedicated TCP middlewares section. !!! warning "The character @ is not authorized in the middleware name ." !!! warning "Conflicts in Declaration" If you declare multiple middlewares with the same name but different parameters, the middleware fails to be declared. Field Description Value tcp.middlewares... With middleware_type the middleware type, such as inFlightConn, and middleware_option the option to set. amount: 10 TCP ServersTransports Define TCP ServersTransports under tcp.serversTransports.. Field Description Value tcp.serversTransports..* See TCP ServersTransport for more information. dialTimeout: 30s UDP You can declare UDP routers and services with the file provider. UDP Routers Define UDP routers under udp.routers.. !!! warning "The character @ is not authorized in the router name ." Field Description Value udp.routers..entryPoints[n] See UDP router entrypoints for more information. dns udp.routers..service See UDP router configuration for more information. dns-service UDP Services Define UDP services under udp.services.. !!! warning "The character @ is not authorized in the service name ." Field Description Value udp.services..loadBalancer.servers[n].address See UDP service for more information. 127.0.0.1:5353 udp.services..weighted.services[n].name See UDP service for more information. dns-v1 udp.services..weighted.services[n].weight See UDP service for more information. 3 TLS You can declare TLS certificates, options, and stores with the file provider. Certificates Field Description Value tls.certificates[n].certFile See TLS certificates for more information. /certs/example.crt tls.certificates[n].keyFile See TLS certificates for more information. /certs/example.key tls.certificates[n].stores[n] See certificate stores for more information. default TLS Options Field Description Value tls.options..minVersion See TLS options for more information. VersionTLS12 tls.options..maxVersion See TLS options for more information. VersionTLS13 tls.options..cipherSuites[n] See TLS options for more information. TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 tls.options..curvePreferences[n] See TLS options for more information. CurveP256 tls.options..clientAuth.caFiles[n] See client authentication for more information. /certs/client-ca.crt tls.options..clientAuth.clientAuthType See client authentication for more information. RequireAndVerifyClientCert tls.options..sniStrict See strict SNI checking for more information. true tls.options..alpnProtocols[n] See TLS options for more information. h2 tls.options..disableSessionTickets See TLS options for more information. true tls.options..preferServerCipherSuites Deprecated: This option is no longer effective and will be ignored by the Go TLS stack. See TLS options for more information. true TLS Stores Field Description Value tls.stores..defaultCertificate.certFile See default certificate for more information. /certs/default.crt tls.stores..defaultCertificate.keyFile See default certificate for more information. /certs/default.key tls.stores..defaultGeneratedCert.resolver See ACME default certificate for more information. myresolver tls.stores..defaultGeneratedCert.domain.main See ACME default certificate for more information. example.org tls.stores..defaultGeneratedCert.domain.sans[n] See ACME default certificate for more information. www.example.org Go Templating !!! warning Go Templating only works with dedicated dynamic configuration files. Templating does not work in the Traefik main static configuration file. Traefik supports using Go templating to automatically generate repetitive sections of configuration files. These sections must be a valid Go template, and can use sprig template functions. To illustrate, it is possible to easily define multiple routers, services, and TLS certificates as described in the following examples: ??? example "Configuring Using Templating" ```yaml tab="YAML" http: routers: {{range $i, $e := until 100 }} router{{ $e }}-{{ env "MY_ENV_VAR" }}: # ... {{end}} services: {{range $i, $e := until 100 }} application{{ $e }}: # ... {{end}} tcp: routers: {{range $i, $e := until 100 }} router{{ $e }}: # ... {{end}} services: {{range $i, $e := until 100 }} service{{ $e }}: # ... {{end}} tls: certificates: {{ range $i, $e := until 10 }} - certFile: "/etc/traefik/cert-{{ $e }}.pem" keyFile: "/etc/traefik/cert-{{ $e }}.key" stores: - "my-store-foo-{{ $e }}" - "my-store-bar-{{ $e }}" {{end}} ``` ```toml tab="TOML" # template-rules.toml [http] [http.routers] {{ range $i, $e := until 100 }} [http.routers.router{{ $e }}-{{ env "MY_ENV_VAR" }}] # ... {{ end }} [http.services] {{ range $i, $e := until 100 }} [http.services.service{{ $e }}] # ... {{ end }} [tcp] [tcp.routers] {{ range $i, $e := until 100 }} [tcp.routers.router{{ $e }}] # ... {{ end }} [tcp.services] {{ range $i, $e := until 100 }} [tcp.services.service{{ $e }}] # ... {{ end }} {{ range $i, $e := until 10 }} [[tls.certificates]] certFile = "/etc/traefik/cert-{{ $e }}.pem" keyFile = "/etc/traefik/cert-{{ $e }}.key" stores = ["my-store-foo-{{ $e }}", "my-store-bar-{{ $e }}"] {{ end }} [tls.options] {{ range $i, $e := until 10 }} [tls.options.TLS{{ $e }}] # ... {{ end }} ``` Traefik & KV Stores Configuration Examples ??? example "Configuring KV Store & Deploying / Exposing one Service" Enabling a KV store provider (example: Consul) ```yaml tab="Structured (YAML)" providers: consul: endpoints: - "127.0.0.1:8500" ``` ```toml tab="Structured (TOML)" [providers.consul] endpoints = ["127.0.0.1:8500"] ``` ```bash tab="CLI" --providers.consul.endpoints=127.0.0.1:8500 ``` Setting keys in the KV store (example: Consul) ```bash consul kv put traefik/http/routers/my-router/rule "Host(`example.com`)" consul kv put traefik/http/routers/my-router/service "my-service" consul kv put traefik/http/services/my-service/loadbalancer/servers/0/url "http://127.0.0.1:8080" ``` ??? example "Specify a Custom Port for the Service" Forward requests for `http://example.com` to `http://127.0.0.1:12345`: ```bash consul kv put traefik/http/routers/my-router/rule "Host(`example.com`)" consul kv put traefik/http/routers/my-router/service "my-service" consul kv put traefik/http/services/my-service/loadbalancer/servers/0/url "http://127.0.0.1:12345" ``` ??? example "Specifying more than one router and service" Forwarding requests to more than one service requires defining multiple routers and services. In this example, requests are forwarded for `http://example-a.com` to `http://127.0.0.1:8000` in addition to `http://example-b.com` forwarding to `http://127.0.0.1:9000`: ```bash consul kv put traefik/http/routers/www-router/rule "Host(`example-a.com`)" consul kv put traefik/http/routers/www-router/service "www-service" consul kv put traefik/http/services/www-service/loadbalancer/servers/0/url "http://127.0.0.1:8000" consul kv put traefik/http/routers/admin-router/rule "Host(`example-b.com`)" consul kv put traefik/http/routers/admin-router/service "admin-service" consul kv put traefik/http/services/admin-service/loadbalancer/servers/0/url "http://127.0.0.1:9000" ``` Configuration Options !!! info "Keys" Keys are case-insensitive. HTTP Routers !!! warning "The character @ is not authorized in the router name ." Key (Path) Description Value traefik/http/routers//rule See rule for more information. Host(`example.com`) traefik/http/routers//ruleSyntax See rule for more information. RuleSyntax option is deprecated and will be removed in the next major version. Please do not use this field and rewrite the router rules to use the v3 syntax. v3 traefik/http/routers//entrypoints/0 See entry points for more information. web traefik/http/routers//entrypoints/1 See entry points for more information. websecure traefik/http/routers//middlewares/0 See middlewares overview for more information. auth traefik/http/routers//middlewares/1 prefix traefik/http/routers//service See service for more information. myservice traefik/http/routers//tls See tls for more information. true traefik/http/routers//tls/certresolver See certResolver for more information. myresolver traefik/http/routers//tls/domains/0/main See domains for more information. example.org traefik/http/routers//tls/domains/0/sans/0 See domains for more information. test.example.org traefik/http/routers//tls/domains/0/sans/1 See domains for more information. dev.example.org traefik/http/routers//tls/options See TLS Options for more information. foobar traefik/http/routers//observability/accesslogs The accessLogs option controls whether the router will produce access-logs. true traefik/http/routers//observability/metrics The metrics option controls whether the router will produce metrics. true traefik/http/routers//observability/tracing The tracing option controls whether the router will produce traces. true traefik/http/routers//priority See priority for more information. 42 Services !!! warning "The character @ is not authorized in the service name ." Key (Path) Description Value traefik/http/services//loadbalancer/servers/0/url See servers for more information. http://:/ traefik/http/services//loadbalancer/servers/0/preservePath See servers for more information. true traefik/http/services//loadbalancer/servers/0/weight See servers for more information. 1 traefik/http/services//loadbalancer/serverstransport Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one. See serverstransport for more information. foobar@file traefik/http/services//loadbalancer/passhostheader See Service for more information. true traefik/http/services//loadbalancer/healthcheck/headers/X-Foo See health check for more information. foobar traefik/http/services//loadbalancer/healthcheck/hostname See health check for more information. example.org traefik/http/services//loadbalancer/healthcheck/interval See health check for more information. 10 traefik/http/services//loadbalancer/healthcheck/path See health check for more information. /foo traefik/http/services//loadbalancer/healthcheck/method See health check for more information. foobar traefik/http/services//loadbalancer/healthcheck/status See health check for more information. 42 traefik/http/services//loadbalancer/healthcheck/port See health check for more information. 42 traefik/http/services//loadbalancer/healthcheck/scheme See health check for more information. http traefik/http/services//loadbalancer/healthcheck/timeout See health check for more information. 10 traefik/http/services//loadbalancer/sticky See Service for more information. true traefik/http/services//loadbalancer/sticky/cookie/httponly See Service for more information. true traefik/http/services//loadbalancer/sticky/cookie/name See Service for more information. foobar traefik/http/services//loadbalancer/sticky/cookie/path See Service for more information. /foobar traefik/http/services//loadbalancer/sticky/cookie/secure See Service for more information. true traefik/http/services//loadbalancer/sticky/cookie/samesite See Service for more information. none traefik/http/services//loadbalancer/sticky/cookie/maxage See Service for more information. 42 traefik/http/services/myservice/loadbalancer/responseforwarding/flushinterval See Service for more information. 10 traefik/http/services//mirroring/service See Service for more information. foobar traefik/http/services//mirroring/mirrors//name See Service for more information. foobar traefik/http/services//mirroring/mirrors//percent See Servicefor more information. 42 traefik/http/services//weighted/services//name See Service for more information. foobar traefik/http/services//weighted/services//weight See Service for more information. 42 traefik/http/services//weighted/sticky/cookie/name See Service for more information. foobar traefik/http/services//weighted/sticky/cookie/secure See Service for more information. true traefik/http/services//weighted/sticky/cookie/samesite See Service for more information. none traefik/http/services//weighted/sticky/cookie/httpOnly See Service for more information. true traefik/http/services//weighted/sticky/cookie/maxage See Service for more information. 42 traefik/http/services//failover/fallback See Failover for more information. backup traefik/http/services//failover/healthcheck See Failover for more information. {} traefik/http/services//failover/service See Failover for more information. main Middleware Configuration Options Key (Path) Description Value traefik/http/middlewares//middleware_type/middleware_option With middleware_type the type of middleware (ex: forwardAuth, headers, etc) and middleware_option the middleware option to set (ex for the middleware addPrefix: prefix). More information about available middlewares in the dedicated middlewares section. foobar !!! warning "The character @ is not authorized in the middleware name." !!! warning "Conflicts in Declaration" If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared. ServerTransport Configuration Options Key (Path) Description Value traefik/http/serversTransports//st_option With st_option the ServerTransport option to set (ex maxIdleConnsPerHost). More information about available options in the dedicated ServerTransport section. ServerTransport Options TCP You can declare TCP Routers and/or Services using KV. Routers Key (Path) Description Value traefik/tcp/routers//entrypoints/0 See entry points for more information. ep1 traefik/tcp/routers//entrypoints/1 See entry points for more information. ep2 traefik/tcp/routers/my-router/rule See entry points for more information. HostSNI(`example.com`) traefik/tcp/routers//service See service for more information. myservice traefik/tcp/routers//tls See TLS for more information. true traefik/tcp/routers//tls/certresolver See certResolver for more information. myresolver traefik/tcp/routers//tls/domains/0/main See TLS for more information. example.org traefik/tcp/routers//tls/domains/0/sans/0 See TLS for more information. test.example.org traefik/tcp/routers//tls/domains/0/sans/1 See TLS for more information. dev.example.org traefik/tcp/routers//tls/options See TLS for more information. foobar traefik/tcp/routers//tls/passthrough See TLS for more information. true traefik/tcp/routers//priority See priority for more information. 42 Services Key (Path) Description Value traefik/tcp/services//loadbalancer/servers/0/address See servers for more information. xx.xx.xx.xx:xx traefik/tcp/services//loadbalancer/servers/0/tls See servers for more information. true traefik/tcp/services//loadbalancer/serverstransport Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one. See serverstransport for more information. foobar@file traefik/tcp/services//weighted/services/0/name See Service for more information. foobar traefik/tcp/services//weighted/services/0/weight See Service for more information. 42 Middleware Configuration Options You can declare pieces of middleware using tags starting with traefik/tcp/middlewares/{name-of-your-choice}., followed by the middleware type/options. For example, to declare a middleware InFlightConn named test-inflightconn, you'd write traefik/tcp/middlewares/test-inflightconn/inflightconn/amount=10. More information about available middlewares in the dedicated middlewares section. Key (Path) Description Value traefik/tcp/middlewares//middleware_type/middleware_option With middleware_type the type of middleware (ex: inflightconn) and middleware_option the middleware option to set (ex for the middleware inflightconn: amount). More information about available middlewares in the dedicated middlewares section. foobar !!! warning "Conflicts in Declaration" If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared. ServerTransport Configuration Options Key (Path) Description Value traefik/tcp/serversTransports//st_option With st_option the ServerTransport option to set (ex maxIdleConnsPerHost). More information about available options in the dedicated ServerTransport section. ServerTransport Options UDP You can declare UDP Routers and/or Services using KV. Routers Key (Path) Description Value traefik/udp/routers//entrypoints/0 See UDP Router for more information. foobar traefik/udp/routers//service See UDP Router for more information. foobar Services Key (Path) Description Value traefik/udp/services//loadBalancer/servers//address See UDP Service for more information. foobar traefik/udp/services//weighted/services/0/name See UDP Service for more information. foobar traefik/udp/services//weighted/services/0/weight See UDP Service for more information. 42 TLS TLS Options With the KV provider, you configure some parameters of the TLS connection using the tls/options key. For example, you can define a basic setup like this: Key (Path) Description Value traefik/tls/options/Options0/alpnProtocols/0 See TLS Options for more information. foobar traefik/tls/options/Options0/cipherSuites/0 See TLS Options for more information. foobar traefik/tls/options/Options0/clientAuth/caFiles/0 See TLS Options for more information. foobar traefik/tls/options/Options0/disableSessiontickets See TLS Options for more information. true TLS Default Generated Certificates You can configure Traefik to use an ACME provider (like Let's Encrypt) to generate the default certificate. The configuration to resolve the default certificate should be defined in a TLS store. Key (Path) Description Value traefik/tls/stores/Store0/defaultGeneratedCert/domain/main See TLS for more information. foobar traefik/tls/stores/Store0/defaultGeneratedCert/domain/sans/0 See TLS for more information foobar traefik/tls/stores/Store0/defaultGeneratedCert/domain/sans/1 See TLS for more information foobar traefik/tls/stores/Store0/defaultGeneratedCert/resolver See TLS for more information foobar Traefik and Nomad Service Discovery One of the best feature of Traefik is to delegate the routing configuration to the application level. With Nomad, Traefik can leverage tags attached to a service to generate routing rules. !!! warning "Tags & sensitive data" We recommend to *not* use tags to store sensitive data (certificates, credentials, etc). Instead, we recommend to store sensitive data in a safer storage (secrets, file, etc). Configuration Examples ??? example "Configuring Nomad & Deploying / Exposing one Service" Enabling the nomad provider ```yaml tab="Structured (YAML)" providers: nomad: {} ``` ```toml tab="Structured (TOML)" [providers.nomad] ``` ```bash tab="CLI" --providers.nomad=true ``` Attaching tags to services (in your Nomad job file) ```hcl job "my-service" { datacenters = ["dc1"] group "web" { task "app" { driver = "docker" service { name = "my-service" tags = [ "traefik.http.routers.my-service.rule=Host(`example.com`)", ] } } } } ``` ??? example "Specify a Custom Port for the Container" Forward requests for `http://example.com` to `http://:12345`: ```hcl job "my-service" { datacenters = ["dc1"] group "web" { task "app" { driver = "docker" service { name = "my-service" tags = [ "traefik.http.routers.my-service.rule=Host(`example.com`)", "traefik.http.routers.my-service.service=my-service", "traefik.http.services.my-service.loadbalancer.server.port=12345", ] } } } } ``` !!! important "Traefik Connecting to the Wrong Port: `HTTP/502 Gateway Error`" By default, Traefik uses the first exposed port of a container. Setting the tag `traefik.http.services.xxx.loadbalancer.server.port` overrides that behavior. ??? example "Specifying more than one router and service per container" Forwarding requests to more than one port on a container requires referencing the service loadbalancer port definition using the service parameter on the router. In this example, requests are forwarded for `http://example-a.com` to `http://:8000` in addition to `http://example-b.com` forwarding to `http://:9000`: ```hcl job "my-service" { datacenters = ["dc1"] group "web" { task "app" { driver = "docker" service { name = "my-service" tags = [ "traefik.http.routers.www-router.rule=Host(`example-a.com`)", "traefik.http.routers.www-router.service=www-service", "traefik.http.services.www-service.loadbalancer.server.port=8000", "traefik.http.routers.admin-router.rule=Host(`example-b.com`)", "traefik.http.routers.admin-router.service=admin-service", "traefik.http.services.admin-service.loadbalancer.server.port=9000", ] } } } } ``` Configuration Options !!! info "Tags" Tags are case-insensitive. !!! tip "TLS Default Generated Certificates" To learn how to configure Traefik default generated certificate, refer to the [TLS Certificates](../http/tls/tls-certificates.md#acme-default-certificate) page. General Traefik creates, for each Nomad service, a corresponding Traefik service and router. The Traefik service automatically gets a server per instance in this Nomad service, and the router gets a default rule attached to it, based on the Nomad service name. Routers To update the configuration of the Router automatically attached to the service, add tags starting with traefik.routers.{name-of-your-choice}. and followed by the option you want to change. For example, to change the rule, you could add the tag traefik.http.routers.my-service.rule=Host(`example.com`). Configuration Options Label Description Value traefik.http.routers..rule See rule for more information. Host(`example.com`) traefik.http.routers..ruleSyntax See ruleSyntax for more information. RuleSyntax option is deprecated and will be removed in the next major version. Please do not use this field and rewrite the router rules to use the v3 syntax. v3 traefik.http.routers..entrypoints See entry points for more information. web,websecure traefik.http.routers..middlewares See middlewares overview for more information. auth,prefix,cb traefik.http.routers..service See service for more information. myservice traefik.http.routers..tls See tls for more information. true traefik.http.routers..tls.certresolver See certResolver for more information. myresolver traefik.http.routers..tls.domains[n].main See domains for more information. example.org traefik.http.routers..tls.domains[n].sans See domains for more information. test.example.org,dev.example.org traefik.http.routers..tls.options See TLS Options for more information, and Conflicting TLS Options when several routers serve the same host name. foobar traefik.http.routers..priority See priority for more information. 42 traefik.http.routers..observability.accesslogs The accessLogs option controls whether the router will produce access-logs. true traefik.http.routers..observability.metrics The metrics option controls whether the router will produce metrics. true traefik.http.routers..observability.tracing The tracing option controls whether the router will produce traces. true Services To update the configuration of the Service automatically attached to the service, add tags starting with traefik.http.services.{name-of-your-choice}., followed by the option you want to change. For example, to change the passHostHeader behavior, you'd add the tag traefik.http.services.{name-of-your-choice}.loadbalancer.passhostheader=false. Configuration Options Label Description Value traefik.http.services..loadbalancer.server.port Registers a port. Useful when the service exposes multiples ports. 8080 traefik.http.services..loadbalancer.server.scheme Overrides the default scheme. http traefik.http.services..loadbalancer.server.weight Overrides the default weight. 42 traefik.http.services..loadbalancer.serverstransport Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one. See serverstransport for more information. foobar@file traefik.http.services..loadbalancer.passhostheader true traefik.http.services..loadbalancer.healthcheck.headers. See health check for more information. foobar traefik.http.services..loadbalancer.healthcheck.hostname See health check for more information. example.org traefik.http.services..loadbalancer.healthcheck.interval See health check for more information. 10 traefik.http.services..loadbalancer.healthcheck.unhealthyinterval See health check for more information. 10 traefik.http.services..loadbalancer.healthcheck.path See health check for more information. /foo traefik.http.services..loadbalancer.healthcheck.status See health check for more information. 42 traefik.http.services..loadbalancer.healthcheck.port See health check for more information. 42 traefik.http.services..loadbalancer.healthcheck.scheme See health check for more information. http traefik.http.services..loadbalancer.healthcheck.timeout See health check for more information. 10 traefik.http.services..loadbalancer.healthcheck.followredirects See health check for more information. true traefik.http.services..loadbalancer.sticky.cookie true traefik.http.services..loadbalancer.sticky.cookie.httponly true traefik.http.services..loadbalancer.sticky.cookie.name foobar traefik.http.services..loadbalancer.sticky.cookie.path /foobar traefik.http.services..loadbalancer.sticky.cookie.secure true traefik.http.services..loadbalancer.sticky.cookie.samesite none traefik.http.services..loadbalancer.sticky.cookie.maxage 42 traefik.http.services..loadbalancer.responseforwarding.flushinterval 10 Middleware You can declare pieces of middleware using tags starting with traefik.http.middlewares.{name-of-your-choice}., followed by the middleware type/options. For example, to declare a middleware redirectscheme named my-redirect, you'd write traefik.http.middlewares.my-redirect.redirectscheme.scheme: https. More information about available middlewares in the dedicated middlewares section. ??? example "Declaring and Referencing a Middleware" ```yaml # ... # Declaring a middleware traefik.http.middlewares.my-redirect.redirectscheme.scheme=https # Referencing a middleware traefik.http.routers.my-service.middlewares=my-redirect ``` !!! warning "Conflicts in Declaration" If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared. TCP You can declare TCP Routers and/or Services using tags. ??? example "Declaring TCP Routers and Services" ```yaml traefik.tcp.routers.my-router.rule=HostSNI(`example.com`) traefik.tcp.routers.my-router.tls=true traefik.tcp.services.my-service.loadbalancer.server.port=4123 ``` !!! warning "TCP and HTTP" If you declare a TCP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no TCP Router/Service is defined). You can declare both a TCP Router/Service and an HTTP Router/Service for the same Nomad service (but you have to do so manually). TCP Routers Configuration Options Label Description Value traefik.tcp.routers..entrypoints See entry points for more information. ep1,ep2 traefik.tcp.routers..rule See rule for more information. HostSNI(`example.com`) traefik.tcp.routers..ruleSyntax configure the rule syntax to be used for parsing the rule on a per-router basis. RuleSyntax option is deprecated and will be removed in the next major version. Please do not use this field and rewrite the router rules to use the v3 syntax. v3 traefik.tcp.routers..priority See priority for more information. 42 traefik.tcp.routers..service See service for more information. myservice traefik.tcp.routers..tls See TLS for more information. true traefik.tcp.routers..tls.certresolver See certResolver for more information. myresolver traefik.tcp.routers..tls.domains[n].main See TLS for more information. example.org traefik.tcp.routers..tls.domains[n].sans See TLS for more information. test.example.org,dev.example.org traefik.tcp.routers..tls.options See TLS for more information. myoptions traefik.tcp.routers..tls.passthrough See Passthrough for more information. true TCP Services Configuration Options Label Description Value traefik.tcp.services..loadbalancer.server.port Registers a port of the application. 423 traefik.tcp.services..loadbalancer.server.tls Determines whether to use TLS when dialing with the backend. true traefik.tcp.services..loadbalancer.serverstransport Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one. See serverstransport for more information. foobar@file TCP Middleware You can declare pieces of middleware using tags starting with traefik.tcp.middlewares.{name-of-your-choice}., followed by the middleware type/options. For example, to declare a middleware InFlightConn named test-inflightconn, you'd write traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10. More information about available middlewares in the dedicated middlewares section. ??? example "Declaring and Referencing a Middleware" ```yaml # ... # Declaring a middleware traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10 # Referencing a middleware traefik.tcp.routers.my-service.middlewares=test-inflightconn ``` !!! warning "Conflicts in Declaration" If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared. UDP You can declare UDP Routers and/or Services using tags. ??? example "Declaring UDP Routers and Services" ```yaml traefik.udp.routers.my-router.entrypoints=udp traefik.udp.services.my-service.loadbalancer.server.port=4123 ``` !!! warning "UDP and HTTP" If you declare a UDP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no UDP Router/Service is defined). You can declare both a UDP Router/Service and an HTTP Router/Service for the same Nomad service (but you have to do so manually). UDP Routers Configuration Options Label Description Value traefik.udp.routers..entrypoints See entry points for more information. ep1,ep2 traefik.udp.routers..service See service for more information. myservice UDP Services Configuration Options Label Description Value traefik.udp.services..loadbalancer.server.port Registers a port of the application. 423 Specific Provider Options Label Description Value traefik.enable You can tell Traefik to consider (or not) the service by setting traefik.enable to true or false. This option overrides the value of exposedByDefault. true traefik.nomad.canary When Nomad orchestrator is a provider (of service registration) for Traefik, one might have the need to distinguish within Traefik between a Canary instance of a service, or a production one. For example if one does not want them to be part of the same load-balancer. Therefore, this option, which is meant to be provided as one of the values of the canary_tags field in the Nomad service stanza, allows Traefik to identify that the associated instance is a canary one. true Port Lookup Traefik is capable of detecting the port to use, by following the default Nomad Service Discovery flow. That means, if you just expose lets say port :1337 on the Nomad job, traefik will pick up this port and use it. Traefik & Docker Swarm One of the best feature of Traefik is to delegate the routing configuration to the application level. With Docker Swarm, Traefik can leverage labels attached to a service to generate routing rules. !!! warning "Labels & sensitive data" We recommend to *not* use labels to store sensitive data (certificates, credentials, etc). Instead, we recommend to store sensitive data in a safer storage (secrets, file, etc). Configuration Examples ??? example "Configuring Docker Swarm & Deploying / Exposing one Service" Enabling the docker provider (Swarm Mode) ```yaml tab="Structured (YAML)" providers: swarm: # swarm classic (1.12-) # endpoint: "tcp://127.0.0.1:2375" # docker swarm mode (1.12+) endpoint: "tcp://127.0.0.1:2377" ``` ```toml tab="Structured (TOML)" [providers.swarm] # swarm classic (1.12-) # endpoint = "tcp://127.0.0.1:2375" # docker swarm mode (1.12+) endpoint = "tcp://127.0.0.1:2377" ``` ```bash tab="CLI" # swarm classic (1.12-) # --providers.swarm.endpoint=tcp://127.0.0.1:2375 # docker swarm mode (1.12+) --providers.swarm.endpoint=tcp://127.0.0.1:2377 ``` Attach labels to services (not containers) while in Swarm mode (in your Docker compose file). When there is only one service, and the router does not specify a service, then that service is automatically assigned to the router. ```yaml services: my-container: deploy: labels: - traefik.http.routers.my-container.rule=Host(`example.com`) - traefik.http.services.my-container-service.loadbalancer.server.port=8080 ``` !!! important "Labels in Docker Swarm Mode" While in Swarm Mode, Traefik uses labels found on services, not on individual containers. Therefore, if you use a compose file with Swarm Mode, labels should be defined in the `deploy` part of your service. This behavior is only enabled for docker-compose version 3+ ([Compose file reference](https://docs.docker.com/compose/compose-file/compose-file-v3/#labels-1)). ??? example "Specify a Custom Port for the Container" Forward requests for `http://example.com` to `http://:12345`: ```yaml services: my-container: # ... deploy: labels: - traefik.http.routers.my-container.rule=Host(`example.com`) - traefik.http.routers.my-container.service=my-service" # Tell Traefik to use the port 12345 to connect to `my-container` - traefik.http.services.my-service.loadbalancer.server.port=12345 ``` !!! important "Traefik Connecting to the Wrong Port: `HTTP/502 Gateway Error`" By default, Traefik uses the lowest exposed port of a container as detailed in [Port Detection](../../install-configuration/providers/swarm.md#port-detection) of the Swarm provider. Setting the label `traefik.http.services.xxx.loadbalancer.server.port` overrides this behavior. ??? example "Specifying more than one router and service per container" Forwarding requests to more than one port on a container requires referencing the service loadbalancer port definition using the service parameter on the router. In this example, requests are forwarded for `http://example-a.com` to `http://:8000` in addition to `http://example-b.com` forwarding to `http://:9000`: ```yaml services: my-container: # ... deploy: labels: - traefik.http.routers.www-router.rule=Host(`example-a.com`) - traefik.http.routers.www-router.service=www-service - traefik.http.services.www-service.loadbalancer.server.port=8000 - traefik.http.routers.admin-router.rule=Host(`example-b.com`) - traefik.http.routers.admin-router.service=admin-service - traefik.http.services.admin-service.loadbalancer.server.port=9000 ``` Configuration Options !!! info "Labels" Labels are case-insensitive. !!! tip "TLS Default Generated Certificates" To learn how to configure Traefik default generated certificate, refer to the [TLS Certificates](../http/tls/tls-certificates.md#acme-default-certificate) page. General Traefik creates, for each container, a corresponding service and router. The Service automatically gets a server per instance of the container, and the router automatically gets a rule defined by defaultRule (if no rule for it was defined in labels). Service definition {% include-markdown "includes/service-by-label.md" %} ??? example "Automatic service assignment with labels" With labels in a compose file ```yaml labels: - "traefik.http.routers.myproxy.rule=Host(`example.net`)" # service myservice gets automatically assigned to router myproxy - "traefik.http.services.myservice.loadbalancer.server.port=8080" ``` ??? example "Automatic service creation and assignment with labels" With labels in a compose file ```yaml labels: # no service specified or defined and yet one gets automatically created # and assigned to router myproxy. - "traefik.http.routers.myproxy.rule=Host(`example.net`)" ``` Routers To update the configuration of the Router automatically attached to the container, add labels starting with traefik.http.routers.. and followed by the option you want to change. For example, to change the rule, you could add the label traefik.http.routers.my-container.rule=Host(`example.com`). !!! warning "The character @ is not authorized in the router name ." Configuration Options Label Description Value traefik.http.routers..rule See rule for more information. Host(`example.com`) traefik.http.routers..ruleSyntax See ruleSyntax for more information. RuleSyntax option is deprecated and will be removed in the next major version. Please do not use this field and rewrite the router rules to use the v3 syntax. v3 traefik.http.routers..entrypoints See entry points for more information. ep1,ep2 traefik.http.routers..middlewares See middlewares overview for more information. auth,prefix,cb traefik.http.routers..service See service for more information. myservice traefik.http.routers..tls See tls for more information. true traefik.http.routers..tls.certresolver See certResolver for more information. myresolver traefik.http.routers..tls.domains[n].main See domains for more information. example.org traefik.http.routers..tls.domains[n].sans See domains for more information. test.example.org,dev.example.org traefik.http.routers..tls.options See TLS Options for more information, and Conflicting TLS Options when several routers serve the same host name. foobar traefik.http.routers..observability.accesslogs The accessLogs option controls whether the router will produce access-logs. true traefik.http.routers..observability.metrics The metrics option controls whether the router will produce metrics. true traefik.http.routers..observability.tracing The tracing option controls whether the router will produce traces. true traefik.http.routers..priority See priority for more information. 42 Services To update the configuration of the Service automatically attached to the container, add labels starting with traefik.http.services.., followed by the option you want to change. For example, to change the passHostHeader behavior, you'd add the label traefik.http.services..loadbalancer.passhostheader=false. !!! warning "The character @ is not authorized in the service name ." Configuration Options Label Description Value traefik.http.services..loadbalancer.server.port Registers a port. Useful when the container exposes multiples ports. Mandatory for Docker Swarm (see the section "Port Detection with Docker Swarm"). 8080 traefik.http.services..loadbalancer.server.scheme Overrides the default scheme. http traefik.http.services..loadbalancer.server.url Defines the service URL. This option cannot be used in combination with port or scheme definition. http://foobar:8080 traefik.http.services..loadbalancer.server.weight Overrides the default weight. 42 traefik.http.services..loadbalancer.serverstransport Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one. See serverstransport for more information. foobar@file traefik.http.services..loadbalancer.passhostheader true traefik.http.services..loadbalancer.healthcheck.headers. See health check for more information. foobar traefik.http.services..loadbalancer.healthcheck.hostname See health check for more information. example.org traefik.http.services..loadbalancer.healthcheck.interval See health check for more information. 10s traefik.http.services..loadbalancer.healthcheck.unhealthyinterval See health check for more information. 10s traefik.http.services..loadbalancer.healthcheck.path See health check for more information. /foo traefik.http.services..loadbalancer.healthcheck.method See health check for more information. foobar traefik.http.services..loadbalancer.healthcheck.status See health check for more information. 42 traefik.http.services..loadbalancer.healthcheck.port See health check for more information. 42 traefik.http.services..loadbalancer.healthcheck.scheme See health check for more information. http traefik.http.services..loadbalancer.healthcheck.timeout See health check for more information. 10s traefik.http.services..loadbalancer.healthcheck.followredirects See health check for more information. true traefik.http.services..loadbalancer.sticky.cookie true traefik.http.services..loadbalancer.sticky.cookie.httponly true traefik.http.services..loadbalancer.sticky.cookie.name foobar traefik.http.services..loadbalancer.sticky.cookie.path /foobar traefik.http.services..loadbalancer.sticky.cookie.secure true traefik.http.services..loadbalancer.sticky.cookie.samesite none traefik.http.services..loadbalancer.responseforwarding.flushinterval See response forwarding for more information. 10 Middleware You can declare pieces of middleware using labels starting with traefik.http.middlewares.., followed by the middleware type/options. For example, to declare a middleware redirectscheme named my-redirect, you'd write traefik.http.middlewares.my-redirect.redirectscheme.scheme=https. More information about available middlewares in the dedicated middlewares section. !!! warning "The character @ is not authorized in the middleware name." ??? example "Declaring and Referencing a Middleware" ```yaml services: my-container: # ... deploy: labels: # Declaring a middleware - traefik.http.middlewares.my-redirect.redirectscheme.scheme=https # Referencing a middleware - traefik.http.routers.my-container.middlewares=my-redirect ``` !!! warning "Conflicts in Declaration" If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared. TCP You can declare TCP Routers and/or Services using labels. ??? example "Declaring TCP Routers and Services" ```yaml services: my-container: # ... deploy: labels: - "traefik.tcp.routers.my-router.rule=HostSNI(`example.com`)" - "traefik.tcp.routers.my-router.tls=true" - "traefik.tcp.services.my-service.loadbalancer.server.port=4123" ``` !!! warning "TCP and HTTP" If you declare a TCP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no TCP Router/Service is defined). You can declare both a TCP Router/Service and an HTTP Router/Service for the same container (but you have to do so manually). TCP Routers Configuration Options Label Description Value traefik.tcp.routers..entrypoints See entry points for more information. ep1,ep2 traefik.tcp.routers..rule See rule for more information. HostSNI(`example.com`) traefik.tcp.routers..ruleSyntax configure the rule syntax to be used for parsing the rule on a per-router basis. RuleSyntax option is deprecated and will be removed in the next major version. Please do not use this field and rewrite the router rules to use the v3 syntax. v3 traefik.tcp.routers..service See service for more information. myservice traefik.tcp.routers..tls See TLS for more information. true traefik.tcp.routers..tls.certresolver See certResolver for more information. myresolver traefik.tcp.routers..tls.domains[n].main See TLS for more information. example.org traefik.tcp.routers..tls.domains[n].sans See TLS for more information. test.example.org,dev.example.org traefik.tcp.routers..tls.options See TLS for more information. mysoptions traefik.tcp.routers..tls.passthrough See Passthrough for more information. true traefik.tcp.routers..priority See priority for more information. 42 TCP Services Configuration Options Label Description Value traefik.tcp.services..loadbalancer.server.port Registers a port of the application. 423 traefik.tcp.services..loadbalancer.server.tls Determines whether to use TLS when dialing with the backend. true traefik.tcp.services..loadbalancer.serverstransport Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one. See serverstransport for more information. foobar@file TCP Middleware You can declare pieces of middleware using tags starting with traefik.tcp.middlewares.{name-of-your-choice}., followed by the middleware type/options. For example, to declare a middleware InFlightConn named test-inflightconn, you'd write traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10. More information about available middlewares in the dedicated middlewares section. ??? example "Declaring and Referencing a Middleware" ```yaml # ... # Declaring a middleware traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10 # Referencing a middleware traefik.tcp.routers.my-service.middlewares=test-inflightconn ``` !!! warning "Conflicts in Declaration" If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared. UDP You can declare UDP Routers and/or Services using labels. ??? example "Declaring UDP Routers and Services" ```yaml services: my-container: # ... deploy: labels: - "traefik.udp.routers.my-router.entrypoints=udp" - "traefik.udp.services.my-service.loadbalancer.server.port=4123" ``` !!! warning "UDP and HTTP" If you declare a UDP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no UDP Router/Service is defined). You can declare both a UDP Router/Service and an HTTP Router/Service for the same container (but you have to do so manually). UDP Routers Configuration Options Label Description Value traefik.udp.routers..entrypoints See entry points for more information. ep1,ep2 traefik.udp.routers..service See service for more information. myservice UDP Services Configuration Options Label Description Value traefik.udp.services..loadbalancer.server.port Registers a port of the application. 423 Specific Provider Options Label Description Value traefik.enable You can tell Traefik to consider (or not) the container by setting traefik.enable to true or false. This option overrides the value of exposedByDefault. true traefik.swarm.network Overrides the default docker network to use for connections to the container. If a container is linked to several networks, be sure to set the proper network name (you can check this with docker inspect ), otherwise it will randomly pick one (depending on how docker is returning them). When deploying a stack from a compose file stack, the networks defined are prefixed with stack. mynetwork traefik.swarm.lbswarm Enables Swarm's inbuilt load balancer (only relevant in Swarm Mode). If you enable this option, Traefik will use the virtual IP provided by docker swarm instead of the containers IPs. Which means that Traefik will not perform any kind of load balancing and will delegate this task to swarm. true ServersTransport TCP ServersTransport allows configuring the transport between Traefik and your TCP servers. Configuration Example Declare the serversTransport: tcp: serversTransports: mytransport: dialTimeout: "30s" dialKeepAlive: "20s" terminationDelay: "200ms" tls: serverName: "example.com" certificates: - "/path/to/cert1.pem" - "/path/to/cert2.pem" insecureSkipVerify: true rootCAs: - "/path/to/rootca.pem" peerCertSANs: - type: DNSName value: foo.com - type: URI value: spiffe://example.org/peer spiffe: ids: - "spiffe://example.org/id1" - "spiffe://example.org/id2" trustDomain: "example.org" [tcp.serversTransports.mytransport] dialTimeout = "30s" dialKeepAlive = "20s" terminationDelay = "200ms" [tcp.serversTransports.mytransport.tls] serverName = "example.com" certificates = ["/path/to/cert1.pem", "/path/to/cert2.pem"] insecureSkipVerify = true rootCAs = ["/path/to/rootca.pem"] peerCertSANs = [{type = "DNSName", value = "foo.com"}, {type = "URI", value = "spiffe://example.org/peer"}] [tcp.serversTransports.mytransport.tls.spiffe] ids = ["spiffe://example.org/id1", "spiffe://example.org/id2"] trustDomain = "example.org" Attach the serversTransport to a service: tcp: services: Service01: loadBalancer: serversTransport: mytransport ## Dynamic configuration [tcp.services] [tcp.services.Service01] [tcp.services.Service01.loadBalancer] serversTransport = "mytransport" labels: - "traefik.tcp.services.Service01.loadBalancer.serversTransport=mytransport" { // ... "Tags": [ "traefik.tcp.services.Service01.loadBalancer.serversTransport=mytransport" ] } Configuration Options Field Description Default Required serverstransport. dialTimeout Defines the timeout when dialing the backend TCP service. If zero, no timeout exists. 30s No serverstransport. dialKeepAlive Defines the interval between keep-alive probes for an active network connection. 15s No serverstransport. terminationDelay Sets the time limit for the proxy to fully terminate connections on both sides after initiating the termination sequence, with a negative value indicating no deadline. More Information here 100ms No serverstransport. proxyProtocol Defines the Proxy Protocol configuration. An empty proxyProtocol section enables Proxy Protocol version 2. No serverstransport. proxyProtocol.version Traefik supports PROXY Protocol version 1 and 2 on TCP Services. More Information here 2 No serverstransport. tls Defines the TLS configuration. An empty tls section enables TLS. No serverstransport. tls .serverName Configures the server name that will be used for SNI. No serverstransport. tls .certificates Defines the list of certificates (as file paths, or data bytes) that will be set as client certificates for mTLS. No serverstransport. tls .insecureSkipVerify Controls whether the server's certificate chain and host name is verified. false No serverstransport. tls .rootCAs Defines the root certificate authorities to use when verifying server certificates. (for mTLS connections). No serverstransport. tls. peerCertSANs Defines the SANs (Subject Alternative Names) used to match against SANs during the peer certificate verification. [] No serverstransport. tls. peerCertSANs[].type Defines the SAN type ( URI or DNSName) to match against the peer certificate's Subject Alternative Names. "" No serverstransport. tls. peerCertSANs[].value Defines the SAN value to match against the peer certificate's Subject Alternative Names. "" No serverstransport. tls.spiffe Defines the SPIFFE configuration. An empty spiffe section enables SPIFFE (that allows any SPIFFE ID). No serverstransport. tls.spiffe .ids Allow SPIFFE IDs. This takes precedence over the SPIFFE TrustDomain. No serverstransport. tls.spiffe .trustDomain Allow SPIFFE trust domain. "" No !!! note "SPIFFE" Please note that SPIFFE must be enabled in the [install configuration](../../install-configuration/tls/spiffe.md) (formerly known as static configuration) before using it to secure the connection between Traefik and the backends. terminationDelay As a proxy between a client and a server, it can happen that either side (e.g. client side) decides to terminate its writing capability on the connection (i.e. issuance of a FIN packet). The proxy needs to propagate that intent to the other side, and so when that happens, it also does the same on its connection with the other side (e.g. backend side). However, if for some reason (bad implementation, or malicious intent) the other side does not eventually do the same as well, the connection would stay half-open, which would lock resources for however long. To that end, as soon as the proxy enters this termination sequence, it sets a deadline on fully terminating the connections on both sides. The termination delay controls that deadline. A negative value means an infinite deadline (i.e. the connection is never fully terminated by the proxy itself). proxyProtocol.version Traefik supports PROXY Protocol version 1 and 2 on TCP Services. It can be configured by setting proxyProtocol.version on the serversTransport. The option specifies the version of the protocol to be used. Either 1 or 2. Traefik TCP Services Documentation Each of the fields of the service section represents a kind of service. Which means, that for each specified service, one of the fields, and only one, has to be enabled to define what kind of service is created. Currently, the two available kinds are LoadBalancer, and Weighted. Servers Load Balancer The servers load balancer is in charge of balancing the requests between the servers of the same service. Configuration Examples Declaring a Service with Two Servers -- Using the File Provider tcp: services: my-service: loadBalancer: servers: - address: "xx.xx.xx.xx:xx" - address: "xx.xx.xx.xx:xx" healthCheck: send: "PING" expect: "PONG" interval: "10s" timeout: "3s" serversTransport: "customTransport@file" [tcp.services] [tcp.services.my-service.loadBalancer] [[tcp.services.my-service.loadBalancer.servers]] address = "xx.xx.xx.xx:xx" [[tcp.services.my-service.loadBalancer.servers]] address = "xx.xx.xx.xx:xx" [tcp.services.my-service.loadBalancer.healthCheck] send = "PING" expect = "PONG" interval = "10s" timeout = "3s" serversTransport = "customTransport@file" labels: - "traefik.tcp.services.my-service.loadBalancer.healthCheck.send=PING" - "traefik.tcp.services.my-service.loadBalancer.healthCheck.expect=PONG" - "traefik.tcp.services.my-service.loadBalancer.healthCheck.interval=10s" - "traefik.tcp.services.my-service.loadBalancer.healthCheck.timeout=3s" - "traefik.tcp.services.my-service.loadBalancer.serversTransport=customTransport@file" { "Tags": [ "traefik.tcp.services.my-service.loadBalancer.healthCheck.send=PING", "traefik.tcp.services.my-service.loadBalancer.healthCheck.expect=PONG", "traefik.tcp.services.my-service.loadBalancer.healthCheck.interval=10s", "traefik.tcp.services.my-service.loadBalancer.healthCheck.timeout=3s", "traefik.tcp.services.my-service.loadBalancer.serversTransport=customTransport@file" ] } Configuration Options Field Description Default servers Servers declare a single instance of your program. "" servers.address The address option (IP:Port) point to a specific instance. "" servers.tls The tls option determines whether to use TLS when dialing with the backend. false serversTransport serversTransport allows referencing a TCP ServersTransport configuration for the communication between Traefik and your servers. If no serversTransport is specified, the default@internal will be used. "" healthCheck Configures health check to remove unhealthy servers from the load balancing rotation. See HealthCheck for details. Health Check The healthCheck option configures health check to remove unhealthy servers from the load balancing rotation. Traefik will consider TCP servers healthy as long as the connection to the target server succeeds. For advanced health checks, you can configure TCP payload exchange by specifying send and expect parameters. To propagate status changes (e.g. all servers of this service are down) upwards, HealthCheck must also be enabled on the parent(s) of this service. Below are the available options for the health check mechanism: Field Description Default Required port Replaces the server address port for the health check endpoint. No send Defines the payload to send to the server during the health check. "" No expect Defines the expected response payload from the server. "" No interval Defines the frequency of the health check calls for healthy targets. 30s No unhealthyInterval Defines the frequency of the health check calls for unhealthy targets. When not defined, it defaults to the interval value. - No timeout Defines the maximum duration Traefik will wait for a health check connection before considering the server unhealthy. 5s No Weighted Round Robin The Weighted Round Robin (alias WRR) load-balancer of services is in charge of balancing the connections between multiple services based on provided weights. This strategy is only available to load balance between services and not between servers. !!! info "Supported Providers" This strategy can be defined currently with the [File provider](../../install-configuration/providers/others/file.md). !!! warning "Weights" A weight must be a non-negative integer, and a `0` weight takes the child service out of the rotation. A weighted service declaring a negative weight is disabled, and the routers referencing it are not created. tcp: services: app: weighted: services: - name: appv1 weight: 3 - name: appv2 weight: 1 appv1: loadBalancer: servers: - address: "xxx.xxx.xxx.xxx:8080" appv2: loadBalancer: servers: - address: "xxx.xxx.xxx.xxx:8080" [tcp.services] [tcp.services.app] [[tcp.services.app.weighted.services]] name = "appv1" weight = 3 [[tcp.services.app.weighted.services]] name = "appv2" weight = 1 [tcp.services.appv1] [tcp.services.appv1.loadBalancer] [[tcp.services.appv1.loadBalancer.servers]] address = "private-ip-server-1:8080/" [tcp.services.appv2] [tcp.services.appv2.loadBalancer] [[tcp.services.appv2.loadBalancer.servers]] address = "private-ip-server-2:8080/" Health Check HealthCheck enables automatic self-healthcheck for this service, i.e. whenever one of its children is reported as down, this service becomes aware of it, and takes it into account (i.e. it ignores the down child) when running the load-balancing algorithm. In addition, if the parent of this service also has HealthCheck enabled, this service reports to its parent any status change. !!! note "Behavior" If HealthCheck is enabled for a given service and any of its descendants does not have it enabled, the creation of the service will fail. HealthCheck on Weighted services can be defined currently only with the [File provider](../../install-configuration/providers/others/file.md). ## Dynamic configuration tcp: services: app: weighted: healthCheck: {} services: - name: appv1 weight: 3 - name: appv2 weight: 1 appv1: loadBalancer: healthCheck: send: "PING" expect: "PONG" interval: 10s timeout: 3s servers: - address: "192.168.1.10:6379" appv2: loadBalancer: healthCheck: send: "PING" expect: "PONG" interval: 10s timeout: 3s servers: - address: "192.168.1.11:6379" ## Dynamic configuration [tcp.services] [tcp.services.app] [tcp.services.app.weighted.healthCheck] [[tcp.services.app.weighted.services]] name = "appv1" weight = 3 [[tcp.services.app.weighted.services]] name = "appv2" weight = 1 [tcp.services.appv1] [tcp.services.appv1.loadBalancer] [tcp.services.appv1.loadBalancer.healthCheck] send = "PING" expect = "PONG" interval = "10s" timeout = "3s" [[tcp.services.appv1.loadBalancer.servers]] address = "192.168.1.10:6379" [tcp.services.appv2] [tcp.services.appv2.loadBalancer] [tcp.services.appv2.loadBalancer.healthCheck] send = "PING" expect = "PONG" interval = "10s" timeout = "3s" [[tcp.services.appv2.loadBalancer.servers]] address = "192.168.1.11:6379" Traefik TLS Documentation When a TCP router is configured to handle TLS traffic, include a tls field in its definition. This field tells Traefik that the router should process only TLS connections and ignore non-TLS traffic. By default, a router with a TLS field will terminate the TLS connections, meaning that it will send decrypted data to the services. Configuration Example tcp: routers: my-tls-router: rule: "HostSNI(`example.com`)" service: "my-tcp-service" tls: passthrough: true options: "my-tls-options" domains: - main: "example.com" sans: - "www.example.com" - "api.example.com" certResolver: "myresolver" [tcp.routers.my-tls-router] rule = "HostSNI(`example.com`)" service = "my-tcp-service" [tcp.routers.my-tls-router.tls] passthrough = true options = "my-tls-options" certResolver = "myresolver" [[tcp.routers.my-tls-router.tls.domains]] main = "example.com" sans = ["www.example.com", "api.example.com"] labels: - "traefik.tcp.routers.my-tls-router.tls=true" - "traefik.tcp.routers.my-tls-router.rule=HostSNI(`example.com`)" - "traefik.tcp.routers.my-tls-router.service=my-tcp-service" - "traefik.tcp.routers.my-tls-router.tls.passthrough=true" - "traefik.tcp.routers.my-tls-router.tls.options=my-tls-options" - "traefik.tcp.routers.my-tls-router.tls.certResolver=myresolver" - "traefik.tcp.routers.my-tls-router.tls.domains[0].main=example.com" - "traefik.tcp.routers.my-tls-router.tls.domains[0].sans=www.example.com,api.example.com" { //... "Tags": [ "traefik.tcp.routers.my-tls-router.tls=true", "traefik.tcp.routers.my-tls-router.rule=HostSNI(`example.com`)", "traefik.tcp.routers.my-tls-router.service=my-tcp-service", "traefik.tcp.routers.my-tls-router.tls.passthrough=true", "traefik.tcp.routers.my-tls-router.tls.options=my-tls-options", "traefik.tcp.routers.my-tls-router.tls.certResolver=myresolver", "traefik.tcp.routers.my-tls-router.tls.domains[0].main=example.com", "traefik.tcp.routers.my-tls-router.tls.domains[0].sans=www.example.com,api.example.com" ] } ??? info "Postgres STARTTLS" Traefik supports the Postgres STARTTLS protocol, which allows TLS routing for Postgres connections. To do so, Traefik reads the first bytes sent by a Postgres client, identifies if they correspond to the message of a STARTTLS negotiation, and, if so, acknowledges and signals the client that it can start the TLS handshake. Please note/remember that there are subtleties inherent to STARTTLS in whether the connection ends up being a TLS one or not. These subtleties depend on the `sslmode` value in the client configuration (and on the server authentication rules). Therefore, it is recommended to use the `require` value for the `sslmode`. Afterwards, the TLS handshake, and routing based on TLS, can proceed as expected. !!! warning "Postgres STARTTLS with TCP TLS PassThrough routers" As mentioned above, the `sslmode` configuration parameter does have an impact on whether a STARTTLS session will succeed. In particular in the context of TCP TLS PassThrough, some of the values (such as `allow`) do not even make sense. Which is why, once more it is recommended to use the `require` value. Configuration Options Field Description Default Required passthrough Defines whether the requests should be forwarded "as is", keeping all data encrypted. false No options enables fine-grained control of the TLS parameters. It refers to a TLS Options and will be applied only if a HostSNI rule is defined. Unlike HTTP routers, several TCP routers can serve the same HostSNI with different TLS options. See TLS Options and HostSNI for more details. "" No certResolver The name of the certificate resolver to use for automatic certificate generation via ACME providers (such as Let's Encrypt). See the Certificate Resolver section for more details. "" No domains List of domains and Subject Alternative Names (SANs) for explicit certificate domain specification. See the Custom Domains section for more details. [] No TLS Options and HostSNI Contrary to the HTTP routers, several TCP routers can serve the same HostSNI with different TLS options, and this is not a conflict. A TCP router rule is not limited to the HostSNI matcher, and the TCP muxer is able to decide which route matches a connection before the TLS handshake happens. The TLS options are therefore selected per route, and not per host name, which makes a configuration such as the following one valid: # Dynamic configuration tcp: routers: routerfoo: rule: "HostSNI(`example.com`) && ClientIP(`192.168.0.11`)" tls: options: foo routerbar: rule: "HostSNI(`example.com`) && ClientIP(`192.168.0.12`)" tls: options: bar # Dynamic configuration [tcp.routers] [tcp.routers.routerfoo] rule = "HostSNI(`example.com`) && ClientIP(`192.168.0.11`)" [tcp.routers.routerfoo.tls] options = "foo" [tcp.routers.routerbar] rule = "HostSNI(`example.com`) && ClientIP(`192.168.0.12`)" [tcp.routers.routerbar.tls] options = "bar" Certificate Resolver The tls.certResolver option allows you to specify a certificate resolver for automatic certificate generation via ACME providers (such as Let's Encrypt). When a certificate resolver is configured for a router, Traefik will automatically obtain and manage TLS certificates for the domains specified in the router's rule (in the HostSNI matcher) or in the tls.domains configuration (with tls.domains taking precedence). !!! important "Prerequisites" - Certificate resolvers must be defined in the [static configuration](../../install-configuration/tls/certificate-resolvers/acme.md) - The router must have `tls` enabled - An ACME challenge type must be configured for the certificate resolver Custom Domains When using ACME certificate resolvers, domains are automatically extracted from router rules, but the tls.domains option allows you to explicitly specify the domains and Subject Alternative Names (SANs) for which certificates should be generated. This provides fine-grained control over certificate generation and takes precedence over domains automatically extracted from router rules. Every domain must have A/AAAA records pointing to Traefik. {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik InFlightConn Middleware - TCP To proactively prevent Services from being overwhelmed with high load, the number of allowed simultaneous connections by IP can be limited with the inFlightConn TCP middleware. Configuration Examples # Limiting to 10 simultaneous connections tcp: middlewares: test-inflightconn: inFlightConn: amount: 10 # Limiting to 10 simultaneous connections [tcp.middlewares] [tcp.middlewares.test-inflightconn.inFlightConn] amount = 10 labels: - "traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10" // Limiting to 10 simultaneous connections { //.. "Tags" : [ "traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10" ] } apiVersion: traefik.io/v1alpha1 kind: MiddlewareTCP metadata: name: test-inflightconn spec: inFlightConn: amount: 10 Configuration Options Field Description Default Required amount The amount option defines the maximum amount of allowed simultaneous connections. The middleware closes the connection if there are already amount connections opened. 0 Yes Traefik TCP Middlewares IPAllowList iPAllowList limits allowed requests based on the client IP. Configuration Examples # Accepts request from defined IP tcp: middlewares: test-ipallowlist: ipAllowList: sourceRange: - "127.0.0.1/32" - "192.168.1.7" # Accepts request from defined IP [tcp.middlewares] [tcp.middlewares.test-ipallowlist.ipAllowList] sourceRange = ["127.0.0.1/32", "192.168.1.7"] # Accepts connections from defined IP labels: - "traefik.tcp.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7" // Accepts request from defined IP { //... "Tags" : [ "traefik.tcp.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7" ] } apiVersion: traefik.io/v1alpha1 kind: MiddlewareTCP metadata: name: test-ipallowlist spec: ipAllowList: sourceRange: - 127.0.0.1/32 - 192.168.1.7 Configuration Options Field Description Default Required sourceRange The sourceRange option sets the allowed IPs (or ranges of allowed IPs by using CIDR notation). Yes TCP Middleware Overview Attached to the routers, pieces of middleware are a means of tweaking the requests before they are sent to your service (or before the answer from the services are sent to the clients). There are several available middlewares in Traefik, some can modify the request, the headers, some are in charge of redirections, some add authentication, and so on. Middlewares that use the same protocol can be combined into chains to fit every scenario. Configuration Example # As YAML Configuration File tcp: routers: router1: service: myService middlewares: - "foo-ip-allowlist" rule: "Host(`example.com`)" middlewares: foo-ip-allowlist: ipAllowList: sourceRange: - "127.0.0.1/32" - "192.168.1.7" services: service1: loadBalancer: servers: - address: "10.0.0.10:4000" - address: "10.0.0.11:4000" # As TOML Configuration File [tcp.routers] [tcp.routers.router1] service = "myService" middlewares = ["foo-ip-allowlist"] rule = "Host(`example.com`)" [tcp.middlewares] [tcp.middlewares.foo-ip-allowlist.ipAllowList] sourceRange = ["127.0.0.1/32", "192.168.1.7"] [tcp.services] [tcp.services.service1] [tcp.services.service1.loadBalancer] [[tcp.services.service1.loadBalancer.servers]] address = "10.0.0.10:4000" [[tcp.services.service1.loadBalancer.servers]] address = "10.0.0.11:4000" labels: # Create a middleware named `foo-ip-allowlist` - "traefik.tcp.middlewares.foo-ip-allowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7" # Apply the middleware named `foo-ip-allowlist` to the router named `router1` - "traefik.tcp.routers.router1.middlewares=foo-ip-allowlist@docker" { //... "Tags" : [ // Create a middleware named `foo-ip-allowlist` "traefik.tcp.middlewares.foo-ip-allowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7", // Apply the middleware named `foo-ip-allowlist` to the router named `router1` "traefik.tcp.routers.router1.middlewares=foo-ip-allowlist@consulcatalog" ] } --- apiVersion: traefik.io/v1alpha1 kind: MiddlewareTCP metadata: name: foo-ip-allowlist spec: ipAllowList: sourceRange: - 127.0.0.1/32 - 192.168.1.7 --- apiVersion: traefik.io/v1alpha1 kind: IngressRouteTCP metadata: name: ingressroute spec: # more fields... routes: # more fields... middlewares: - name: foo-ip-allowlist Available TCP Middlewares Middleware Purpose Area InFlightConn Limits the number of simultaneous connections. Security, Request lifecycle IPAllowList Limit the allowed client IPs. Security, Request lifecycle Traefik TCP Routers Documentation A TCP router is in charge of connecting incoming TCP connections to the services that can handle them. TCP routers analyze incoming connections based on rules, and when a match is found, forward the connection through any configured middlewares to the appropriate service. !!! note "TCP vs HTTP Routing" If both HTTP routers and TCP routers listen to the same EntryPoint, the TCP routers will apply before the HTTP routers. If no matching route is found for the TCP routers, then the HTTP routers will take over. Configuration Example tcp: routers: my-tcp-router: entryPoints: - "tcp-ep" - "websecure" rule: "HostSNI(`example.com`)" priority: 10 middlewares: - "tcp-ipallowlist" tls: passthrough: false certResolver: "letsencrypt" options: "modern-tls" domains: - main: "example.com" sans: - "www.example.com" service: my-tcp-service [tcp.routers] [tcp.routers.my-tcp-router] entryPoints = ["tcp-ep", "websecure"] rule = "HostSNI(`example.com`)" priority = 10 middlewares = ["tcp-ipallowlist"] service = "my-tcp-service" [tcp.routers.my-tcp-router.tls] passthrough = false certResolver = "letsencrypt" options = "modern-tls" [[tcp.routers.my-tcp-router.tls.domains]] main = "example.com" sans = ["www.example.com"] labels: - "traefik.tcp.routers.my-tcp-router.entrypoints=tcp-ep,websecure" - "traefik.tcp.routers.my-tcp-router.rule=HostSNI(`example.com`)" - "traefik.tcp.routers.my-tcp-router.priority=10" - "traefik.tcp.routers.my-tcp-router.middlewares=tcp-ipallowlist" - "traefik.tcp.routers.my-tcp-router.tls.certresolver=letsencrypt" - "traefik.tcp.routers.my-tcp-router.tls.passthrough=false" - "traefik.tcp.routers.my-tcp-router.tls.options=modern-tls" - "traefik.tcp.routers.my-tcp-router.tls.domains[0].main=example.com" - "traefik.tcp.routers.my-tcp-router.tls.domains[0].sans=www.example.com" - "traefik.tcp.routers.my-tcp-router.service=my-tcp-service" { "Tags": [ "traefik.tcp.routers.my-tcp-router.entrypoints=tcp-ep,websecure", "traefik.tcp.routers.my-tcp-router.rule=HostSNI(`example.com`)", "traefik.tcp.routers.my-tcp-router.priority=10", "traefik.tcp.routers.my-tcp-router.middlewares=tcp-ipallowlist", "traefik.tcp.routers.my-tcp-router.tls.certresolver=letsencrypt", "traefik.tcp.routers.my-tcp-router.tls.passthrough=false", "traefik.tcp.routers.my-tcp-router.tls.options=modern-tls", "traefik.tcp.routers.my-tcp-router.tls.domains[0].main=example.com", "traefik.tcp.routers.my-tcp-router.tls.domains[0].sans=www.example.com", "traefik.tcp.routers.my-tcp-router.service=my-tcp-service" ] } Configuration Options Field Description Default Required entryPoints The list of entry points to which the router is attached. If not specified, TCP routers are attached to all TCP entry points. All TCP entry points No rule Rules are a set of matchers configured with values, that determine if a particular connection matches specific criteria. If the rule is verified, the router becomes active, calls middlewares, and then forwards the connection to the service. See Rules & Priority for details. Yes ruleSyntax Deprecated. Specifies the syntax used for the rule field to support v2→v3 migrations. Do not use this field in new configurations; rewrite router rules to use the v3 syntax instead. No priority To avoid rule overlap, routes are sorted, by default, in descending order using rules length. The priority is directly equal to the length of the rule, and so the longest length has the highest priority. A value of 0 for the priority is ignored. Negative values are supported. See Rules & Priority for details. Rule length No middlewares The list of middlewares that are applied to the router. Middlewares are applied in the order they are declared. See TCP Middlewares overview for available TCP middlewares. No tls TLS configuration for the router. When specified, the router will only handle TLS connections. See TLS configuration for detailed TLS options. No service The name of the service that will handle the matched connections. Services can be load balancer services or weighted round robin services. See TCP Service for details. Yes Router Naming The character @ is not authorized in the router name Router names should be descriptive and follow your naming conventions In provider-specific configurations (Docker, Kubernetes), router names are often auto-generated based on service names and rules {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik TCP Routers Rules & Priority Documentation !!! note - The character @ is not authorized in the router name - If both HTTP routers and TCP routers listen to the same EntryPoint, the TCP routers will apply before the HTTP routers. If no matching route is found for the TCP routers, then the HTTP routers will take over. Rules Rules are a set of matchers configured with values, that determine if a particular connection matches specific criteria. If the rule is verified, the router becomes active, calls middlewares, and then forwards the request to the service. The table below lists all the available matchers: Rule Description HostSNI(`domain`) Checks if the connection's Server Name Indication is equal to domain. Supports wildcard subdomain matching (e.g. *.example.com, **.example.com). More information here. HostSNIRegexp(`regexp`) Checks if the connection's Server Name Indication matches regexp. Use a Go flavored syntax. More information here. ClientIP(`ip`) Checks if the connection's client IP correspond to ip. It accepts IPv4, IPv6 and CIDR formats. More information here. ALPN(`protocol`) Checks if the connection's ALPN protocol equals protocol. More information here. !!! tip "Backticks or Quotes?" To set the value of a rule, use [backticks](https://en.wiktionary.org/wiki/backtick) ``` ` ``` or escaped double-quotes `\"`. Single quotes `'` are not accepted since the values are [Go's String Literals](https://golang.org/ref/spec#String_literals). Expressing Complex Rules Using Operators and Parenthesis The usual AND ( &&) and OR ( ||) logical operators can be used, with the expected precedence rules, as well as parentheses. One can invert a matcher by using the NOT ( !) operator. The following rule matches connections where: Either Server Name Indication is example.com OR, Server Name Indication is example.org AND ALPN protocol is NOT h2 HostSNI(`example.com`) || (HostSNI(`example.org`) && !ALPN(`h2`)) HostSNI and HostSNIRegexp HostSNI and HostSNIRegexp matchers allow matching connections targeted to a given domain. These matchers do not support non-ASCII characters, use punycode encoded values (rfc 3492) to match such domains. !!! note "HostSNI & TLS" It is important to note that the Server Name Indication is an extension of the TLS protocol. Hence, only TLS routers will be able to specify a domain name with that rule. However, there is one special use case for `HostSNI` with non-TLS routers: when one wants a non-TLS router that matches all (non-TLS) requests, one should use the specific ```HostSNI(`*`)``` syntax. !!! info "Wildcard subdomain matching" The `HostSNI` matcher supports a wildcard prefix to match the subdomains of a domain. It should be preferred over the `HostSNIRegexp` matcher as it allows attaching a TLS option and is more efficient. A single wildcard matches exactly one subdomain label, a double wildcard one or more: `*.example.com` matches `foo.example.com` but not `foo.bar.example.com`, while `**.example.com` matches both. Neither matches `example.com` itself. This is only available with the **v3 rule syntax** (the default). Examples Match all connections: HostSNI(`*`) HostSNIRegexp(`^.*$`) Match TCP connections sent to example.com: HostSNI(`example.com`) Match TCP connections opened on any direct subdomain of example.com (e.g. foo.example.com): HostSNI(`*.example.com`) Match TCP connections opened on any subdomain of example.com, nested ones included (e.g. foo.bar.example.com): HostSNI(`**.example.com`) Match TCP connections opened on any subdomain of example.com (including nested subdomains), using a regular expression: HostSNIRegexp(`^.+\.example\.com$`) ClientIP The ClientIP matcher allows matching connections opened by a client with the given IP. Examples Match connections opened by a given IP: ClientIP(`10.76.105.11`) ClientIP(`::1`) Match connections coming from a given subnet: ClientIP(`192.168.1.0/24`) ClientIP(`fe80::/10`) ALPN The ALPN matcher allows matching connections the given protocol. It would be a security issue to let a user-defined router catch the response to an ACME TLS challenge previously initiated by Traefik. For this reason, the ALPN matcher is not allowed to match the ACME-TLS/1 protocol, and Traefik returns an error if this is attempted. Example Match connections using the ALPN protocol h2: ALPN(`h2`) Priority Calculation ???+ info "How default priorities are computed" ```yaml tab="Structured (YAML)" tcp: routers: Router-1: rule: "ClientIP(`192.168.0.12`)" entryPoints: - "web" service: service-1 priority: 2 Router-2: rule: "ClientIP(`192.168.0.0/24`)" entryPoints: - "web" priority: 1 service: service-2 ``` ```toml tab="Structured (TOML)" [tcp.routers] [tcp.routers.Router-1] rule = "ClientIP(`192.168.0.12`)" entryPoints = ["web"] service = "service-1" priority = 2 [tcp.routers.Router-2] rule = "ClientIP(`192.168.0.0/24`)" entryPoints = ["web"] priority = 1 service = "service-2" ``` ```yaml tab="Labels" labels: - 'traefik.tcp.routers.Router-1.rule=ClientIP(`192.168.0.12`)' - "traefik.tcp.routers.Router-1.entryPoints=web" - "traefik.tcp.routers.Router-1.service=service-1" - "traefik.tcp.routers.Router-1.priority=2" - 'traefik.tcp.routers.Router-2.rule=ClientIP(`192.168.0.0/24`)' - "traefik.tcp.routers.Router-2.entryPoints=web" - "traefik.tcp.routers.Router-2.service=service-2" - "traefik.tcp.routers.Router-2.priority=1" ``` ```json tab="Tags" { //... "Tags": [ "traefik.tcp.routers.Router-1.rule=ClientIP(`192.168.0.12`)", "traefik.tcp.routers.Router-1.entryPoints=web", "traefik.tcp.routers.Router-1.service=service-1", "traefik.tcp.routers.Router-1.priority=2", "traefik.tcp.routers.Router-2.rule=ClientIP(`192.168.0.0/24`)", "traefik.tcp.routers.Router-2.entryPoints=web", "traefik.tcp.routers.Router-2.service=service-2", "traefik.tcp.routers.Router-2.priority=1" ] } ``` In the example above, the priority is configured so that `Router-1` will handle requests from `192.168.0.12`. To avoid path overlap, routes are sorted, by default, in descending order using rules length. The priority is directly equal to the length of the rule, and so the longest length has the highest priority. The stars of a double wildcard host do not count toward this length, so that it always ranks below the single wildcard and the exact hosts it covers: HostSNI(`foo.example.com`) has a priority of 26, HostSNI(`*.example.com`) of 24, and HostSNI(`**.example.com`) of 23. A value of 0 for the priority is ignored: priority: 0 means that the default rules length sorting is used. Negative priority values are supported. Traefik reserves a range of priorities for its internal routers, the maximum user-defined router priority value is: (MaxInt32 - 1000) for 32-bit platforms, (MaxInt64 - 1000) for 64-bit platforms. !!! info "Providers Precedence" When two routes from **different providers** share the same numeric priority, Traefik uses the [`providers.precedence`](../../../install-configuration/providers/overview.md#providers-precedence) install configuration option to determine which route takes precedence. The provider listed first in `precedence` wins the tie. Traefik UDP Services Documentation General Each of the fields of the service section represents a kind of service. Which means, that for each specified service, one of the fields, and only one, has to be enabled to define what kind of service is created. Currently, the two available kinds are LoadBalancer, and Weighted. Servers Load Balancer The servers load balancer is in charge of balancing the requests between the servers of the same service. Servers The Servers field defines all the servers that are part of this load-balancing group, i.e. each address (IP:Port) on which an instance of the service's program is deployed. Configuration Example A Service with One Server -- Using the File Provider ## Dynamic configuration udp: services: my-service: loadBalancer: servers: - address: "xx.xx.xx.xx:xx" ## Dynamic configuration [udp.services] [udp.services.my-service.loadBalancer] [[udp.services.my-service.loadBalancer.servers]] address = "xx.xx.xx.xx:xx" Weighted Round Robin The Weighted Round Robin (alias WRR) load-balancer of services is in charge of balancing the connections between multiple services based on provided weights. This strategy is only available to load balance between services and not between servers. !!! info "Supported Providers" This strategy can currently be defined with the [File provider](../../install-configuration/providers/others/file.md) and the [Kubernetes CRD provider (IngressRouteUDP)](../kubernetes/crd/udp/ingressrouteudp.md). !!! warning "Weights" A weight must be a non-negative integer, and a `0` weight takes the child service out of the rotation. A weighted service declaring a negative weight is disabled, and the routers referencing it are not created. udp: services: app: weighted: services: - name: appv1 weight: 3 - name: appv2 weight: 1 appv1: loadBalancer: servers: - address: "xxx.xxx.xxx.xxx:8080" appv2: loadBalancer: servers: - address: "xxx.xxx.xxx.xxx:8080" [udp.services] [udp.services.app] [[udp.services.app.weighted.services]] name = "appv1" weight = 3 [[udp.services.app.weighted.services]] name = "appv2" weight = 1 [udp.services.appv1] [udp.services.appv1.loadBalancer] [[udp.services.appv1.loadBalancer.servers]] address = "xxx.xxx.xxx.xxx:8080" [udp.services.appv2] [udp.services.appv2.loadBalancer] [[udp.services.appv2.loadBalancer.servers]] address = "xxx.xxx.xxx.xxx:8080" Configuration Options Field Description Default Required services Defines the list of services to load balance between. Yes services.name The name of the service to load balance to. "" Yes services.weight The weight applied to the service when balancing connections. 1 No {% include-markdown "includes/traefik-for-business-applications.md" %} Traefik UDP Routers Documentation A UDP router is in charge of connecting incoming UDP packets to the services that can handle them. Unlike HTTP and TCP routers, UDP routers operate at the transport layer and have unique characteristics due to the connectionless nature of UDP. !!! important "UDP Router Characteristics" - UDP is connectionless, so there is no concept of a request URL path or Host SNI to match against - UDP routers are essentially load-balancers that distribute packets to backend services - UDP routers can only target UDP services (not HTTP or TCP services) - Sessions are tracked with configurable timeouts to maintain state between client and backend Configuration Example udp: routers: my-udp-router: entryPoints: - "udp-ep" - "dns" service: my-udp-service [udp.routers] [udp.routers.my-udp-router] entryPoints = ["udp-ep", "dns"] service = "my-udp-service" labels: - "traefik.udp.routers.my-udp-router.entrypoints=udp-ep,dns" - "traefik.udp.routers.my-udp-router.service=my-udp-service" { "Tags": [ "traefik.udp.routers.my-udp-router.entrypoints=udp-ep,dns", "traefik.udp.routers.my-udp-router.service=my-udp-service" ] } Configuration Options Field Description Default Required entryPoints The list of entry points to which the router is attached. If not specified, UDP routers are attached to all UDP entry points. All UDP entry points No service The name of the service that will handle the matched UDP packets. UDP services are typically load balancer services that distribute packets to multiple backend servers. See UDP Service for details. Yes Sessions and Timeout Even though UDP is connectionless, Traefik's UDP router implementation relies on sessions to maintain state about ongoing communication between clients and backends. This allows the proxy to know where to forward response packets from backends. Each session has an associated timeout that cleans up inactive sessions after a specified duration of inactivity. Session timeout can be configured using the entryPoints.name.udp.timeout option in the static configuration. See EntryPoints documentation for details. Router Naming The character @ is not authorized in the router name Router names should be descriptive and follow your naming conventions In provider-specific configurations (Docker, Kubernetes), router names are often auto-generated based on service names Traefik UDP Routers Rules & Priority Documentation A router is in charge of connecting incoming requests to the services that can handle them. Similarly to TCP, as UDP is the transport layer, there is no concept of a request, so there is no notion of an URL path prefix to match an incoming UDP packet with. Furthermore, as there is no good TLS support at the moment for multiple hosts, there is no Host SNI notion to match against either. Therefore, there is no criterion that could be used as a rule to match incoming packets in order to route them. So UDP routers at this time are pretty much only load-balancers in one form or another. !!! tip UDP routers can only target UDP services (and not HTTP or TCP services). Sessions and timeout Even though UDP is connectionless (and because of that), the implementation of an UDP router in Traefik relies on what we (and a couple of other implementations) call a session. It means that some state is kept about an ongoing communication between a client and a backend, notably so that the proxy knows where to forward a response packet from a backend. As expected, a timeout is associated to each of these sessions, so that they get cleaned out if they go through a period of inactivity longer than a given duration. Timeout can be configured using the entryPoints.name.udp.timeout option as described under EntryPoints EntryPoints If not specified, UDP routers will accept packets from all defined (UDP) EntryPoints. If one wants to limit the router scope to a set of EntryPoints, one should set the entryPoints option. Configuration Example Listens to Every Entry Point udp: routers: Router-1: # By default, routers listen to all UDP entrypoints # i.e. "other", and "streaming". service: "service-1" [udp.routers] [udp.routers.Router-1] # By default, routers listen to all UDP entrypoints, # i.e. "other", and "streaming". service = "service-1" labels: - "traefik.udp.routers.Router-1.service=service-1" { //... "Tags": [ "traefik.udp.routers.Router-1.service=service-1" ] } Listens to Specific EntryPoints udp: routers: Router-1: # does not listen on "other" entry point entryPoints: - "streaming" service: "service-1" [udp.routers] [udp.routers.Router-1] # does not listen on "other" entry point entryPoints = ["streaming"] service = "service-1" labels: - "traefik.udp.routers.Router-1.entryPoints=streaming" - "traefik.udp.routers.Router-1.service=service-1" { //... "Tags": [ "traefik.udp.routers.Router-1.entryPoints=streaming", "traefik.udp.routers.Router-1.service=service-1" ] } !!! info "Service" There must be one (and only one) UDP [service](../service.md) referenced per UDP router. Services are the target for the router. {% include-markdown "includes/traefik-for-business-applications.md" %} Secure API Access with JWT !!! info "Traefik Hub Feature" This middleware is available exclusively in Traefik Hub. Learn more about Traefik Hub's advanced features. JSON Web Token (JWT) (defined in the RFC 7519) allows Traefik Hub API Gateway to secure the API access using a token signed using either a private signing secret or a public/private key. Traefik Hub API Gateway provides many kinds of sources to perform the token validation: Setting a secret value in the middleware configuration (option signingSecret). Setting a public key: In that case, users should sign their token using a private key, and the public key can be used to verify the signature (option publicKey). Setting a JSON Web Key (JWK) file to define a set of JWK to be used to verify the signature of the incoming JWT (option jwksFile). Setting a JSON Web Key (JWK) URL to define the URL of the host serving a JWK set (option jwksUrl). !!! note "One single source" The JWT middleware does not allow you to set more than one way to validate the incoming tokens. When a Hub API Gateway receives a request that must be validated using the JWT middleware, it verifies the token using the source configured as described above. If the token is successfully checked, the request is accepted. !!! note "Claim Usage" A JWT can contain metadata in the form of claims (key-value pairs). The claims contained in the JWT can be used for advanced use-cases such as adding an Authorization layer using the claims. More information in the [dedicated section](../reference/routing-configuration/http/middlewares/jwt.md#claims). Verify a JWT with a secret To allow the Traefik Hub API Gateway to validate a JWT with a secret value stored in a Kubernetes Secret, apply the following configuration: apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-jwt namespace: apps spec: plugin: jwt: signingSecret: "urn:k8s:secret:jwt:signingSecret" apiVersion: v1 kind: Secret metadata: name: jwt namespace: apps stringData: signingSecret: mysuperlongsecret apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: my-app namespace: apps spec: entryPoints: - websecure routes: - match: Path(`/my-app`) kind: Rule services: - name: whoami port: 80 middlewares: - name: test-jwt kind: Deployment apiVersion: apps/v1 metadata: name: whoami namespace: apps spec: replicas: 3 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami --- apiVersion: v1 kind: Service metadata: name: whoami namespace: apps spec: ports: - port: 80 name: whoami selector: app: whoami Verify a JWT using an Identity Provider To allow the Traefik Hub API Gateway to validate a JWT using an Identity Provider, such as Keycloak and Azure AD in the examples below, apply the following configuration: apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-jwt namespace: apps spec: plugin: jwt: # Replace KEYCLOAK_URL and REALM_NAME with your values jwksUrl: https://KEYCLOAK_URL/realms/REALM_NAME/protocol/openid-connect/certs # Forward the content of the claim grp in the header Group forwardHeaders: Group: grp # Check the value of the claim grp before sending the request to the backend claims: Equals(`grp`, `admin`) apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: test-jwt namespace: apps spec: plugin: jwt: jwksUrl: https://login.microsoftonline.com/common/discovery/v2.0/keys apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: my-app namespace: apps spec: entryPoints: - websecure routes: - match: Path(`/my-app`) kind: Rule services: - name: whoami port: 80 middlewares: - name: test-jwt kind: Deployment apiVersion: apps/v1 metadata: name: whoami namespace: apps spec: replicas: 3 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami --- apiVersion: v1 kind: Service metadata: name: whoami namespace: apps spec: ports: - port: 80 name: whoami selector: app: whoami !!! note "Advanced Configuration" Advanced options are described in the reference page. For example, the metadata recovered from the Identity Provider can be used to restrict the access to the applications. To do so, you can use the `claims` option, more information in the [dedicated section](../reference/routing-configuration/http/middlewares/jwt.md#claims). {% include-markdown "includes/traefik-for-business-applications.md" %} Secure API Access with OIDC !!! info "Traefik Hub Feature" This middleware is available exclusively in Traefik Hub. Learn more about Traefik Hub's advanced features. OpenID Connect Authentication is built on top of the OAuth2 Authorization Code Flow (defined in OAuth 2.0 RFC 6749, section 4.1). It allows an application to be secured by delegating authentication to an external provider (Keycloak, Okta etc.) and obtaining the end user's session claims and scopes for authorization purposes. To authenticate the user, the middleware redirects through the authentication provider. Once the authentication is complete, users are redirected back to the middleware before being authorized to access the upstream application, as described in the diagram below: To allow the OIDC Middleware to use the credentials provided by the requests, apply the following configuration: apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: oidc-login namespace: apps spec: plugin: oidc: issuer: MY_ISSUER_URL clientId: "urn:k8s:secret:oidc-client:client_id" clientSecret: "urn:k8s:secret:oidc-client:client_secret" redirectUrl: /oidc/callback apiVersion: v1 kind: Secret metadata: name: oidc-client stringData: client_id: my-oauth-client-ID # Set your ClientID here client_secret: my-oauth-client-secret # Set your client secret here apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: secure-applications-apigateway-oauth2-client-credentials namespace: apps spec: entryPoints: - websecure routes: - match: Path(`/my-app`) kind: Rule services: - name: whoami port: 80 middlewares: - name: oidc-login kind: Deployment apiVersion: apps/v1 metadata: name: whoami namespace: apps spec: replicas: 3 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami --- apiVersion: v1 kind: Service metadata: name: whoami namespace: apps spec: ports: - port: 80 name: whoami selector: app: whoami !!! note "Advanced Configuration" Advanced options are described in the [reference page](../reference/routing-configuration/http/middlewares/oidc.md). For example, you can find how to customize the session storage: - Using a cookie ([Options `session`](../reference/routing-configuration/http/middlewares/oidc.md#configuration-options) (default behavior)) - Using a [Redis store](../reference/routing-configuration/http/middlewares/oidc.md#sessionstore). {% include-markdown "includes/traefik-for-business-applications.md" %} Secure API Access with WAF !!! info "Traefik Hub Feature" This middleware is available exclusively in Traefik Hub. Learn more about Traefik Hub's advanced features. The Coraza Web Application Firewall middleware in Traefik Hub API Gateway provides comprehensive protection against common web application attacks. The middleware supports the Coraza rule syntax and is compatible with OWASP Core Rule Set (CRS), allowing you to leverage proven security rules maintained by the security community. Basic WAF Protection To protect your applications with custom security rules, apply the following configuration: apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: waf-protection namespace: apps spec: plugin: coraza: directives: - SecRuleEngine On - SecRule REQUEST_URI "@streq /admin" "id:101,phase:1,t:lowercase,log,deny" - SecRule ARGS "@detectSQLi" "id:102,phase:2,block,msg:'SQL Injection Attack Detected',logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}'" This configuration implements three security directives that work together to protect an application: SecRuleEngine On: Activates the WAF engine to begin processing incoming requests. Without this directive, all other rules remain inactive regardless of their configuration. Admin Path Protection: The second rule blocks all access to /admin paths by examining the request URI. This completely prevents access to administrative interfaces that often contain sensitive functionality like user management, system configuration, or database administration tools. The rule triggers during phase 1 (request headers processing) and applies lowercase transformation to catch variations like /Admin or /ADMIN. SQL Injection Detection: The third rule scans request parameters (query strings and form data) for SQL injection patterns using Coraza's built-in detection engine. The ARGS variable covers query string parameters like ?id=1 and form data from POST requests like username=admin&password=123, but does not include cookies. SQL injection attacks attempt to manipulate database queries by injecting malicious SQL code through user inputs. When detected, the rule blocks the request and logs detailed information about the attempted attack, including which parameter contained the malicious payload. apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: protected-app namespace: apps spec: entryPoints: - websecure routes: - match: Path(`/my-app`) kind: Rule services: - name: whoami port: 80 middlewares: - name: waf-protection kind: Deployment apiVersion: apps/v1 metadata: name: whoami namespace: apps spec: replicas: 3 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami --- apiVersion: v1 kind: Service metadata: name: whoami namespace: apps spec: ports: - port: 80 name: whoami selector: app: whoami Advanced Protection with OWASP Core Rule Set To implement comprehensive protection using the OWASP Core Rule Set, which provides battle-tested rules against common attack patterns, apply the following configuration: apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: waf-crs-protection namespace: apps spec: plugin: coraza: crsEnabled: true directives: - SecRuleEngine On - SecDefaultAction "phase:1,log,auditlog,deny,status:403" - SecDefaultAction "phase:2,log,auditlog,deny,status:403" - SecAction "id:900110, phase:1, pass, t:none, nolog, setvar:tx.inbound_anomaly_score_threshold=5, setvar:tx.outbound_anomaly_score_threshold=4" - SecAction "id:900200, phase:1, pass, t:none, nolog, setvar:'tx.allowed_methods=GET POST'" - Include @owasp_crs/REQUEST-911-METHOD-ENFORCEMENT.conf - Include @owasp_crs/REQUEST-949-BLOCKING-EVALUATION.conf This advanced configuration implements OWASP Core Rule Set (CRS) protection with anomaly scoring: SecDefaultAction for Phase 1 & 2: Sets default behavior for request processing phases. Phase 1 processes request headers while Phase 2 processes request body. When rules match, they log the event to both standard and audit logs, then deny the request with a 403 status code. Anomaly Score Configuration: The first SecAction sets anomaly score thresholds where inbound_anomaly_score_threshold=5 means requests scoring 5 or higher are blocked, and outbound_anomaly_score_threshold=4 applies the same logic to responses. This scoring system allows multiple suspicious patterns to accumulate points rather than blocking on first detection, reducing false positives while maintaining security. Allowed Methods Configuration: The second SecAction restricts HTTP methods to only GET and POST requests. This prevents potentially dangerous methods like PUT, DELETE, PATCH, or OPTIONS that could modify server resources or reveal system information. METHOD-ENFORCEMENT Rule Set: The REQUEST-911-METHOD-ENFORCEMENT.conf file enforces the allowed HTTP methods policy defined above. It checks incoming requests against the permitted methods and contributes to the anomaly score for disallowed methods. BLOCKING-EVALUATION Rule Set: The REQUEST-949-BLOCKING-EVALUATION.conf file evaluates the accumulated anomaly score against the configured thresholds. If the total score exceeds the threshold, it triggers the blocking action, preventing the request from reaching your application. apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: crs-protected-app namespace: apps spec: entryPoints: - websecure routes: - match: Path(`/my-app`) kind: Rule services: - name: whoami port: 80 middlewares: - name: waf-crs-protection kind: Deployment apiVersion: apps/v1 metadata: name: whoami namespace: apps spec: replicas: 3 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami --- apiVersion: v1 kind: Service metadata: name: whoami namespace: apps spec: ports: - port: 80 name: whoami selector: app: whoami !!! warning Starting with Traefik Hub v3.11.0, Coraza requires read/write permissions to /tmp. This requirement stems from upstream changes in the Coraza engine. !!! note "Advanced Configuration" Advanced options and detailed rule configuration are described in the reference page. The WAF middleware supports extensive customization through Coraza directives. You can create custom rules, tune detection thresholds, configure logging levels, and integrate with external threat intelligence feeds. For comprehensive rule writing guidance, consult the [Coraza documentation](https://coraza.io/docs/tutorials/introduction/) and [OWASP CRS documentation](https://coreruleset.org/docs/). {% include-markdown "includes/traefik-for-business-applications.md" %} Content-Length Traefik acts as a streaming proxy. By default, it checks each chunk of data against the Content-Length header as it passes it on to the backend or client. This live check blocks truncated or over‑long streams without holding the entire message. If you need Traefik to read and verify the full body before any data moves on, add the buffering middleware: http: middlewares: buffer-and-validate: buffering: {} With buffering enabled, Traefik will: Read the entire request or response into memory. Compare the actual byte count to the Content-Length header. Reject the message if the counts do not match. !!! warning Buffering adds overhead. Every request and response is held in full before forwarding, which can increase memory use and latency. Use it when strict content validation is critical to your security posture. Headers with Aliasing Names Preventing Header Spoofing Through Aliasing Header Names {: .subtitle } Go canonicalizes header names on dashes only, therefore it handles X-Auth-User, X_Auth_User and X.Auth.User as three distinct headers. Many backends derive their variable names from the header names (CGI, WSGI, PHP, NGINX, ...): they uppercase the header name, and replace every character that is neither a letter nor a digit with an underscore. For them, the three names above are the same HTTP_X_AUTH_USER variable. Underscores and dots are not the only characters concerned. On top of the letters, the digits and the dash, HTTP allows the following characters in a header name: ! # $ % & ' * + . ^ _ ` | ~ Each of them is turned into an underscore by such backends, hence each of them builds an alias: X_Auth_User, X.Auth.User, X!Auth!User, X~Auth~User and X+Auth+User are all read as X-Auth-User. Only the letters, the digits and the dash are left untouched, so only the dash form is unambiguous. As a consequence, a client can smuggle an alias of a header managed by Traefik past the middleware managing it, and have such a backend read the spoofed value instead of the value asserted by Traefik. Configuration The aliasHeadersStrategy entry point option is the mitigation against this class of spoofing. It controls how the request headers whose name aliases another header name are handled before routing: keep (default): request headers with an aliasing name are forwarded as is. delete: any request header whose name contains a character which is neither a letter, a digit, nor a dash is silently removed from the request. reject: any request carrying a header whose name contains a character which is neither a letter, a digit, nor a dash is rejected with a 400 Bad Request response. !!! warning "Legitimate headers are dropped too" The `delete` and `reject` strategies apply to every request header, not only to the ones Traefik manages: they cannot tell a spoofing attempt from a legitimate header whose name happens to contain such a character. An application relying on a header named for example `X_Request_Id` stops receiving it with `delete`, and its requests are rejected with `reject`. In practice, header names are built with letters, digits and dashes only, and no header of the IANA registry contains any other character. A backend deliberately using such names (which a default NGINX configuration already drops for underscores) is the case to check before enabling this option. !!! warning "Security Considerations" Setting `aliasHeadersStrategy` to `delete` or `reject` is strongly recommended when an entry point fronts a backend normalizing the header names. The middlewares managing request headers (ForwardAuth `authResponseHeaders`, BasicAuth and DigestAuth `headerField`, PassTLSClientCert, Headers `customRequestHeaders`, StripPrefix, ReplacePath, ...) only manage the canonical form of the headers they set, and rely on this option to not be spoofed with an aliasing name. Traefik logs a warning at startup for every entry point left without this option configured. entryPoints: websecure: address: ":443" http: aliasHeadersStrategy: delete # Default: keep [entryPoints.websecure] address = ":443" [entryPoints.websecure.http] aliasHeadersStrategy = "delete" --entryPoints.websecure.address=:443 --entryPoints.websecure.http.aliasHeadersStrategy=delete !!! info "Deprecated option" The `underscoreHeadersStrategy` option is deprecated in favor of `aliasHeadersStrategy`, which handles every aliasing character instead of the underscore only. See the [feature deprecation notices](../deprecation/features.md#entry-point-underscoreheadersstrategy-option) for more details. HTTP/2 Header Memory Exhaustion Traefik serves HTTP/2 through the Go standard library. With HTTP/2, a single connection can multiplex many concurrent requests, each carrying its own header block. A client can abuse HPACK header compression together with the HTTP/2 flow-control window to expand a small amount of wire data into a large memory allocation on the proxy, and keep that allocation pinned by stalling the streams. With enough concurrent streams and connections, this can exhaust the available memory and terminate the Traefik process. Two entry point options bound this exposure. It is recommended to use them together. Limit the Request Header Size The maxHeaderBytes option caps the size, in bytes, of the request headers Traefik reads for each request. Lowering it from the default ( 1048576, that is 1 MiB) to the smallest value your largest legitimate headers need lets Traefik reject an oversized header block before it can be amplified. entryPoints: websecure: address: ':443' http: maxHeaderBytes: 65536 [entryPoints.websecure] address = ":443" [entryPoints.websecure.http] maxHeaderBytes = 65536 --entryPoints.websecure.address=:443 --entryPoints.websecure.http.maxHeaderBytes=65536 Limit Concurrent Streams per Connection The maxConcurrentStreams option caps the number of concurrent HTTP/2 streams each client is allowed to initiate on a single connection (default 250). Lowering it reduces the amount of memory a single connection can pin. entryPoints: websecure: address: ':443' http2: maxConcurrentStreams: 100 [entryPoints.websecure] address = ":443" [entryPoints.websecure.http2] maxConcurrentStreams = 100 --entryPoints.websecure.address=:443 --entryPoints.websecure.http2.maxConcurrentStreams=100 !!! note "Defense in Depth" These two limits bound the memory a single connection can consume. For additional protection, also limit the number of concurrent connections and the request rate per source IP at a fronting load balancer or firewall, and provision the Traefik instance with enough memory to handle the expected legitimate load. Traefik in Multi-Tenant Kubernetes Clusters Traefik is primarily designed as a cluster-wide ingress controller. For this reason, when using the Kubernetes Ingress or IngressRoute specifications, it is not recommended to use a shared instance of Traefik in multi-tenant Kubernetes clusters, where multiple teams or tenants share the same cluster. The main reasons include: Resource visibility and isolation: Traefik requires cluster-level permissions and watches resources across namespaces. Misconfigurations in one tenant’s resources may affect others. Shared CRDs: Advanced configuration resources, like Middleware or TLSOptions, are cluster-scoped. Conflicting definitions can impact multiple tenants. Traffic and availability risks: Routing rules, middleware, or heavy traffic from one tenant can interfere with others, affecting reliability and performance. Observability and privacy: Logs, metrics, and traces are shared by default, which may expose sensitive information across tenants. TLS Certificates Management At the core of this limitation is the TLS Store, which holds all the TLS certificates used by Traefik. As this Store is global in Traefik, it is shared across all namespaces, meaning any Ingress or IngressRoute in the cluster can potentially reference or affect TLS configurations intended for other tenants. This lack of isolation poses a risk in multi-tenant environments where different teams or applications require strict boundaries between resources, especially around sensitive data like TLS certificates. Recommended Setup The recommended approach for multi-tenant Kubernetes clusters is to deploy one dedicated Traefik instance per tenant, scoped to that tenant's namespace(s). This ensures strict boundaries between tenants and prevents cross-tenant configuration leakage. Each Traefik instance should be: Deployed in the tenant's namespace with a dedicated ServiceAccount Configured with providers.kubernetesCRD.namespaces and/or providers.kubernetesIngress.namespaces to restrict resource watch to that tenant's namespaces only Subject to Kubernetes RBAC that limits its access to only the resources it needs This namespace-per-tenant topology, combined with Kubernetes NetworkPolicy resources, provides the strongest available isolation when running Traefik on a shared cluster. !!! tip "Dedicate one Traefik instance per tenant using the Helm Chart" ```yaml providers: kubernetesCRD: namespaces: - tenant kubernetesIngress: namespaces: - tenant ``` Gateway API We also encourage users to adopt Kubernetes Gateway API, which is designed with multi-tenancy as a first-class concern. Gateway API provides a more expressive and role-oriented model for managing ingress, with built-in support for delegating route configuration to individual tenants while preserving infrastructure-level control for cluster operators. This tooling handles multi-tenant scenarios more robustly than the traditional Ingress model and is the recommended direction for new deployments. For example, concerning TLS certificate management, the Listener resource allows administrators to explicitly define which Route resources (e.g., HTTPRoute) are permitted to bind to which domain names or ports. This enforces stricter ownership and isolation between tenants, making the Gateway API a safer and more robust choice for multi-tenant use cases than the traditional Ingress model. For new deployments in multi-tenant environments, adopting Gateway API is the recommended direction. Request Path Protecting Against Path-Based Attacks Through Sanitization and Filtering {: .subtitle } Traefik implements multiple layers of security when processing incoming request paths. This includes path sanitization to normalize potentially dangerous sequences and encoded character filtering to prevent attack vectors that use URL encoding. Understanding how Traefik handles request paths is crucial for maintaining a secure routing infrastructure. How Traefik Processes Request Paths When Traefik receives an HTTP request, it processes the request path through several security-focused stages: 1. Encoded Character Filtering Traefik inspects the path for potentially dangerous encoded characters and rejects requests containing them unless explicitly allowed. Here is the list of the encoded characters that are allowed by default: Encoded Character Character %2f or %2F / (slash) %5c or %5C \ (backslash) %00 NULL (null character) %3b or %3B ; (semicolon) %25 % (percent) %3f or %3F ? (question mark) %23 # (hash) 2. Path Normalization Traefik normalizes the request path by decoding the unreserved percent-encoded characters, as they are equivalent to their non-encoded form (according to rfc3986#section-2.3), and capitalizing the percent-encoded characters (according to rfc3986#section-6.2.2.1). 3. Path Sanitization Traefik sanitizes request paths to prevent common attack vectors, by removing the .., . and duplicate slash segments from the URL (according to rfc3986#section-6.2.2.3). Path Security Configuration Traefik provides two main mechanisms for path security that work together to protect your applications. Path Sanitization Path sanitization is enabled by default and helps prevent directory traversal attacks by normalizing request paths. Configure it in the EntryPoints HTTP section: entryPoints: websecure: address: ":443" http: sanitizePath: true # Default: true (recommended) [entryPoints.websecure] address = ":443" [entryPoints.websecure.http] sanitizePath = true --entryPoints.websecure.address=:443 --entryPoints.websecure.http.sanitizePath=true Sanitization behavior: ./foo/bar → /foo/bar (removes relative current directory) /foo/../bar → /bar (resolves parent directory traversal) /foo/bar// → /foo/bar/ (removes duplicate slashes) /./foo/../bar// → /bar/ (combines all normalizations) Encoded Character Filtering Encoded character filtering provides an additional security layer by rejecting potentially dangerous URL-encoded characters. Configure it in the EntryPoints HTTP section. This filtering occurs before path sanitization and catches attack attempts that use encoding to bypass other security controls. All encoded character filtering is disabled by default ( true means encoded characters are allowed). !!! info "Security Considerations" When your backend is not fully compliant with [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) and notably decode encoded reserved characters in the requests path, it is recommended to set these options to `false` to avoid split-view situation and helps prevent path traversal attacks or other malicious attempts to bypass security controls. entryPoints: websecure: address: ":443" http: encodedCharacters: allowEncodedSlash: false # %2F - Default: true allowEncodedBackSlash: false # %5C - Default: true allowEncodedNullCharacter: false # %00 - Default: true allowEncodedSemicolon: false # %3B - Default: true allowEncodedPercent: false # %25 - Default: true allowEncodedQuestionMark: false # %3F - Default: true allowEncodedHash: false # %23 - Default: true [entryPoints.websecure] address = ":443" [entryPoints.websecure.http.encodedCharacters] allowEncodedSlash = false allowEncodedBackSlash = false allowEncodedNullCharacter = false allowEncodedSemicolon = false allowEncodedPercent = false allowEncodedQuestionMark = false allowEncodedHash = false --entryPoints.websecure.address=:443 --entryPoints.websecure.http.encodedCharacters.allowEncodedSlash=false --entryPoints.websecure.http.encodedCharacters.allowEncodedBackSlash=false --entryPoints.websecure.http.encodedCharacters.allowEncodedNullCharacter=false --entryPoints.websecure.http.encodedCharacters.allowEncodedSemicolon=false --entryPoints.websecure.http.encodedCharacters.allowEncodedPercent=false --entryPoints.websecure.http.encodedCharacters.allowEncodedQuestionMark=false --entryPoints.websecure.http.encodedCharacters.allowEncodedHash=false !!! info "Encoded Characters filtering on a per-route basis" If you need to configure encoded character filtering on a per-route basis, you can use the `EncodedCharacters` middleware. Refer to the documentation for the [`EncodedCharacter` middleware](../reference/routing-configuration/http/middlewares/encodedcharacters.md) for detailed implementation instructions and configuration options. Setup Traefik Proxy in Docker Standalone This guide provides an in-depth walkthrough for installing and configuring Traefik Proxy within a Docker container using the official Traefik Docker image & Docker Compose. In this guide, we'll cover the following: Enable the Docker provider Expose web (HTTP :80) and websecure (HTTPS :443) entrypoints Redirect all HTTP traffic to HTTPS Secure the Traefik dashboard with basic‑auth Terminate TLS with a self‑signed certificate for *.docker.localhost Deploy the whoami demo service Enable access‑logs and Prometheus metrics Prerequisites Docker Desktop / Engine Docker Compose openssl htpasswd from apache2-utils Create a self‑signed certificate Before Traefik can serve HTTPS locally it needs a certificate. In production you’d use one from a trusted CA, but for a single‑machine stack a quick self‑signed cert is enough. We can create one with openssl by running the following commands: mkdir -p certs openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout certs/local.key -out certs/local.crt \ -subj "/CN=*.docker.localhost" The certs folder now holds local.crt and local.key, which will be mounted read‑only into Traefik. Create the Traefik Dashboard Credentials In production, it is advisable to have some form of authentication/security for the Traefik dashboard. Traefik can be secured with the basic‑auth middleware. To do this, generate a hashed username / password pair that Traefik’s middleware will validate: htpasswd -nb admin "P@ssw0rd" | sed -e 's/\$/\$\$/g' Copy the full output (e.g., admin:$$apr1$$…) — we'll need this for the middleware configuration. Create a docker-compose.yaml Now define the whole stack in a Compose file. This file declares Traefik, mounts the certificate, sets up a dedicated network, and later hosts the whoami demo service. !!! note You can also choose to use the Docker CLI and a configuration file to run Traefik, but for this tutorial, we'll be using Docker Compose. First, create a folder named dynamic and create a file named tls.yaml for dynamic configuration. Paste the TLS certificate configuration into the file: tls: certificates: - certFile: /certs/local.crt keyFile: /certs/local.key In your project root folder (the parent folder to the dynamic/tls.yaml file), create a docker-compose.yaml file and include the following: services: traefik: image: traefik:v3.8 container_name: traefik restart: unless-stopped security_opt: - no-new-privileges:true networks: # Connect to the 'traefik_proxy' overlay network for inter-container communication across nodes - proxy ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock - ./certs:/certs:ro - ./dynamic:/dynamic:ro command: # EntryPoints - "--entrypoints.web.address=:80" - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - "--entrypoints.web.http.redirections.entrypoint.scheme=https" - "--entrypoints.web.http.redirections.entrypoint.permanent=true" - "--entrypoints.websecure.address=:443" - "--entrypoints.websecure.http.tls=true" # Attach the static configuration tls.yaml file that contains the tls configuration settings - "--providers.file.filename=/dynamic/tls.yaml" # Providers - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=proxy" # API & Dashboard - "--api.dashboard=true" - "--api.insecure=false" # Observability - "--log.level=INFO" - "--accesslog=true" - "--metrics.prometheus=true" # Traefik Dynamic configuration via Docker labels labels: # Enable self‑routing - "traefik.enable=true" # Dashboard router - "traefik.http.routers.dashboard.rule=Host(`dashboard.docker.localhost`)" - "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.tls=true" # Basic‑auth middleware - "traefik.http.middlewares.dashboard-auth.basicauth.users=" - "traefik.http.routers.dashboard.middlewares=dashboard-auth@docker" # Whoami application whoami: image: traefik/whoami container_name: whoami restart: unless-stopped networks: - proxy labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)" - "traefik.http.routers.whoami.entrypoints=websecure" - "traefik.http.routers.whoami.tls=true" networks: proxy: name: proxy !!! info - Remember to replace with the hash generated earlier. - The --api.insecure=false flag is used to secure the API and prevent the dashboard from being exposed on port 8080. This is done because we are exposing the dashboard with a HTTPS router. Launch the stack With the Compose file and supporting assets in place, start the containers and let Docker wire up networking behind the scenes: docker compose up -d Traefik will start, read its static configuration from the command arguments, connect to the Docker socket, detect its own labels for dynamic configuration (dashboard routing and auth), and begin listening on ports 80 and 443. HTTP requests will be redirected to HTTPS. Access the Dashboard Now that Traefik is deployed, you can access the dashboard at https://dashboard.docker.localhost and it should prompt for the Basic Authentication credentials you configured: Test the whoami Application You can test the application using curl: curl -k https://whoami.docker.localhost/ Hostname: whoami-76c9859cfc-k7jzs IP: 127.0.0.1 IP: ::1 IP: 10.42.0.59 IP: fe80::50d7:a2ff:fed5:2530 RemoteAddr: 10.42.0.60:54148 GET / HTTP/1.1 Host: whoami.docker.localhost User-Agent: curl/8.7.1 Accept: */* Accept-Encoding: gzip X-Forwarded-For: 10.42.0.1 X-Forwarded-Host: whoami.docker.localhost X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Forwarded-Server: traefik-644b7c67d9-f2tn9 X-Real-Ip: 10.42.0.1 Making the same request to the HTTP entrypoint will return the following: curl -k http://whoami.docker.localhost Moved Permanently The above confirms that a redirection has taken place which means our setup works correctly. You can also open a browser and navigate to https://whoami.docker.localhost to see a JSON dump from the service: !!! info You can also navigate to the Traefik Dashboard at https://dashboard.docker.localhost to see that the route has been created. Other Key Configuration Areas Beyond this initial setup, Traefik offers extensive configuration possibilities. Here are brief introductions and minimal examples using Docker Compose command arguments or labels. Consult the main documentation linked for comprehensive details. TLS Certificate Management (Let's Encrypt) To make the websecure entry point serve valid HTTPS certificates automatically, enable Let's Encrypt (ACME). Example command additions: command: # ... other command arguments ... - "--certificatesresolvers.le.acme.email=your-email@example.com" - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json" # Path inside container volume - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web" # - "--certificatesresolvers.le.acme.dnschallenge.provider=your-dns-provider" # Needs provider setup # Optionally make 'le' the default resolver for TLS-enabled routers - "--entrypoints.websecure.http.tls.certresolver=le" This defines a resolver named le, sets the required email and storage path (within the mounted /letsencrypt volume), and enables the HTTP challenge. Refer to the HTTPS/TLS Documentation and Let's Encrypt Documentation for details on challenges and DNS provider configuration. Metrics (Prometheus) You can expose Traefik's internal metrics for monitoring with Prometheus. We already enabled prometheus in our setup but we can further configure it. Example command additions: command: # If using a dedicated metrics entry point, define it: - "--entrypoints.metrics.address=:8082" # ... other command arguments ... - "--metrics.prometheus=true" # Optionally change the entry point metrics are exposed on (defaults to 'traefik') - "--metrics.prometheus.entrypoint=metrics" # Add labels to metrics for routers/services (can increase cardinality) - "--metrics.prometheus.addrouterslabels=true" - "--metrics.prometheus.addserviceslabels=true" This enables the /metrics endpoint (typically accessed via the internal API port, often 8080 by default if not secured, or via a dedicated entry point). See the Metrics Documentation for options. Tracing (OTel): You can enable distributed tracing to follow requests through Traefik. Example command additions: command: # ... other command arguments ... - "--tracing.otel=true" - "--tracing.otel.grpcendpoint=otel-collector:4317" # Adjust endpoint as needed - "--tracing.otel.httpendpoint=otel-collector.observability:4318" # Adjust endpoint as needed !!! note This option requires a running OTEL collector accessible by Traefik. Consult the Tracing Documentation. Access Logs You can configure Traefik to log incoming requests for debugging and analysis. Example command additions: command: # ... other command arguments ... - "--accesslog=true" # Enable access logs to stdout # Optionally change format or output file (requires volume) - "--accesslog.format=json" - "--accesslog.filepath=/path/to/access.log" # Optionally filter logs - "--accesslog.filters.statuscodes=400-599" This enables access logs to the container's standard output (viewable via docker compose logs ). See the Access Logs Documentation. Conclusion You now have a basic Traefik setup in Docker with secure dashboard access and HTTP-to-HTTPS redirection. {% include-markdown "includes/traefik-for-business-applications.md" %} Setup Traefik on Kubernetes This guide provides an in-depth walkthrough for installing and configuring Traefik Proxy within a Kubernetes cluster using the official Helm chart. In this guide, we'll cover the following: Configure standard HTTP ( web) and HTTPS ( websecure) entry points Implement automatic redirection from HTTP to HTTPS Secure the Traefik Dashboard using Basic Authentication Deploy a demo application to test the setup Explore some other key configuration options Prerequisites A Kubernetes cluster Helm v3 Kubectl Create the Cluster If you do not have a Kubernetes cluster already, you can spin up one with K3d: k3d cluster create traefik \ --port 80:80@loadbalancer \ --port 443:443@loadbalancer \ --port 8000:8000@loadbalancer \ --k3s-arg "--disable=traefik@server:0" Ports 80 and 443 reach Traefik from the host, while port 8000 remains free for later demos. The built-in Traefik shipped with k3s is disabled to avoid conflicts. Check the context: kubectl cluster-info --context k3d-traefik You should see something like this: Kubernetes control plane is running at https://0.0.0.0:56049 CoreDNS is running at https://0.0.0.0:56049/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy Metrics-server is running at https://0.0.0.0:56049/api/v1/namespaces/kube-system/services/https:metrics-server:https/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. Add the chart repo and namespace Using Helm streamlines Kubernetes application deployment. Helm packages applications into "charts," which are collections of template files describing Kubernetes resources. We use the official Traefik Helm chart for a managed and customizable installation. helm repo add traefik https://traefik.github.io/charts helm repo update kubectl create namespace traefik The first command registers the traefik repository alias pointing to the official chart location. The second command refreshes your local cache to ensure you have the latest list of charts and versions available from all configured repositories. Create a Local Self‑Signed TLS Secret Traefik's Gateway listeners require a certificate whenever a listener uses protocol: HTTPS. For local development create a throw‑away self‑signed certificate and store it in a Kubernetes Secret named local‑selfsigned‑tls. The Gateway references this secret to terminate TLS on the websecure listener. # 1) Generate a self‑signed certificate valid for *.docker.localhost openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout tls.key -out tls.crt \ -subj "/CN=*.docker.localhost" # 2) Create the TLS secret in the traefik namespace kubectl create secret tls local-selfsigned-tls \ --cert=tls.crt --key=tls.key \ --namespace traefik Why Do We Need To Do This The Gateway's HTTPS listener references this secret via certificateRefs. Without it, the helm chart validation fails and the HTTP→HTTPS redirect chain breaks. !!! info "Production tip" The self-signed certificate above is only for local development. For production, either store a certificate issued by your organization's CA in a Secret or let an automated issuer such as cert-manager or Traefik's ACME (Let's Encrypt) generate certificates on demand. Update the certificateRefs in the websecure listener—or use traefik.io/tls.certresolver—so clients receive a trusted certificate and no longer see browser warnings. Prepare Helm Chart Configuration Values Create a values.yaml file with the following content: # Configure Network Ports and EntryPoints # EntryPoints are the network listeners for incoming traffic. ports: # Defines the HTTP entry point named 'web' web: port: 80 nodePort: 30000 # Instructs this entry point to redirect all traffic to the 'websecure' entry point http: redirections: entryPoint: to: websecure scheme: https permanent: true # Defines the HTTPS entry point named 'websecure' websecure: port: 443 nodePort: 30001 # Enables the dashboard in Secure Mode api: dashboard: true insecure: false ingressRoute: dashboard: enabled: true matchRule: Host(`dashboard.docker.localhost`) entryPoints: - websecure middlewares: - name: dashboard-auth # Creates a BasicAuth Middleware and Secret for the Dashboard Security extraObjects: - apiVersion: v1 kind: Secret metadata: name: dashboard-auth-secret type: kubernetes.io/basic-auth stringData: username: admin password: "P@ssw0rd" # Replace with an Actual Password - apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: dashboard-auth spec: basicAuth: secret: dashboard-auth-secret # We will route with Gateway API instead. ingressClass: enabled: false # Enable Gateway API Provider & Disables the KubernetesIngress provider # Providers tell Traefik where to find routing configuration. providers: kubernetesIngress: enabled: false kubernetesGateway: enabled: true ## Gateway Listeners gateway: listeners: web: # HTTP listener that matches entryPoint `web` port: 80 protocol: HTTP namespacePolicy: from: All websecure: # HTTPS listener that matches entryPoint `websecure` port: 443 protocol: HTTPS # TLS terminates inside Traefik namespacePolicy: from: All mode: Terminate certificateRefs: - kind: Secret name: local-selfsigned-tls # the Secret we created before the installation group: "" # Enable Observability log: level: INFO # This enables access logs, outputting them to Traefik's standard output by default. The [Access Logs Documentation](https://doc.traefik.io/traefik/observability/access-logs/) covers formatting, filtering, and output options. accessLog: enabled: true # Enables Prometheus for Metrics metrics: prometheus: enabled: true Install the Traefik Using the Helm Values Now, apply the configuration using the Helm client. # Install the chart into the 'traefik' namespace helm install traefik traefik/traefik \ --namespace traefik \ --values values.yaml Command Breakdown: helm install traefik: Instructs Helm to install a new release named traefik. traefik/traefik: Specifies the chart to use ( traefik chart from the traefik repository added earlier). --namespace traefik: Specifies the Kubernetes namespace to install into. Using a dedicated namespace is recommended practice. --values values.yaml: Applies the custom configuration from your values.yaml file. Accessing the Dashboard Now that Traefik is deployed, you can access its dashboard at https://dashboard.docker.localhost/. When you access this link, your browser will prompt for the username and password. Ensure you use the credentials set in the values.yaml file to log in. Upon successful login, the dashboard will be displayed as shown below: Deploy a Demo Application To test the setup, deploy the Traefik whoami application in the Kubernetes cluster. Create a file named whoami.yaml and paste the following: apiVersion: apps/v1 kind: Deployment metadata: name: whoami namespace: traefik spec: replicas: 2 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: whoami namespace: traefik spec: selector: app: whoami ports: - port: 80 Apply the manifest: kubectl apply -f whoami.yaml After deploying the application, you can expose the application by creating a Gateway API HTTPRoute. To do this, create a file named whoami-route.yaml and paste the following: apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami namespace: traefik spec: parentRefs: - name: traefik-gateway # Name of the Gateway that Traefik creates when you enable the Gateway API provider hostnames: - "whoami.docker.localhost" rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: whoami port: 80 Apply the manifest: kubectl apply -f whoami-route.yaml After you apply the manifest, navigate to the Routes in the Traefik Dashboard; you’ll see that the https://whoami.docker.localhost route has been created. You can test the application using curl: curl -k https://whoami.docker.localhost/ Hostname: whoami-76c9859cfc-k7jzs IP: 127.0.0.1 IP: ::1 IP: 10.42.0.59 IP: fe80::50d7:a2ff:fed5:2530 RemoteAddr: 10.42.0.60:54148 GET / HTTP/1.1 Host: whoami.docker.localhost User-Agent: curl/8.7.1 Accept: */* Accept-Encoding: gzip X-Forwarded-For: 10.42.0.1 X-Forwarded-Host: whoami.docker.localhost X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Forwarded-Server: traefik-644b7c67d9-f2tn9 X-Real-Ip: 10.42.0.1 You can also open a browser and navigate to https://whoami.docker.localhost to see a JSON dump from the service. Other Key Configuration Areas The above setup provides a secure base, but Traefik offers much more. Here's a brief overview of other essential configurations, with minimal examples using Helm values.yaml overrides. These examples illustrate how to enable features; consult the main documentation for detailed options. TLS Certificate Management (Let's Encrypt) On the websecure entry point TLS is enabled by default. However, it currently lacks a valid certificate. Traefik can automatically obtain and renew TLS certificates from Let's Encrypt using the ACME protocol. Example values.yaml addition: additionalArguments: - "--certificatesresolvers.le.acme.email=your-email@example.com" - "--certificatesresolvers.le.acme.storage=/data/acme.json" - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web" # - "--certificatesresolvers.le.acme.dnschallenge.provider=your-dns-provider" # Requires provider-specific config, adjust if you control your DNS provider # Enable persistence for ACME data (certificates, account) to ensure it survives pod restarts: persistence: enabled: true name: data size: 1Gi storageClass: "" This enables a certificate resolver named le, configures the mandatory email and storage file, and sets up the HTTP challenge (requires port 80 access). Refer to the HTTPS/TLS Documentation and Let's Encrypt Documentation for full details, including DNS challenge configuration. !!!info "Let's Encrypt in Production" Let's Encrypt can only issue certificates for hostnames that point to a public IP address reachable on ports 80 (HTTP‑01) or via your DNS provider's API (DNS‑01). Replace the *.docker.localhost examples with a real domain you control, create the DNS records, and keep ports 80/443 open to your cluster so the validation can succeed. Gateway API & ACME Traefik’s built‑in ACME/Let’s Encrypt integration works for IngressRoute and Ingress resources, but it does not issue certificates for Gateway API listeners. If you’re using the Gateway API, install cert‑manager (or another certificate controller) and reference the secret it creates in gateway.listeners.websecure.certificateRefs. Metrics (Prometheus) Traefik can expose detailed metrics in Prometheus format, essential for monitoring its performance and the traffic it handles. Example values.yaml addition: # Enable metrics endpoint metrics: prometheus: # The entry point metrics will be available on (usually internal/admin) entryPoint: metrics # Add standard Prometheus metrics addRoutersLabels: true addServicesLabels: true # ... other options available This enables the Prometheus endpoint on a dedicated metrics entry point (port 9100). See the Metrics Documentation for configuration details and available metrics. Tracing (OTel) Distributed tracing helps understand request latency and flow through your system, including Traefik itself. Example values.yaml addition: additionalArguments: - "--tracing.otel=true" - "--tracing.otel.grpcendpoint=otel-collector.observability:4317" # Adjust endpoint as needed - "--tracing.otel.httpendpoint=otel-collector.observability:4318" # Adjust endpoint as needed This enables OTel tracing and specifies the collector endpoint. Consult the Tracing Documentation for details on OTel tracing. Conclusion This setup establishes Traefik with secure dashboard access and HTTPS redirection, along with pointers to enable observability & TLS. {% include-markdown "includes/traefik-for-business-applications.md" %} Setup Traefik Proxy in Docker Swarm This guide provides an in‑depth walkthrough for installing and configuring Traefik Proxy as a Swarm service using docker stack deploy. It follows the same structure as the standalone‑Docker tutorial and covers: Enable the Swarm provider Expose web (HTTP :80) and websecure (HTTPS :443) entrypoints Redirect all HTTP traffic to HTTPS Secure the Traefik dashboard with basic‑auth Terminate TLS with a self‑signed certificate for *.swarm.localhost Deploy the whoami demo service Enable access‑logs and Prometheus metrics Prerequisites Docker Engine with Swarm mode initialised ( docker swarm init) Docker Compose openssl htpasswd Create a self‑signed certificate Before Traefik can serve HTTPS locally it needs a certificate. In production you’d use one from a trusted CA, but for a multi‑node dev swarm a quick self‑signed cert is enough: mkdir -p certs openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout certs/local.key -out certs/local.crt \ -subj "/CN=*.swarm.localhost" Create the Traefik Dashboard Credentials Generate a hashed username / password pair that Traefik’s middleware will validate: htpasswd -nb admin "P@ssw0rd" | sed -e 's/\$/\$\$/g' Copy the full output (e.g., admin:$$apr1$$…) — we’ll paste it into the middleware label. Create a docker‑compose‑swarm.yaml !!! note Swarm uses  docker stack deploy. The compose file can be named anything; we’ll use docker‑compose‑swarm.yaml. First, create a folder named dynamic and add tls.yaml for dynamic TLS configuration: # dynamic/tls.yaml tls: certificates: - certFile: /certs/local.crt keyFile: /certs/local.key In the same directory, create docker‑compose‑swarm.yaml: services: traefik: image: traefik:v3.8 networks: # Connect to the 'traefik_proxy' overlay network for inter-container communication across nodes - traefik_proxy ports: # Expose Traefik's entry points to the Swarm # Swarm requires the long syntax for ports. - target: 80 # Container port (Traefik web entry point) published: 80 # Host port exposed on the nodes protocol: tcp # 'host' mode binds directly to the node's IP where the task runs. # 'ingress' mode uses Swarm's Routing Mesh (load balances across nodes). # Choose based on your load balancing strategy. 'host' is often simpler if using an external LB. mode: host - target: 443 # Container port ( Traefik websecure entry point) published: 443 # Host port protocol: tcp mode: host volumes: # Mount the Docker socket for the Swarm provider # This MUST be run from a manager node to access the Swarm API via the socket. - /var/run/docker.sock:/var/run/docker.sock:ro # Swarm API socket - ./certs:/certs:ro - ./dynamic:/dynamic:ro # Traefik Static configuration via command-line arguments command: # HTTP EntryPoint - "--entrypoints.web.address=:80" # Configure HTTP to HTTPS Redirection - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - "--entrypoints.web.http.redirections.entrypoint.scheme=https" - "--entrypoints.web.http.redirections.entrypoint.permanent=true" # HTTPS EntryPoint - "--entrypoints.websecure.address=:443" - "--entrypoints.websecure.http.tls=true" # Attach dynamic TLS file - "--providers.file.filename=/dynamic/tls.yaml" # Providers # Enable the Docker Swarm provider (instead of Docker provider) - "--providers.swarm.endpoint=unix:///var/run/docker.sock" # Watch for Swarm service changes (requires socket access) - "--providers.swarm.watch=true" # Recommended: Don't expose services by default; require explicit labels - "--providers.swarm.exposedbydefault=false" # Specify the default network for Traefik to connect to services - "--providers.swarm.network=traefik_traefik_proxy" # API & Dashboard - "--api.dashboard=true" # Enable the dashboard - "--api.insecure=false" # Explicitly disable insecure API mod # Observability - "--log.level=INFO" # Set the Log Level e.g INFO, DEBUG - "--accesslog=true" # Enable Access Logs - "--metrics.prometheus=true" # Enable Prometheus deploy: mode: replicated replicas: 1 placement: # Placement constraints restrict where Traefik tasks can run. # Running on manager nodes is common for accessing the Swarm API via the socket. constraints: - node.role == manager # Traefik Dynamic configuration via labels # In Swarm, labels on the service definition configure Traefik routing for that service. labels: - "traefik.enable=true" # Dashboard router - "traefik.http.routers.dashboard.rule=Host(`dashboard.swarm.localhost`)" - "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.tls=true" # Basic‑auth middleware - "traefik.http.middlewares.dashboard-auth.basicauth.users=" - "traefik.http.routers.dashboard.middlewares=dashboard-auth@swarm" # Service hint - "traefik.http.services.traefik.loadbalancer.server.port=8080" # Deploy the Whoami application whoami: image: traefik/whoami networks: - traefik_proxy deploy: labels: # Enable Service discovery for Traefik - "traefik.enable=true" # Define the WHoami router rule - "traefik.http.routers.whoami.rule=Host(`whoami.swarm.localhost`)" # Expose Whoami on the HTTPS entrypoint - "traefik.http.routers.whoami.entrypoints=websecure" # Enable TLS - "traefik.http.routers.whoami.tls=true" # Expose the whoami port number to Traefik - traefik.http.services.whoami.loadbalancer.server.port=80 # Define the overlay network for Swarm networks: traefik_proxy: driver: overlay attachable: true !!! info - Replace with the escaped hash from the previous step. - The password hash is stored directly in a service label. This is fine for local development, but anyone with access to the Docker API can view it using docker service inspect. For production, use a more secure method to store secrets. Launch the stack Create the overlay network once (if it doesn’t exist) and deploy: docker network create --driver overlay --attachable traefik_proxy || true docker stack deploy -c docker-compose-swarm.yaml traefik Swarm schedules the services on a manager node and binds ports 80/443. Access the Dashboard Open https://dashboard.swarm.localhost/ in your browser — the dashboard should prompt for the basic‑auth credentials you configured. Test the whoami Application You can test the application using curl: curl -k https://whoami.swarm.localhost/ Hostname: whoami-76c9859cfc-k7jzs IP: 127.0.0.1 IP: ::1 IP: 10.42.0.59 IP: fe80::50d7:a2ff:fed5:2530 RemoteAddr: 10.42.0.60:54148 GET / HTTP/1.1 Host: whoami.swarm.localhost User-Agent: curl/8.7.1 Accept: */* Accept-Encoding: gzip X-Forwarded-For: 10.42.0.1 X-Forwarded-Host: whoami.swarm.localhost X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Forwarded-Server: traefik-644b7c67d9-f2tn9 X-Real-Ip: 10.42.0.1 Making the same request to the HTTP entrypoint will return the following: curl -k http://whoami.swarm.localhost Moved Permanently Requesting the HTTP endpoint redirects to HTTPS, confirming the setup works. You can also open a browser and navigate to https://whoami.swarm.localhost to see a JSON dump from the service: Other Key Configuration Areas Beyond this initial setup, Traefik offers extensive configuration possibilities. Here are brief introductions and minimal examples using Docker Compose command arguments or labels. Consult the main documentation linked for comprehensive details. TLS Certificate Management (Let’s Encrypt) To make the websecure entry point serve valid HTTPS certificates automatically, enable Let's Encrypt (ACME). command: # ... - "--certificatesresolvers.le.acme.email=you@example.com" - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json" - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web" - "--entrypoints.websecure.http.tls.certresolver=le" This defines a resolver named le, sets the required email and storage path (within the mounted /letsencrypt volume), and enables the HTTP challenge. Refer to the HTTPS/TLS Documentation and Let's Encrypt Documentation for details on challenges and DNS provider configuration. !!! note - Ensure the `/letsencrypt` path is on a **shared volume** or NFS so all nodes can read certificates. - Ensure to mount the `/letsencrypt` volume in the `traefik` service in the `docker-compose-swarm.yaml` file. Metrics (Prometheus) You can expose Traefik's internal metrics for monitoring with Prometheus. We already enabled prometheus in our setup but we can further configure it. Example command additions: command: # If using a dedicated metrics entry point, define it: - "--entrypoints.metrics.address=:8082" - "--metrics.prometheus=true" # Optionally change the entry point metrics are exposed on (defaults to 'traefik') - "--metrics.prometheus.entrypoint=metrics" # Add labels to metrics for routers/services (can increase cardinality) - "--metrics.prometheus.addrouterslabels=true" This enables the /metrics endpoint (typically accessed via the internal API port, often 8080 by default if not secured, or via a dedicated entry point). See the Metrics Documentation for options. Tracing (OTel) You can enable distributed tracing to follow requests through Traefik. Example command additions: command: # ... - "--tracing.otel=true" - "--tracing.otel.grpcendpoint=otel-collector:4317" !!! note This option requires a running OTEL collector accessible by Traefik. Consult the Tracing Documentation. Access Logs You can configure Traefik to log incoming requests for debugging and analysis. Example command additions: command: # ... other command arguments ... - "--accesslog=true" # Enable access logs to stdout # Optionally change format or output file (requires volume) - "--accesslog.format=json" - "--accesslog.filepath=/path/to/access.log" # Optionally filter logs - "--accesslog.filters.statuscodes=400-599" Conclusion You now have Traefik running on Docker Swarm with HTTPS, a secured dashboard, automatic HTTP → HTTPS redirects, and foundational observability. Expand this stack with Let’s Encrypt, additional middlewares, or multiple Traefik replicas as your Swarm grows. {% include-markdown "includes/traefik-for-business-applications.md" %} LICENSE The MIT License (MIT) Copyright (c) 2016-2020 Containous SAS; 2020-2025 Traefik Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Documentation Tooling Tool Documentation Sources mkdocs documentation Sources mkdocs-material documentation Sources pymdown-extensions documentation Sources Build locally without docker # Pre-requisite: python3, pip and virtualenv DOCS="/tmp/traefik-docs" mkdir "$DOCS" virtualenv "$DOCS" source "$DOCS/bin/activate" pip install -r requirements.txt mkdocs serve # or mkdocs build