davestephens / ansible-nas

Build a full-featured home server or NAS replacement with an Ubuntu box and this playbook.
MIT License
3.22k stars 488 forks source link

Upgrade to Traefik 2.0 #142

Closed davestephens closed 3 years ago

davestephens commented 5 years ago

Traefik 2 is now GA, Ansible-NAS currently uses 1.7.

mahalel commented 4 years ago

Hi, and thank you for an awesome project. I have got my traefik container working with traefik:latest - using dns01 challenge (using digitalocean api) I don't have enough right now to submit a pull request that matches the current way you are doing it but if it helps I can add my current configs as a starting point idea. Please let me know.

Malpractis commented 4 years ago

Hey mahalel,

I've pretty much got a Traefik 2 PR ready, I'm just testing some options for using cloudflare dns01 and http challenges. If you could provide your digitalocean config as well that would be great! I'll add that in as another option.

mahalel commented 4 years ago

Hey Malpractis, no worries - here's what I've currently got (you could probaly setup a variable for the provider):

./templates/traefik/traefik.yml excerpt:

certificatesResolvers:
  LetsEncrypt:
    acme:
      email: {{ ansible_nas_email }}
      storage: /etc/traefik/acme/acme.json
      dnsChallenge:
        provider: digitalocean
        resolvers:
          - "1.1.1.1:53"
          - "8.8.8.8:53"
            #caServer: https://acme-staging-v02.api.letsencrypt.org/directory

./tasks/traefik.yml

---
- name: Ensure Nginx Docker Container is absent
  docker_container:
    name: nginx-proxy
    state: absent

- name: Nginx Letsencrypt Container is absent
  docker_container:
    name: letsencrypt-nginx-proxy-companion
    state: absent

- name: Create Traefik Directories
  file:
    path: "{{ item }}"
    state: directory
  with_items:
    - "{{ traefik_data_directory }}"

- name: Check if acme file exists
  stat: 
    path: "{{ traefik_data_directory }}/acme.json"
  register: acme_rules

- name: Create new acme file if it does not already exist
  file:
    path: "{{ traefik_data_directory }}/acme.json"
    state: touch
    mode: 0600
  when: acme_rules.stat.exists == False

- name: Template Traefik config.yml
  template:
    src: traefik/traefik.yml
    dest: "{{ traefik_data_directory }}/traefik.yml"

- name: Traefik Docker Container
  docker_container:
    name: traefik
    image: "{{ traefik_docker_image }}"
    pull: true
    network_mode: bridge
    ports:
      - 443:443/tcp
      - 80:80/tcp
    env: 
      DO_AUTH_TOKEN: "{{ digitalocean_api_key }}"
    volumes:
      - "{{ traefik_data_directory }}/traefik.yml:/etc/traefik/traefik.yml:ro"
      - "{{ traefik_data_directory }}/acme.json:/etc/traefik/acme/acme.json:rw"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    restart_policy: unless-stopped
    memory: 1g
    labels:
      traefik.enable: "{{ traefik_available_externally }}"
      traefik.http.routers.traefik.entrypoints: https
      traefik.http.routers.traefik.rule: "Host(`traefik.{{ ansible_nas_domain }}`)"
      traefik.http.routers.traefik.tls.certresolver: "{{ certresolver }}"
      traefik.http.routers.traefik.middlewares: traefik-auth
      traefik.http.routers.traefik.service: api@internal
      traefik.http.middlewares.traefik-auth.basicauth.users: test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/

./inventories/my-ansible-nas/group_vars/nas.yml

traefik_enabled: true
traefik_available_externally: "true"
traefik_docker_image: traefik:latest
digitalocean_api_key: aabbccddeeffgghhiijjkkllmmnn
certresolver: LetsEncrypt

Hope this helps.

ckoehler commented 4 years ago

For reference, here's my traefik.yml task:

- name: Traefik Docker Container
  docker_container:
    name: traefik
    image: "{{ traefik_docker_image }}"
    pull: true
    network_mode: host
    env:
      CF_DNS_API_TOKEN: "{{ cloudflare_api_token }}"
    volumes:
      - "{{ traefik_data_directory }}/traefik.toml:/etc/traefik/traefik.toml:ro"
      - "{{ traefik_data_directory }}/acme.json:/etc/traefik/acme.json:rw"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    restart_policy: unless-stopped
    memory: 1g
    labels:
      traefik.enable: "{{ traefik_available_externally }}"
      traefik.http.routers.traefik.entrypoints: "https"
      traefik.http.routers.traefik.rule: "Host(`traefik.{{ ansible_nas_domain }}`)"
      traefik.http.services.traefik.loadbalancer.server.port: "{{ traefik_port_ui }}"
      traefik.http.routers.traefik.tls: "true"
      traefik.http.routers.traefik.tls.certResolver: "cloudflare"
      traefik.http.routers.traefik.tls.domains[0].main: "*.{{ ansible_nas_domain }}"
      traefik.http.routers.traefik.service: "api@internal"
      traefik.http.routers.http-catchall.rule: "hostregexp(`{host:.+}`)"
      traefik.http.routers.http-catchall.entrypoints: http
      traefik.http.routers.http-catchall.middlewares: redirect-to-https
      traefik.http.middlewares.redirect-to-https.redirectscheme.scheme: https

And my labels for Nextcloud:

    labels:
      traefik.enable: "{{ nextcloud_available_externally }}"
      traefik.http.routers.nextcloud.rule: "Host(`nextcloud.{{ ansible_nas_domain }}`)"
      traefik.http.routers.nextcloud.tls: "true"
      traefik.http.routers.nextcloud.middlewares: "stsheader,ncdav"
      traefik.http.services.nextcloud.loadbalancer.server.port: "80"
      traefik.http.middlewares.stsheader.headers.stsSeconds: "15552000"
      traefik.http.middlewares.stsheader.headers.referrerPolicy: no-referrer
      traefik.http.middlewares.ncdav.redirectregex.regex: https://(.*)/.well-known/(card|cal)dav
      traefik.http.middlewares.ncdav.redirectregex.replacement: https://$1/remote.php/dav/
      traefik.http.middlewares.ncdav.redirectregex.permanent: "true"
bcurran3 commented 4 years ago

Hey guys, is there any movement on this? I'd like to give Traefik v2 a whirl and don't want to go through the growing pains of converting it myself. :)

Malpractis commented 4 years ago

TBH I've had it setup and running since before this issue was raised. Not had any issues. Happily running 2.2.8 now.

The reason I haven't pushed a PR is that I've done it with a wildcard cert and DNS-01 challenge. Which I don't think was how Dave wanted to proceed. And I got a bit stuck trying to support both individual certs and wildcard at once.

I can pop some config in here though if you wanted to look at what I've done? Or I could chuck up a PR to my fork.

Oh I should also mention I've used cloudflare for the DNS provider.

codemeister64 commented 4 years ago

Hi guys, is there any progress on this task?)

PurpleNinja225 commented 3 years ago

Here's what I have for my traefik v2.2 with cloudflare DNS Challenge

traefik.yml

- name: Ensure Nginx Docker Container is absent
  docker_container:
    name: nginx-proxy
    state: absent

- name: Nginx Letsencrypt Container is absent
  docker_container:
    name: letsencrypt-nginx-proxy-companion
    state: absent

- name: Create Traefik Directories
  file:
    path: "{{ item }}"
    state: directory
  with_items:
    - "{{ traefik_data_directory }}"

- name: Template Traefik config.toml
  template:
    src: traefik/traefik.toml
    dest: "{{ traefik_data_directory }}/traefik.toml"

- name: Traefik Docker Container
  docker_container:
    name: traefik2
    image: "{{ traefik_docker_image }}"
    pull: true
    network_mode: bridge
    volumes:
      - "{{ traefik_data_directory }}/traefik.toml:/etc/traefik/traefik.toml:ro"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "/Data/docker-containers/traefik/letsencrypt:/letsencrypt:rw"
    restart_policy: unless-stopped
    env:
      CF_API_EMAIL: "admin@example.com"
      CF_API_KEY: "supersecretglobalapikey"
      PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    labels:
      traefik.enable: true
      traefik.http.middlewares.monitor-auth.basicauth.users: "admin:$2y$12$llZBTxLQWpnbKawmSoSv9ejdtIJkUdk27aY7Pv/6o2ADVVgPCvN9C"
      traefik.http.middlewares.redirect-to-https.redirectscheme.scheme: "https"
      traefik.http.routers.http-catchall.entrypoints: "http"
      traefik.http.routers.http-catchall.middlewares: "redirect-to-https"
      traefik.http.routers.http-catchall.rule: "HostRegexp(`{host:.+}`)"
      traefik.http.routers.monitor.entrypoints: "https"
      traefik.http.routers.monitor.middlewares: "monitor-auth"
      traefik.http.routers.monitor.rule: "Host(`{{ .Name }}.{{ ansible_nas_domain }}`)"
      traefik.http.routers.monitor.service: "api@internal"
      traefik.http.routers.monitor.tls: true
      traefik.http.routers.monitor.tls.certresolver: "dns-cloudflare"
      traefik.http.routers.monitor.tls.domains[0].main: "example.com"
      traefik.http.routers.monitor.tls.domains[0].sans: ("mail.example.com", "webmail.example.com", "smtp.example.com")

#- name: Whoami Docker Container
#  docker_container:
#    name: whoami
#    image: "containous/whoami"
#    labels:
#      - "traefik.enable=true"
#      - "traefik.http.routers.whoami.rule=Host(`whoami.arknet.media`)"
#      - "traefik.http.routers.whoami.entrypoints=websecure"
#      - "traefik.http.routers.whoami.tls.certresolver=myresolver"

traefik.toml

################################################################
# Global configuration
################################################################

[global]
  checkNewVersion = true
  sendAnonymousUsage = false
  defaultEntryPoints = ["http", "https"]

[serversTransport]
  insecureSkipVerify = true

################################################################
# Entrypoints configuration
################################################################

[entryPoints]
  [entryPoints.http]
    address = ":{{ traefik_port_http }}"
    [entryPoints.http.redirect]
      entryPoint = "https"

  [entryPoints.https]
  address = ":{{ traefik_port_https }}"
    [entryPoints.https.tls]

  [entryPoints.traefik]
  address = ":{{ traefik_port_ui }}"

################################################################
# Traefik logs configuration
################################################################

[log]
  logLevel = "ERROR"
  filePath = "/logs/traefik.log"

################################################################
# Access logs configuration
################################################################

[accessLog]
  filePath = "/logs/access.log"
  bufferingSize = 100
  [accessLog.filters]
    retryAttempts = true

################################################################
# API and dashboard configuration
################################################################

[api]
  entryPoint = "traefik"
  dashboard = true
  debug = '{{ traefik_debug }}'

################################################################
# Ping configuration
################################################################

[ping]
  entryPoint = "traefik"

################################################################
# Cloudflare DNS Cert Resolver
################################################################

[certificatesResolvers.dns-cloudflare.acme]
  email = "admin@example.com
  storage = "/acme.json"
  [certificatesResolvers.dns-cloudflare.acme.dnsChallenge]
    provider = "cloudflare"

################################################################
# Docker configuration backend
################################################################

[providers]
  [providers.docker]
    exposedByDefault = false
    defaultRule = "Host(`{{ .Name }}.{{ ansible_nas_domain }}`)"
    network = "bridge"
    swarmMode = false

Typical label convention for containers (this one is from my ombi config)

    labels:
      traefik.http.routers.requests.tls.certs: "dns-cloudflare"
      traefik.http.routers.requests.rule: "Host('requests.{{ ansible_nas_domain }}')"
      traefik.enable: "{{ ombi_available_externally }}"
      traefik.http.routers.requests.tls: "true"
PurpleNinja225 commented 3 years ago

I've got most of the work done for a pull request and a couple additional linuxserver.io containers, but I'm still pretty new to contributing to github and not really a coder :sweat_smile: I can start making pull requests if main devs can bare with me and going through some growing pains ha!

joao-p-marques commented 3 years ago

Hi! :wave: Nice to know this is in the roadmap :smiley:.

@PurpleNinja225 or @Malpractis if you have a working configuration, could you then push something like a draft PR with that? That could shed some light on the progress and help someone else to possibly take it from there also for a fork, or finish it if you don't want to.

davestephens commented 3 years ago

I've actually got this working this morning, will get it tidied up and pushed soon.

On Sun, 17 Jan 2021, 12:33 João Marques, notifications@github.com wrote:

Hi! 👋 Nice to know this is in the roadmap 😃.

@PurpleNinja225 https://github.com/PurpleNinja225 or @Malpractis https://github.com/Malpractis if you have a working configuration, could you then push something like a draft PR with that? That could shed some light on the progress and help someone else to possibly take it from there also for a fork, or finish it if you don't want to.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/davestephens/ansible-nas/issues/142#issuecomment-761805047, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFDGMBQWIU5EAGZIEAEIW3S2LKKDANCNFSM4JAIZHEA .

joao-p-marques commented 3 years ago

Nice 🤩👍

On Sun, 17 Jan 2021, 13:39 David Stephens, notifications@github.com wrote:

I've actually got this working this morning, will get it tidied up and pushed soon.

On Sun, 17 Jan 2021, 12:33 João Marques, notifications@github.com wrote:

Hi! 👋 Nice to know this is in the roadmap 😃.

@PurpleNinja225 https://github.com/PurpleNinja225 or @Malpractis https://github.com/Malpractis if you have a working configuration, could you then push something like a draft PR with that? That could shed some light on the progress and help someone else to possibly take it from there also for a fork, or finish it if you don't want to.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub < https://github.com/davestephens/ansible-nas/issues/142#issuecomment-761805047 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AAFDGMBQWIU5EAGZIEAEIW3S2LKKDANCNFSM4JAIZHEA

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/davestephens/ansible-nas/issues/142#issuecomment-761814235, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJJMDDX3EV23ARCV6GZG5XTS2LSB5ANCNFSM4JAIZHEA .

davestephens commented 3 years ago

It's done and pushed!

We now request one wildcard certificate that's used across all the applications, and I've made it easy to use DNS providers other than Cloudflare without having to mess with the task ymls.

Apps in roles also now have configurable hostnames.

Feedback appreciated!