chore: upgrade reverseproxy role for use with vagrant and ssl
This commit is contained in:
parent
a4aa64777e
commit
9e7b2b3b84
7 changed files with 177 additions and 104 deletions
|
|
@ -2,13 +2,68 @@
|
||||||
---
|
---
|
||||||
# defaults file for reverseproxy
|
# defaults file for reverseproxy
|
||||||
|
|
||||||
|
# Base directory configuration (inherited from base role or defined here)
|
||||||
|
docker_compose_base_dir: /etc/docker/compose
|
||||||
|
docker_volume_base_dir: /srv/data
|
||||||
|
|
||||||
# Service-specific configuration
|
# Service-specific configuration
|
||||||
service_name: reverseproxy
|
service_name: reverseproxy
|
||||||
docker_compose_dir: "{{ docker_compose_base_dir }}/{{ service_name }}"
|
docker_compose_dir: "{{ docker_compose_base_dir }}/{{ service_name }}"
|
||||||
docker_volume_dir: "{{ docker_volume_base_dir }}/{{ service_name }}"
|
docker_volume_dir: "{{ docker_volume_base_dir }}/{{ service_name }}"
|
||||||
|
|
||||||
# Provider configuration
|
# Deployment mode: 'dmz' or 'backend'
|
||||||
use_static_services: false # Use all_services from services.yml for outward-facing proxies
|
# - dmz: Public-facing reverse proxy that routes to backend servers using file provider
|
||||||
use_docker_provider: true # Use Docker provider for service discovery via labels
|
# - backend: Application server with docker provider for local container discovery
|
||||||
use_ssl: false # Enable SSL termination with Let's Encrypt
|
reverseproxy_mode: "backend"
|
||||||
enable_dashboard: true # Enable Traefik dashboard
|
|
||||||
|
# SSL configuration
|
||||||
|
use_ssl: true
|
||||||
|
ssl_email: "admin@example.com"
|
||||||
|
ssl_cert_resolver: "dns" # Certificate resolver name
|
||||||
|
|
||||||
|
# Certificate mode: 'acme' for Let's Encrypt with DNS challenge or 'selfsigned' for self-signed certs
|
||||||
|
cert_mode: "selfsigned" # Use selfsigned for vagrant, acme for production
|
||||||
|
|
||||||
|
# ACME DNS Challenge with RFC2136 (TSIG) configuration
|
||||||
|
acme_dns_zone: "" # e.g., "digitalboard._acme.digitalboard.ch."
|
||||||
|
acme_dns_nameserver: "" # e.g., "192.168.1.1:53"
|
||||||
|
acme_tsig_algorithm: "hmac-sha256"
|
||||||
|
acme_tsig_key: "" # TSIG key name
|
||||||
|
acme_tsig_secret: "" # TSIG secret
|
||||||
|
acme_propagation_timeout: "120"
|
||||||
|
acme_polling_interval: "2"
|
||||||
|
acme_ttl: "60"
|
||||||
|
|
||||||
|
# Self-signed certificate configuration (for vagrant/testing)
|
||||||
|
selfsigned_cert_dir: "{{ docker_volume_dir }}/certs"
|
||||||
|
selfsigned_cert_days: 365
|
||||||
|
selfsigned_common_name: "*.local.test"
|
||||||
|
|
||||||
|
# Dashboard
|
||||||
|
enable_dashboard: false
|
||||||
|
|
||||||
|
# Access log configuration
|
||||||
|
enable_access_logs: true
|
||||||
|
access_log_format: "common"
|
||||||
|
log_level: "INFO"
|
||||||
|
|
||||||
|
# Network name
|
||||||
|
traefik_network: "proxy"
|
||||||
|
|
||||||
|
# Services to expose (defined by application roles via host_vars or group_vars)
|
||||||
|
# Each backend server should define this variable with their services
|
||||||
|
# reverseproxy_services:
|
||||||
|
# - name: httpbin
|
||||||
|
# domain: httpbin.example.com
|
||||||
|
# port: 8080
|
||||||
|
# protocol: http # http or https
|
||||||
|
# entrypoints: [websecure] # optional, defaults based on SSL config
|
||||||
|
|
||||||
|
# DMZ mode: Explicit backend server mapping
|
||||||
|
# Define which backend servers this DMZ proxy should route to
|
||||||
|
# If empty or undefined, routes to all servers in backend_servers group
|
||||||
|
backend_servers_to_proxy: []
|
||||||
|
# Example:
|
||||||
|
# backend_servers_to_proxy:
|
||||||
|
# - backend1
|
||||||
|
# - backend2
|
||||||
|
|
@ -30,6 +30,5 @@ galaxy_info:
|
||||||
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
|
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
|
||||||
# Maximum 20 tags per role.
|
# Maximum 20 tags per role.
|
||||||
|
|
||||||
dependencies: []
|
dependencies:
|
||||||
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
|
- digitalboard.core.base
|
||||||
# if you add dependencies to this list.
|
|
||||||
|
|
|
||||||
|
|
@ -2,23 +2,23 @@
|
||||||
---
|
---
|
||||||
# tasks file for reverseproxy
|
# tasks file for reverseproxy
|
||||||
|
|
||||||
- name: Gather service information from all hosts
|
- name: Determine which backend servers to proxy (DMZ mode)
|
||||||
setup:
|
|
||||||
delegate_to: "{{ item }}"
|
|
||||||
delegate_facts: true
|
|
||||||
loop: "{{ groups['all_servers'] }}"
|
|
||||||
when: use_static_services | bool
|
|
||||||
|
|
||||||
- name: Build service registry from all hosts
|
|
||||||
set_fact:
|
set_fact:
|
||||||
all_services: "{{ all_services | default([]) + hostvars[item].services | default([]) | map('combine', {'backend_host': item}) | list }}"
|
_backend_servers: "{{ backend_servers_to_proxy if backend_servers_to_proxy | length > 0 else groups['backend_servers'] | default([]) }}"
|
||||||
loop: "{{ groups['all_servers'] }}"
|
when: reverseproxy_mode == 'dmz'
|
||||||
when: use_static_services | bool
|
|
||||||
|
- name: Build service registry from backend servers (DMZ mode)
|
||||||
|
set_fact:
|
||||||
|
proxied_services: "{{ proxied_services | default([]) + hostvars[item].reverseproxy_services | default([]) | map('combine', {'backend_host': hostvars[item].ansible_host | default(item)}) | list }}"
|
||||||
|
loop: "{{ _backend_servers | default([]) }}"
|
||||||
|
when: reverseproxy_mode == 'dmz'
|
||||||
|
|
||||||
- name: Debug service registry
|
- name: Debug service registry
|
||||||
debug:
|
debug:
|
||||||
var: all_services
|
var: proxied_services
|
||||||
when: use_static_services | bool
|
when:
|
||||||
|
- reverseproxy_mode == 'dmz'
|
||||||
|
- proxied_services is defined
|
||||||
|
|
||||||
- name: Create docker compose directory
|
- name: Create docker compose directory
|
||||||
file:
|
file:
|
||||||
|
|
@ -26,33 +26,45 @@
|
||||||
state: directory
|
state: directory
|
||||||
mode: '0755'
|
mode: '0755'
|
||||||
|
|
||||||
- name: Create docker volume directories
|
- name: Create docker volume directory
|
||||||
file:
|
file:
|
||||||
path: "{{ docker_volume_dir }}/traefik/{{ item }}"
|
path: "{{ docker_volume_dir }}"
|
||||||
state: directory
|
state: directory
|
||||||
mode: '0755'
|
mode: '0755'
|
||||||
loop:
|
|
||||||
- letsencrypt
|
- name: Create traefik config directory
|
||||||
|
file:
|
||||||
|
path: "{{ docker_volume_dir }}/config"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
when: reverseproxy_mode == 'dmz'
|
||||||
|
|
||||||
|
- name: Create letsencrypt directory
|
||||||
|
file:
|
||||||
|
path: "{{ docker_volume_dir }}/letsencrypt"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
when: cert_mode == 'acme'
|
||||||
|
|
||||||
- name: Create traefik Docker network
|
- name: Create traefik Docker network
|
||||||
community.docker.docker_network:
|
community.docker.docker_network:
|
||||||
name: traefik
|
name: "{{ traefik_network }}"
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Generate traefik static configuration
|
- name: Generate traefik static configuration
|
||||||
template:
|
template:
|
||||||
src: traefik.yml.j2
|
src: traefik.yml.j2
|
||||||
dest: "{{ docker_compose_dir }}/traefik.yml"
|
dest: "{{ docker_volume_dir }}/traefik.yml"
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
notify: restart traefik
|
notify: restart traefik
|
||||||
|
|
||||||
- name: Generate traefik services configuration for discovered services
|
- name: Generate traefik dynamic configuration for DMZ services
|
||||||
template:
|
template:
|
||||||
src: services.yml.j2
|
src: services.yml.j2
|
||||||
dest: "{{ docker_compose_dir }}/services.yml"
|
dest: "{{ docker_volume_dir }}/config/services.yml"
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
notify: restart traefik
|
notify: restart traefik
|
||||||
when: use_static_services | bool
|
when: reverseproxy_mode == 'dmz'
|
||||||
|
|
||||||
- name: Create docker-compose file for traefik
|
- name: Create docker-compose file for traefik
|
||||||
template:
|
template:
|
||||||
|
|
@ -63,4 +75,4 @@
|
||||||
- name: Start traefik container
|
- name: Start traefik container
|
||||||
community.docker.docker_compose_v2:
|
community.docker.docker_compose_v2:
|
||||||
project_src: "{{ docker_compose_dir }}"
|
project_src: "{{ docker_compose_dir }}"
|
||||||
state: present
|
state: present
|
||||||
|
|
@ -1,21 +1,39 @@
|
||||||
services:
|
services:
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik:v3.5
|
image: traefik:latest
|
||||||
container_name: traefik
|
container_name: reverseproxy
|
||||||
restart: always
|
restart: always
|
||||||
|
{% if cert_mode == 'acme' %}
|
||||||
|
environment:
|
||||||
|
RFC2136_NAMESERVER: "{{ acme_dns_nameserver }}"
|
||||||
|
RFC2136_TSIG_ALGORITHM: "{{ acme_tsig_algorithm }}"
|
||||||
|
RFC2136_TSIG_KEY: "{{ acme_tsig_key }}"
|
||||||
|
RFC2136_TSIG_SECRET: "{{ acme_tsig_secret }}"
|
||||||
|
RFC2136_PROPAGATION_TIMEOUT: "{{ acme_propagation_timeout }}"
|
||||||
|
RFC2136_POLLING_INTERVAL: "{{ acme_polling_interval }}"
|
||||||
|
RFC2136_TTL: "{{ acme_ttl }}"
|
||||||
|
{% endif %}
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
- "443:443"
|
- "443:443"
|
||||||
{% if enable_dashboard %}
|
{% if enable_dashboard %}
|
||||||
- "8080:8080" # Dashboard
|
- "8080:8080"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
volumes:
|
volumes:
|
||||||
- {{ docker_volume_dir }}/traefik/etc/traefik:/etc/traefik:ro
|
- {{ docker_volume_dir }}/traefik.yml:/traefik.yml:ro
|
||||||
- {{ docker_volume_dir }}/traefik/letsencrypt:/letsencrypt
|
{% if cert_mode == 'acme' %}
|
||||||
|
- {{ docker_volume_dir }}/letsencrypt:/letsencrypt
|
||||||
|
{% endif %}
|
||||||
|
{% if reverseproxy_mode == 'dmz' %}
|
||||||
|
- {{ docker_volume_dir }}/config:/config:ro
|
||||||
|
{% endif %}
|
||||||
|
{% if reverseproxy_mode == 'backend' %}
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
{% endif %}
|
||||||
networks:
|
networks:
|
||||||
- traefik
|
- {{ traefik_network }}
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
traefik:
|
{{ traefik_network }}:
|
||||||
|
name: {{ traefik_network }}
|
||||||
external: true
|
external: true
|
||||||
|
|
@ -1,47 +1,11 @@
|
||||||
{% if enable_dashboard %}
|
http:
|
||||||
api:
|
middlewares:
|
||||||
dashboard: true
|
secure-headers:
|
||||||
insecure: true
|
headers:
|
||||||
{% endif %}
|
frameDeny: true
|
||||||
|
contentTypeNosniff: true
|
||||||
{% if enable_access_logs %}
|
browserXssFilter: true
|
||||||
accessLog:
|
forceSTSHeader: true
|
||||||
format: {{ access_log_format }}
|
stsSeconds: 31536000
|
||||||
{% endif %}
|
stsIncludeSubdomains: true
|
||||||
|
stsPreload: true
|
||||||
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
|
|
||||||
|
|
@ -1,30 +1,35 @@
|
||||||
{% if use_static_services | default(false) %}
|
|
||||||
http:
|
http:
|
||||||
routers:
|
routers:
|
||||||
{% for service in all_services %}
|
{% for service in proxied_services %}
|
||||||
{{ service.name }}:
|
{{ service.name }}:
|
||||||
rule: "Host(`{{ service.domain }}`)"
|
rule: "Host(`{{ service.domain }}`)"
|
||||||
service: {{ service.name }}-service
|
service: {{ service.name }}-service
|
||||||
entryPoints:
|
entryPoints:
|
||||||
{% if use_ssl | default(false) %}
|
- {{ 'websecure' if use_ssl else 'web' }}
|
||||||
- websecure
|
{% if use_ssl %}
|
||||||
tls:
|
tls:
|
||||||
certResolver: letsencrypt
|
{% if cert_mode == 'acme' %}
|
||||||
|
certResolver: {{ ssl_cert_resolver }}
|
||||||
{% else %}
|
{% else %}
|
||||||
- web
|
{}
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
services:
|
services:
|
||||||
{% for service in all_services %}
|
{% for service in proxied_services %}
|
||||||
{{ service.name }}-service:
|
{{ service.name }}-service:
|
||||||
loadBalancer:
|
loadBalancer:
|
||||||
|
passHostHeader: true
|
||||||
servers:
|
servers:
|
||||||
- url: "{{ service.upstream_protocol }}://{{ service.backend_host }}:{{ service.port }}"
|
- url: "{{ service.protocol }}://{{ service.backend_host }}:{{ service.port }}"
|
||||||
{% if service.health_check is defined %}
|
{% if service.protocol == 'https' and cert_mode == 'selfsigned' %}
|
||||||
healthCheck:
|
serversTransport: insecure-transport
|
||||||
path: "{{ service.health_check }}"
|
|
||||||
interval: "30s"
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if cert_mode == 'selfsigned' %}
|
||||||
|
serversTransports:
|
||||||
|
insecure-transport:
|
||||||
|
insecureSkipVerify: true
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
@ -1,9 +1,17 @@
|
||||||
|
log:
|
||||||
|
level: {{ log_level }}
|
||||||
|
|
||||||
{% if enable_dashboard %}
|
{% if enable_dashboard %}
|
||||||
api:
|
api:
|
||||||
dashboard: true
|
dashboard: true
|
||||||
insecure: true
|
insecure: true
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if enable_access_logs %}
|
||||||
|
accessLog:
|
||||||
|
format: {{ access_log_format }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
entryPoints:
|
entryPoints:
|
||||||
web:
|
web:
|
||||||
address: ":80"
|
address: ":80"
|
||||||
|
|
@ -18,24 +26,36 @@ entryPoints:
|
||||||
address: ":443"
|
address: ":443"
|
||||||
|
|
||||||
providers:
|
providers:
|
||||||
{% if use_static_services | default(false) %}
|
{% if reverseproxy_mode == 'dmz' %}
|
||||||
file:
|
file:
|
||||||
filename: /etc/traefik/services.yml
|
directory: /config
|
||||||
watch: true
|
watch: true
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if use_docker_provider | default(true) %}
|
{% if reverseproxy_mode == 'backend' %}
|
||||||
docker:
|
docker:
|
||||||
endpoint: "unix:///var/run/docker.sock"
|
endpoint: "unix:///var/run/docker.sock"
|
||||||
|
network: {{ traefik_network }}
|
||||||
exposedByDefault: false
|
exposedByDefault: false
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if use_ssl and cert_mode == 'acme' %}
|
||||||
certificatesResolvers:
|
certificatesResolvers:
|
||||||
letsencrypt:
|
{{ ssl_cert_resolver }}:
|
||||||
acme:
|
acme:
|
||||||
email: admin@digitalboard.ch
|
email: {{ ssl_email }}
|
||||||
storage: /letsencrypt/acme.json
|
storage: /letsencrypt/acme.json
|
||||||
httpChallenge:
|
dnsChallenge:
|
||||||
entryPoint: web
|
provider: rfc2136
|
||||||
|
resolvers:
|
||||||
|
- "{{ acme_dns_nameserver }}"
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if use_ssl %}
|
||||||
|
tls:
|
||||||
|
options:
|
||||||
|
default:
|
||||||
|
minVersion: VersionTLS12
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
global:
|
global:
|
||||||
checkNewVersion: false
|
checkNewVersion: false
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue