Compare commits

...

18 Commits

Author SHA1 Message Date
uumas
d8bd645a80 Support ssh_pubkeys as list 2025-10-12 19:26:12 +03:00
uumas
6d2d305fd0 caddy: Use firewalld 2025-09-14 03:02:59 +03:00
uumas
90ade1e766 Add readmes 2025-09-14 03:02:48 +03:00
uumas
f2840d79a7 prometheus_node_exporter: Allow listening on all 2025-09-14 03:02:09 +03:00
uumas
217b79b225 Add firewalld role 2025-09-14 03:01:52 +03:00
uumas
37066850a0 compatcheck: support macosx 2025-09-14 02:58:39 +03:00
uumas
7617edfdde borgmatic_config: Initialize repos 2025-09-14 02:58:15 +03:00
uumas
e4c8a2343a borgmatic: ignore unreachable backup target 2025-09-14 02:57:45 +03:00
uumas
9b40f06804 Revert "prometheus_node_exporter: Make listening on localhost possible"
This reverts commit 273da948b5.
2025-07-27 19:42:24 +03:00
uumas
273da948b5 prometheus_node_exporter: Make listening on localhost possible 2025-07-26 23:07:09 +03:00
uumas
7e0538ae20 prometheus_node_exporter: move compatcheck to tasks 2025-07-26 23:06:34 +03:00
uumas
1c9649e8d6 prometheus_node_exporter: rename variable 2025-07-26 23:05:26 +03:00
uumas
648da9266b prometheus_node_exporter: Use systemd_service 2025-07-26 14:34:13 +03:00
uumas
8af49bcc3e vhost: Support regex matching paths 2025-07-19 20:01:34 +03:00
uumas
cb0817fc54 caddy: indent email by 4 spaces 2025-07-19 20:01:09 +03:00
uumas
c0753aeaa2 vhost: Support proxy forward auth 2025-07-13 19:03:02 +03:00
uumas
83569c59ee lint 2025-07-05 15:41:01 +03:00
uumas
6c340c5111 vhost: Add support for custom matchers and specifying response status 2025-07-05 15:40:52 +03:00
26 changed files with 594 additions and 68 deletions

View File

@@ -0,0 +1,2 @@
This role enables automatic package updates.
It currently supports Debian and Ubuntu.

View File

@@ -0,0 +1 @@
Installs borgmatic

View File

@@ -2,6 +2,7 @@
- name: Gather facts - name: Gather facts
ansible.builtin.setup: ansible.builtin.setup:
delegate_facts: true delegate_facts: true
ignore_unreachable: true
retries: 3 retries: 3
- name: Add ssh key to authorized_keys - name: Add ssh key to authorized_keys

View File

@@ -0,0 +1 @@
Creates a bormatic configuration in /etc/borgmatic.d/ and creates the repos

View File

@@ -1,4 +1,10 @@
--- ---
- name: Initialize borgmatic
ansible.builtin.command:
cmd: borgmatic init --encryption repokey
register: _borgmatic_init_out
changed_when: _borgmatic_init_out.stdout | length > 0
- name: Restart borgmatic timer {{ borgmatic_config_name }} - name: Restart borgmatic timer {{ borgmatic_config_name }}
ansible.builtin.systemd_service: ansible.builtin.systemd_service:
name: "borgmatic@{{ borgmatic_config_name }}.timer" name: "borgmatic@{{ borgmatic_config_name }}.timer"

View File

@@ -18,6 +18,7 @@
dest: /etc/borgmatic.d/{{ borgmatic_config_name }}.yaml dest: /etc/borgmatic.d/{{ borgmatic_config_name }}.yaml
mode: "0600" mode: "0600"
no_log: true no_log: true
notify: Initialize borgmatic
- name: Add systemd timer for borgmatic {{ borgmatic_config_name }} - name: Add systemd timer for borgmatic {{ borgmatic_config_name }}
ansible.builtin.template: ansible.builtin.template:

View File

@@ -4,6 +4,7 @@ dependencies:
vars: vars:
compatcheck_supported_distributions: compatcheck_supported_distributions:
- name: debian - name: debian
version_min: 11 version_min: 12
- name: ubuntu - name: ubuntu
version_min: 22 version_min: 22
- role: uumas.general.firewalld

View File

@@ -41,3 +41,14 @@
validate: 'caddy validate --config %s --adapter caddyfile' validate: 'caddy validate --config %s --adapter caddyfile'
backup: true backup: true
notify: Reload caddy notify: Reload caddy
- name: Open ports for caddy
ansible.posix.firewalld:
service: "{{ item }}"
state: enabled
permanent: true
immediate: true
loop:
- http
- https
- http3

View File

@@ -22,6 +22,7 @@ argument_specs:
- ubuntu - ubuntu
- fedora - fedora
- archlinux - archlinux
- macosx
version_min: version_min:
description: Earliest supported major version. Allows any version if not specified. description: Earliest supported major version. Allows any version if not specified.
type: int type: int
@@ -31,7 +32,9 @@ argument_specs:
type: int type: int
required: false required: false
package_managers: package_managers:
description: List of supported package managers. Defaults to apt for debian and ubuntu, dnf for fedora, pacman for archlinux description: >-
List of supported package managers. Defaults to apt for debian and ubuntu,
dnf for fedora, pacman for archlinux, homebrew for macosx
type: list type: list
required: false required: false
elements: str elements: str
@@ -40,3 +43,4 @@ argument_specs:
- dnf - dnf
- pacman - pacman
- atomic_container - atomic_container
- homebrew

View File

@@ -5,4 +5,5 @@ _compatcheck_default_package_managers:
ubuntu: apt ubuntu: apt
fedora: dnf fedora: dnf
archlinux: pacman archlinux: pacman
macosx: homebrew
_compatcheck_default_package_manager: "{{ _compatcheck_default_package_managers[ansible_distribution | lower] }}" _compatcheck_default_package_manager: "{{ _compatcheck_default_package_managers[ansible_distribution | lower] }}"

View File

@@ -0,0 +1 @@
Installs firewalld

View File

@@ -0,0 +1,5 @@
---
argument_specs:
main:
description: Installs firewalld
options: {}

View File

@@ -0,0 +1,9 @@
---
dependencies:
- role: uumas.general.compatcheck
vars:
compatcheck_supported_distributions:
- name: debian
version_min: 12
- name: ubuntu
version_min: 22

View File

@@ -0,0 +1,4 @@
---
- name: Install firewalld
ansible.builtin.apt:
name: firewalld

View File

@@ -0,0 +1,2 @@
---
prometheus_node_exporter_local_network: ""

View File

@@ -1,5 +1,5 @@
--- ---
- name: Restart prometheus-node-exporter - name: Restart prometheus-node-exporter
ansible.builtin.systemd: ansible.builtin.systemd_service:
name: prometheus-node-exporter name: prometheus-node-exporter
state: restarted state: restarted

View File

@@ -3,7 +3,10 @@ argument_specs:
main: main:
description: Installs and configures prometheus node exporter to listen on local ipv4 address description: Installs and configures prometheus node exporter to listen on local ipv4 address
options: options:
local_network: prometheus_node_exporter_local_network:
description: The local ipv4 network block, listen address is taken from this block description: >-
The local ipv4 network block, listen address is taken from this block.
If empty, listens on 0.0.0.0
type: str type: str
required: true required: false
default: ""

View File

@@ -1,9 +1,3 @@
--- ---
dependencies: dependencies:
- role: uumas.general.compatcheck - role: uumas.general.firewalld
vars:
compatcheck_supported_distributions:
- name: debian
version_min: 11
- name: ubuntu
version_min: 24

View File

@@ -1,7 +1,18 @@
--- ---
- name: Compatibility check
ansible.builtin.import_role:
name: uumas.general.compatcheck
vars:
compatcheck_supported_distributions:
- name: debian
version_min: 11
- name: ubuntu
version_min: 22
- name: Install prometheus node exporter - name: Install prometheus node exporter
ansible.builtin.apt: ansible.builtin.apt:
name: prometheus-node-exporter name: prometheus-node-exporter
install_recommends: false
- name: Set prometheus options in /etc/default/prometheus-node-exporter - name: Set prometheus options in /etc/default/prometheus-node-exporter
ansible.builtin.template: ansible.builtin.template:

View File

@@ -1 +1 @@
ARGS="--web.listen-address {{ (ansible_all_ipv4_addresses | ansible.utils.ipaddr(local_network))[0] }}:9100 --collector.logind --collector.systemd --collector.processes" ARGS="--web.listen-address {{ (ansible_all_ipv4_addresses | ansible.utils.ipaddr(prometheus_node_exporter_local_network))[0] if prometheus_node_exporter_local_network | length > 0 else '0.0.0.0' }}:9100 --collector.logind --collector.systemd --collector.processes"

View File

@@ -26,7 +26,8 @@
- name: Set ssh authorized keys for users - name: Set ssh authorized keys for users
ansible.posix.authorized_key: ansible.posix.authorized_key:
user: "{{ item.name }}" user: "{{ item.name }}"
key: "{{ item.ssh_pubkey }}" key: "{{ item.ssh_pubkeys | default([item.ssh_pubkey]) | join('\n') }}"
exclusive: true
when: item.state | default('present') == 'present' when: item.state | default('present') == 'present'
loop: "{{ users }}" loop: "{{ users }}"

View File

@@ -17,9 +17,15 @@ vhost_proxy_target_host: localhost
vhost_proxy_headers: {} vhost_proxy_headers: {}
vhost_proxy_delete_headers: [] vhost_proxy_delete_headers: []
vhost_proxy_pass_host_header: true vhost_proxy_pass_host_header: true
vhost_proxy_auth_socket: ""
vhost_proxy_auth_uri: ""
vhost_proxy_auth_unauthorized_redir: ""
vhost_redirect_type: temporary vhost_redirect_type: temporary
vhost_redirect_preserve_path: false vhost_redirect_preserve_path: false
vhost_redirect_preserve_query: "{{ vhost_redirect_preserve_path }}" vhost_redirect_preserve_query: "{{ vhost_redirect_preserve_path }}"
vhost_respond_content_type: plain vhost_respond_content_type: plain
vhost_respond_status: 200
vhost_matchers: []

View File

@@ -116,9 +116,30 @@ argument_specs:
default: [] default: []
vhost_proxy_pass_host_header: vhost_proxy_pass_host_header:
description: Whether to pass the host header unchanged (true) or change it to the proxy target host (false) description: Whether to pass the host header unchanged (true) or change it to the proxy target host (false)
trpe: bool type: bool
required: false required: false
default: true default: true
vhost_proxy_auth_socket:
description: >-
Unix socket path to forward requests to for auhtentication, before
proxying them
type: str
required: false
default: ""
vhost_proxy_auth_uri:
description: >-
The authentication endpoint of the auth host. Required if
proxy_auth_socket is defined. Does nothing otherwise.
type: str
required: false
default: ""
vhost_proxy_auth_unauthorized_redir:
description: >-
Where to redirect requests if authentication service returns 401
unathorized. If not set, returns responses as is.
type: str
required: false
default: ""
vhost_redirect_target: vhost_redirect_target:
description: "Only applicable if vhost_type is redirect. Example: https://www.domain.tld/location" description: "Only applicable if vhost_type is redirect. Example: https://www.domain.tld/location"
@@ -155,6 +176,199 @@ argument_specs:
choices: choices:
- plain - plain
- json - json
vhost_respond_status:
description: Status code of response
type: int
required: false
default: 200
vhost_matchers:
description: >
List of matchers to handle differently from the default for vhost.
A matcher matches if all of its conditions match
type: list
elements: dict
required: false
default: []
options:
name:
description: Name of the matcher used to reference it
type: str
required: true
match_methods:
description: HTTP methods to match against. Matching one method is enough.
type: list
elements: str
choices:
- GET
- HEAD
- OPTIONS
- TRACE
- PUT
- DELETE
- POST
- PATCH
- CONNECT
required: false
default: []
match_headers:
description: >-
Headers to match against.
If the value begins with ^ and end with $, the value is matched as regex.
type: dict
required: false
default: {}
type:
type: str
required: false
default: "{{ vhost_type }}"
choices:
- reverse_proxy
- redirect
- respond
headers:
description: Dict of response headers and their values
type: dict
required: false
default: "{{ vhost_headers }}"
delete_headers:
description: List of response headers to delete
type: list
elements: str
required: false
default: "{{ vhost_delete_headers }}"
basicauth:
description: Whether to require basic auth for the location
type: bool
required: false
default: "{{ vhost_basicauth }}"
basicauth_users:
description: A dict of basic auth users and their password hashes. Required if basicauth is true
type: dict
default: "{{ vhost_basicauth_users }}"
proxy_target_netproto:
description:
- Network protocol to use for proxy requests.
- Only applicable if type is reverse_proxy.
type: str
required: false
default: "{{ vhost_proxy_target_netproto }}"
choices:
- tcp
- unix
proxy_target_protocol:
description:
- Transport protocol (scheme) to use for proxy requests.
- Only applicable if type is reverse_proxy.
type: str
required: false
default: "{{ vhost_proxy_target_protocol }}"
choices:
- http
- https
proxy_target_host:
description: Host where to proxy requests to. Only applicable if type is reverse_proxy
type: str
required: false
default: "{{ vhost_proxy_target_host }}"
proxy_target_port:
description: Port where to proxy requests to. Only applicable if type is reverse_proxy.
type: int
required: false
default: "{{ vhost_proxy_target_port if vhost_type == 'reverse_proxy' and vhost_proxy_target_netproto == 'tcp' else 0 }}"
proxy_target_socket:
description:
- Unix socket path to proxy requests to.
- Only applicable if type is reverse_proxy and proxy_target_netproto is unix.
type: str
required: false
default: "{{ vhost_proxy_target_socket if vhost_type == 'reverse_proxy' and vhost_proxy_target_netproto == 'unix' else '' }}"
proxy_headers:
description: Dict of request headers and their values to set for proxied requests
type: dict
required: false
default: "{{ vhost_proxy_headers }}"
proxy_delete_headers:
description: List of request headers to delete from proxied requests
type: list
elements: str
required: false
default: "{{ vhost_proxy_delete_headers }}"
proxy_pass_host_header:
description: Whether to pass the host header unchanged (true) or change it to the proxy target host (false)
type: bool
required: false
default: "{{ vhost_proxy_pass_host_header }}"
proxy_auth_socket:
description: >-
Unix socket path to forward requests to for auhtentication, before
proxying them
type: str
required: false
default: "{{ vhost_proxy_auth_socket }}"
proxy_auth_uri:
description: >-
The authentication endpoint of the auth host. Required if
proxy_auth_socket is defined. Does nothing otherwise.
type: str
required: false
default: "{{ vhost_proxy_auth_uri }}"
proxy_auth_unauthorized_redir:
description: >-
Where to redirect requests if authentication service returns 401
unathorized. If not set, returns responses as is.
type: str
required: false
default: "{{ vhost_proxy_auth_unauthorized_redir }}"
redirect_target:
description: "Only applicable if vhost_type is redirect. Example: https://www.domain.tld/location"
type: str
required: false
default: "{{ vhost_redirect_target if vhost_type == 'redirect' else '' }}"
redirect_preserve_path:
description: Whether to keep the original request path
type: bool
required: false
default: "{{ vhost_redirect_preserve_path }}"
redirect_preserve_query:
description: Whether to keep the original request query string
type: bool
required: false
default: "{{ vhost_redirect_preserve_query }}"
redirect_type:
description: Only applicable if vhost_type is redirect
type: str
required: false
default: "{{ vhost_redirect_type }}"
choices:
- temporary
- permanent
respond_content:
description: >-
Content to respond with.
Json content can be set as yaml as long as respond_content_type is set to json.
type: str
required: false
default: "{{ vhost_respond_content if vhost_type == 'respond' else '' }}"
respond_content_type:
description: Type of the respond content
type: str
required: false
default: "{{ vhost_respond_content_type }}"
choices:
- plain
- json
respond_status:
description: Status code of response
type: int
required: false
default: "{{ vhost_respond_status }}"
vhost_locations: vhost_locations:
description: List of locations to handle differently from the default for vhost description: List of locations to handle differently from the default for vhost
@@ -164,7 +378,9 @@ argument_specs:
elements: dict elements: dict
options: options:
path: path:
description: Path to match. Only supports full paths for now. description: >-
Path to match.
If the value begins with ^ and end with $, the value is matched as regex.
type: str type: str
required: true required: true
type: type:
@@ -247,9 +463,30 @@ argument_specs:
default: "{{ vhost_proxy_delete_headers }}" default: "{{ vhost_proxy_delete_headers }}"
proxy_pass_host_header: proxy_pass_host_header:
description: Whether to pass the host header unchanged (true) or change it to the proxy target host (false) description: Whether to pass the host header unchanged (true) or change it to the proxy target host (false)
trpe: bool type: bool
required: false required: false
default: "{{ vhost_proxy_pass_host_header }}" default: "{{ vhost_proxy_pass_host_header }}"
proxy_auth_socket:
description: >-
Unix socket path to forward requests to for auhtentication, before
proxying them
type: str
required: false
default: "{{ vhost_proxy_auth_socket }}"
proxy_auth_uri:
description: >-
The authentication endpoint of the auth host. Required if
proxy_auth_socket is defined. Does nothing otherwise.
type: str
required: false
default: "{{ vhost_proxy_auth_uri }}"
proxy_auth_unauthorized_redir:
description: >-
Where to redirect requests if authentication service returns 401
unathorized. If not set, returns responses as is.
type: str
required: false
default: "{{ vhost_proxy_auth_unauthorized_redir }}"
redirect_target: redirect_target:
description: "Only applicable if vhost_type is redirect. Example: https://www.domain.tld/location" description: "Only applicable if vhost_type is redirect. Example: https://www.domain.tld/location"
@@ -276,7 +513,9 @@ argument_specs:
- permanent - permanent
respond_content: respond_content:
description: Content to respond with. Json content can be set as yaml as long as respond_content_type is set to json description: >-
Content to respond with.
Json content can be set as yaml as long as respond_content_type is set to json.
type: str type: str
required: false required: false
default: "{{ vhost_respond_content if vhost_type == 'respond' else '' }}" default: "{{ vhost_respond_content if vhost_type == 'respond' else '' }}"
@@ -288,3 +527,156 @@ argument_specs:
choices: choices:
- plain - plain
- json - json
respond_status:
description: Status code of response
type: int
required: false
default: "{{ vhost_respond_status }}"
matchers:
description: >
List of matchers to handle differently from the default for vhost.
A matcher matches if all of its conditions match.
Options without a specified default will default to location's corresponding option.
type: list
elements: dict
required: false
default: "{{ vhost_matchers }}"
options:
name:
description: Name of the matcher used to reference it
type: str
required: true
match_methods:
description: HTTP methods to match against. Matching one method is enough.
type: list
elements: str
choices:
- GET
- HEAD
- OPTIONS
- TRACE
- PUT
- DELETE
- POST
- PATCH
- CONNECT
required: false
default: []
match_headers:
description: >-
Headers to match against.
If the value begins with ^ and end with $, the value is matched as regex.
type: dict
required: false
default: {}
type:
type: str
required: false
choices:
- reverse_proxy
- redirect
- respond
headers:
description: Dict of response headers and their values
type: dict
required: false
delete_headers:
description: List of response headers to delete
type: list
elements: str
required: false
basicauth:
description: Whether to require basic auth for the location
type: bool
required: false
basicauth_users:
description: A dict of basic auth users and their password hashes. Required if basicauth is true
type: dict
proxy_target_netproto:
description:
- Network protocol to use for proxy requests.
- Only applicable if type is reverse_proxy.
type: str
required: false
choices:
- tcp
- unix
proxy_target_protocol:
description:
- Transport protocol (scheme) to use for proxy requests.
- Only applicable if type is reverse_proxy.
type: str
required: false
choices:
- http
- https
proxy_target_host:
description: Host where to proxy requests to. Only applicable if type is reverse_proxy
type: str
required: false
proxy_target_port:
description: Port where to proxy requests to. Only applicable if type is reverse_proxy.
type: int
required: false
proxy_target_socket:
description:
- Unix socket path to proxy requests to.
- Only applicable if type is reverse_proxy and proxy_target_netproto is unix.
type: str
required: false
proxy_headers:
description: Dict of request headers and their values to set for proxied requests
type: dict
required: false
proxy_delete_headers:
description: List of request headers to delete from proxied requests
type: list
elements: str
required: false
proxy_pass_host_header:
description: Whether to pass the host header unchanged (true) or change it to the proxy target host (false)
type: bool
required: false
redirect_target:
description: "Only applicable if vhost_type is redirect. Example: https://www.domain.tld/location"
type: str
required: false
redirect_preserve_path:
description: Whether to keep the original request path
type: bool
required: false
redirect_preserve_query:
description: Whether to keep the original request query string
type: bool
required: false
redirect_type:
description: Only applicable if vhost_type is redirect
type: str
required: false
choices:
- temporary
- permanent
respond_content:
description: >-
Content to respond with.
Json content can be set as yaml as long as respond_content_type is set to json.
type: str
required: false
respond_content_type:
description: Type of the respond content
type: str
required: false
choices:
- plain
- json
respond_status:
description: Status code of response
type: int
required: false

View File

@@ -1,54 +1,85 @@
#jinja2: lstrip_blocks: True #jinja2: lstrip_blocks: True
{{ vhost_domains | join(' ') }} { {{ vhost_domains | join(' ') }} {
{% for location in _vhost_locations_complete %} {% for location in _vhost_locations_complete %}
handle {{ location.path }} { {% if location.path != '' %}
{% for header in location.delete_headers %} @{{ location.path }} path{{ '_regexp' if location.path.startswith('^') and location.path.endswith('$') else '' }} {{ location.path }}
handle @{{ location.path }} {
{% else %}
handle {
{% endif %}
{% for matcher in location.matchers %}
{% if matcher.name != '' %}
@{{ matcher.name }} {
{% if matcher.match_methods | length > 0 %}
method {{ matcher.match_methods | join(' ') }}
{% endif %}
{% for header in matcher.match_headers | dict2items %}
header{{ '_regexp' if header.value.startswith('^') and header.value.endswith('$') else '' }} {{ header.key }} {{ header.value }}
{% endfor %}
}
{% endif %}
handle{{ ' @' ~ matcher.name if matcher.name != '' else '' }} {
{% for header in matcher.delete_headers %}
header -{{ header }} header -{{ header }}
{% endfor %} {% endfor %}
{% for header in location.headers | dict2items %} {% for header in matcher.headers | dict2items %}
header {{ header.key }} `{{ header.value }}` header {{ header.key }} `{{ header.value }}`
{% endfor %} {% endfor %}
{% if location.basicauth %} {% if matcher.basicauth %}
basicauth { basicauth {
{% for user in location.basicauth_users | dict2items %} {% for user in matcher.basicauth_users | dict2items %}
{{ user.key }} {{ user.value }} {{ user.key }} {{ user.value }}
{% endfor %} {% endfor %}
} }
{% endif %} {% endif %}
{% if location.type == 'reverse_proxy' %} {% if matcher.type == 'reverse_proxy' %}
reverse_proxy { {% if matcher.proxy_auth_socket | length > 0 %}
{% if location.proxy_target_netproto == 'tcp' %} forward_auth {
to tcp/{{ location.proxy_target_host }}:{{ location.proxy_target_port }} to unix//{{ matcher.proxy_auth_socket }}
{% else %} uri {{ matcher.proxy_auth_uri }}
to unix/{{ location.proxy_target_socket }} {% if matcher.proxy_auth_unauthorized_redir | length > 0 %}
@unauthorized status 401
handle_response @unauthorized {
redir * {{ matcher.proxy_auth_unauthorized_redir }}
}
{% endif %} {% endif %}
{% if location.proxy_target_protocol == 'https' %} }
{% endif %}
reverse_proxy {
{% if matcher.proxy_target_netproto == 'tcp' %}
to tcp/{{ matcher.proxy_target_host }}:{{ matcher.proxy_target_port }}
{% else %}
to unix/{{ matcher.proxy_target_socket }}
{% endif %}
{% if matcher.proxy_target_protocol == 'https' %}
transport http { transport http {
tls tls
{% if location.proxy_target_host == 'localhost' %} {% if matcher.proxy_target_host == 'localhost' %}
tls_insecure_skip_verify tls_insecure_skip_verify
{% endif %} {% endif %}
} }
{% endif %} {% endif %}
{% for header in location.proxy_delete_headers %} {% for header in matcher.proxy_delete_headers %}
header_up -{{ header }} header_up -{{ header }}
{% endfor %} {% endfor %}
{% for header in location.proxy_headers | dict2items %} {% for header in matcher.proxy_headers | dict2items %}
header_up {{ header.key }} `{{ header.value }}` header_up {{ header.key }} `{{ header.value }}`
{% endfor %} {% endfor %}
{% if (not location.proxy_pass_host_header) and ('host' not in location.proxy_headers | map('lower')) %} {% if (not matcher.proxy_pass_host_header) and ('host' not in matcher.proxy_headers | map('lower')) %}
header_up Host {upstream_hostport} header_up Host {upstream_hostport}
{% endif %} {% endif %}
} }
{% elif location.type == 'redirect' %} {% elif matcher.type == 'redirect' %}
redir * {{ location.redirect_target }}{{ '{path}' if location.redirect_preserve_path }}{{ '?{query}' if location.redirect_preserve_query }} {{ location.redirect_type }} redir * {{ matcher.redirect_target }}{{ '{path}' if matcher.redirect_preserve_path }}{{ '?{query}' if matcher.redirect_preserve_query }} {{ matcher.redirect_type }}
{% elif location.type == 'respond' %} {% elif matcher.type == 'respond' %}
{% if location.respond_content_type == 'json' %} {% if matcher.respond_content_type == 'json' %}
respond `{{ location.respond_content | to_json }}` respond `{{ matcher.respond_content | to_json }}`
{% else %} {% else %}
respond `{{ location.respond_content }}` respond `{{ matcher.respond_content }}` {{ matcher.respond_status }}
{% endif %} {% endif %}
{% endif %} {% endif %}
} }
{% endfor %} {% endfor %}
} }
{% endfor %}
}

View File

@@ -1,4 +1,15 @@
--- ---
_vhost_matcher_defaults:
match_headers: {}
match_method: []
_vhost_matchers: >-
{{
vhost_matchers
| map('combine', _vhost_matcher_defaults)
| zip(vhost_matchers)
| map('combine')
}}
_vhost_location_defaults: _vhost_location_defaults:
type: "{{ vhost_type }}" type: "{{ vhost_type }}"
headers: "{{ vhost_headers }}" headers: "{{ vhost_headers }}"
@@ -17,6 +28,9 @@ _vhost_location_defaults:
proxy_headers: "{{ vhost_proxy_headers }}" proxy_headers: "{{ vhost_proxy_headers }}"
proxy_delete_headers: "{{ vhost_proxy_delete_headers }}" proxy_delete_headers: "{{ vhost_proxy_delete_headers }}"
proxy_pass_host_header: "{{ vhost_proxy_pass_host_header }}" proxy_pass_host_header: "{{ vhost_proxy_pass_host_header }}"
proxy_auth_socket: "{{ vhost_proxy_auth_socket }}"
proxy_auth_uri: "{{ vhost_proxy_auth_uri }}"
proxy_auth_unauthorized_redir: "{{ vhost_proxy_auth_unauthorized_redir }}"
redirect_target: "{{ vhost_redirect_target if vhost_type == 'redirect' else '' }}" redirect_target: "{{ vhost_redirect_target if vhost_type == 'redirect' else '' }}"
redirect_preserve_path: "{{ vhost_redirect_preserve_path }}" redirect_preserve_path: "{{ vhost_redirect_preserve_path }}"
@@ -25,12 +39,36 @@ _vhost_location_defaults:
respond_content: "{{ vhost_respond_content if vhost_type == 'respond' else '' }}" respond_content: "{{ vhost_respond_content if vhost_type == 'respond' else '' }}"
respond_content_type: "{{ vhost_respond_content_type }}" respond_content_type: "{{ vhost_respond_content_type }}"
respond_status: "{{ vhost_respond_status }}"
matchers: "{{ _vhost_matchers }}"
_vhost_locations: "{{ vhost_locations + [{'path': ''}] }}" _vhost_locations: "{{ vhost_locations + [{'path': ''}] }}"
_vhost_locations_complete: "{{ _vhost_locations_withdefaults: >-
{{
_vhost_locations _vhost_locations
| map('combine', _vhost_location_defaults) | map('combine', _vhost_location_defaults)
| zip(_vhost_locations) | zip(
_vhost_locations
)
| map('combine') | map('combine')
}}" | map('combine', {'matchers': [{'name': ''}]}, list_merge='append')
}}
_vhost_locations_complete: >-
{{
_vhost_locations_withdefaults |
sort(attribute='path') |
zip(
_vhost_locations_withdefaults |
subelements('matchers') |
map('combine') |
groupby('path') |
map('last') |
map('community.general.remove_keys', ['matchers', 'path']) |
map('community.general.dict_kv', 'matchers')
) |
map('combine') |
reverse
}}