diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index b920e1793..000000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-# These are supported funding model platforms
-
-github: traefik
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index 8d124b341..000000000
--- a/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,77 +0,0 @@
-
-
-### Do you want to request a *feature* or report a *bug*?
-
-
-
-Bug
-
-
-
-### What did you do?
-
-
-
-### What did you expect to see?
-
-
-
-### What did you see instead?
-
-
-
-### Output of `traefik version`: (_What version of Traefik are you using?_)
-
-
-
-```
-(paste your output here)
-```
-
-### What is your environment & configuration (arguments, toml, provider, platform, ...)?
-
-```toml
-# (paste your configuration here)
-```
-
-
-
-
-### If applicable, please paste the log output in DEBUG level (`--log.level=DEBUG` switch)
-
-```
-(paste your output here)
-```
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
deleted file mode 100644
index ce21d35ee..000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ /dev/null
@@ -1,82 +0,0 @@
-name: Bug Report (Traefik)
-description: Create a report to help us improve.
-body:
- - type: checkboxes
- id: terms
- attributes:
- label: Welcome!
- description: |
- The issue tracker is for reporting bugs and feature requests only.
- For end-user related support questions, please use the [Traefik community forum](https://community.traefik.io/).
-
- All new/updated issues are triaged regularly by the maintainers.
- All issues closed by a bot are subsequently double-checked by the maintainers.
-
- DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
-
- options:
- - label: Yes, I've searched similar issues on [GitHub](https://github.com/traefik/traefik/issues) and didn't find any.
- required: true
- - label: Yes, I've searched similar issues on the [Traefik community forum](https://community.traefik.io) and didn't find any.
- required: true
-
- - type: textarea
- attributes:
- label: What did you do?
- description: |
- How to write a good bug report?
-
- - Respect the issue template as much as possible.
- - The title should be short and descriptive.
- - Explain the conditions which led you to report this issue: the context.
- - The context should lead to something, an idea or a problem that you’re facing.
- - Remain clear and concise.
- - Format your messages to help the reader focus on what matters and understand the structure of your message, use [Markdown syntax](https://help.github.com/articles/github-flavored-markdown)
- placeholder: What did you do?
- validations:
- required: true
-
- - type: textarea
- attributes:
- label: What did you see instead?
- placeholder: What did you see instead?
- validations:
- required: true
-
- - type: textarea
- attributes:
- label: What version of Traefik are you using?
- description: |
- `latest` is not considered as a valid version.
-
- Output of `traefik version`.
-
- For the Traefik Docker image (`docker run [IMAGE] version`), example:
- ```console
- $ docker run traefik version
- ```
- placeholder: Paste your output here.
- validations:
- required: true
-
- - type: textarea
- attributes:
- label: What is your environment & configuration?
- description: arguments, toml, provider, platform, ...
- placeholder: Add information here.
- value: |
- ```yaml
- # (paste your configuration here)
- ```
-
- Add more configuration information here.
- validations:
- required: true
-
- - type: textarea
- attributes:
- label: If applicable, please paste the log output in DEBUG level
- description: "`--log.level=DEBUG` switch."
- placeholder: Paste your output here.
- validations:
- required: false
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
deleted file mode 100644
index 80c8c86b5..000000000
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-blank_issues_enabled: false
-contact_links:
- - name: Traefik Community Support
- url: https://community.traefik.io/
- about: If you have a question, or are looking for advice, please post on our Discuss forum! The community loves to chime in to help. Happy Coding!
- - name: Traefik Helm Chart Issues
- url: https://github.com/traefik/traefik-helm-chart
- about: Are you submitting an issue or feature enhancement for the Traefik helm chart? Please post in the traefik-helm-chart GitHub Issues.
diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml
deleted file mode 100644
index 5a092594d..000000000
--- a/.github/ISSUE_TEMPLATE/feature-request.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-name: Feature Request (Traefik)
-description: Suggest an idea for this project.
-body:
- - type: checkboxes
- id: terms
- attributes:
- label: Welcome!
- description: |
- The issue tracker is for reporting bugs and feature requests only. For end-user related support questions, please refer to one of the following:
- - the Traefik community forum: https://community.traefik.io/
-
- DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
- options:
- - label: Yes, I've searched similar issues on [GitHub](https://github.com/traefik/traefik/issues) and didn't find any.
- required: true
- - label: Yes, I've searched similar issues on the [Traefik community forum](https://community.traefik.io) and didn't find any.
- required: true
-
- - type: textarea
- attributes:
- label: What did you expect to see?
- description: |
- How to write a good issue?
-
- - Respect the issue template as much as possible.
- - The title should be short and descriptive.
- - Explain the conditions which led you to report this issue: the context.
- - The context should lead to something, an idea or a problem that you’re facing.
- - Remain clear and concise.
- - Format your messages to help the reader focus on what matters and understand the structure of your message, use [Markdown syntax](https://help.github.com/articles/github-flavored-markdown)
- placeholder: What did you expect to see?
- validations:
- required: true
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
deleted file mode 100644
index 2594684f6..000000000
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-### What does this PR do?
-
-
-
-
-### Motivation
-
-
-
-
-### More
-
-- [ ] Added/updated tests
-- [ ] Added/updated documentation
-
-### Additional Notes
-
-
diff --git a/.github/PULL_REQUEST_TEMPLATE/mergeback.md b/.github/PULL_REQUEST_TEMPLATE/mergeback.md
deleted file mode 100644
index dfc856011..000000000
--- a/.github/PULL_REQUEST_TEMPLATE/mergeback.md
+++ /dev/null
@@ -1,7 +0,0 @@
-### What does this PR do?
-
-Merge v{{.Version}} into master
-
-### Motivation
-
-Be sync.
diff --git a/.github/PULL_REQUEST_TEMPLATE/release.md b/.github/PULL_REQUEST_TEMPLATE/release.md
deleted file mode 100644
index 226a85a73..000000000
--- a/.github/PULL_REQUEST_TEMPLATE/release.md
+++ /dev/null
@@ -1,7 +0,0 @@
-### What does this PR do?
-
-Prepare release v{{.Version}}.
-
-### Motivation
-
-Create a new release.
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
deleted file mode 100644
index 0122f29e6..000000000
--- a/.github/workflows/build.yaml
+++ /dev/null
@@ -1,81 +0,0 @@
-name: Build Binaries
-
-on:
- pull_request:
- branches:
- - '*'
- paths-ignore:
- - 'docs/**'
- - '**.md'
- - 'script/gcg/**'
-
-env:
- GO_VERSION: '1.23'
- CGO_ENABLED: 0
-
-jobs:
-
- build-webui:
- uses: ./.github/workflows/template-webui.yaml
-
- build:
- runs-on: ubuntu-latest
-
- strategy:
- matrix:
- os: [ darwin, freebsd, linux, openbsd, windows ]
- arch: [ amd64, arm64 ]
- include:
- - os: freebsd
- arch: 386
- - os: linux
- arch: 386
- - os: linux
- arch: arm
- goarm: 6
- - os: linux
- arch: arm
- goarm: 7
- - os: linux
- arch: ppc64le
- - os: linux
- arch: riscv64
- - os: linux
- arch: s390x
- - os: openbsd
- arch: 386
- - os: windows
- arch: 386
- needs:
- - build-webui
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up Go ${{ env.GO_VERSION }}
- uses: actions/setup-go@v5
- env:
- ImageOS: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.goarm }}
- with:
- go-version: ${{ env.GO_VERSION }}
- check-latest: true
-
- - name: Artifact webui
- uses: actions/download-artifact@v4
- with:
- name: webui.tar.gz
-
- - name: Untar webui
- run: |
- tar xvf webui.tar.gz
- rm webui.tar.gz
-
- - name: Build
- env:
- GOOS: ${{ matrix.os }}
- GOARCH: ${{ matrix.arch }}
- GOARM: ${{ matrix.goarm }}
- run: make binary
diff --git a/.github/workflows/check_doc.yml b/.github/workflows/check_doc.yml
deleted file mode 100644
index c5fbddcec..000000000
--- a/.github/workflows/check_doc.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-name: Check Documentation
-
-on:
- pull_request:
- branches:
- - '*'
-
-jobs:
-
- docs:
- name: Check, verify and build documentation
- runs-on: ubuntu-latest
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Check documentation
- run: make docs-pull-images docs
- env:
- # These variables are not passed to workflows that are triggered by a pull request from a fork.
- DOCS_VERIFY_SKIP: ${{ vars.DOCS_VERIFY_SKIP }}
- DOCS_LINT_SKIP: ${{ vars.DOCS_LINT_SKIP }}
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
deleted file mode 100644
index f921d7789..000000000
--- a/.github/workflows/codeql.yml
+++ /dev/null
@@ -1,70 +0,0 @@
-name: "CodeQL"
-
-on:
- push:
- branches:
- - master
- - v*
- schedule:
- - cron: '11 22 * * 1'
-
-jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-latest
- permissions:
- actions: read
- contents: read
- security-events: write
-
- strategy:
- fail-fast: false
- matrix:
- language: [ 'javascript', 'go' ]
- # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
- # Use only 'java' to analyze code written in Java, Kotlin or both
- # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
- # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
-
- - name: setup go
- uses: actions/setup-go@v5
- if: ${{ matrix.language == 'go' }}
- with:
- go-version-file: 'go.mod'
-
- # Initializes the CodeQL tools for scanning.
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v3
- with:
- languages: ${{ matrix.language }}
- # If you wish to specify custom queries, you can do so here or in a config file.
- # By default, queries listed here will override any specified in a config file.
- # Prefix the list here with "+" to use these queries and those in the config file.
-
- # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
- # queries: security-extended,security-and-quality
-
-
- # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
- # If this step fails, then you should remove it and run the build manually (see below)
- - name: Autobuild
- uses: github/codeql-action/autobuild@v3
-
- # ℹ️ Command-line programs to run using the OS shell.
- # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
-
- # If the Autobuild fails above, remove it and uncomment the following three lines.
- # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
-
- # - run: |
- # echo "Run, Build Application using script"
- # ./location_of_script_within_repo/buildscript.sh
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v3
- with:
- category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml
deleted file mode 100644
index adfdcc74e..000000000
--- a/.github/workflows/documentation.yml
+++ /dev/null
@@ -1,52 +0,0 @@
-name: Build and Publish Documentation
-
-on:
- push:
- branches:
- - master
- - v*
-
-env:
- STRUCTOR_VERSION: v1.13.2
- MIXTUS_VERSION: v0.4.1
-
-jobs:
-
- docs:
- name: Doc Process
- runs-on: ubuntu-latest
- if: github.repository == 'traefik/traefik'
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Login to DockerHub
- uses: docker/login-action@v3
- with:
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Install Structor ${{ env.STRUCTOR_VERSION }}
- run: curl -sSfL https://raw.githubusercontent.com/traefik/structor/master/godownloader.sh | sh -s -- -b $HOME/bin ${STRUCTOR_VERSION}
-
- - name: Install Seo-doc
- run: curl -sSfL https://raw.githubusercontent.com/traefik/seo-doc/master/godownloader.sh | sh -s -- -b "${HOME}/bin"
-
- - name: Install Mixtus ${{ env.MIXTUS_VERSION }}
- run: curl -sSfL https://raw.githubusercontent.com/traefik/mixtus/master/godownloader.sh | sh -s -- -b $HOME/bin ${MIXTUS_VERSION}
-
- - name: Build documentation
- run: $HOME/bin/structor -o traefik -r traefik --dockerfile-url="https://raw.githubusercontent.com/traefik/traefik/v1.7/docs.Dockerfile" --menu.js-url="https://raw.githubusercontent.com/traefik/structor/master/traefik-menu.js.gotmpl" --rqts-url="https://raw.githubusercontent.com/traefik/structor/master/requirements-override.txt" --force-edit-url --exp-branch=master --debug
- env:
- STRUCTOR_LATEST_TAG: ${{ vars.STRUCTOR_LATEST_TAG }}
-
- - name: Apply seo
- run: $HOME/bin/seo -path=./site -product=traefik
-
- - name: Publish documentation
- run: $HOME/bin/mixtus --dst-doc-path="./traefik" --dst-owner=traefik --dst-repo-name=doc --git-user-email="30906710+traefiker@users.noreply.github.com" --git-user-name=traefiker --src-doc-path="./site" --src-owner=traefik --src-repo-name=traefik
- env:
- GITHUB_TOKEN: ${{ secrets.GH_TOKEN_REPO }}
diff --git a/.github/workflows/experimental.yaml b/.github/workflows/experimental.yaml
deleted file mode 100644
index 76959bbd5..000000000
--- a/.github/workflows/experimental.yaml
+++ /dev/null
@@ -1,70 +0,0 @@
-name: Build experimental image on branch
-
-on:
- push:
- branches:
- - master
- - v*
-
-env:
- GO_VERSION: '1.23'
- CGO_ENABLED: 0
-
-jobs:
-
- build-webui:
- if: github.repository == 'traefik/traefik'
- uses: ./.github/workflows/template-webui.yaml
-
- experimental:
- if: github.repository == 'traefik/traefik'
- name: Build experimental image on branch
- runs-on: ubuntu-latest
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up Go ${{ env.GO_VERSION }}
- uses: actions/setup-go@v5
- env:
- ImageOS: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.goarm }}
- with:
- go-version: ${{ env.GO_VERSION }}
- check-latest: true
-
- - name: Build
- run: make generate binary
-
- - name: Branch name
- run: echo ${GITHUB_REF##*/}
-
- - name: Login to Docker Hub
- uses: docker/login-action@v3
- with:
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v3
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
-
- - name: Artifact webui
- uses: actions/download-artifact@v4
- with:
- name: webui.tar.gz
-
- - name: Untar webui
- run: |
- tar xvf webui.tar.gz
- rm webui.tar.gz
-
- - name: Build docker experimental image
- env:
- DOCKER_BUILDX_ARGS: "--push"
- run: |
- make multi-arch-image-experimental-${GITHUB_REF##*/}
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
deleted file mode 100644
index 03a94ec91..000000000
--- a/.github/workflows/release.yaml
+++ /dev/null
@@ -1,138 +0,0 @@
-name: Release
-
-on:
- push:
- tags:
- - 'v*.*.*'
-
-env:
- GO_VERSION: '1.23'
- CGO_ENABLED: 0
- VERSION: ${{ github.ref_name }}
- TRAEFIKER_EMAIL: "traefiker@traefik.io"
- CODENAME: chaource
-
-jobs:
-
- build-webui:
- if: github.ref_type == 'tag' && github.repository == 'traefik/traefik'
- uses: ./.github/workflows/template-webui.yaml
-
- build:
- if: github.ref_type == 'tag' && github.repository == 'traefik/traefik'
- runs-on: ubuntu-latest
-
- strategy:
- matrix:
- os: [ linux-amd64, linux-386, linux-arm, linux-arm64, linux-ppc64le, linux-s390x, linux-riscv64, darwin, windows-amd64, windows-arm64, windows-386, freebsd, openbsd ]
- needs:
- - build-webui
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up Go ${{ env.GO_VERSION }}
- uses: actions/setup-go@v5
- env:
- # Ensure cache consistency on Linux, see https://github.com/actions/setup-go/pull/383
- ImageOS: ${{ matrix.os }}
- with:
- go-version: ${{ env.GO_VERSION }}
- check-latest: true
-
- - name: Artifact webui
- uses: actions/download-artifact@v4
- with:
- name: webui.tar.gz
-
- - name: Untar webui
- run: |
- tar xvf webui.tar.gz
- rm webui.tar.gz
-
- - name: Go generate
- run: go generate
-
-
- - name: Generate goreleaser file
- run: |
- GORELEASER_CONFIG_FILE_PATH=$(go run ./internal/release "${{ matrix.os }}")
- echo "GORELEASER_CONFIG_FILE_PATH=$GORELEASER_CONFIG_FILE_PATH" >> $GITHUB_ENV
-
- - name: Build with goreleaser
- uses: goreleaser/goreleaser-action@v6
- with:
- distribution: goreleaser
- # 'latest', 'nightly', or a semver
- version: '~> v2'
- args: release --clean --timeout="90m" --config "${{ env.GORELEASER_CONFIG_FILE_PATH }}"
-
- - name: Artifact binaries
- uses: actions/upload-artifact@v4
- with:
- name: ${{ matrix.os }}-binaries
- path: |
- dist/**/*_checksums.txt
- dist/**/*.tar.gz
- dist/**/*.zip
- retention-days: 1
-
- release:
- if: github.ref_type == 'tag' && github.repository == 'traefik/traefik'
- runs-on: ubuntu-latest
-
- needs:
- - build
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Artifact webui
- uses: actions/download-artifact@v4
- with:
- name: webui.tar.gz
-
- - name: Untar webui
- run: |
- tar xvf webui.tar.gz
- rm webui.tar.gz
-
- - name: Retrieve the secret and decode it to a file
- env:
- TRAEFIKER_RSA: ${{ secrets.TRAEFIKER_RSA }}
- run: |
- mkdir -p ~/.ssh
- echo "${TRAEFIKER_RSA}" | base64 --decode > ~/.ssh/traefiker_rsa
-
- - name: Download All Artifacts
- uses: actions/download-artifact@v4
- with:
- path: dist/
- pattern: "*-binaries"
- merge-multiple: true
-
- - name: Publish Release
- env:
- GH_TOKEN: ${{ github.token }}
- run: |
- cat dist/**/*_checksums.txt >> "dist/traefik_${VERSION}_checksums.txt"
- rm dist/**/*_checksums.txt
- tar cfz "dist/traefik-${VERSION}.src.tar.gz" \
- --exclude-vcs \
- --exclude .idea \
- --exclude .travis \
- --exclude .semaphoreci \
- --exclude .github \
- --exclude dist .
-
- chown -R "$(id -u)":"$(id -g)" dist/
- gh release create ${VERSION} ./dist/**/traefik*.{zip,tar.gz} ./dist/traefik*.{tar.gz,txt} --repo traefik/traefik --title ${VERSION} --notes ${VERSION}
-
- ./script/deploy.sh
-
diff --git a/.github/workflows/sync-docker-images.yaml b/.github/workflows/sync-docker-images.yaml
deleted file mode 100644
index 6f0b3c103..000000000
--- a/.github/workflows/sync-docker-images.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-name: Sync Docker Images
-
-on:
- workflow_dispatch:
- schedule:
- - cron: "0 0 * * *" # Run every day
-
-jobs:
- sync:
- runs-on: ubuntu-latest
- permissions:
- packages: write
- contents: read
- if: github.repository == 'traefik/traefik'
-
- steps:
- - uses: actions/checkout@v4
-
- - uses: imjasonh/setup-crane@v0.4
-
- - name: Sync
- run: |
- EXCLUDED_TAGS="1.7.9-alpine v1.0.0-beta.392 v1.0.0-beta.404 v1.0.0-beta.704 v1.0.0-rc1 v1.7.9-alpine"
- EXCLUDED_REGEX=$(echo $EXCLUDED_TAGS | sed 's/ /|/g')
- diff <(crane ls traefik) <(crane ls ghcr.io/traefik/traefik) | grep '^<' | awk '{print $2}' | while read -r tag; do [[ "$tag" =~ ^($EXCLUDED_REGEX)$ ]] || (echo "Processing image: traefik:$tag"; crane cp "traefik:$tag" "ghcr.io/traefik/traefik:$tag"); done
- crane cp traefik:latest ghcr.io/traefik/traefik:latest
diff --git a/.github/workflows/template-webui.yaml b/.github/workflows/template-webui.yaml
deleted file mode 100644
index df52d75c1..000000000
--- a/.github/workflows/template-webui.yaml
+++ /dev/null
@@ -1,37 +0,0 @@
-name: Build Web UI
-on:
- workflow_call: {}
-jobs:
-
- build-webui:
- runs-on: ubuntu-latest
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Setup node
- uses: actions/setup-node@v4
- with:
- node-version-file: webui/.nvmrc
- cache: yarn
- cache-dependency-path: webui/yarn.lock
-
- - name: Build webui
- working-directory: ./webui
- run: |
- yarn install
- yarn build
-
- - name: Package webui
- run: |
- tar czvf webui.tar.gz ./webui/static/
-
- - name: Artifact webui
- uses: actions/upload-artifact@v4
- with:
- name: webui.tar.gz
- path: webui.tar.gz
- retention-days: 1
diff --git a/.github/workflows/test-conformance.yaml b/.github/workflows/test-conformance.yaml
deleted file mode 100644
index f1f02709b..000000000
--- a/.github/workflows/test-conformance.yaml
+++ /dev/null
@@ -1,39 +0,0 @@
-name: Test K8s Gateway API conformance
-
-on:
- pull_request:
- branches:
- - '*'
- paths:
- - '.github/workflows/test-conformance.yaml'
- - 'pkg/provider/kubernetes/gateway/**'
- - 'integration/fixtures/k8s-conformance/**'
- - 'integration/k8s_conformance_test.go'
-
-env:
- GO_VERSION: '1.23'
- CGO_ENABLED: 0
-
-jobs:
-
- test-conformance:
- runs-on: ubuntu-latest
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up Go ${{ env.GO_VERSION }}
- uses: actions/setup-go@v5
- with:
- go-version: ${{ env.GO_VERSION }}
-
- - name: Avoid generating webui
- run: touch webui/static/index.html
-
- - name: K8s Gateway API conformance test and report
- run: |
- make test-gateway-api-conformance
- git diff --exit-code
diff --git a/.github/workflows/test-integration.yaml b/.github/workflows/test-integration.yaml
deleted file mode 100644
index f8eac5dc6..000000000
--- a/.github/workflows/test-integration.yaml
+++ /dev/null
@@ -1,78 +0,0 @@
-name: Test Integration
-
-on:
- pull_request:
- branches:
- - '*'
- paths-ignore:
- - 'docs/**'
- - '**.md'
- - 'script/gcg/**'
-
-env:
- GO_VERSION: '1.23'
- CGO_ENABLED: 0
-
-jobs:
-
- build:
- runs-on: ubuntu-latest
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up Go ${{ env.GO_VERSION }}
- uses: actions/setup-go@v5
- with:
- go-version: ${{ env.GO_VERSION }}
- check-latest: true
-
- - name: Avoid generating webui
- run: touch webui/static/index.html
-
- - name: Build binary
- run: make binary
-
- test-integration:
- runs-on: ubuntu-latest
- needs:
- - build
- strategy:
- fail-fast: true
- matrix:
- parallel: [12]
- index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up Go ${{ env.GO_VERSION }}
- uses: actions/setup-go@v5
- with:
- go-version: ${{ env.GO_VERSION }}
- check-latest: true
-
- - name: Avoid generating webui
- run: touch webui/static/index.html
-
- - name: Build binary
- run: make binary
-
- - name: Generate go test Slice
- id: test_split
- uses: hashicorp-forge/go-test-split-action@v2.0.0
- with:
- packages: ./integration
- total: ${{ matrix.parallel }}
- index: ${{ matrix.index }}
-
- - name: Run Integration tests
- run: |
- TESTS=$(echo "${{ steps.test_split.outputs.run}}" | sed 's/\$/\$\$/g')
- TESTFLAGS="-run \"${TESTS}\"" make test-integration
diff --git a/.github/workflows/test-unit.yaml b/.github/workflows/test-unit.yaml
deleted file mode 100644
index 7d4a0fa66..000000000
--- a/.github/workflows/test-unit.yaml
+++ /dev/null
@@ -1,57 +0,0 @@
-name: Test Unit
-
-on:
- pull_request:
- branches:
- - '*'
- paths-ignore:
- - 'docs/**'
- - '**.md'
- - 'script/gcg/**'
-
-env:
- GO_VERSION: '1.23'
-
-jobs:
-
- test-unit:
- runs-on: ubuntu-latest
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up Go ${{ env.GO_VERSION }}
- uses: actions/setup-go@v5
- with:
- go-version: ${{ env.GO_VERSION }}
- check-latest: true
-
- - name: Avoid generating webui
- run: touch webui/static/index.html
-
- - name: Tests
- run: make test-unit
-
- test-ui-unit:
- runs-on: ubuntu-latest
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up Node.js ${{ env.NODE_VERSION }}
- uses: actions/setup-node@v4
- with:
- node-version-file: webui/.nvmrc
- cache: 'yarn'
- cache-dependency-path: webui/yarn.lock
-
- - name: UI unit tests
- run: |
- yarn --cwd webui install
- yarn --cwd webui test:unit:ci
diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml
deleted file mode 100644
index 4ed5faec5..000000000
--- a/.github/workflows/validate.yaml
+++ /dev/null
@@ -1,87 +0,0 @@
-name: Validate
-
-on:
- pull_request:
- branches:
- - '*'
-
-env:
- GO_VERSION: '1.23'
- GOLANGCI_LINT_VERSION: v2.0.2
- MISSPELL_VERSION: v0.6.0
-
-jobs:
-
- lint:
- runs-on: ubuntu-latest
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up Go ${{ env.GO_VERSION }}
- uses: actions/setup-go@v5
- with:
- go-version: ${{ env.GO_VERSION }}
- check-latest: true
-
- - name: golangci-lint
- uses: golangci/golangci-lint-action@v7
- with:
- version: "${{ env.GOLANGCI_LINT_VERSION }}"
-
- validate:
- runs-on: ubuntu-latest
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up Go ${{ env.GO_VERSION }}
- uses: actions/setup-go@v5
- with:
- go-version: ${{ env.GO_VERSION }}
- check-latest: true
-
- - name: Install misspell ${{ env.MISSPELL_VERSION }}
- run: curl -sfL https://raw.githubusercontent.com/golangci/misspell/HEAD/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSPELL_VERSION}
-
- - name: Avoid generating webui
- run: touch webui/static/index.html
-
- - name: Validate
- run: make validate-files
-
- validate-generate:
- runs-on: ubuntu-latest
-
- steps:
- - name: Check out code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up Go ${{ env.GO_VERSION }}
- uses: actions/setup-go@v5
- with:
- go-version: ${{ env.GO_VERSION }}
- check-latest: true
-
- - name: go generate
- run: |
- make generate
- git diff --exit-code
-
- - name: go mod tidy
- run: |
- go mod tidy
- git diff --exit-code
-
- - name: make generate-crd
- run: |
- make generate-crd
- git diff --exit-code
diff --git a/Dockerfile b/Dockerfile
index fcf9c49b9..710d31a74 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -5,6 +5,7 @@ RUN apk add --no-cache --no-progress ca-certificates tzdata
ARG TARGETPLATFORM
COPY ./dist/$TARGETPLATFORM/traefik /
+COPY ./traefik.yml /etc/traefik/traefik.yml
EXPOSE 80
VOLUME ["/tmp"]
diff --git a/README.md b/README.md
index 652b4e5b7..aa7336940 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,7 @@
+# My modified version of Traefik
+slightly modified version of traefik, will be rebased on the latest tag from time to time
+this version includes callbacks to external services on configuration update and custom docker label mappings
+feel free to check out last 2 commits, they are like 100sloc together
@@ -43,14 +47,14 @@ Pointing Traefik at your orchestrator should be the _only_ configuration step yo
Imagine that you have deployed a bunch of microservices with the help of an orchestrator (like Swarm or Kubernetes) or a service registry (like etcd or consul).
Now you want users to access these microservices, and you need a reverse proxy.
-Traditional reverse-proxies require that you configure _each_ route that will connect paths and subdomains to _each_ microservice.
-In an environment where you add, remove, kill, upgrade, or scale your services _many_ times a day, the task of keeping the routes up to date becomes tedious.
+Traditional reverse-proxies require that you configure _each_ route that will connect paths and subdomains to _each_ microservice.
+In an environment where you add, remove, kill, upgrade, or scale your services _many_ times a day, the task of keeping the routes up to date becomes tedious.
**This is when Traefik can help you!**
-Traefik listens to your service registry/orchestrator API and instantly generates the routes so your microservices are connected to the outside world -- without further intervention from your part.
+Traefik listens to your service registry/orchestrator API and instantly generates the routes so your microservices are connected to the outside world -- without further intervention from your part.
-**Run Traefik and let it do the work for you!**
+**Run Traefik and let it do the work for you!**
_(But if you'd rather configure some of your routes manually, Traefik supports that too!)_

diff --git a/cmd/traefik/traefik.go b/cmd/traefik/traefik.go
index 77930754b..413907f17 100644
--- a/cmd/traefik/traefik.go
+++ b/cmd/traefik/traefik.go
@@ -49,6 +49,7 @@ import (
"github.com/traefik/traefik/v3/pkg/tracing"
"github.com/traefik/traefik/v3/pkg/types"
"github.com/traefik/traefik/v3/pkg/version"
+ "github.com/traefik/traefik/v3/pkg/updater"
)
func main() {
@@ -197,6 +198,8 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
tsProviders := initTailscaleProviders(staticConfiguration, providerAggregator)
+ updaterProvider := updater.New(staticConfiguration);
+
// Observability
metricRegistries := registerMetricClients(staticConfiguration.Metrics)
@@ -386,6 +389,9 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
}
})
+ // Updater
+ watcher.AddListener(updaterProvider.HandleConfigUpdate)
+
return server.NewServer(routinesPool, serverEntryPointsTCP, serverEntryPointsUDP, watcher, observabilityMgr), nil
}
diff --git a/docs/content/reference/static-configuration/cli-ref.md b/docs/content/reference/static-configuration/cli-ref.md
index b35cbc982..193f0c65d 100644
--- a/docs/content/reference/static-configuration/cli-ref.md
+++ b/docs/content/reference/static-configuration/cli-ref.md
@@ -369,6 +369,9 @@ Periodically check if a new version has been released. (Default: ```true```)
`--global.sendanonymoususage`:
Periodically send anonymous usage statistics. If the option is not specified, it will be disabled by default. (Default: ```false```)
+`--global.updatercallbacks`:
+Callback urls for updater script (example: https://localhost:8080/callback)
+
`--hostresolver`:
Enable CNAME Flattening. (Default: ```false```)
@@ -765,6 +768,18 @@ Expose containers by default. (Default: ```true```)
`--providers.docker.httpclienttimeout`:
Client timeout for HTTP connections. (Default: ```0```)
+`--providers.docker.labelmap`:
+Label shorthands.
+
+`--providers.docker.labelmap[n].from`:
+Shorthand label.
+
+`--providers.docker.labelmap[n].to`:
+Full label with templates.
+
+`--providers.docker.labelmap[n].value`:
+Optional override; used instead of user input if set.
+
`--providers.docker.network`:
Default Docker network used.
@@ -1164,6 +1179,18 @@ Expose containers by default. (Default: ```true```)
`--providers.swarm.httpclienttimeout`:
Client timeout for HTTP connections. (Default: ```0```)
+`--providers.swarm.labelmap`:
+Label shorthands.
+
+`--providers.swarm.labelmap[n].from`:
+Shorthand label.
+
+`--providers.swarm.labelmap[n].to`:
+Full label with templates.
+
+`--providers.swarm.labelmap[n].value`:
+Optional override; used instead of user input if set.
+
`--providers.swarm.network`:
Default Docker network used.
diff --git a/docs/content/reference/static-configuration/env-ref.md b/docs/content/reference/static-configuration/env-ref.md
index 8f6e25c05..849d058ab 100644
--- a/docs/content/reference/static-configuration/env-ref.md
+++ b/docs/content/reference/static-configuration/env-ref.md
@@ -369,6 +369,9 @@ Periodically check if a new version has been released. (Default: ```true```)
`TRAEFIK_GLOBAL_SENDANONYMOUSUSAGE`:
Periodically send anonymous usage statistics. If the option is not specified, it will be disabled by default. (Default: ```false```)
+`TRAEFIK_GLOBAL_UPDATERCALLBACKS`:
+Callback urls for updater script (example: https://localhost:8080/callback)
+
`TRAEFIK_HOSTRESOLVER`:
Enable CNAME Flattening. (Default: ```false```)
@@ -765,6 +768,18 @@ Expose containers by default. (Default: ```true```)
`TRAEFIK_PROVIDERS_DOCKER_HTTPCLIENTTIMEOUT`:
Client timeout for HTTP connections. (Default: ```0```)
+`TRAEFIK_PROVIDERS_DOCKER_LABELMAP`:
+Label shorthands.
+
+`TRAEFIK_PROVIDERS_DOCKER_LABELMAP_n_FROM`:
+Shorthand label.
+
+`TRAEFIK_PROVIDERS_DOCKER_LABELMAP_n_TO`:
+Full label with templates.
+
+`TRAEFIK_PROVIDERS_DOCKER_LABELMAP_n_VALUE`:
+Optional override; used instead of user input if set.
+
`TRAEFIK_PROVIDERS_DOCKER_NETWORK`:
Default Docker network used.
@@ -1164,6 +1179,18 @@ Expose containers by default. (Default: ```true```)
`TRAEFIK_PROVIDERS_SWARM_HTTPCLIENTTIMEOUT`:
Client timeout for HTTP connections. (Default: ```0```)
+`TRAEFIK_PROVIDERS_SWARM_LABELMAP`:
+Label shorthands.
+
+`TRAEFIK_PROVIDERS_SWARM_LABELMAP_n_FROM`:
+Shorthand label.
+
+`TRAEFIK_PROVIDERS_SWARM_LABELMAP_n_TO`:
+Full label with templates.
+
+`TRAEFIK_PROVIDERS_SWARM_LABELMAP_n_VALUE`:
+Optional override; used instead of user input if set.
+
`TRAEFIK_PROVIDERS_SWARM_NETWORK`:
Default Docker network used.
diff --git a/docs/content/reference/static-configuration/file.toml b/docs/content/reference/static-configuration/file.toml
index e548ee76d..13fd6b2bc 100644
--- a/docs/content/reference/static-configuration/file.toml
+++ b/docs/content/reference/static-configuration/file.toml
@@ -3,6 +3,7 @@
[global]
checkNewVersion = true
sendAnonymousUsage = true
+ updaterCallbacks = ["foobar", "foobar"]
[serversTransport]
insecureSkipVerify = true
@@ -97,6 +98,16 @@
password = "foobar"
endpoint = "foobar"
httpClientTimeout = "42s"
+
+ [[providers.docker.labelMap]]
+ from = "foobar"
+ to = "foobar"
+ value = "foobar"
+
+ [[providers.docker.labelMap]]
+ from = "foobar"
+ to = "foobar"
+ value = "foobar"
[providers.docker.tls]
ca = "foobar"
cert = "foobar"
@@ -115,6 +126,16 @@
endpoint = "foobar"
httpClientTimeout = "42s"
refreshSeconds = "42s"
+
+ [[providers.swarm.labelMap]]
+ from = "foobar"
+ to = "foobar"
+ value = "foobar"
+
+ [[providers.swarm.labelMap]]
+ from = "foobar"
+ to = "foobar"
+ value = "foobar"
[providers.swarm.tls]
ca = "foobar"
cert = "foobar"
diff --git a/docs/content/reference/static-configuration/file.yaml b/docs/content/reference/static-configuration/file.yaml
index 760802591..4c4fdc109 100644
--- a/docs/content/reference/static-configuration/file.yaml
+++ b/docs/content/reference/static-configuration/file.yaml
@@ -3,6 +3,9 @@
global:
checkNewVersion: true
sendAnonymousUsage: true
+ updaterCallbacks:
+ - foobar
+ - foobar
serversTransport:
insecureSkipVerify: true
rootCAs:
@@ -106,6 +109,13 @@ providers:
useBindPortIP: true
watch: true
defaultRule: foobar
+ labelMap:
+ - from: foobar
+ to: foobar
+ value: foobar
+ - from: foobar
+ to: foobar
+ value: foobar
username: foobar
password: foobar
endpoint: foobar
@@ -123,6 +133,13 @@ providers:
useBindPortIP: true
watch: true
defaultRule: foobar
+ labelMap:
+ - from: foobar
+ to: foobar
+ value: foobar
+ - from: foobar
+ to: foobar
+ value: foobar
username: foobar
password: foobar
endpoint: foobar
diff --git a/pkg/config/static/static_config.go b/pkg/config/static/static_config.go
index af60efbb8..73f740472 100644
--- a/pkg/config/static/static_config.go
+++ b/pkg/config/static/static_config.go
@@ -108,6 +108,7 @@ type CertificateResolver struct {
type Global struct {
CheckNewVersion bool `description:"Periodically check if a new version has been released." json:"checkNewVersion,omitempty" toml:"checkNewVersion,omitempty" yaml:"checkNewVersion,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
SendAnonymousUsage bool `description:"Periodically send anonymous usage statistics. If the option is not specified, it will be disabled by default." json:"sendAnonymousUsage,omitempty" toml:"sendAnonymousUsage,omitempty" yaml:"sendAnonymousUsage,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
+ UpdaterCallbacks []string `description:"Callback urls for updater script (example: https://localhost:8080/callback)" json:"updaterCallbacks,omitempty" toml:"updaterCallbacks,omitempty" yaml:"updaterCallbacks,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// ServersTransport options to configure communication between Traefik and the servers.
diff --git a/pkg/provider/configuration.go b/pkg/provider/configuration.go
index bbb393425..70dd14144 100644
--- a/pkg/provider/configuration.go
+++ b/pkg/provider/configuration.go
@@ -396,8 +396,8 @@ func AddStore(configuration *dynamic.TLSConfiguration, storeName string, store t
return reflect.DeepEqual(configuration.Stores[storeName], store)
}
-// MakeDefaultRuleTemplate creates the default rule template.
-func MakeDefaultRuleTemplate(defaultRule string, funcMap template.FuncMap) (*template.Template, error) {
+// MakeAnyTemplate creates a template with any name
+func MakeAnyTemplate(name string, value string, funcMap template.FuncMap) (*template.Template, error) {
defaultFuncMap := sprig.TxtFuncMap()
defaultFuncMap["normalize"] = Normalize
@@ -405,7 +405,12 @@ func MakeDefaultRuleTemplate(defaultRule string, funcMap template.FuncMap) (*tem
defaultFuncMap[k] = fn
}
- return template.New("defaultRule").Funcs(defaultFuncMap).Parse(defaultRule)
+ return template.New(name).Funcs(defaultFuncMap).Parse(value)
+}
+
+// MakeDefaultRuleTemplate creates the default rule template.
+func MakeDefaultRuleTemplate(defaultRule string, funcMap template.FuncMap) (*template.Template, error) {
+ return MakeAnyTemplate("defaultRule", defaultRule, funcMap)
}
// BuildTCPRouterConfiguration builds a router configuration.
diff --git a/pkg/provider/docker/config.go b/pkg/provider/docker/config.go
index b3bbe2411..3a6e75bee 100644
--- a/pkg/provider/docker/config.go
+++ b/pkg/provider/docker/config.go
@@ -1,6 +1,7 @@
package docker
import (
+ "bytes"
"context"
"errors"
"fmt"
@@ -28,15 +29,50 @@ func NewDynConfBuilder(configuration Shared, apiClient client.APIClient, swarm b
return &DynConfBuilder{Shared: configuration, apiClient: apiClient, swarm: swarm}
}
+func (p *DynConfBuilder) applyLabels(container *dockerData, model interface{}) {
+ for _, item := range p.LabelMap {
+ value, ok := container.Labels[item.From]
+ if !ok { // label doesn't exist
+ continue
+ }
+
+ writer := &bytes.Buffer{}
+ if err := item.toTpl.Execute(writer, model); err != nil {
+ continue // should never happen?
+ }
+
+ to := writer.String()
+ if item.Value != nil {
+ container.Labels[to] = *item.Value
+ } else {
+ container.Labels[to] = value
+ }
+ }
+}
+
func (p *DynConfBuilder) build(ctx context.Context, containersInspected []dockerData) *dynamic.Configuration {
configurations := make(map[string]*dynamic.Configuration)
for _, container := range containersInspected {
+ serviceName := getServiceName(container)
+
+ model := struct {
+ Name string
+ ContainerName string
+ Labels *map[string]string
+ }{
+ Name: serviceName,
+ ContainerName: strings.TrimPrefix(container.Name, "/"),
+ Labels: &container.Labels,
+ }
+
containerName := getServiceName(container) + "-" + container.ID
logger := log.Ctx(ctx).With().Str("container", containerName).Logger()
ctxContainer := logger.WithContext(ctx)
+ p.applyLabels(&container, model)
+
if !p.keepContainer(ctxContainer, container) {
continue
}
@@ -83,18 +119,6 @@ func (p *DynConfBuilder) build(ctx context.Context, containersInspected []docker
continue
}
- serviceName := getServiceName(container)
-
- model := struct {
- Name string
- ContainerName string
- Labels map[string]string
- }{
- Name: serviceName,
- ContainerName: strings.TrimPrefix(container.Name, "/"),
- Labels: container.Labels,
- }
-
provider.BuildRouterConfiguration(ctx, confFromLabel.HTTP, serviceName, p.defaultRuleTpl, model)
configurations[containerName] = confFromLabel
diff --git a/pkg/provider/docker/pdocker.go b/pkg/provider/docker/pdocker.go
index 44ff3470d..8deb4f146 100644
--- a/pkg/provider/docker/pdocker.go
+++ b/pkg/provider/docker/pdocker.go
@@ -49,8 +49,15 @@ func (p *Provider) Init() error {
if err != nil {
return fmt.Errorf("error while parsing default rule: %w", err)
}
-
p.defaultRuleTpl = defaultRuleTpl
+
+ for _, item := range p.LabelMap {
+ toTpl, err := provider.MakeAnyTemplate(item.From, item.To, nil)
+ if err != nil {
+ return fmt.Errorf("error while parsing label %v: %w", item.To, err)
+ }
+ item.toTpl = toTpl
+ }
return nil
}
diff --git a/pkg/provider/docker/shared.go b/pkg/provider/docker/shared.go
index 97c8d519b..027c398fd 100644
--- a/pkg/provider/docker/shared.go
+++ b/pkg/provider/docker/shared.go
@@ -33,9 +33,19 @@ type Shared struct {
Watch bool `description:"Watch Docker events." json:"watch,omitempty" toml:"watch,omitempty" yaml:"watch,omitempty" export:"true"`
DefaultRule string `description:"Default rule." json:"defaultRule,omitempty" toml:"defaultRule,omitempty" yaml:"defaultRule,omitempty"`
+ LabelMap []*LabelMapItem `description:"Label shorthands." json:"labelMap,omitempty" toml:"labelMap,omitempty" yaml:"labelMap,omitempty"`
+
defaultRuleTpl *template.Template
}
+type LabelMapItem struct {
+ From string `description:"Shorthand label." json:"from,omitempty" toml:"from,omitempty" yaml:"from,omitempty"`
+ To string `description:"Full label with templates." json:"to,omitempty" toml:"to,omitempty" yaml:"to,omitempty"`
+ Value *string `description:"Optional override; used instead of user input if set." json:"value,omitempty" toml:"value,omitempty" yaml:"value,omitempty"`
+ toTpl *template.Template
+}
+
+
func inspectContainers(ctx context.Context, dockerClient client.ContainerAPIClient, containerID string) dockerData {
containerInspected, err := dockerClient.ContainerInspect(ctx, containerID)
if err != nil {
diff --git a/pkg/updater/provider.go b/pkg/updater/provider.go
new file mode 100644
index 000000000..26d1fc469
--- /dev/null
+++ b/pkg/updater/provider.go
@@ -0,0 +1,49 @@
+package updater
+
+import (
+ "bytes"
+ "encoding/json"
+ "net/http"
+
+ "github.com/rs/zerolog/log"
+ "github.com/traefik/traefik/v3/pkg/config/dynamic"
+ "github.com/traefik/traefik/v3/pkg/config/static"
+ "github.com/traefik/traefik/v3/pkg/safe"
+)
+
+type Updater struct {
+ callbackUrls []string
+}
+
+func New(config *static.Configuration) *Updater {
+ updater := &Updater{
+ callbackUrls: config.Global.UpdaterCallbacks,
+ }
+
+ return updater
+}
+
+func (u *Updater) HandleConfigUpdate(cfg dynamic.Configuration) {
+ body, err := json.Marshal(cfg)
+
+ if err != nil {
+ // should never happen?
+ log.Error().Err(err).Msg("Error while marshalling dynamic configuration data to json")
+ return
+ }
+
+ requestBody := bytes.NewBuffer(body)
+
+ for _, url := range u.callbackUrls {
+ safe.Go(func() {
+ resp, err := http.Post(url, "application/json", requestBody)
+
+ if err != nil {
+ log.Error().Err(err).Str("url", url).Msg("Error while sending configuration data to callback")
+ } else {
+ log.Debug().Str("url", url).Msg("Configuration data sent")
+ resp.Body.Close()
+ }
+ })
+ }
+}
diff --git a/schema.json b/schema.json
new file mode 100644
index 000000000..0f8823ad9
--- /dev/null
+++ b/schema.json
@@ -0,0 +1,1851 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://json.schemastore.org/traefik-v3.json",
+ "$defs": {
+ "CertificateResolverTailscaleStruct": {
+ "additionalProperties": false,
+ "type": "object"
+ },
+ "acmeConfiguration": {
+ "additionalProperties": false,
+ "properties": {
+ "caCertificates": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "caServer": {
+ "type": "string"
+ },
+ "caServerName": {
+ "type": "string"
+ },
+ "caSystemCertPool": {
+ "type": "boolean"
+ },
+ "certificatesDuration": {
+ "type": "integer"
+ },
+ "dnsChallenge": {
+ "$ref": "#/$defs/acmeDNSChallenge"
+ },
+ "eab": {
+ "$ref": "#/$defs/acmeEAB"
+ },
+ "email": {
+ "type": "string"
+ },
+ "httpChallenge": {
+ "$ref": "#/$defs/acmeHTTPChallenge"
+ },
+ "keyType": {
+ "type": "string"
+ },
+ "preferredChain": {
+ "type": "string"
+ },
+ "storage": {
+ "type": "string"
+ },
+ "tlsChallenge": {
+ "$ref": "#/$defs/acmeTLSChallenge"
+ }
+ },
+ "type": "object"
+ },
+ "acmeDNSChallenge": {
+ "additionalProperties": false,
+ "properties": {
+ "delayBeforeCheck": {
+ "type": "string"
+ },
+ "disablePropagationCheck": {
+ "type": "boolean"
+ },
+ "propagation": {
+ "$ref": "#/$defs/acmePropagation"
+ },
+ "provider": {
+ "type": "string"
+ },
+ "resolvers": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ }
+ },
+ "type": "object"
+ },
+ "acmeEAB": {
+ "additionalProperties": false,
+ "properties": {
+ "hmacEncoded": {
+ "type": "string"
+ },
+ "kid": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "acmeHTTPChallenge": {
+ "additionalProperties": false,
+ "properties": {
+ "entryPoint": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "acmePropagation": {
+ "additionalProperties": false,
+ "properties": {
+ "delayBeforeChecks": {
+ "type": "string"
+ },
+ "disableANSChecks": {
+ "type": "boolean"
+ },
+ "disableChecks": {
+ "type": "boolean"
+ },
+ "requireAllRNS": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ },
+ "acmeTLSChallenge": {
+ "additionalProperties": false,
+ "type": "object"
+ },
+ "consulProviderBuilder": {
+ "additionalProperties": false,
+ "properties": {
+ "endpoints": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "namespaces": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "rootKey": {
+ "type": "string"
+ },
+ "tls": {
+ "$ref": "#/$defs/typesClientTLS"
+ },
+ "token": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "consulcatalogEndpointConfig": {
+ "additionalProperties": false,
+ "properties": {
+ "address": {
+ "type": "string"
+ },
+ "datacenter": {
+ "type": "string"
+ },
+ "endpointWaitTime": {
+ "type": "string"
+ },
+ "httpAuth": {
+ "$ref": "#/$defs/consulcatalogEndpointHTTPAuthConfig"
+ },
+ "scheme": {
+ "type": "string"
+ },
+ "tls": {
+ "$ref": "#/$defs/typesClientTLS"
+ },
+ "token": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "consulcatalogEndpointHTTPAuthConfig": {
+ "additionalProperties": false,
+ "properties": {
+ "password": {
+ "type": "string"
+ },
+ "username": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "consulcatalogProviderBuilder": {
+ "additionalProperties": false,
+ "properties": {
+ "cache": {
+ "type": "boolean"
+ },
+ "connectAware": {
+ "type": "boolean"
+ },
+ "connectByDefault": {
+ "type": "boolean"
+ },
+ "constraints": {
+ "type": "string"
+ },
+ "defaultRule": {
+ "type": "string"
+ },
+ "endpoint": {
+ "$ref": "#/$defs/consulcatalogEndpointConfig"
+ },
+ "exposedByDefault": {
+ "type": "boolean"
+ },
+ "namespaces": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "prefix": {
+ "type": "string"
+ },
+ "refreshInterval": {
+ "type": "string"
+ },
+ "requireConsistent": {
+ "type": "boolean"
+ },
+ "serviceName": {
+ "type": "string"
+ },
+ "stale": {
+ "type": "boolean"
+ },
+ "strictChecks": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "watch": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ },
+ "crdProvider": {
+ "additionalProperties": false,
+ "properties": {
+ "allowCrossNamespace": {
+ "type": "boolean"
+ },
+ "allowEmptyServices": {
+ "type": "boolean"
+ },
+ "allowExternalNameServices": {
+ "type": "boolean"
+ },
+ "certAuthFilePath": {
+ "type": "string"
+ },
+ "disableClusterScopeResources": {
+ "type": "boolean"
+ },
+ "endpoint": {
+ "type": "string"
+ },
+ "ingressClass": {
+ "type": "string"
+ },
+ "labelSelector": {
+ "type": "string"
+ },
+ "namespaces": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "nativeLBByDefault": {
+ "type": "boolean"
+ },
+ "throttleDuration": {
+ "type": "string"
+ },
+ "token": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "dockerProvider": {
+ "additionalProperties": false,
+ "properties": {
+ "allowEmptyServices": {
+ "type": "boolean"
+ },
+ "constraints": {
+ "type": "string"
+ },
+ "defaultRule": {
+ "type": "string"
+ },
+ "endpoint": {
+ "type": "string"
+ },
+ "exposedByDefault": {
+ "type": "boolean"
+ },
+ "httpClientTimeout": {
+ "type": "string"
+ },
+ "network": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "tls": {
+ "$ref": "#/$defs/typesClientTLS"
+ },
+ "useBindPortIP": {
+ "type": "boolean"
+ },
+ "username": {
+ "type": "string"
+ },
+ "watch": {
+ "type": "boolean"
+ },
+ "labelMap": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "from": {
+ "type": "string",
+ "description": "Shorthand label."
+ },
+ "to": {
+ "type": "string",
+ "description": "Full label with templates."
+ },
+ "value": {
+ "type": "string",
+ "description": "Optional override; used instead of user input if set."
+ }
+ },
+ "required": ["from", "to"],
+ "additionalProperties": false
+ }
+ }
+ },
+ "type": "object"
+ },
+ "dockerSwarmProvider": {
+ "additionalProperties": false,
+ "properties": {
+ "allowEmptyServices": {
+ "type": "boolean"
+ },
+ "constraints": {
+ "type": "string"
+ },
+ "defaultRule": {
+ "type": "string"
+ },
+ "endpoint": {
+ "type": "string"
+ },
+ "exposedByDefault": {
+ "type": "boolean"
+ },
+ "httpClientTimeout": {
+ "type": "string"
+ },
+ "network": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "refreshSeconds": {
+ "type": "string"
+ },
+ "tls": {
+ "$ref": "#/$defs/typesClientTLS"
+ },
+ "useBindPortIP": {
+ "type": "boolean"
+ },
+ "username": {
+ "type": "string"
+ },
+ "watch": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ },
+ "ecsProvider": {
+ "additionalProperties": false,
+ "properties": {
+ "accessKeyID": {
+ "type": "string"
+ },
+ "autoDiscoverClusters": {
+ "type": "boolean"
+ },
+ "clusters": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "constraints": {
+ "type": "string"
+ },
+ "defaultRule": {
+ "type": "string"
+ },
+ "ecsAnywhere": {
+ "type": "boolean"
+ },
+ "exposedByDefault": {
+ "type": "boolean"
+ },
+ "healthyTasksOnly": {
+ "type": "boolean"
+ },
+ "refreshSeconds": {
+ "type": "integer"
+ },
+ "region": {
+ "type": "string"
+ },
+ "secretAccessKey": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "etcdProvider": {
+ "additionalProperties": false,
+ "properties": {
+ "endpoints": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "password": {
+ "type": "string"
+ },
+ "rootKey": {
+ "type": "string"
+ },
+ "tls": {
+ "$ref": "#/$defs/typesClientTLS"
+ },
+ "username": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "fileProvider": {
+ "additionalProperties": false,
+ "properties": {
+ "debugLogGeneratedTemplate": {
+ "type": "boolean"
+ },
+ "directory": {
+ "type": "string"
+ },
+ "filename": {
+ "type": "string"
+ },
+ "watch": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ },
+ "gatewayProvider": {
+ "additionalProperties": false,
+ "properties": {
+ "certAuthFilePath": {
+ "type": "string"
+ },
+ "endpoint": {
+ "type": "string"
+ },
+ "experimentalChannel": {
+ "type": "boolean"
+ },
+ "labelSelector": {
+ "type": "string"
+ },
+ "namespaces": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "nativeLBByDefault": {
+ "type": "boolean"
+ },
+ "statusAddress": {
+ "$ref": "#/$defs/gatewayStatusAddress"
+ },
+ "throttleDuration": {
+ "type": "string"
+ },
+ "token": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "gatewayServiceRef": {
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "namespace": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "gatewayStatusAddress": {
+ "additionalProperties": false,
+ "properties": {
+ "hostname": {
+ "type": "string"
+ },
+ "ip": {
+ "type": "string"
+ },
+ "service": {
+ "$ref": "#/$defs/gatewayServiceRef"
+ }
+ },
+ "type": "object"
+ },
+ "httpProvider": {
+ "additionalProperties": false,
+ "properties": {
+ "endpoint": {
+ "type": "string"
+ },
+ "headers": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ "pollInterval": {
+ "type": "string"
+ },
+ "pollTimeout": {
+ "type": "string"
+ },
+ "tls": {
+ "$ref": "#/$defs/typesClientTLS"
+ }
+ },
+ "required": ["endpoint"],
+ "type": "object"
+ },
+ "ingressEndpointIngress": {
+ "additionalProperties": false,
+ "properties": {
+ "hostname": {
+ "type": "string"
+ },
+ "ip": {
+ "type": "string"
+ },
+ "publishedService": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "ingressProvider": {
+ "additionalProperties": false,
+ "properties": {
+ "allowEmptyServices": {
+ "type": "boolean"
+ },
+ "allowExternalNameServices": {
+ "type": "boolean"
+ },
+ "certAuthFilePath": {
+ "type": "string"
+ },
+ "disableClusterScopeResources": {
+ "type": "boolean"
+ },
+ "disableIngressClassLookup": {
+ "type": "boolean"
+ },
+ "endpoint": {
+ "type": "string"
+ },
+ "ingressClass": {
+ "type": "string"
+ },
+ "ingressEndpoint": {
+ "$ref": "#/$defs/ingressEndpointIngress"
+ },
+ "labelSelector": {
+ "type": "string"
+ },
+ "namespaces": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "nativeLBByDefault": {
+ "type": "boolean"
+ },
+ "throttleDuration": {
+ "type": "string"
+ },
+ "token": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "nomadEndpointConfig": {
+ "additionalProperties": false,
+ "properties": {
+ "address": {
+ "type": "string"
+ },
+ "endpointWaitTime": {
+ "type": "string"
+ },
+ "region": {
+ "type": "string"
+ },
+ "tls": {
+ "$ref": "#/$defs/typesClientTLS"
+ },
+ "token": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "nomadProviderBuilder": {
+ "additionalProperties": false,
+ "properties": {
+ "allowEmptyServices": {
+ "type": "boolean"
+ },
+ "constraints": {
+ "type": "string"
+ },
+ "defaultRule": {
+ "type": "string"
+ },
+ "endpoint": {
+ "$ref": "#/$defs/nomadEndpointConfig"
+ },
+ "exposedByDefault": {
+ "type": "boolean"
+ },
+ "namespaces": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "prefix": {
+ "type": "string"
+ },
+ "refreshInterval": {
+ "type": "string"
+ },
+ "stale": {
+ "type": "boolean"
+ },
+ "throttleDuration": {
+ "type": "string"
+ },
+ "watch": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ },
+ "pingHandler": {
+ "additionalProperties": false,
+ "properties": {
+ "entryPoint": {
+ "type": "string"
+ },
+ "manualRouting": {
+ "type": "boolean"
+ },
+ "terminatingStatusCode": {
+ "type": "integer"
+ }
+ },
+ "type": "object"
+ },
+ "pluginsDescriptor": {
+ "additionalProperties": false,
+ "properties": {
+ "moduleName": {
+ "type": "string"
+ },
+ "settings": {
+ "$ref": "#/$defs/pluginsSettings"
+ },
+ "version": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "pluginsLocalDescriptor": {
+ "additionalProperties": false,
+ "properties": {
+ "moduleName": {
+ "type": "string"
+ },
+ "settings": {
+ "$ref": "#/$defs/pluginsSettings"
+ }
+ },
+ "type": "object"
+ },
+ "pluginsSettings": {
+ "additionalProperties": false,
+ "properties": {
+ "envs": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "mounts": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ }
+ },
+ "type": "object"
+ },
+ "redisProvider": {
+ "additionalProperties": false,
+ "properties": {
+ "db": {
+ "type": "integer"
+ },
+ "endpoints": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "password": {
+ "type": "string"
+ },
+ "rootKey": {
+ "type": "string"
+ },
+ "sentinel": {
+ "$ref": "#/$defs/redisSentinel"
+ },
+ "tls": {
+ "$ref": "#/$defs/typesClientTLS"
+ },
+ "username": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "redisSentinel": {
+ "additionalProperties": false,
+ "properties": {
+ "latencyStrategy": {
+ "type": "boolean"
+ },
+ "masterName": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "randomStrategy": {
+ "type": "boolean"
+ },
+ "replicaStrategy": {
+ "type": "boolean"
+ },
+ "useDisconnectedReplicas": {
+ "type": "boolean"
+ },
+ "username": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "restProvider": {
+ "additionalProperties": false,
+ "properties": {
+ "insecure": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ },
+ "staticAPI": {
+ "additionalProperties": false,
+ "properties": {
+ "basePath": {
+ "type": "string"
+ },
+ "dashboard": {
+ "type": "boolean"
+ },
+ "debug": {
+ "type": "boolean"
+ },
+ "disableDashboardAd": {
+ "type": "boolean"
+ },
+ "insecure": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ },
+ "staticCertificateResolver": {
+ "additionalProperties": false,
+ "properties": {
+ "acme": {
+ "$ref": "#/$defs/acmeConfiguration"
+ },
+ "tailscale": {
+ "$ref": "#/$defs/CertificateResolverTailscaleStruct"
+ }
+ },
+ "type": "object"
+ },
+ "staticCore": {
+ "additionalProperties": false,
+ "properties": {
+ "defaultRuleSyntax": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "staticEntryPoint": {
+ "additionalProperties": false,
+ "properties": {
+ "address": {
+ "type": "string"
+ },
+ "allowACMEByPass": {
+ "type": "boolean"
+ },
+ "asDefault": {
+ "type": "boolean"
+ },
+ "forwardedHeaders": {
+ "$ref": "#/$defs/staticForwardedHeaders"
+ },
+ "http": {
+ "$ref": "#/$defs/staticHTTPConfig"
+ },
+ "http2": {
+ "$ref": "#/$defs/staticHTTP2Config"
+ },
+ "http3": {
+ "$ref": "#/$defs/staticHTTP3Config"
+ },
+ "observability": {
+ "$ref": "#/$defs/staticObservabilityConfig"
+ },
+ "proxyProtocol": {
+ "$ref": "#/$defs/staticProxyProtocol"
+ },
+ "reusePort": {
+ "type": "boolean"
+ },
+ "transport": {
+ "$ref": "#/$defs/staticEntryPointsTransport"
+ },
+ "udp": {
+ "$ref": "#/$defs/staticUDPConfig"
+ }
+ },
+ "type": "object"
+ },
+ "staticEntryPointsTransport": {
+ "additionalProperties": false,
+ "properties": {
+ "keepAliveMaxRequests": {
+ "type": "integer"
+ },
+ "keepAliveMaxTime": {
+ "type": "string"
+ },
+ "lifeCycle": {
+ "$ref": "#/$defs/staticLifeCycle"
+ },
+ "respondingTimeouts": {
+ "$ref": "#/$defs/staticRespondingTimeouts"
+ }
+ },
+ "type": "object"
+ },
+ "staticExperimental": {
+ "additionalProperties": false,
+ "properties": {
+ "abortOnPluginFailure": {
+ "type": "boolean"
+ },
+ "fastProxy": {
+ "$ref": "#/$defs/staticFastProxyConfig"
+ },
+ "kubernetesGateway": {
+ "type": "boolean"
+ },
+ "localPlugins": {
+ "additionalProperties": {
+ "$ref": "#/$defs/pluginsLocalDescriptor"
+ },
+ "type": "object"
+ },
+ "otlplogs": {
+ "type": "boolean"
+ },
+ "plugins": {
+ "additionalProperties": {
+ "$ref": "#/$defs/pluginsDescriptor"
+ },
+ "type": "object"
+ }
+ },
+ "type": "object"
+ },
+ "staticFastProxyConfig": {
+ "additionalProperties": false,
+ "properties": {
+ "debug": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ },
+ "staticForwardedHeaders": {
+ "additionalProperties": false,
+ "properties": {
+ "connection": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "insecure": {
+ "type": "boolean"
+ },
+ "trustedIPs": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ }
+ },
+ "type": "object"
+ },
+ "staticForwardingTimeouts": {
+ "additionalProperties": false,
+ "properties": {
+ "dialTimeout": {
+ "type": "string"
+ },
+ "idleConnTimeout": {
+ "type": "string"
+ },
+ "responseHeaderTimeout": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "staticGlobal": {
+ "additionalProperties": false,
+ "properties": {
+ "checkNewVersion": {
+ "type": "boolean"
+ },
+ "sendAnonymousUsage": {
+ "type": "boolean"
+ },
+ "updaterCallbacks": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "type": "object"
+ },
+ "staticHTTP2Config": {
+ "additionalProperties": false,
+ "properties": {
+ "maxConcurrentStreams": {
+ "type": "integer"
+ }
+ },
+ "type": "object"
+ },
+ "staticHTTP3Config": {
+ "additionalProperties": false,
+ "properties": {
+ "advertisedPort": {
+ "type": "integer"
+ }
+ },
+ "type": "object"
+ },
+ "staticHTTPConfig": {
+ "additionalProperties": false,
+ "properties": {
+ "encodeQuerySemicolons": {
+ "type": "boolean"
+ },
+ "maxHeaderBytes": {
+ "type": "integer"
+ },
+ "middlewares": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "redirections": {
+ "$ref": "#/$defs/staticRedirections"
+ },
+ "tls": {
+ "$ref": "#/$defs/staticTLSConfig"
+ }
+ },
+ "type": "object"
+ },
+ "staticLifeCycle": {
+ "additionalProperties": false,
+ "properties": {
+ "graceTimeOut": {
+ "type": "string"
+ },
+ "requestAcceptGraceTimeout": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "staticObservabilityConfig": {
+ "additionalProperties": false,
+ "properties": {
+ "accessLogs": {
+ "type": "boolean"
+ },
+ "metrics": {
+ "type": "boolean"
+ },
+ "tracing": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ },
+ "staticProviders": {
+ "additionalProperties": false,
+ "properties": {
+ "consul": {
+ "$ref": "#/$defs/consulProviderBuilder"
+ },
+ "consulCatalog": {
+ "$ref": "#/$defs/consulcatalogProviderBuilder"
+ },
+ "docker": {
+ "$ref": "#/$defs/dockerProvider"
+ },
+ "ecs": {
+ "$ref": "#/$defs/ecsProvider"
+ },
+ "etcd": {
+ "$ref": "#/$defs/etcdProvider"
+ },
+ "file": {
+ "$ref": "#/$defs/fileProvider"
+ },
+ "http": {
+ "$ref": "#/$defs/httpProvider"
+ },
+ "kubernetesCRD": {
+ "$ref": "#/$defs/crdProvider"
+ },
+ "kubernetesGateway": {
+ "$ref": "#/$defs/gatewayProvider"
+ },
+ "kubernetesIngress": {
+ "$ref": "#/$defs/ingressProvider"
+ },
+ "nomad": {
+ "$ref": "#/$defs/nomadProviderBuilder"
+ },
+ "plugin": {
+ "additionalProperties": {
+ "additionalProperties": {},
+ "type": "object"
+ },
+ "type": "object"
+ },
+ "providersThrottleDuration": {
+ "type": "string"
+ },
+ "redis": {
+ "$ref": "#/$defs/redisProvider"
+ },
+ "rest": {
+ "$ref": "#/$defs/restProvider"
+ },
+ "swarm": {
+ "$ref": "#/$defs/dockerSwarmProvider"
+ },
+ "zooKeeper": {
+ "$ref": "#/$defs/zkProvider"
+ }
+ },
+ "type": "object"
+ },
+ "staticProxyProtocol": {
+ "additionalProperties": false,
+ "properties": {
+ "insecure": {
+ "type": "boolean"
+ },
+ "trustedIPs": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ }
+ },
+ "type": "object"
+ },
+ "staticRedirectEntryPoint": {
+ "additionalProperties": false,
+ "properties": {
+ "permanent": {
+ "type": "boolean"
+ },
+ "priority": {
+ "type": "integer"
+ },
+ "scheme": {
+ "type": "string"
+ },
+ "to": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "staticRedirections": {
+ "additionalProperties": false,
+ "properties": {
+ "entryPoint": {
+ "$ref": "#/$defs/staticRedirectEntryPoint"
+ }
+ },
+ "type": "object"
+ },
+ "staticRespondingTimeouts": {
+ "additionalProperties": false,
+ "properties": {
+ "idleTimeout": {
+ "type": "string"
+ },
+ "readTimeout": {
+ "type": "string"
+ },
+ "writeTimeout": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "staticServersTransport": {
+ "additionalProperties": false,
+ "properties": {
+ "forwardingTimeouts": {
+ "$ref": "#/$defs/staticForwardingTimeouts"
+ },
+ "insecureSkipVerify": {
+ "type": "boolean"
+ },
+ "maxIdleConnsPerHost": {
+ "type": "integer"
+ },
+ "rootCAs": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "spiffe": {
+ "$ref": "#/$defs/staticSpiffe"
+ }
+ },
+ "type": "object"
+ },
+ "staticSpiffe": {
+ "additionalProperties": false,
+ "properties": {
+ "ids": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "trustDomain": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "staticSpiffeClientConfig": {
+ "additionalProperties": false,
+ "properties": {
+ "workloadAPIAddr": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "staticTCPServersTransport": {
+ "additionalProperties": false,
+ "properties": {
+ "dialKeepAlive": {
+ "type": "string"
+ },
+ "dialTimeout": {
+ "type": "string"
+ },
+ "terminationDelay": {
+ "type": "string"
+ },
+ "tls": {
+ "$ref": "#/$defs/staticTLSClientConfig"
+ }
+ },
+ "type": "object"
+ },
+ "staticTLSClientConfig": {
+ "additionalProperties": false,
+ "properties": {
+ "insecureSkipVerify": {
+ "type": "boolean"
+ },
+ "rootCAs": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "spiffe": {
+ "$ref": "#/$defs/staticSpiffe"
+ }
+ },
+ "type": "object"
+ },
+ "staticTLSConfig": {
+ "additionalProperties": false,
+ "properties": {
+ "certResolver": {
+ "type": "string"
+ },
+ "domains": {
+ "items": {
+ "$ref": "#/$defs/typesDomain"
+ },
+ "type": ["array", "null"]
+ },
+ "options": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "staticTracing": {
+ "additionalProperties": false,
+ "properties": {
+ "addInternals": {
+ "type": "boolean"
+ },
+ "capturedRequestHeaders": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "capturedResponseHeaders": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "globalAttributes": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ "otlp": {
+ "$ref": "#/$defs/typesOTelTracing"
+ },
+ "resourceAttributes": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ "safeQueryParams": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "sampleRate": {
+ "type": "number"
+ },
+ "serviceName": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "staticUDPConfig": {
+ "additionalProperties": false,
+ "properties": {
+ "timeout": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "typesAccessLog": {
+ "additionalProperties": false,
+ "properties": {
+ "addInternals": {
+ "type": "boolean"
+ },
+ "bufferingSize": {
+ "type": "integer"
+ },
+ "fields": {
+ "$ref": "#/$defs/typesAccessLogFields"
+ },
+ "filePath": {
+ "type": "string"
+ },
+ "filters": {
+ "$ref": "#/$defs/typesAccessLogFilters"
+ },
+ "format": {
+ "type": "string"
+ },
+ "otlp": {
+ "$ref": "#/$defs/typesOTelLog"
+ }
+ },
+ "type": "object"
+ },
+ "typesAccessLogFields": {
+ "additionalProperties": false,
+ "properties": {
+ "defaultMode": {
+ "type": "string"
+ },
+ "headers": {
+ "$ref": "#/$defs/typesFieldHeaders"
+ },
+ "names": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ }
+ },
+ "type": "object"
+ },
+ "typesAccessLogFilters": {
+ "additionalProperties": false,
+ "properties": {
+ "minDuration": {
+ "type": "string"
+ },
+ "retryAttempts": {
+ "type": "boolean"
+ },
+ "statusCodes": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ }
+ },
+ "type": "object"
+ },
+ "typesClientTLS": {
+ "additionalProperties": false,
+ "properties": {
+ "ca": {
+ "type": "string"
+ },
+ "cert": {
+ "type": "string"
+ },
+ "insecureSkipVerify": {
+ "type": "boolean"
+ },
+ "key": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "typesDatadog": {
+ "additionalProperties": false,
+ "properties": {
+ "addEntryPointsLabels": {
+ "type": "boolean"
+ },
+ "addRoutersLabels": {
+ "type": "boolean"
+ },
+ "addServicesLabels": {
+ "type": "boolean"
+ },
+ "address": {
+ "type": "string"
+ },
+ "prefix": {
+ "type": "string"
+ },
+ "pushInterval": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "typesDomain": {
+ "additionalProperties": false,
+ "properties": {
+ "main": {
+ "type": "string"
+ },
+ "sans": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ }
+ },
+ "type": "object"
+ },
+ "typesFieldHeaders": {
+ "additionalProperties": false,
+ "properties": {
+ "defaultMode": {
+ "type": "string"
+ },
+ "names": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ }
+ },
+ "type": "object"
+ },
+ "typesHostResolverConfig": {
+ "additionalProperties": false,
+ "properties": {
+ "cnameFlattening": {
+ "type": "boolean"
+ },
+ "resolvConfig": {
+ "type": "string"
+ },
+ "resolvDepth": {
+ "type": "integer"
+ }
+ },
+ "type": "object"
+ },
+ "typesInfluxDB2": {
+ "additionalProperties": false,
+ "properties": {
+ "addEntryPointsLabels": {
+ "type": "boolean"
+ },
+ "addRoutersLabels": {
+ "type": "boolean"
+ },
+ "addServicesLabels": {
+ "type": "boolean"
+ },
+ "additionalLabels": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ "address": {
+ "type": "string"
+ },
+ "bucket": {
+ "type": "string"
+ },
+ "org": {
+ "type": "string"
+ },
+ "pushInterval": {
+ "type": "string"
+ },
+ "token": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "typesMetrics": {
+ "additionalProperties": false,
+ "properties": {
+ "addInternals": {
+ "type": "boolean"
+ },
+ "datadog": {
+ "$ref": "#/$defs/typesDatadog"
+ },
+ "influxDB2": {
+ "$ref": "#/$defs/typesInfluxDB2"
+ },
+ "otlp": {
+ "$ref": "#/$defs/typesOTLP"
+ },
+ "prometheus": {
+ "$ref": "#/$defs/typesPrometheus"
+ },
+ "statsD": {
+ "$ref": "#/$defs/typesStatsd"
+ }
+ },
+ "type": "object"
+ },
+ "typesOTLP": {
+ "additionalProperties": false,
+ "properties": {
+ "addEntryPointsLabels": {
+ "type": "boolean"
+ },
+ "addRoutersLabels": {
+ "type": "boolean"
+ },
+ "addServicesLabels": {
+ "type": "boolean"
+ },
+ "explicitBoundaries": {
+ "items": {
+ "type": "number"
+ },
+ "type": ["array", "null"]
+ },
+ "grpc": {
+ "$ref": "#/$defs/typesOTelGRPC"
+ },
+ "http": {
+ "$ref": "#/$defs/typesOTelHTTP"
+ },
+ "pushInterval": {
+ "type": "string"
+ },
+ "serviceName": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "typesOTelGRPC": {
+ "additionalProperties": false,
+ "properties": {
+ "endpoint": {
+ "type": "string"
+ },
+ "headers": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ "insecure": {
+ "type": "boolean"
+ },
+ "tls": {
+ "$ref": "#/$defs/typesClientTLS"
+ }
+ },
+ "type": "object"
+ },
+ "typesOTelHTTP": {
+ "additionalProperties": false,
+ "properties": {
+ "endpoint": {
+ "type": "string"
+ },
+ "headers": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ "tls": {
+ "$ref": "#/$defs/typesClientTLS"
+ }
+ },
+ "type": "object"
+ },
+ "typesOTelLog": {
+ "additionalProperties": false,
+ "properties": {
+ "grpc": {
+ "$ref": "#/$defs/typesOTelGRPC"
+ },
+ "http": {
+ "$ref": "#/$defs/typesOTelHTTP"
+ },
+ "resourceAttributes": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ "serviceName": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "typesOTelTracing": {
+ "additionalProperties": false,
+ "properties": {
+ "grpc": {
+ "$ref": "#/$defs/typesOTelGRPC"
+ },
+ "http": {
+ "$ref": "#/$defs/typesOTelHTTP"
+ }
+ },
+ "type": "object"
+ },
+ "typesPrometheus": {
+ "additionalProperties": false,
+ "properties": {
+ "addEntryPointsLabels": {
+ "type": "boolean"
+ },
+ "addRoutersLabels": {
+ "type": "boolean"
+ },
+ "addServicesLabels": {
+ "type": "boolean"
+ },
+ "buckets": {
+ "items": {
+ "type": "number"
+ },
+ "type": ["array", "null"]
+ },
+ "entryPoint": {
+ "type": "string"
+ },
+ "headerLabels": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ "manualRouting": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ },
+ "typesStatsd": {
+ "additionalProperties": false,
+ "properties": {
+ "addEntryPointsLabels": {
+ "type": "boolean"
+ },
+ "addRoutersLabels": {
+ "type": "boolean"
+ },
+ "addServicesLabels": {
+ "type": "boolean"
+ },
+ "address": {
+ "type": "string"
+ },
+ "prefix": {
+ "type": "string"
+ },
+ "pushInterval": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "typesTraefikLog": {
+ "additionalProperties": false,
+ "properties": {
+ "compress": {
+ "type": "boolean"
+ },
+ "filePath": {
+ "type": "string"
+ },
+ "format": {
+ "type": "string"
+ },
+ "level": {
+ "type": "string"
+ },
+ "maxAge": {
+ "type": "integer"
+ },
+ "maxBackups": {
+ "type": "integer"
+ },
+ "maxSize": {
+ "type": "integer"
+ },
+ "noColor": {
+ "type": "boolean"
+ },
+ "otlp": {
+ "$ref": "#/$defs/typesOTelLog"
+ }
+ },
+ "type": "object"
+ },
+ "zkProvider": {
+ "additionalProperties": false,
+ "properties": {
+ "endpoints": {
+ "items": {
+ "type": "string"
+ },
+ "type": ["array", "null"]
+ },
+ "password": {
+ "type": "string"
+ },
+ "rootKey": {
+ "type": "string"
+ },
+ "username": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ }
+ },
+ "title": "Traefik v3 Static Configuration",
+ "properties": {
+ "accessLog": {
+ "$ref": "#/$defs/typesAccessLog"
+ },
+ "api": {
+ "$ref": "#/$defs/staticAPI"
+ },
+ "certificatesResolvers": {
+ "additionalProperties": {
+ "$ref": "#/$defs/staticCertificateResolver"
+ },
+ "type": "object"
+ },
+ "core": {
+ "$ref": "#/$defs/staticCore"
+ },
+ "entryPoints": {
+ "additionalProperties": {
+ "$ref": "#/$defs/staticEntryPoint"
+ },
+ "type": "object"
+ },
+ "experimental": {
+ "$ref": "#/$defs/staticExperimental"
+ },
+ "global": {
+ "$ref": "#/$defs/staticGlobal"
+ },
+ "hostResolver": {
+ "$ref": "#/$defs/typesHostResolverConfig"
+ },
+ "log": {
+ "$ref": "#/$defs/typesTraefikLog"
+ },
+ "metrics": {
+ "$ref": "#/$defs/typesMetrics"
+ },
+ "ping": {
+ "$ref": "#/$defs/pingHandler"
+ },
+ "providers": {
+ "$ref": "#/$defs/staticProviders"
+ },
+ "serversTransport": {
+ "$ref": "#/$defs/staticServersTransport"
+ },
+ "spiffe": {
+ "$ref": "#/$defs/staticSpiffeClientConfig"
+ },
+ "tcpServersTransport": {
+ "$ref": "#/$defs/staticTCPServersTransport"
+ },
+ "tracing": {
+ "$ref": "#/$defs/staticTracing"
+ }
+ },
+ "type": "object"
+}