Routers

将请求连接到服务

routers

路由器负责将传入请求连接到可以处理这些请求的服务. 在此过程中,路由器可以使用中间件来更新请求,或者在将请求转发到服务之前采取行动.

Configuration Example

请求/ foo由service-foo处理-使用文件提供程序
## Dynamic configuration
[http.routers]
  [http.routers.my-router]
    rule = "Path(`/foo`)"
    service = "service-foo"
## Dynamic configuration
http:
  routers:
    my-router:
      rule: "Path(`/foo`)"
      service: service-foo
将端口3306上的所有(非tls)请求转发到数据库服务

动态配置

## Dynamic configuration
[tcp]
  [tcp.routers]
    [tcp.routers.to-database]
      entryPoints = ["mysql"]
      # Catch every request (only available rule for non-tls routers. See below.)
      rule = "HostSNI(`*`)"
      service = "database"
## Dynamic configuration
tcp:
  routers:
    to-database:
      entryPoints:
        - "mysql"
      # Catch every request (only available rule for non-tls routers. See below.)
      rule: "HostSNI(`*`)"
      service: database

静态配置

## Static configuration
[entryPoints]
  [entryPoints.web]
    address = ":80"
  [entryPoints.mysql]
    address = ":3306"   
## Static configuration
entryPoints:
  web:
    address: ":80"
  mysql:
    address: ":3306"   
## Static configuration
--entryPoints.web.address=:80
--entryPoints.mysql.address=:3306

Configuring HTTP Routers

路由器名称中未授权字符@

EntryPoints

如果未指定,HTTP路由器将接受来自所有定义的入口点的请求. 如果要将路由器范围限制为一组入口点,请设置entryPoints选项.

聆听每个切入点

动态配置

## Dynamic configuration
[http.routers]
  [http.routers.Router-1]
    # By default, routers listen to every entry points
    rule = "Host(`traefik.io`)"
    service = "service-1"
## Dynamic configuration
http:
  routers:
    Router-1:
      # By default, routers listen to every entry points
      rule: "Host(`traefik.io`)"
      service: "service-1"

静态配置

## Static configuration
[entryPoints]
  [entryPoints.web]
    address = ":80"
  [entryPoints.websecure]
    address = ":443"
  [entryPoints.other]
    address = ":9090"
## Static configuration
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
  other:
    address: ":9090"
## Static configuration
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
--entrypoints.other.address=:9090
侦听特定的切入点

动态配置

## Dynamic configuration
[http.routers]
  [http.routers.Router-1]
    # won't listen to entry point web
    entryPoints = ["websecure", "other"]
    rule = "Host(`traefik.io`)"
    service = "service-1"
## Dynamic configuration
http:
  routers:
    Router-1:
      # won't listen to entry point web
      entryPoints:
        - "websecure"
        - "other"
      rule: "Host(`traefik.io`)"
      service: "service-1"

静态配置

## Static configuration
[entryPoints]
  [entryPoints.web]
    address = ":80"
  [entryPoints.websecure]
    address = ":443"
  [entryPoints.other]
    address = ":9090"
## Static configuration
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
  other:
    address: ":9090"
## Static configuration
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
--entrypoints.other.address=:9090

Rule

规则是一组配置有值的匹配器,这些值确定特定请求是否匹配特定条件. 如果该规则得到验证,则路由器将变为活动状态,调用中间件,然后将请求转发到服务.

反引号或引号?

要设置规则的值,请使用反引号 `或转义的双引号\" .

单引号'不接受值Golang的字符串字面 .

房东是traefik.io

rule = "Host(`traefik.io`)"

主机是traefik.io或主机是containo.us并且路径是/ traefik

rule = "Host(`traefik.io`) || (Host(`containo.us`) && Path(`/traefik`))"

下表列出了所有可用的匹配器:

Rule Description
Headers(`key`, `value`) 检查是否有一个关键的key在头文件中定义,其值为value
HeadersRegexp(`key`, `regexp`) 检查标题中是否定义了一个键, key的值与正则表达式regexp匹配
Host(`domain-1`, ...) 检查请求域是否以给定domains之一为目标.
HostRegexp(`traefik.io`, `{subdomain:[a-z]+}.traefik.io`, ...) 检查请求域是否与给定的regexp相匹配.
Method(`GET`, ...) 检查请求方法是否为给定methodsGETPOSTPUTDELETEPATCH
Path(`/path`, `/articles/{category}/{id:[0-9]+}`, ...) 匹配确切的请求路径. 它接受文字和正则表达式路径的序列.
PathPrefix(`/products/`, `/articles/{category}/{id:[0-9]+}`) 匹配请求前缀路径. 它接受一系列文字和正则表达式前缀路径.
Query(`foo=bar`, `bar=baz`) 匹配查询字符串参数. 它接受键=值对的序列.

正则表达式语法

为了将正则表达式与HostPath表达式一起使用,必须声明一个任意命名的变量,后跟用冒号分隔的正则表达式,所有这些都括在花括号中. 可以使用Go的regexp软件包支持的任何模式(例如: /posts/{id:[0-9]+} ).

使用运算符和括号组合匹配器

您可以使用AND( && )和OR( || )运算符组合多个匹配器. 您也可以使用括号.

规则,中间件和服务

在任何中间件有机会工作之前"评估"规则,并且在"中间"将请求转发给服务之前.

路径与路径前缀

如果您的服务仅侦听确切路径,请使用Path . 例如, Path: /products将匹配/products但不匹配/products/shoes .

如果您的服务在特定的基本路径上侦听,但在子路径上也提供请求,请使用*Prefix*匹配器. 例如, PathPrefix: /products可以匹配/products ,也可以匹配/products/shoes/products/shirts . 由于路径是按原样转发的,因此您的服务应在/products上进行监听.

Priority

为避免路径重叠,默认情况下,使用规则长度以降序对路由进行排序. 优先级直接等于规则的长度,因此最长的长度具有最高的优先级.

优先级的值为0被忽略: priority = 0表示使用默认规则长度排序.

如何计算默认优先级
## Dynamic configuration
[http.routers]
  [http.routers.Router-1]
    rule = "HostRegexp(`.*\.traefik\.com`)"
    # ...
  [http.routers.Router-2]
    rule = "Host(`foobar.traefik.com`)"
    # ...
## Dynamic configuration
http:
  routers:
    Router-1:
      rule: "HostRegexp(`.*\.traefik\.com`)"
      # ...
    Router-2:
      rule: "Host(`foobar.traefik.com`)"
      # ...

在这种情况下,所有具有主机foobar.traefik.com请求都将通过Router-1而不是Router-2进行Router-2 .

Name Rule Priority
Router-1 HostRegexp(`.*\.traefik\.com`) 30
Router-2 Host(`foobar.traefik.com`) 26

上表显示Router-1的优先级高于Router-2优先级.

要解决此问题,必须设置优先级.

设置优先级-使用文件提供程序
## Dynamic configuration
[http.routers]
  [http.routers.Router-1]
    rule = "HostRegexp(`.*\.traefik\.com`)"
    entryPoints = ["web"]
    service = "service-1"
    priority = 1
  [http.routers.Router-2]
    rule = "Host(`foobar.traefik.com`)"
    entryPoints = ["web"]
    priority = 2
    service = "service-2"
## Dynamic configuration
http:
  routers:
    Router-1:
      rule: "HostRegexp(`.*\.traefik\.com`)"
      entryPoints:
      - "web"
      service: service-1
      priority: 1
    Router-2:
      rule: "Host(`foobar.traefik.com`)"
      entryPoints:
      - "web"
      priority: 2
      service: service-2

在此配置中,优先级配置为允许Router-2处理与foobar.traefik.com主机的请求.

Middlewares

您可以将中间件列表附加到每个HTTP路由器. 仅当规则匹配时,并且在将请求转发到服务之前,中间件才会生效.

中间件名称中未授权字符@ .

Middlewares order

中间件的应用顺序与其在路由器中声明的顺序相同.

使用中间件 -使用文件提供程序
## Dynamic configuration
[http.routers]
  [http.routers.my-router]
    rule = "Path(`/foo`)"
    # declared elsewhere
    middlewares = ["authentication"]
    service = "service-foo"
## Dynamic configuration
http:
  routers:
    my-router:
      rule: "Path(`/foo`)"
      # declared elsewhere
      middlewares:
      - authentication
      service: service-foo

Service

每个请求最终都必须由服务处理,这就是为什么每个路由器定义都应包括服务目标的原因,该服务目标基本上是将请求传递到的目标.

通常,应该已经定义了分配给路由器的服务,但是基于标签的提供程序有例外. 请参阅特定的dockerranchermarathon文档.

中间件名称中未授权字符@ .

HTTP路由器只能定位HTTP服务(不能定位TCP服务).

TLS

General

当指定TLS节时,它指示Traefik当前路由器仅专用于HTTPS请求(并且该路由器应忽略HTTP(非TLS)请求). Traefik将终止SSL连接(意味着它将解密的数据发送到服务).

配置路由器仅接受HTTPS请求
## Dynamic configuration
[http.routers]
  [http.routers.Router-1]
    rule = "Host(`foo-domain`) && Path(`/foo-path/`)"
    service = "service-id"
    # will terminate the TLS request
    [http.routers.Router-1.tls]
## Dynamic configuration
http:
  routers:
    Router-1:
      rule: "Host(`foo-domain`) && Path(`/foo-path/`)"
      service: service-id
      # will terminate the TLS request
      tls: {}

HTTP和HTTPS的路由器

如果需要为HTTP和HTTPS请求定义相同的路由,则将需要定义两个不同的路由器:一个带有tls部分,一个没有.

HTTP和HTTPS路由
## Dynamic configuration
[http.routers]
  [http.routers.my-https-router]
    rule = "Host(`foo-domain`) && Path(`/foo-path/`)"
    service = "service-id"
    # will terminate the TLS request
    [http.routers.my-https-router.tls]

  [http.routers.my-http-router]
    rule = "Host(`foo-domain`) && Path(`/foo-path/`)"
    service = "service-id"
## Dynamic configuration
http:
  routers:
    my-https-router:
      rule: "Host(`foo-domain`) && Path(`/foo-path/`)"
      service: service-id
      # will terminate the TLS request
      tls: {}

    my-http-router:
      rule: "Host(`foo-domain`) && Path(`/foo-path/`)"
      service: service-id

options

options字段启用对TLS参数的细粒度控制. 它指的是TLS选项,并且仅在定义Host规则时才适用.

服务器名称关联

即使可能会给人一种TLS选项参考已映射到路由器或路由器规则的印象,但人们应该意识到,它实际上仅映射到在规则的" Host部分中找到的主机名. 当然,规则中也可能包含多个Host部分,在这种情况下,TLS选项参考将映射到尽可能多的主机名.

要记住的另一件事是:TLS选项是从上述映射中选择的,并且基于TLS握手期间提供的服务器名称,并且所有这些操作都在路由实际发生之前发生.

配置TLS选项
## Dynamic configuration
[http.routers]
  [http.routers.Router-1]
    rule = "Host(`foo-domain`) && Path(`/foo-path/`)"
    service = "service-id"
    # will terminate the TLS request
    [http.routers.Router-1.tls]
      options = "foo"

[tls.options]
  [tls.options.foo]
    minVersion = "VersionTLS12"
    cipherSuites = [
      "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
      "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
      "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
      "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
      "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
    ]
## Dynamic configuration
http:
  routers:
    Router-1:
      rule: "Host(`foo-domain`) && Path(`/foo-path/`)"
      service: service-id
      # will terminate the TLS request
      tls:
        options: foo

tls:
  options:
    foo:
      minVersion: VersionTLS12
      cipherSuites:
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
        - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
        - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

TLS选项冲突

由于TLS选项引用已映射到主机名,因此,如果配置引入了以下情况:同一主机名(来自Host规则)与两个TLS选项引用相匹配,则会发生冲突,例如以下示例:

## Dynamic configuration
[http.routers]
  [http.routers.routerfoo]
    rule = "Host(`snitest.com`) && Path(`/foo`)"
    [http.routers.routerfoo.tls]
      options = "foo"

[http.routers]
  [http.routers.routerbar]
    rule = "Host(`snitest.com`) && Path(`/bar`)"
    [http.routers.routerbar.tls]
      options = "bar"
## Dynamic configuration
http:
  routers:
    routerfoo:
      rule: "Host(`snitest.com`) && Path(`/foo`)"
      tls:
        options: foo

    routerbar:
      rule: "Host(`snitest.com`) && Path(`/bar`)"
      tls:
        options: bar

如果发生这种情况,两个映射都将被丢弃,并且这些路由器的主机名(在本例中为snitest.com )将与默认的TLS选项关联.

certResolver

如果certResolver定义,Traefik将尝试基于路由器证书HostHostSNI规则.

## Dynamic configuration
[http.routers]
  [http.routers.routerfoo]
    rule = "Host(`snitest.com`) && Path(`/foo`)"
    [http.routers.routerfoo.tls]
      certResolver = "foo"
## Dynamic configuration
http:
  routers:
    routerfoo:
      rule: "Host(`snitest.com`) && Path(`/foo`)"
      tls:
        certResolver: foo

规则中的多个主机

规则Host(`test1.traefik.io`,`test2.traefik.io`)将请求具有主域test1.traefik.io和SAN test2.traefik.io .

domains

您可以为每个主域设置SAN(备用域). 每个域都必须具有指向Traefik的A / AAAA记录. 每个域和SAN都会导致一个证书请求.

## Dynamic configuration
[http.routers]
  [http.routers.routerbar]
    rule = "Host(`snitest.com`) && Path(`/bar`)"
    [http.routers.routerbar.tls]
      certResolver = "bar"
      [[http.routers.routerbar.tls.domains]]
        main = "snitest.com"
        sans = ["*.snitest.com"]
## Dynamic configuration
http:
  routers:
    routerbar:
      rule: "Host(`snitest.com`) && Path(`/bar`)"
      tls:
        certResolver: "bar"
        domains:
          - main: "snitest.com"
            sans:
              - "*.snitest.com"

ACME v2支持通配符证书. 如《 让我们加密》中的通配符证书中所述,只能通过DNS-01挑战生成.

根域很可能也应该收到证书,因此需要将其指定为SAN并执行2个DNS-01挑战. 在这种情况下,两个域生成的DNS TXT记录是相同的. 即使此行为符合DNS RFC ,也可能导致问题,因为所有DNS提供程序都将DNS记录缓存给定时间(TTL),并且此TTL可能大于质询超时,从而使DNS-01质询失败.

Traefik ACME客户端库lego支持部分但不是全部DNS提供程序来解决此问题. 支持的provider指示它们是否允许为通配符域及其根域生成证书.

通配符证书只能通过DNS-01质询进行验证.

双通配符证书

无法为域请求双通配符证书(例如*.*.local.com ).

Configuring TCP Routers

路由器名称中未授权字符@

General

如果HTTP路由器和TCP路由器都侦听相同的入口点,则TCP路由器将 HTTP路由器之前应用. 如果找不到与TCP路由器匹配的路由,则HTTP路由器将接管.

EntryPoints

如果未指定,TCP路由器将接受来自所有已定义入口点的请求. 如果要将路由器范围限制为一组入口点,请设置入口点选项.

聆听每个入口点

动态配置

## Dynamic configuration

[tcp.routers]
  [tcp.routers.Router-1]
    # By default, routers listen to every entrypoints
    rule = "HostSNI(`traefik.io`)"
    service = "service-1"
    # will route TLS requests (and ignore non tls requests)
    [tcp.routers.Router-1.tls]
## Dynamic configuration

tcp:
  routers:
    Router-1:
      # By default, routers listen to every entrypoints
      rule: "HostSNI(`traefik.io`)"
      service: "service-1"
      # will route TLS requests (and ignore non tls requests)
      tls: {}

静态配置

## Static configuration

[entryPoints]
  [entryPoints.web]
    address = ":80"
  [entryPoints.websecure]
    address = ":443"
  [entryPoints.other]
    address = ":9090"
## Static configuration

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
  other:
    address: ":9090"
## Static configuration
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
--entrypoints.other.address=:9090
听特定的入口点

动态配置

## Dynamic configuration
[tcp.routers]
  [tcp.routers.Router-1]
    # won't listen to entry point web
    entryPoints = ["websecure", "other"]
    rule = "HostSNI(`traefik.io`)"
    service = "service-1"
    # will route TLS requests (and ignore non tls requests)
    [tcp.routers.Router-1.tls]
## Dynamic configuration
tcp:
  routers:
    Router-1:
      # won't listen to entry point web
      entryPoints:
        - "websecure"
        - "other"
      rule: "HostSNI(`traefik.io`)"
      service: "service-1"
      # will route TLS requests (and ignore non tls requests)
      tls: {}

静态配置

## Static configuration

[entryPoints]
  [entryPoints.web]
    address = ":80"
  [entryPoints.websecure]
    address = ":443"
  [entryPoints.other]
    address = ":9090"
## Static configuration

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
  other:
    address: ":9090"
## Static configuration
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
--entrypoints.other.address=:9090

Rule

Rule Description
HostSNI(`domain-1`, ...) 检查服务器名称指示是否对应于给定的domains .

HostSNI和TLS

请务必注意,服务器名称指示是TLS协议的扩展. 因此,只有TLS路由器才能使用该规则指定域名. 但是,非TLS路由器必须使用带有* (每个域)的规则,以声明每个非TLS请求都将由路由器处理.

Services

您必须为每个TCP路由器附加一个TCP 服务 . 服务是路由器的目标.

TCP路由器只能定位TCP服务(不能定位HTTP服务).

TLS

General

当指定TLS部分时,它指示Traefik当前路由器仅专用于TLS请求(并且路由器应忽略非TLS请求).

默认情况下,Traefik将终止SSL连接(这意味着它将将解密的数据发送到服务),但是可以配置Traefik以便让请求通过(将数据保持加密),然后转发给服务"是".

配置TLS终止
## Dynamic configuration
[tcp.routers]
  [tcp.routers.Router-1]
    rule = "HostSNI(`foo-domain`)"
    service = "service-id"
    # will terminate the TLS request by default
    [tcp.routers.Router-1.tls]
## Dynamic configuration
tcp:
  routers:
    Router-1:
      rule: "HostSNI(`foo-domain`)"
      service: service-id
      # will terminate the TLS request by default
      tls: {}
配置直通
## Dynamic configuration
[tcp.routers]
  [tcp.routers.Router-1]
    rule = "HostSNI(`foo-domain`)"
    service = "service-id"
    [tcp.routers.Router-1.tls]
      passthrough = true
## Dynamic configuration
tcp:
  routers:
    Router-1:
      rule: "HostSNI(`foo-domain`)"
      service: service-id
      tls:
        passthrough: true

options

options字段启用对TLS参数的细粒度控制.
它指的是TLS选项 ,仅在定义了HostSNI规则HostSNI适用.

配置tls选项

## Dynamic configuration
[tcp.routers]
  [tcp.routers.Router-1]
    rule = "HostSNI(`foo-domain`)"
    service = "service-id"
    # will terminate the TLS request
    [tcp.routers.Router-1.tls]
      options = "foo"

[tls.options]
  [tls.options.foo]
    minVersion = "VersionTLS12"
    cipherSuites = [
      "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
      "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
      "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
      "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
      "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
    ]
## Dynamic configuration
tcp:
  routers:
    Router-1:
      rule: "HostSNI(`foo-domain`)"
      service: service-id
      # will terminate the TLS request
      tls:
        options: foo

tls:
  options:
    foo:
      minVersion: VersionTLS12
      cipherSuites:
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
        - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
        - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

certResolver

有关更多信息,请参见HTTP路由器的certResolver .

## Dynamic configuration
[tcp.routers]
  [tcp.routers.routerfoo]
    rule = "HostSNI(`snitest.com`)"
    [tcp.routers.routerfoo.tls]
      certResolver = "foo"
## Dynamic configuration
tcp:
  routers:
    routerfoo:
      rule: "HostSNI(`snitest.com`)"
      tls:
        certResolver: foo

domains

有关更多信息,请参见HTTP路由器的domains .

## Dynamic configuration
[tcp.routers]
  [tcp.routers.routerbar]
    rule = "HostSNI(`snitest.com`)"
    [tcp.routers.routerbar.tls]
      certResolver = "bar"
      [[tcp.routers.routerbar.tls.domains]]
        main = "snitest.com"
        sans = ["*.snitest.com"]
## Dynamic configuration
tcp:
  routers:
    routerbar:
      rule: "HostSNI(`snitest.com`)"
      tls:
        certResolver: "bar"
        domains:
          - main: "snitest.com"
            sans: 
              - "*.snitest.com"