Can I have someone give me a sanity check on this upgrade from a traefik 1.7 toml file to a 2.X yaml file?

Hey there,

I am pretty new to traefik. It is super cool software and I look forward to using it. That being said, I am still a super newbie at this. I patched together my 1.7 config file from across the internet. I am just upgrading to v2, and while my config file looks correct, I am unsure. Mostly, it seemed like v2 was changing some variable names. However, I also just had to remove some variables without replacement. If it is not listed in the v2 docs, is it no longer needed?

I do not seem to set the domain, watched, onDemand, onHostRule, the storageFile (super important) and some other variables. Can someone provide me with some guidance? I would be super thankful.

Attached are my config files for reference.

V1 config:

# ---- Log level ----
logLevel = "ERROR"

# Entrypoints
defaultEntryPoints = ["http", "https"]

[web]
# Port for the status page
# address = ":8080"

# Entrypoints, http and https
[entryPoints]
  # http should be redirected to https
  [entryPoints.http]
  address = ":80"
    [entryPoints.http.redirect]
    entryPoint = "https"
  # https is the default
  [entryPoints.https]
  address = ":443"
    [entryPoints.https.tls]


# Enable ACME (Let's Encrypt): automatic SSL
[acme]
# Email address used for registration
email = "frick-david@protonmail.com"
storageFile = "/etc/traefik/acme/acme.json"
entryPoint = "https"
onDemand = false

# Enable certificate generation on frontends Host rules. This will request a certificate from Let's Encrypt for each frontend with a Host rule
# For example, a rule Host:test1.traefik.io,test2.traefik.io will request a certificate with main domain test1.traefik.io and SAN test2.traefik.io.
OnHostRule = true
# Use a HTTP-01 acme challenge rather than TLS-SNI-01 challenge
# Optional but recommend
  [acme.httpChallenge]
  # EntryPoint to use for the challenges.
  # Required
  entryPoint = "http"

# Enable Docker configuration backend
[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "ohba.io"
# Enable watch docker changes
watch = true
# Expose containers by default in traefik
# If set to false, containers that don't have `traefik.enable=true` will be ignored
exposedbydefault = false

[api]
  dashboard=false

Here is my v2 config file:

# Traefik configuration
# ----------------------

entryPoints:
  web:
    address: ":80"

  websecure:
    address: ":443"


# Dynamic configuration
https:
  routers:
    web:
      rule: "Host(`ohba.io`) && Path(`*`)"
      tls:
        certResolver: myresolver


# Redirect to https
http:
  middlewares:
    test-redirectscheme:
      redirectScheme:
        scheme: https
        permanent: true


# Enable ACME (Let's Encrypt): automatic SSL.
certificatesResolvers:
  myresolver:
    acme:
      email: frick-david@protonmail.com
      storage: acme.json
      httpChallenge:
        entryPoint: web


# Configure the traefik logger.
log:
  level: INFO
  filePath: "/etc/traefik/traefik.logs"


# Enable Docker configuration backend.
providers:
    docker:
        endpoint: "unix:///var/run/docker.sock"
        exposedByDefault: false


# Disable the traefik dashboard.
api:
  dashboard: false

Thanks

Hi David,

This is the migration guide in case you missed it.

It's a bit difficult to compare v1 and v2 config easy to miss things. Does you conversion work? If not, post logs/errors, and we'll try to figure that out. If it does but you are concerned that some settings that is important to you did not get included, please note which ones, and we'll go over them.

Generally I would say if your new configuration works for you, you have nothing else to worry about.

Okay, I edited the file a bit to clean stuff up:
My log message dumps are

traefik_1  | time="2020-07-15T19:21:15Z" level=debug msg="No default certificate, generating one"
traefik_1  | time="2020-07-15T19:21:16Z" level=info msg="Starting provider aggregator.ProviderAggregator {}"
traefik_1  | time="2020-07-15T19:21:16Z" level=debug msg="Start TCP Server" entryPointName=web
traefik_1  | time="2020-07-15T19:21:16Z" level=debug msg="Start TCP Server" entryPointName=websecure
traefik_1  | time="2020-07-15T19:21:17Z" level=debug msg="Provider connection established with docker 19.03.11 (API 1.40)" providerName=docker
traefik_1  | time="2020-07-15T19:21:17Z" level=debug msg="No default certificate, generating one"
traefik_1  | time="2020-07-15T19:21:17Z" level=debug msg="Filtering disabled container" container=traefik_ohba-d5dfffb7b49febcc58de7d323b52446282558e653a8ee2facc28ba9dfbca54be providerName=docker
traefik_1  | time="2020-07-15T19:21:17Z" level=debug msg="Filtering disabled container" container=db_ohba-a500e8d0994694e42234363e21a00947990b0792ea013da18c61b104c4399927 providerName=docker
traefik_1  | time="2020-07-15T19:21:17Z" level=debug msg="No entryPoint defined for this router, using the default one(s) instead: [web websecure]" routerName=website@docker
traefik_1  | time="2020-07-15T19:21:17Z" level=debug msg="Creating middleware" middlewareName=pipelining middlewareType=Pipelining entryPointName=web routerName=website@docker serviceName=website_ohba
traefik_1  | time="2020-07-15T19:21:17Z" level=debug msg="Creating load-balancer" entryPointName=web routerName=website@docker serviceName=website_ohba
traefik_1  | time="2020-07-15T19:21:17Z" level=debug msg="Creating server 0 http://172.22.0.3:5000" serverName=0 entryPointName=web routerName=website@docker serviceName=website_ohba
traefik_1  | time="2020-07-15T19:21:17Z" level=debug msg="Added outgoing tracing middleware website_ohba" routerName=website@docker middlewareName=tracing entryPointName=web middlewareType=TracingForwarder
traefik_1  | time="2020-07-15T19:21:17Z" level=error msg="error while parsing rule Host('ohba.io') || Host('www.ohba.io'): 1:6: illegal rune literal (and 1 more errors)" entryPointName=web routerName=website@docker
traefik_1  | time="2020-07-15T19:21:17Z" level=debug msg="Creating middleware" middlewareName=traefik-internal-recovery middlewareType=Recovery entryPointName=web
traefik_1  | time="2020-07-15T19:21:17Z" level=error msg="error while parsing rule Host('ohba.io') || Host('www.ohba.io'): 1:6: illegal rune literal (and 1 more errors)" routerName=website@docker entryPointName=websecure
traefik_1  | time="2020-07-15T19:21:17Z" level=debug msg="Creating middleware" entryPointName=websecure middlewareName=traefik-internal-recovery middlewareType=Recovery
traefik_1  | time="2020-07-15T19:21:17Z" level=debug msg="No default certificate, generating one"

So I can see it is trying to the the SSL cert. Good.
I can see the error about the invalid rune:

Host('ohba.io') || Host('www.ohba.io')

Although I looked at the docs and I am not sure why this is invalid? Can I not define two hosts?
How would I define two separate hosts for the same router to catch all paths?
I see No entrypoint defined for this router. in traefik_1 | time="2020-07-15T19:21:17Z" level=debug msg="No entryPoint defined for this router, using the default one(s) instead: [web websecure]" routerName=website@docker

Okay, fair enough. Would I define http and https to be the default entrypoints? I took out anything that did not relate to what I was confused about. This truly is an awesome piece of software. Wish I understood networking a bit better ;/

Thanks for your help,
David Frick

That's weird, in your configuration those are back ticks, which is correct, but in the log they are single quotes, which is wrong. Can you double check that please?

Would I define http and https to be the default entrypoints?

In my experience a router is either TLS or non TLS. It is not very useful to have http entry point on a tls router and https on a non-tls one, so I prefer to do this explicitly, e.g. (following your example):

http:
  routers:
    web:
      entryPoints:
        - websecure
      rule: "Host(`ohba.io`) && Path(`*`)"
      tls:
        certResolver: myresolver

Okay, I think I have it done save a couple of small questions.

Here is my finalish file if it helps anyone
docker-compose.yml

version: "3"
services:

  website:
    build: .
    labels:
      - traefik.enable=true
      - traefik.http.routers.website.rule=Host(`ohba.io`) || Host(`www.ohba.io`)
    ports:
      - "5000:5000"
    networks:
      - backend


  traefik:
    image: traefik:2.2
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./config/traefik/acme/:/etc/traefik/acme/
      - ./config/traefik/traefikv2.yaml:/etc/traefik/traefik.yaml:ro
    ports:
     - "80:80"
     - "443:443"
     - "8080:8080"
    networks:
     - backend

My traefikv2.yaml:

version: "3"
services:

  website:
    build: .
    labels:
      - traefik.enable=true
      - traefik.http.routers.website.rule=Host(`ohba.io`) || Host(`www.ohba.io`)
    ports:
      - "5000:5000"
    networks:
      - backend


  traefik:
    image: traefik:2.2
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./config/traefik/acme/:/etc/traefik/acme/
      - ./config/traefik/traefikv2.yaml:/etc/traefik/traefik.yaml:ro
    ports:
     - "80:80"
     - "443:443"
     - "8080:8080"
    networks:
     - backend

networks:
   backend:
     driver: bridge
# HTTP and HTTPS entrypoints
entryPoints:
  web:  # User named
    address: :80
    http:
      redirections:
        entryPoint:
          to: websecure


  websecure:  # User named
    address: :443
    http:
      tls:
        certResolver: sslcertresolver


# Routers
http:
  routers:
    websiterouter:  # User defined
      entryPoints:
        - "web"
        - "websecure"
      rule: "Host(`ohba.io`) || Host(`www.ohba.io`)"      
      tls:
        certResolver: sslcertresolver 


# Enable ACME (Let's Encrypt): automatic SSL.
certificatesResolvers:
  sslcertresolver:  # User named
    acme:
      email: frick-david@protonmail.com
      storage: "acme.json"
      httpChallenge:
        entryPoint: web


# Configure the traefik logger.
log:
  level: DEBUG   # Debug will log the most messages. Good alternative is INFO.


# Enable Docker configuration backend.
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    watch: true

# Disable the traefik dashboard.
api:
  dashboard: false

It works for my website.

  1. However, it is not clear from the docs if the new storage replaces the old storage file. I certainly hope I am not spamming for an SSL because of retry number attempts. I am unsure if store is acme.json or /etc/traefik/acme

  2. Can not seem to find if there is an 2.2-alpine. Get an error when I try so I guess not. shame

  3. I am not sure how to explicitly assign a router to a docker container. I get info messages when docker compose up'ing that it is making its own router for my stuff but I can not tell if this is because it dynamically works with docker or because I have not successfully assigned the router.
    I am not sure if docker allows the static config for quite a few things unfortunately. It would be nice to get rid of the website rule in my docker-compose but I can not seem to set the router explicitly.

  4. It is still not clear to me if I did my host-name rule for my website right. How does one capture www. in front? Is that best of with a regex?

  5. This has opened my eyes quite a bit. I am wondering if I also need to add my database port in here to get something unrelated done as well.

@zespri, yeah I saw that after I posted and edited it to be exactly as you said. Nice. Traefik is super clutch.

David

in the v2, the dynamic configuration and the static configuration must be defined in separated files:

also like in the v1, you have to enable the file provider to be able to use it:


Static configuration
# HTTP and HTTPS entrypoints
entryPoints:
  web:  # User named
    address: :80
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https


  websecure:  # User named
    address: :443
    http:
      tls:
        certResolver: sslcertresolver

# Enable ACME (Let's Encrypt): automatic SSL.
certificatesResolvers:
  sslcertresolver:  # User named
    acme:
      email: frick-david@protonmail.com
      storage: "acme.json"
      httpChallenge:
        entryPoint: web


# Configure the traefik logger.
log:
  level: DEBUG   # Debug will log the most messages. Good alternative is INFO.

# Enable Docker configuration backend.
providers:
  docker:
    endpoint: unix:///var/run/docker.sock
    exposedByDefault: false

  file:
    directory: /dyn-config/
    watch: true

# Disable the traefik dashboard.
api:
  dashboard: false
dynamic configuration

# Routers
http:
  routers:
    websiterouter:  # User defined
      entryPoints:
        - web
        - websecure
      rule: Host(`ohba.io`) || Host(`www.ohba.io`)

There are some issues in your configuration, I will let @zespri explain this.

My version of your configuration
version: '3.8'

services:
  traefik:
    image: traefik:v2.2.5
    ports:
      - 80:80
      - 443:443
    command:
      - --global.sendAnonymousUsage
      - --global.checkNewVersion
      - --log.level=DEBUG
      - --api

      - --providers.docker.exposedbydefault=false

      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entryPoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https

      - --entrypoints.websecure.address=:443
      - --entrypoints.websecure.http.tls.certresolver=sslcertresolver

      - --certificatesResolvers.sslcertresolver.acme.email=frick-david@protonmail.com
      - --certificatesResolvers.sslcertresolver.acme.storage=/letsencrypt/acme.json
      # - --certificatesResolvers.sslcertresolver.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory
      - --certificatesResolvers.sslcertresolver.acme.httpchallenge.entrypoint=web

    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./conf/letsencrypt/:/letsencrypt/

    labels:
      traefik.enable: true

      traefik.http.routers.traefik.rule: Host(`traefik.ohba.io`)
      traefik.http.routers.traefik.entrypoints: websecure
      traefik.http.routers.traefik.service: api@internal

  whoami:
    image: containous/whoami:v1.5.0
    command:
    # It tells whoami to start listening on 5000 instead of 80
    - --port=5000
    labels:
      traefik.enable: true

      traefik.http.routers.app.rule: Host(`ohba.io`) || Host(`www.ohba.io`)
      traefik.http.routers.app.entrypoints: websecure
2 Likes

Oh yeah, I vaguely remember this is being a migration issue. The format has changed and I think on that page there is an upgrade script, or used to be. If we are talking about a couple of domains though in my view there is no harm to deleting acme.json completely and let traefik regenerate it.

I usually use staging lets encrypt so I do not get over the rate limit first, and when I'm satisfied I switch over to production one.

From version 2 alpine is the only one. So they dropped the name from the tag.

Yes, I feel that there is some lack of clarity here. This is all explained in the documentation, but let me give you a quick run down:

  • There is static and dynamic configuration, never mix them they should come from different sources / files. Read the doco on the difference. Entrypoints are static configuration, where as routers are dynamic.
  • Dynamic configuration comes from providers, such as a docker provider (that is from labels) and file provider (that is a file where you describe your routers, etc). With docker it's easier to use the docker provider because it does the discovery for you. This means that is it's easier to tell the router where to route to, since most of this information traefik can query from docker. Note, that while part of configuration can come from file provider and part from docker provider, I would recommend as much as possible stick to a single one. This is because if you configure the same objects from two different source it's more difficult to reason about which one is used.

I would advice moving all your configuration to docker-compose labels as above. This is because when using a separate file you will need to tell traefik how to connect to your container. Currently docker provider does this for you automatically, but docker provider means that further configuration need to come form the labels.

I have not had a lot of experience with that but I do not see anything from with the rule. Are you still getting the error? If not, what is the concern?

Sorry not sure what this is in relation to.

This tool can be useful to convert a configuration: https://github.com/containous/traefik-migration-tool :wink:

Nice about the alpine being the main one. Very sweet.

Okay, I see what you are saying about static versus dynamic. Is there a way to have docker work with a static setup. My group likes to keep stuff compartmentalized so is it possible to have something like

docker-compose:
   website:
     # look at traefik

   traefik:
       # use the traefik.yml

versus using the dynamic configuration where I stick the variables under the website container? I know you suggest moving it all to docker labels (which is probably what will happen), but just wondering. I use postgres and other containers too which have their own conf files much like the traefik.yaml. A little easy to maintain that way.

The host rule has been working for www.ohba.io and ohba.io so I am good on that.

Sorry for the cryptic message on opening my eyes on the database port. I got inspiration from traefik on what an issue with database replication was from my server machine to my local computer. Idk why but traefik made me realize what was wrong with my setup for it. It not works. Odd how tech does that! haha

Anyhow thanks for your help so far, I look forward to your response. I hope all is well for y'all

David

P.S.: In regards to the acme.json. Is there a way to have it changed into a .pem key file in 2.X+? I am also setting up a mailserver with postfix and dovecot and I am trying to determine the best way to update its SSL keys that traefik generates for the domain. Could you tell me a little more about the new format of SSL keys?
@zespri

@idez I think I tried that before posting this and it gave me a bunch of this needs to be changed by hand ;/

I did find the certdumper.sh file super helpful although it might be in a slightly different repo.