diff --git a/roles/reverseproxy/defaults/main.yml b/roles/reverseproxy/defaults/main.yml index 023acd7..a1d5300 100644 --- a/roles/reverseproxy/defaults/main.yml +++ b/roles/reverseproxy/defaults/main.yml @@ -8,7 +8,7 @@ docker_compose_dir: "{{ docker_compose_base_dir }}/{{ service_name }}" docker_volume_dir: "{{ docker_volume_base_dir }}/{{ service_name }}" # Provider configuration -use_static_services: false # Use all_services from dynamic.yml for outward-facing proxies +use_static_services: false # Use all_services from services.yml for outward-facing proxies use_docker_provider: true # Use Docker provider for service discovery via labels use_ssl: false # Enable SSL termination with Let's Encrypt enable_dashboard: true # Enable Traefik dashboard \ No newline at end of file diff --git a/roles/reverseproxy/handlers/main.yml b/roles/reverseproxy/handlers/main.yml index e2a4018..0ed6010 100644 --- a/roles/reverseproxy/handlers/main.yml +++ b/roles/reverseproxy/handlers/main.yml @@ -1,3 +1,8 @@ #SPDX-License-Identifier: MIT-0 --- # handlers file for reverseproxy + +- name: restart traefik + docker_compose: + project_src: "{{ docker_compose_dir }}" + restarted: yes diff --git a/roles/reverseproxy/tasks/main.yml b/roles/reverseproxy/tasks/main.yml index 2345178..c50910c 100644 --- a/roles/reverseproxy/tasks/main.yml +++ b/roles/reverseproxy/tasks/main.yml @@ -1,3 +1,57 @@ #SPDX-License-Identifier: MIT-0 --- # tasks file for reverseproxy + +- name: Gather service information from all hosts + setup: + delegate_to: "{{ item }}" + delegate_facts: true + loop: "{{ groups['all_servers'] }}" + +- name: Build service registry from all hosts + set_fact: + all_services: "{{ all_services | default([]) + hostvars[item].services | default([]) | map('combine', {'backend_host': item}) | list }}" + loop: "{{ groups['all_servers'] }}" + +- name: Debug service registry + debug: + var: all_services + +- name: Create docker compose directory + file: + path: "{{ docker_compose_dir }}" + state: directory + mode: '0755' + +- name: Create docker volume directories + file: + path: "{{ docker_volume_dir }}/traefik/{{ item }}" + state: directory + mode: '0755' + loop: + - letsencrypt + +- name: Generate traefik static configuration + template: + src: traefik.yml.j2 + dest: "{{ docker_compose_dir }}/traefik.yml" + mode: '0644' + notify: restart traefik + +- name: Generate traefik services configuration for discovered services + template: + src: services.yml.j2 + dest: "{{ docker_compose_dir }}/services.yml" + mode: '0644' + notify: restart traefik + +- name: Create docker-compose file for traefik + template: + src: docker-compose.yml.j2 + dest: "{{ docker_compose_dir }}/docker-compose.yml" + mode: '0644' + +- name: Start traefik container + docker_compose: + project_src: "{{ docker_compose_dir }}" + state: present diff --git a/roles/reverseproxy/templates/docker-compose.yml.j2 b/roles/reverseproxy/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..2184aee --- /dev/null +++ b/roles/reverseproxy/templates/docker-compose.yml.j2 @@ -0,0 +1,23 @@ +version: '3.8' + +services: + traefik: + image: traefik:v3.5 + container_name: traefik + restart: always + ports: + - "80:80" + - "443:443" +{% if enable_dashboard %} + - "8080:8080" # Dashboard +{% endif %} + volumes: + - {{ docker_volume_dir }}/traefik/etc/traefik:/etc/traefik:ro + - {{ docker_volume_dir }}/traefik/letsencrypt:/letsencrypt + - /var/run/docker.sock:/var/run/docker.sock:ro + networks: + - traefik + +networks: + traefik: + external: true \ No newline at end of file diff --git a/roles/reverseproxy/templates/services.yml.j2 b/roles/reverseproxy/templates/services.yml.j2 new file mode 100644 index 0000000..98eecad --- /dev/null +++ b/roles/reverseproxy/templates/services.yml.j2 @@ -0,0 +1,30 @@ +{% if use_static_services | default(false) %} +http: + routers: +{% for service in all_services %} + {{ service.name }}: + rule: "Host(`{{ service.domain }}`)" + service: {{ service.name }}-service + entryPoints: +{% if use_ssl | default(false) %} + - websecure + tls: + certResolver: letsencrypt +{% else %} + - web +{% endif %} +{% endfor %} + + services: +{% for service in all_services %} + {{ service.name }}-service: + loadBalancer: + servers: + - url: "{{ service.upstream_protocol }}://{{ service.backend_host }}:{{ service.port }}" +{% if service.health_check is defined %} + healthCheck: + path: "{{ service.health_check }}" + interval: "30s" +{% endif %} +{% endfor %} +{% endif %} \ No newline at end of file diff --git a/roles/reverseproxy/templates/traefik.yml.j2 b/roles/reverseproxy/templates/traefik.yml.j2 new file mode 100644 index 0000000..18cc369 --- /dev/null +++ b/roles/reverseproxy/templates/traefik.yml.j2 @@ -0,0 +1,42 @@ +{% if enable_dashboard %} +api: + dashboard: true + insecure: true +{% endif %} + +entryPoints: + web: + address: ":80" +{% if use_ssl %} + http: + redirections: + entryPoint: + to: websecure + scheme: https +{% endif %} + websecure: + address: ":443" + +providers: +{% if use_static_services | default(false) %} + file: + filename: /etc/traefik/services.yml + watch: true +{% endif %} +{% if use_docker_provider | default(true) %} + docker: + endpoint: "unix:///var/run/docker.sock" + exposedByDefault: false +{% endif %} + +certificatesResolvers: + letsencrypt: + acme: + email: admin@digitalboard.ch + storage: /letsencrypt/acme.json + httpChallenge: + entryPoint: web + +global: + checkNewVersion: false + sendAnonymousUsage: false \ No newline at end of file