Private
Public Access
2
0
Files
bgwaf/seb4itik/byow/roles/caddy/templates/Caddyfile

352 lines
15 KiB
Caddyfile
Raw Normal View History

2026-01-20 12:27:03 +03:00
{
http_port {{ caddy_http_port }}
https_port {{ caddy_https_port }}
admin off
persist_config off
2026-02-12 06:48:37 +01:00
{% if caddy_default_bind != None %}
default_bind {{ caddy_default_bind }}
2026-02-02 22:09:18 +03:00
{% endif %}
{% if caddy_crowdsec %}
order crowdsec first
{% endif %}
{% if caddy_geoip %}
2026-01-23 14:08:31 +03:00
order geoip2_vars first
{% endif %}
{% if caddy_coraza %}
2026-01-20 12:27:03 +03:00
order coraza_waf first
{% endif %}
2026-02-06 17:35:03 +03:00
{% if caddy_consul %}
2026-04-08 08:12:29 +03:00
# See: https://github.com/pteich/caddy-tlsconsul
2026-02-06 17:35:03 +03:00
storage consul {
address "{{ caddy_consul_server }}"
token "{{ caddy_out_consul_token.token.SecretID | mandatory }}"
2026-02-06 17:35:03 +03:00
timeout 10
prefix "caddy-{{ caddy_my_name }}-tls"
value_prefix "{{ caddy_my_name }}"
aes_key "{{ caddy_consul_aes_key | mandatory }}"
2026-02-12 14:37:42 +01:00
tls_enabled "true"
2026-02-06 17:35:03 +03:00
tls_insecure "false"
}
{% endif %}
{% if caddy_geoip %}
2026-04-08 08:12:29 +03:00
# See: https://github.com/zhangjiayin/caddy-geoip2
2026-01-23 14:08:31 +03:00
geoip2 {
accountId "{{ caddy_geoip_account_id | mandatory }}"
licenseKey "{{ caddy_geoip_license_key | mandatory }}"
databaseDirectory "{{ caddy_home_dir }}/geoip2"
lockFile "{{ caddy_home_dir }}/geoip2/.geoip2.lock"
2026-01-23 14:08:31 +03:00
editionID "{{ caddy_geoip_edition_ids }}"
updateUrl "https://updates.maxmind.com"
updateFrequency {{ caddy_geoip_update_frequency }}
}
{% endif %}
2026-01-20 12:27:03 +03:00
{% if caddy_email | default(None) != None %}
email "{{ caddy_email }}"
{% endif %}
{% if caddy_crowdsec %}
2026-04-08 08:12:29 +03:00
# See: https://github.com/hslatman/caddy-crowdsec-bouncer
crowdsec {
api_key {{ caddy_crowdsec_api_key | mandatory }}
api_url {{ caddy_crowdsec_api_url }}
ticker_interval {{ caddy_crowdsec_ticker_interval }}s
{% if caddy_crowdsec_appsec_url != None %}
appsec_url {{ caddy_crowdsec_appsec_url }}
{% endif %}
{% if not caddy_crowdsec_streaming %}
disable_streaming
{% endif %}
{% if caddy_crowdsec_hard_fails %}
enable_hard_fails
2026-01-22 07:55:19 +03:00
{% endif %}
}
2026-01-20 12:27:03 +03:00
{% endif %}
{% if caddy_coraza %}
2026-01-20 12:27:03 +03:00
log waf {
include "http.handlers.waf"
format {{ caddy_log_format }}
2026-02-06 19:58:35 +03:00
format append {
waf_id {{ caddy_my_name }}
}
{% if caddy_log_to_file %}
2026-01-20 17:40:16 +03:00
output file {{ caddy_log_dir }}/waf.log
2026-02-03 15:36:35 +03:00
{% else %}
output stdout
{% endif %}
2026-01-20 12:27:03 +03:00
}
{% endif %}
{% if caddy_log_debug %}
log {
level DEBUG
format {{ caddy_log_format }}
format append {
waf_id {{ caddy_my_name }}
}
output file {{ caddy_log_dir }}/debug.log
}
{% endif %}
2026-01-20 12:27:03 +03:00
}
2026-02-02 22:09:18 +03:00
# 0=origin, 1=methods, 2=headers, 3=allow credentials, 4=max age, 5=vary, 6=expose headers
(cors) {
@match-cors-preflight-{args[0]} {
header Origin {args[0]}
2026-02-02 22:09:18 +03:00
method OPTIONS
}
header @match-cors-preflight-{args[0]} {
Access-Control-Allow-Origin "{args[0]}"
Access-Control-Allow-Methods "{args[1]}"
Access-Control-Allow-Headers "{args[2]}"
Access-Control-Allow-Credentials "{args[3]}"
Access-Control-Max-Age "{args[4]}"
Vary "{args[5]}"
2026-02-02 22:09:18 +03:00
}
handle @match-cors-preflight-{args[0]} {
2026-02-02 22:09:18 +03:00
respond "" 204
}
@match-cors-request-{args[0]} {
header Origin {args[0]}
2026-02-02 22:09:18 +03:00
not method OPTIONS
}
header @match-cors-request-{args[0]} {
>Access-Control-Allow-Origin "{args[0]}"
>Access-Control-Allow-Credentials "{args[3]}"
>Vary "{args[5]}"
>Access-Control-Expose-Headers "{args[6]}"
2026-02-02 22:09:18 +03:00
}
}
(cors-deny) {
@cors-preflight-deny method OPTIONS
handle @cors-preflight-deny {
respond "" 403
}
}
2026-01-20 12:27:03 +03:00
{% for site in caddy_sites %}
{% if (site.site_aliases_redirect | default(caddy_sites_defaults.site_aliases_redirect)) and (site.site_aliases | default([]) | length) > 0 %}
{{ site.site_aliases | join(', ') }} {
redir https://{{ site.name }}{uri}
2026-01-20 12:27:03 +03:00
}
{% else %}
{% for alias in site.site_aliases | default(caddy_sites_defaults.site_aliases) %}
2026-01-20 12:27:03 +03:00
{{ alias }},
{% endfor %}
{% endif %}
{{ site.name }} {
2026-01-20 12:27:03 +03:00
encode gzip zstd
{% if caddy_crowdsec and site.crowdsec | default(caddy_sites_defaults.crowdsec) %}
crowdsec
{% endif %}
2026-01-20 12:27:03 +03:00
{% for path in site.paths %}
handle{% if path.strip_prefix | default(false) %}_path{% endif %} {{ path.path | default('*') }} {
2026-01-20 12:27:03 +03:00
reverse_proxy {
to {{ path.addrs | join(' ') }}
header_up X-Real-IP {remote}
lb_policy {{ site.proxy_lb_policy | default(caddy_sites_defaults.proxy_lb_policy) }}
{% if site.proxy_active_checks | default(caddy_sites_defaults.proxy_active_checks) %}
health_uri {{ site.proxy_active_checks_uri | default(caddy_sites_defaults.proxy_active_checks_uri) }}
health_port {{ site.proxy_active_checks_port | default(caddy_sites_defaults.proxy_active_checks_port) }}
health_interval {{ site.proxy_active_checks_interval | default(caddy_sites_defaults.proxy_active_checks_interval) }}
health_timeout {{ site.proxy_active_checks_timeout | default(caddy_sites_defaults.proxy_active_checks_timeout) }}
health_method {{ site.proxy_active_checks_method | default(caddy_sites_defaults.proxy_active_checks_method) }}
health_status {{ site.proxy_active_checks_status | default(caddy_sites_defaults.proxy_active_checks_status) }}
{% if site.proxy_active_checks_body | default(caddy_sites_defaults.proxy_active_checks_body) != None %}
health_body {{ site.proxy_active_checks_body | default(caddy_sites_defaults.proxy_active_checks_body) }}
{% endif %}
{% endif %}
{% if site.proxy_passive_checks | default(caddy_sites_defaults.proxy_passive_checks) %}
fail_duration {{ site.proxy_passive_checks_fail_duration | default(caddy_sites_defaults.proxy_passive_checks_fail_duration) }}
max_fails {{ site.proxy_passive_checks_max_fails | default(caddy_sites_defaults.proxy_passive_checks_max_fails) }}
unhealthy_status {{ site.proxy_passive_checks_unhealthy_status | default(caddy_sites_defaults.proxy_passive_checks_unhealthy_status) }}
unhealthy_latency {{ site.proxy_passive_checks_unhealthy_latency | default(caddy_sites_defaults.proxy_passive_checks_unhealthy_latency) }}
{% if site.proxy_passive_checks_unhealthy_request_count | default(caddy_sites_defaults.proxy_passive_checks_unhealthy_request_count) != None %}
unhealthy_request_count {{ site.proxy_passive_checks_unhealthy_request_count | default(caddy_sites_defaults.proxy_passive_checks_unhealthy_request_count) }}
{% endif %}
{% endif %}
2026-01-20 12:27:03 +03:00
}
}
{% endfor %}
{% if site.custom_cert | default (false) %}
tls {{ site.custom_cert_file }} {{ site.custom_cert_key_file }}
2026-01-20 12:27:03 +03:00
{% endif %}
{% if site.filter_blacklist | default(caddy_sites_defaults.filter_blacklist) | length > 0 %}
2026-01-20 12:27:03 +03:00
@blocked {
{% for ip in site.filter_blacklist | default(caddy_sites_defaults.filter_blacklist) %}
2026-01-20 12:27:03 +03:00
remote_ip {{ ip }}
{% endfor %}
}
respond @blocked "Access Denied" 403
2026-01-23 14:08:31 +03:00
{% endif %}
{% if caddy_geoip and site.geoip | default(caddy_sites_defaults.geoip) %}
2026-01-23 14:08:31 +03:00
geoip2_vars strict
@geofilter expression {{ site.geoip_filter_expression | default(caddy_sites_defaults.geoip_filter_expression) }}
respond @geofilter "Access Denied" 403
{% if site.geoip_debug | default(caddy_sites_defaults.geoip_debug) %}
2026-02-02 22:09:18 +03:00
header x-geoip-is-anonymous "{geoip2.is_anonymous}"
header x-geoip-is-anonymous-vpn "{geoip2.is_anonymous_vpn}"
header x-geoip-is-hosting-provider "{geoip2.is_hosting_provider}"
header x-geoip-is-public-proxy "{geoip2.is_public_proxy}"
header x-geoip-is-residential-proxy "{geoip2.is_residential_proxy}"
header x-geoip-is-tor-exit-node "{geoip2.is_tor_exit_node}"
header x-geoip-connection-type "{geoip2.connection_type}"
header x-geoip-domain "{geoip2.domain}"
header x-geoip-country-code "{geoip2.country_code}"
# header x-geoip-country-confidence "{geoip2.country_confidence}"
header x-geoip-country-eu "{geoip2.country_eu}"
header x-geoip-country-geoname-id "{geoip2.country_geoname_id}"
header x-geoip-country-name "{geoip2.country_name}"
header x-geoip-continent-code "{geoip2.continent_code}"
header x-geoip-continent-geoname-id "{geoip2.continent_geoname_id}"
header x-geoip-continent-name "{geoip2.continent_name}"
# header x-geoip-city-confidence "{geoip2.city_confidence}"
header x-geoip-city-geoname-id "{geoip2.city_geoname_id}"
header x-geoip-city-name "{geoip2.city_name}"
header x-geoip-location-time-zone "{geoip2.location_time_zone}"
header x-geoip-autonomous-system-number "{geoip2.autonomous_system_number}"
header x-geoip-autonomous-system-organization "{geoip2.autonomous_system_organization}"
header x-geoip-isp "{geoip2.isp}"
header x-geoip-mobile-country-code "{geoip2.mobile_country_code}"
header x-geoip-mobile-network-code "{geoip2.mobile_network_code}"
header x-geoip-organization "{geoip2.organization}"
header x-geoip-ip-address "{geoip2.ip_address}"
2026-01-23 14:08:31 +03:00
{% endif %}
2026-01-20 12:27:03 +03:00
{% endif %}
@not_whitelisted not {
{% for ip in site.filter_whitelist | default(caddy_sites_defaults.filter_whitelist) %}
remote_ip {{ ip }}
{% endfor %}
2026-01-20 12:27:03 +03:00
}
{% if caddy_ratelimit and site.rate_limit | default(caddy_sites_defaults.rate_limit) %}
2026-04-08 08:12:29 +03:00
# See: https://github.com/mholt/caddy-ratelimit
rate_limit @not_whitelisted {
2026-02-06 17:35:03 +03:00
{% if caddy_consul %}
distributed
storage consul {
address "{{ caddy_consul_server }}"
token "{{ caddy_out_consul_token.token.SecretID }}"
timeout 10
prefix "caddy-{{ caddy_my_name }}-rl"
value_prefix "{{ caddy_my_name }}"
aes_key "{{ caddy_consul_aes_key }}"
2026-02-12 14:37:42 +01:00
tls_enabled "true"
2026-02-06 17:35:03 +03:00
tls_insecure "false"
}
2026-02-06 17:35:03 +03:00
{% endif %}
log_key
2026-01-20 12:27:03 +03:00
zone remote_ip {
key {remote.ip}
events {{ site.rate_limit_events | default(caddy_sites_defaults.rate_limit_events) }}
window {{ site.rate_limit_window | default(caddy_sites_defaults.rate_limit_window) }}
2026-01-20 12:27:03 +03:00
}
}
{% endif %}
2026-01-20 12:27:03 +03:00
{% if caddy_coraza and site.crs | default(caddy_sites_defaults.crs) %}
coraza_waf @not_whitelisted {
2026-01-20 12:27:03 +03:00
load_owasp_crs
directives `
2026-02-05 09:53:38 +03:00
Include "{{ caddy_sites_dir }}/{{ site.id }}/coraza.conf"
Include "{{ caddy_sites_dir }}/{{ site.id }}/crs-setup.conf"
{% for plugin in site.crs_plugins | default(caddy_sites_defaults.crs_plugins) %}
2026-02-05 09:53:38 +03:00
Include "{{ caddy_crs_plugins_dir }}/{{ plugin }}-config.conf"
Include "{{ caddy_crs_plugins_dir }}/{{ plugin }}-before.conf"
2026-01-20 12:27:03 +03:00
{% endfor %}
2026-02-05 09:53:38 +03:00
Include "{{ caddy_sites_dir }}/{{ site.id }}/exclusions-request-before.conf"
Include "{{ caddy_config_dir }}/coreruleset-{{ site.crs_version | default(caddy_sites_defaults.crs_version) }}/rules/*.conf"
2026-02-05 09:53:38 +03:00
Include "{{ caddy_sites_dir }}/{{ site.id }}/exclusions-response-after.conf"
{% for plugin in site.crs_plugins | default(caddy_sites_defaults.crs_plugins) %}
2026-02-05 09:53:38 +03:00
Include "{{ caddy_crs_plugins_dir }}/{{ plugin }}-after.conf"
2026-01-20 12:27:03 +03:00
{% endfor %}
SecRuleEngine On
`
}
2026-01-20 17:40:16 +03:00
{% endif %}
2026-01-20 12:27:03 +03:00
2026-02-02 22:09:18 +03:00
{% if site.cors | default(caddy_sites_defaults.cors) %}
{% for origin in site.cors_allowed_origins | mandatory %}
import cors https://{{ origin }} "{{
site.cors_allowed_methods | default(caddy_sites_defaults.cors_allowed_methods) | listadddel(site.cors_allowed_methods_add | default([]), site.cors_allowed_methods_del | default([])) | join(', ') }}" "{{
site.cors_allowed_headers | default(caddy_sites_defaults.cors_allowed_headers) | listadddel(site.cors_allowed_headers_add | default([]), site.cors_allowed_headers_del | default([])) | join(', ') }}" "{{
site.cors_allowed_credentials | default(caddy_sites_defaults.cors_allowed_credentials) | ternary('true', 'false') }}" "{{
site.cors_max_age | default(caddy_sites_defaults.cors_max_age) }}" "{{
site.cors_vary | default(caddy_sites_defaults.cors_vary) | listadddel(site.cors_vary_add | default([]), site.cors_vary_del | default([])) | join(', ') }}" "{{
site.cors_exposed_headers | default(caddy_sites_defaults.cors_exposed_headers) | listadddel(site.cors_exposed_headers_add | default([]), site.cors_exposed_headers_del | default([])) | join(', ') }}"
2026-02-02 22:09:18 +03:00
{% endfor %}
import cors-deny
{% endif %}
{% if caddy_bot_barrier and site.bot_barrier | default(caddy_sites_defaults.bot_barrier) %}
2026-04-08 08:12:29 +03:00
# See: https://github.com/steffenbusch/caddy-bot-barrier
2026-02-02 22:09:18 +03:00
bot_barrier @not_whitelisted {
secret {{ site.bot_barrier_secret | default(caddy_sites_defaults.bot_barrier_secret) | mandatory }}
complexity {{ site.bot_barrier_complexity | default(caddy_sites_defaults.bot_barrier_complexity) }}
valid_for {{ site.bot_barrier_valid_for | default(caddy_sites_defaults.bot_barrier_valid_for) }}
seed_cookie_name __chall_{{ site.id }}_seed
solution_cookie_name __chall_{{ site.id }}_solution
mac_cookie_name __chall_{{ site.id }}_mac
template {{ caddy_config_dir }}/bot_barrier_template.html
}
{% endif %}
{% if site.header | default(caddy_sites_defaults.header) %}
2026-01-20 12:27:03 +03:00
header {
Content-Security-Policy "{{ caddy_sites_defaults.header_content_security_policy | combine(site.header_content_security_policy | default({})) | dict2str(sep1=' ', sep2='; ', sep3=';') }}"
Cross-Origin-Embedder-Policy "{{ site.header_cross_origin_embedder_policy | default(caddy_sites_defaults.header_cross_origin_embedder_policy) }}"
Cross-Origin-Opener-Policy "{{ site.header_cross_origin_opener_policy | default(caddy_sites_defaults.header_cross_origin_opener_policy) }}"
Cross-Origin-Resource-Policy "{{ site.header_cross_origin_resource_policy | default(caddy_sites_defaults.header_cross_origin_resource_policy) }}"
Feature-Policy "{{ caddy_sites_defaults.header_feature_policy | combine(site.header_feature_policy | default({})) | dict2str(sep1=' ', sep2='; ', sep3=';') }}"
Permissions-Policy "{{ caddy_sites_defaults.header_permissions_policy | combine(site.header_permissions_policy | default({})) | dict2str(sep2=', ') }}"
Referrer-Policy "{{ site.header_referrer_policy | default(caddy_sites_defaults.header_referrer_policy) }}"
Strict-Transport-Security "{{ site.header_strict_transport_security | default(caddy_sites_defaults.header_strict_transport_security) }}"
X-Content-Type-Options "{{ site.header_x_content_type_options | default(caddy_sites_defaults.header_x_content_type_options) }}"
X-Frame-Options "{{ site.header_x_frame_options | default(caddy_sites_defaults.header_x_frame_options) }}"
X-Robots-Tag "{{ site.header_x_robots_tag | default(caddy_sites_defaults.header_x_robots_tag) }}"
?Content-Type "{{ site.header_default_content_type | default(caddy_sites_defaults.header_default_content_type) }}"
>Set-Cookie "(.*)" "$1; {{ site.header_cookies_attributes | default(caddy_sites_defaults.header_cookies_attributes) }}"
{% for header in site.header_delete | default(caddy_sites_defaults.header_delete) %}
2026-01-20 12:27:03 +03:00
-{{ header }}
{% endfor %}
{% for header in site.header_add | default(caddy_sites_defaults.header_add) %}
2026-01-20 12:27:03 +03:00
{{ header.name }} "{{ header.value }}"
{% endfor %}
}
{% endif %}
2026-01-20 12:27:03 +03:00
handle_errors 403 {
header X-Blocked "true"
respond "Your request was blocked. 🔴"
2026-01-20 12:27:03 +03:00
}
log {
2026-02-03 15:36:35 +03:00
level INFO
format {{ caddy_log_format }}
2026-02-06 19:58:35 +03:00
format append {
waf_id {{ caddy_my_name }}
}
{% if caddy_log_to_file %}
output file {{ caddy_log_dir }}/site_{{ site.id }}.log
2026-02-03 15:36:35 +03:00
{% else %}
output stdout
{% endif %}
2026-01-20 12:27:03 +03:00
}
}
{% endfor %}