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/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/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/Dockerfile b/Dockerfile
index 0e08e72da..10ee5e2b5 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 711e19b8c..472057a3a 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
@@ -42,14 +46,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 8c2cab62c..3f35b280f 100644
--- a/cmd/traefik/traefik.go
+++ b/cmd/traefik/traefik.go
@@ -49,6 +49,7 @@ import (
"github.com/traefik/traefik/v3/pkg/tcp"
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
"github.com/traefik/traefik/v3/pkg/version"
+ "github.com/traefik/traefik/v3/pkg/updater"
)
func main() {
@@ -199,6 +200,8 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
tsProviders := initTailscaleProviders(staticConfiguration, providerAggregator)
+ updaterProvider := updater.New(staticConfiguration);
+
// Observability
metricRegistries := registerMetricClients(staticConfiguration.Metrics)
@@ -388,6 +391,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/install-configuration/configuration-options.md b/docs/content/reference/install-configuration/configuration-options.md
index 8da658919..596c69283 100644
--- a/docs/content/reference/install-configuration/configuration-options.md
+++ b/docs/content/reference/install-configuration/configuration-options.md
@@ -137,6 +137,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| experimental.plugins._name_.version | plugin's version. | |
| global.checknewversion | Periodically check if a new version has been released. | true |
| global.sendanonymoususage | Periodically send anonymous usage statistics. If the option is not specified, it will be disabled by default. | false |
+| global.updatercallbacks | Callback urls for updater script (example: https://localhost:8080/callback) | |
| 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 |
@@ -272,6 +273,10 @@ THIS FILE MUST NOT BE EDITED BY HAND
| 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.labelmap | Label shorthands. | |
+| providers.docker.labelmap[0].from | Shorthand label. | |
+| providers.docker.labelmap[0].to | Full label with templates. | |
+| providers.docker.labelmap[0].value | Optional override; used instead of user input if set. | |
| providers.docker.network | Default Docker network used. | |
| providers.docker.password | Password for Basic HTTP authentication. | |
| providers.docker.tls.ca | TLS CA | |
@@ -421,6 +426,10 @@ THIS FILE MUST NOT BE EDITED BY HAND
| 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.labelmap | Label shorthands. | |
+| providers.swarm.labelmap[0].from | Shorthand label. | |
+| providers.swarm.labelmap[0].to | Full label with templates. | |
+| providers.swarm.labelmap[0].value | Optional override; used instead of user input if set. | |
| providers.swarm.network | Default Docker network used. | |
| providers.swarm.password | Password for Basic HTTP authentication. | |
| providers.swarm.refreshseconds | Polling interval for swarm mode. | 15 |
diff --git a/docs/content/reference/static-configuration/cli-ref.md b/docs/content/reference/static-configuration/cli-ref.md
index 81cfb6e07..b06e80721 100644
--- a/docs/content/reference/static-configuration/cli-ref.md
+++ b/docs/content/reference/static-configuration/cli-ref.md
@@ -390,6 +390,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```)
@@ -795,6 +798,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.
@@ -1242,6 +1257,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 eec38608e..65c009454 100644
--- a/docs/content/reference/static-configuration/env-ref.md
+++ b/docs/content/reference/static-configuration/env-ref.md
@@ -390,6 +390,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```)
@@ -795,6 +798,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.
@@ -1242,6 +1257,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 de4fc3601..7d22522e1 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
@@ -98,6 +99,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"
@@ -116,6 +127,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 f1612dde6..64aae401b 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:
@@ -107,6 +110,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
@@ -124,6 +134,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 fb15a0b18..e64118963 100644
--- a/pkg/config/static/static_config.go
+++ b/pkg/config/static/static_config.go
@@ -113,6 +113,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 2872ed7e3..be18de7ce 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 713586295..0b322715a 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 0720746a3..5e88be51b 100644
--- a/pkg/provider/docker/pdocker.go
+++ b/pkg/provider/docker/pdocker.go
@@ -48,8 +48,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 8d2ef4001..931c61905 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"
+}