do traefik for ansible

This commit is contained in:
Kyattsukuro 2026-09-10 23:15:35 +02:00
parent 21ef8778af
commit 852e36d8bc
9 changed files with 140 additions and 37 deletions

1
README.md Normal file
View File

@ -0,0 +1 @@
# traefik

17
defaults/main.yml Normal file
View File

@ -0,0 +1,17 @@
path: /srv/{{ role_name }}
traefik_override: {}
traefik_defaults:
expose_additional_ports: [] # 22 and 2022 will activate ssh
include_external_services:
config.yml.j2:
main_domain: ""
arpa_top_level: ""
http_port: ""
https_port: ""
hetzner_api_token: ""
duckdns_api_token: ""
basic_auth_password: ""

9
handlers/main.yml Normal file
View File

@ -0,0 +1,9 @@
- name: restart container
community.docker.docker_compose_v2:
project_src: "{{ path }}"
project_name: "{{ role_name }}"
recreate: "always"
services: ["traefik"]
state: "restarted"
when: not _traefik_already_restarted

17
meta/main.yml Normal file
View File

@ -0,0 +1,17 @@
---
galaxy_info:
author: "Niklas Freese <niklas@urmel.de>"
description: traefik
company: "Urmel Services"
license: AGPL-3.0-or-later
min_ansible_version: 2.1
# If this a Container Enabled role, provide the minimum Ansible Container version.
# min_ansible_container_version:
galaxy_tags: []
# List tags for your role here, one per line. A tag is a keyword that describes
# and categorizes the role. Users find roles by searching for tags. Be sure to
# remove the '[]' above, if you add tags to this list.
#
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
# Maximum 20 tags per role.

47
tasks/main.yml Normal file
View File

@ -0,0 +1,47 @@
---
- name: "set local variables from overrides and defaults"
set_fact:
traefik: "{{ (traefik_defaults | combine(traefik_override, recursive=True)) if traefik_override else traefik_defaults }}"
- name: "Set arpa domain"
set_fact:
arpa_top_level: "{{ traefik.arpa_top_level | default(traefik.main_domain.split('.')[-2:] | join('.'), true) }}"
- name: ensure that path exists
file:
path: "{{ path }}/config/file_provider"
state: directory
- name: ensure that data exists
file:
path: "{{ path }}/data"
state: directory
- name: template docker-compose
template:
src: compose.yml.j2
dest: "{{ path }}/compose.yml"
- name: template traefik.yml
template:
src: traefik.yml.j2
dest: "{{ path }}/config/traefik.yml"
- name: Populate templates
template:
src: "configs/{{ item.path }}"
dest: "{{ path }}/config/file_provider/{{ item.path | regex_replace('\\.j2$', '') }}"
with_filetree: "{{ role_path }}/templates/configs"
when:
- item.state == "file"
- item.path | regex_replace('\\.yml\\.j2$', '') | basename in traefik.include_external_services.keys()
- name: ensure container is running
community.docker.docker_compose_v2:
project_src: "{{ path }}"
project_name: "{{ role_name }}"
state: "present"
pull: "always"
wait: true
services: ["traefik"]
register: _compose_result

View File

@ -1,5 +1,3 @@
version: '3'
services:
traefik:
image: traefik:v3.6.7
@ -10,33 +8,36 @@ services:
networks:
- exposed
ports:
- 80:80
- 443:443
- 2022:2022
- {{ traefik.http_port }}:{{ traefik.http_port }}
- {{ traefik.https_port }}:{{ traefik.https_port }}
{% for port in traefik.expose_additional_ports %}
- "{{ port }}"
{% endfor %}
environment:
- HETZNER_API_TOKEN=${HETZNER_API_TOKEN}
- DUCKDNS_TOKEN=${DUCKDNS_TOKEN}
- AUTH_STRING=${AUTH_STRING}
- HETZNER_API_TOKEN={{ traefik.hetzner_api_token }}
{% if traefik.duckdns_api_token %}
- DUCKDNS_TOKEN={{ traefik.duckdns_api_token }}
{%- endif -%}
- AUTH_STRING={{ traefik.basic_auth_password }}
- DUCKDNS_POLLING_INTERVAL=5
- DUCKDNS_PROPAGATION_TIMEOUT=120
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ${PROJECT_PATH-$PWD}/traefik.yml:/traefik.yml:ro
- ${PROJECT_PATH-$PWD}/config:/config:ro
- traefik-certs:/certs
- ./config/traefik.yml:/traefik.yml:ro
- ./config/file_provider:/config:ro
- ./data/certs:/certs
labels:
traefik.enable: true
traefik.http.routers.traefik-dashboard.entrypoints: https
traefik.http.routers.traefik-dashboard.rule: Host(`traefik.arpa.urmel.de`)
traefik.http.routers.traefik-dashboard.rule: Host(`traefik.arpa.{{ arpa_top_level }}`)
traefik.http.routers.traefik-dashboard.tls: "true"
traefik.http.routers.traefik-dashboard.tls.certresolver: hetzner
traefik.http.routers.traefik-dashboard.service: api@internal
traefik.http.routers.traefik-dashboard.middlewares: local-only@file, traefik-auth@file
volumes:
traefik-certs:
traefik.http.routers.traefik-dashboard.middlewares: local-only@file
networks:
exposed:
@ -45,4 +46,4 @@ networks:
config:
- subnet: 172.18.0.0/16
ip_range: 172.18.128.0/17
gateway: 172.18.0.1
gateway: 172.18.0.1

View File

@ -1,51 +1,58 @@
http:
http:
routers:
traefik-secure:
service: noop@internal
rule: Host(`urmel.de`)
rule: Host(`{{ traefik.main_domain }}`)
entryPoints:
- https
- http
tls:
certResolver: hetzner
domains:
- main: "arpa.urmel.de"
sans:
- "*.arpa.urmel.de"
- main: "urmel.de"
sans:
- "*.urmel.de"
- main: "arpa.{{ arpa_top_level }}"
sans:
- "*.arpa.{{ arpa_top_level }}"
- main: "{{ traefik.main_domain }}"
sans:
- "*.{{ traefik.main_domain }}"
{% if traefik.duckdns_api_token -%}
forward-duckdns:
service: noop@internal
rule: HostRegexp(`(.+\.)?urmel\.duckdns\.org`)
priority: 1
middlewares: redirect-duckdns@file
tls:
tls:
certResolver: duckdns
domains:
- main: "urmel.duckdns.org"
sans:
sans:
- "*.urmel.duckdns.org"
entryPoints:
- https
- http
{%- endif %}
middlewares:
traefik-auth:
basicauth:
users: '{{ env "AUTH_STRING" }}'
users: '{% raw %}{{ env "AUTH_STRING" }}{% endraw %}'
{% if traefik.duckdns_api_token %}
redirect-duckdns:
redirectRegex:
regex: "^http(s?)://(.+\\.)?urmel\\.duckdns\\.org(:[0-9]+)?(/.*$|$)"
replacement: "http${1}://${2}urmel.de${3}${4}"
{% endif %}
local-only:
ipAllowList:
sourceRange:
- "10.0.0.0/8"
- "172.16.0.0/12"
- "168.168.0.0/16"
- "192.168.0.0/16"
secure-only:
ipAllowList:
sourceRange:
- "172.24.2.0/24"
- "10.99.0.4/24"
- "10.99.0.4/24"

View File

@ -2,7 +2,7 @@ http:
routers:
homeassistant:
service: homeassistant
rule: Host(`home.urmel.de`)
rule: Host(`home.{{ traefik.main_domain }}`)
priority: 10
entryPoints:
- https
@ -15,11 +15,11 @@ http:
homeassistant:
loadbalancer:
servers:
- url: "http://172.24.2.4:8123"
- url: "http://{{ traefik.include_external_services.homeassistant.url }}:8123"
passHostHeader: true
middlewares:
homeassistant-headers:
headers:
customResponseHeaders:
X-Frame-Options: "ALLOW-FROM *.urmel.de"
Content-Security-Policy: "frame-ancestors *.urmel.de"
X-Frame-Options: "ALLOW-FROM *.{{ traefik.main_domain }}"
Content-Security-Policy: "frame-ancestors *.{{ traefik.main_domain }}"

View File

@ -4,7 +4,7 @@ api:
entryPoints:
http:
asDefault: true
address: ":80"
address: ":{{ traefik.http_port }}"
http:
redirections:
entryPoint:
@ -12,9 +12,11 @@ entryPoints:
scheme: https
https:
asDefault: true
address: ":443"
address: ":{{ traefik.https_port }}"
{% if 2022 in traefik.expose_additional_ports -%}
public_ssh:
address: ":2022"
{% endif -%}
serversTransport:
insecureSkipVerify: true
providers:
@ -35,6 +37,7 @@ certificatesResolvers:
provider: "hetzner"
resolvers:
- "hydrogen.ns.hetzner.com"
{% if traefik.duckdns_api_token -%}
duckdns:
acme:
email: nikl.free44@gmail.com
@ -48,4 +51,5 @@ certificatesResolvers:
requireAllRNS: true
resolvers:
- "8.8.8.8:53"
- "1.1.1.1:53"
- "1.1.1.1:53"
{%- endif %}