diff --git a/roles/deploy_container_traefik/defaults/main.yml b/roles/deploy_container_traefik/defaults/main.yml new file mode 100644 index 0000000..1eea22b --- /dev/null +++ b/roles/deploy_container_traefik/defaults/main.yml @@ -0,0 +1,35 @@ +--- +container_traefik_version: "latest" +container_traefik_http_port: 80 +container_traefik_https_port: 443 +container_traefik_domain: "example.com" +container_traefik_san_domains: + - "example.com" + - "example.org" +container_traefik_cloudflare_mail: "your-email@example.com" +container_traefik_cloudflare_token: "your-cloudflare-token" +container_traefik_basicauth_user: "admin" +container_traefik_basicauth_password: "yourpassword" + +# Static Traefik Routes +container_traefik_routers: + traefik: + entryPoints: + - "https" + rule: "Host(`example.example.com`)" + middlewares: + - default-headers + tls: {} + service: traefik + +container_traefik_services: + traefik: + loadBalancer: + servers: + - url: "http://127.0.0.1" + passHostHeader: true + serversTransport: insecure-https + +container_traefik_serversTransports: + insecure-https: + insecureSkipVerify: true diff --git a/roles/deploy_container_traefik/handlers/main.yml b/roles/deploy_container_traefik/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/deploy_container_traefik/meta/main.yml b/roles/deploy_container_traefik/meta/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/deploy_container_traefik/tasks/main.yml b/roles/deploy_container_traefik/tasks/main.yml new file mode 100644 index 0000000..da3e7a6 --- /dev/null +++ b/roles/deploy_container_traefik/tasks/main.yml @@ -0,0 +1,57 @@ +--- +- name: Ensure data directories exist + ansible.builtin.file: + path: "{{ traefik_container_dir }}/data/{{ item }}" + state: directory + mode: '0755' + loop: + - "traefik" + - "certs" + - "logs" + - "traefik/config.d" + become: false + +- name: Ensure log files exist + ansible.builtin.file: + path: "{{ traefik_container_dir }}/data/logs/{{ item }}" + state: touch + mode: '0644' + loop: + - "traefik.log" + - "access.log" + become: false + +- name: Deploy Traefik configuration files + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ traefik_container_dir }}/data/{{ item.dest }}" + mode: '0644' + loop: + - { src: 'traefik.yml.j2', dest: 'traefik/traefik.yml' } + - { src: 'default.yml.j2', dest: 'traefik/config.d/default.yml' } + - { src: 'hosts.yml.j2', dest: 'traefik/config.d/hosts.yml' } + become: false + +- name: Deploy Docker Compose and .env files + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ traefik_container_dir }}/{{ item.dest }}" + mode: '0644' + loop: + - { src: 'docker-compose.yml.j2', dest: 'docker-compose.yml' } + - { src: '.env.j2', dest: '.env' } + become: false + +- name: Ensure Docker network exists + community.docker.docker_network: + name: traefik + state: present + docker_host: "unix:///run/user/1000/docker.sock" + become: false + +- name: Start Traefik container + community.docker.docker_compose_v2: + project_src: "{{ traefik_container_dir }}" + pull: always + docker_host: "unix:///run/user/1000/docker.sock" + become: false diff --git a/roles/deploy_container_traefik/templates/.env.j2 b/roles/deploy_container_traefik/templates/.env.j2 new file mode 100644 index 0000000..8428d72 --- /dev/null +++ b/roles/deploy_container_traefik/templates/.env.j2 @@ -0,0 +1,29 @@ +# Traefik Version +# Defines the version of Traefik to be used. By default, "latest" is used. +TRAEFIK_VERSION={{ container_traefik_version }} + +TRAEFIK_DOMAIN={{ container_traefik_domain }} + +# Ports +# Defines the ports on which Traefik will be available for HTTP and HTTPS traffic. +# By default, these are 80 (HTTP) and 443 (HTTPS). +TRAEFIK_HTTP_PORT={{ container_traefik_http_port }} +TRAEFIK_HTTPS_PORT={{ container_traefik_https_port }} + +# Cloudflare API Access +# Your Cloudflare API credentials that Traefik uses to automatically obtain TLS certificates +# via the Cloudflare DNS provider. +# Replace the following placeholders with your actual Cloudflare details: +# - CLOUDFLARE_MAIL: Your Cloudflare email address +# - CLOUDFLARE_TOKEN: Your Cloudflare API token +CLOUDFLARE_MAIL={{ container_traefik_cloudflare_mail }} +CLOUDFLARE_TOKEN={{ container_traefik_cloudflare_token }} + +# Basic Auth Configuration +# Basic authentication credentials for securing the Traefik dashboard. +# You can generate the password using the following command: +# echo $(htpasswd -nB yourusername) | sed -e s/\\$/\\$\\$/g +# Replace `yourusername` with the desired username. +# The generated value can then be placed in the `BASICAUTH_PASSWORD` variable. +TRAEFIK_BASICAUTH_USER={{ container_traefik_basicauth_user }} +TRAEFIK_BASICAUTH_PASSWORD={{ container_traefik_basicauth_password }} \ No newline at end of file diff --git a/roles/deploy_container_traefik/templates/default.yml.j2 b/roles/deploy_container_traefik/templates/default.yml.j2 new file mode 100644 index 0000000..a9485b6 --- /dev/null +++ b/roles/deploy_container_traefik/templates/default.yml.j2 @@ -0,0 +1,19 @@ +http: + middlewares: + https-redirect: + redirectScheme: + scheme: https + + default-headers: + headers: + frameDeny: true + sslRedirect: true + browserXssFilter: true + contentTypeNosniff: true + forceSTSHeader: true + stsIncludeSubdomains: true + stsPreload: true + stsSeconds: 15552000 + customFrameOptionsValue: SAMEORIGIN + customRequestHeaders: + X-Forwarded-Proto: https diff --git a/roles/deploy_container_traefik/templates/docker-compose.yml.j2 b/roles/deploy_container_traefik/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..90a5f2c --- /dev/null +++ b/roles/deploy_container_traefik/templates/docker-compose.yml.j2 @@ -0,0 +1,44 @@ +--- +services: + traefik: + image: traefik:${TRAEFIK_VERSION} + container_name: traefik + restart: always + security_opt: + - "no-new-privileges:true" + networks: + - traefik + ports: + - ${TRAEFIK_HTTP_PORT}:80 + - ${TRAEFIK_HTTPS_PORT}:443 + volumes: + - /run/user/1000/docker.sock:/var/run/docker.sock:ro + - ./data/traefik:/etc/traefik + - ./data/certs:/etc/certs:ro + - ./data/logs/traefik.log:/var/log/traefik.log + - ./data/logs/access.log:/var/log/crowdsec/traefik.log + environment: + - "CF_API_EMAIL=${CLOUDFLARE_MAIL:?error}" + - "CF_DNS_API_TOKEN=${CLOUDFLARE_TOKEN:?error}" + labels: + - "traefik.enable=true" + - "traefik.http.routers.traefik.entrypoints=http" + - "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN}`)" + - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https" + - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https" + - "traefik.http.routers.traefik.middlewares=traefik-https-redirect" + - "traefik.http.routers.traefik-secure.entrypoints=https" + - "traefik.http.middlewares.basic-auth.basicauth.users=${TRAEFIK_BASICAUTH_USER}:${TRAEFIK_BASICAUTH_PASSWORD}" + - "traefik.http.routers.traefik-secure.middlewares=basic-auth" + - "traefik.http.routers.traefik-secure.rule=Host(`${TRAEFIK_DOMAIN}`)" + - "traefik.http.routers.traefik-secure.tls=true" + - "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare" +{% for domain in container_traefik_san_domains %} + - "traefik.http.routers.traefik-secure.tls.domains[{{ loop.index0 }}].main={{ domain }}" + - "traefik.http.routers.traefik-secure.tls.domains[{{ loop.index0 }}].sans=*.{{ domain }}" +{% endfor %} + - "traefik.http.routers.traefik-secure.service=api@internal" + +networks: + traefik: + external: true diff --git a/roles/deploy_container_traefik/templates/hosts.yml.j2 b/roles/deploy_container_traefik/templates/hosts.yml.j2 new file mode 100644 index 0000000..dc23f3d --- /dev/null +++ b/roles/deploy_container_traefik/templates/hosts.yml.j2 @@ -0,0 +1,42 @@ +http: + routers: +{% for router_name, router in container_traefik_routers.items() %} + {{ router_name }}: + entryPoints: +{% for ep in router.entryPoints %} + - "{{ ep }}" +{% endfor %} + rule: "{{ router.rule }}" +{% if router.middlewares is defined and router.middlewares %} + middlewares: +{% for m in router.middlewares %} + - {{ m }} +{% endfor %} +{% endif %} +{% if router.tls is defined and router.tls %} + tls: {} +{% endif %} + service: {{ router.service }} +{% endfor %} + + services: +{% for service_name, service in container_traefik_services.items() %} + {{ service_name }}: + loadBalancer: + servers: +{% for server in service.loadBalancer.servers %} + - url: "{{ server.url }}" +{% endfor %} + passHostHeader: {{ service.loadBalancer.passHostHeader | default(true) | lower }} +{% if service.loadBalancer.serversTransport is defined %} + serversTransport: {{ service.loadBalancer.serversTransport }} +{% endif %} +{% endfor %} + + serversTransports: +{% for transport_name, transport in container_traefik_serversTransports.items() %} + {{ transport_name }}: +{% for key, value in transport.items() %} + {{ key }}: {{ value | lower if value is boolean else value }} +{% endfor %} +{% endfor %} diff --git a/roles/deploy_container_traefik/templates/traefik.yml.j2 b/roles/deploy_container_traefik/templates/traefik.yml.j2 new file mode 100644 index 0000000..ea2511d --- /dev/null +++ b/roles/deploy_container_traefik/templates/traefik.yml.j2 @@ -0,0 +1,43 @@ +api: + dashboard: true + +log: + level: INFO + format: json + filePath: "/var/log/traefik.log" + +accessLog: + filePath: "/var/log/access.log" + bufferingSize: 50 + +entryPoints: + http: + address: ":80" + https: + address: ":443" + +serversTransport: + insecureSkipVerify: false + forwardingTimeouts: + dialTimeout: 10s + responseHeaderTimeout: 10s + +providers: + docker: + endpoint: "unix:///var/run/docker.sock" + exposedByDefault: false + watch: true + file: + directory: "/etc/traefik/config.d/" + watch: true + +certificatesResolvers: + cloudflare: + acme: + email: "{{ container_traefik_cloudflare_mail }}" + storage: acme.json + dnsChallenge: + provider: cloudflare + resolvers: + - "1.1.1.1:53" + - "1.0.0.1:53" diff --git a/roles/deploy_container_traefik/vars/main.yml b/roles/deploy_container_traefik/vars/main.yml new file mode 100644 index 0000000..fbf5ac5 --- /dev/null +++ b/roles/deploy_container_traefik/vars/main.yml @@ -0,0 +1,2 @@ +--- +traefik_container_dir: "/opt/docker/traefik"