Wireguard standalone touches /etc/wireguard + sysctl exclusively (genuine root) -> runSystem for all its mkdir/chmod/sed/rm/grep/tee/qrencode. Traefik dynamic configs live under containers/traefik (docker-install-owned) -> runFileOp/runFileWrite (whitelist.yml, protectionauth.yml, the router-rewrite awk|tee|mv in port_subdomains). sudo -u drops left. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
97 lines
3.6 KiB
Bash
97 lines
3.6 KiB
Bash
#!/bin/bash
|
|
|
|
# Per-port Traefik subdomain/host writer.
|
|
#
|
|
# Companion to traefik_port_middlewares.sh. Where that stamps a per-port
|
|
# MIDDLEWARE_TAG_<i>, this stamps a per-port DOMAINSUBNAME_TAG_<i> holding the
|
|
# fully-qualified host for that port's Traefik router, derived from the port's
|
|
# `subdomain` column (the 11th field of the 12-col PORT format).
|
|
#
|
|
# A single container can expose any number of hosts — one per Traefik-managed port.
|
|
#
|
|
# subdomain "" | "@" | "root" -> <domain> (apex / root of domain)
|
|
# subdomain "vault" -> vault.<domain> (single label)
|
|
# subdomain "admin.headscale" -> admin.headscale.<domain> (multi-level allowed)
|
|
#
|
|
# Index scheme matches traefik_port_middlewares.sh exactly: i walks every
|
|
# parsed port (0-based), idx = i+1 is the 1-based position used in the tag
|
|
# suffix, and only Traefik-managed ports (traefik=true) are stamped — so a
|
|
# port's MIDDLEWARE_TAG_<idx> and DOMAINSUBNAME_TAG_<idx> always line up on the
|
|
# same router.
|
|
tagsProcessorPortSubdomains()
|
|
{
|
|
local file="$1"
|
|
local app_name="$2"
|
|
|
|
if [[ -z "$file" || -z "$app_name" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
local count=${#port_service_names[@]}
|
|
local i=0
|
|
while [[ $i -lt $count ]]; do
|
|
local idx=$((i + 1))
|
|
local p_traefik="${port_traefik_managed[$i]}"
|
|
local p_sub="${port_subdomains[$i]}"
|
|
|
|
if [[ "$p_traefik" == "true" ]]; then
|
|
local host
|
|
if [[ "$p_sub" == "@" || "$p_sub" == "root" ]]; then
|
|
host="${domain_full}" # apex / root of the domain (explicit only)
|
|
elif [[ -n "$p_sub" ]]; then
|
|
host="${p_sub}.${domain_full}" # subdomain (single or multi-level)
|
|
else
|
|
host="${app_name}.${domain_full}" # no subdomain set -> app-name default
|
|
fi
|
|
tagsManagerUpdateUniversalTag "$file" "DOMAINSUBNAME_TAG_${idx}" "$host"
|
|
fi
|
|
i=$((i + 1))
|
|
done
|
|
}
|
|
|
|
# Comments out the Traefik router block for any port that is NOT Traefik-managed
|
|
# (non-public, metrics-only, or a slot with no router at all), so an unfilled
|
|
# DOMAINSUBNAME_DATA_<n> placeholder can never reach a live compose. Each router
|
|
# is wrapped in # TRAEFIK_PORT_<n>_BEGIN ... # TRAEFIK_PORT_<n>_END markers;
|
|
# this mirrors the GLUETUN_OFF region-commenting in tags_processor_network_mode.sh.
|
|
tagsProcessorPortRouterBlocks()
|
|
{
|
|
local file="$1"
|
|
local app_name="$2"
|
|
if [[ -z "$file" || ! -f "$file" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
# Space-padded list of 1-based indices of Traefik-managed ports, e.g. " 1 3 ".
|
|
local active=" "
|
|
local count=${#port_service_names[@]}
|
|
local i=0
|
|
while [[ $i -lt $count ]]; do
|
|
[[ "${port_traefik_managed[$i]}" == "true" ]] && active+="$((i + 1)) "
|
|
i=$((i + 1))
|
|
done
|
|
|
|
local tmp="${file}.routers.$$"
|
|
runFileOp awk -v active="$active" '
|
|
BEGIN { off = 0 }
|
|
/#[[:space:]]*TRAEFIK_PORT_[0-9]+_BEGIN/ {
|
|
match($0, /TRAEFIK_PORT_[0-9]+/); key = substr($0, RSTART, RLENGTH)
|
|
sub(/TRAEFIK_PORT_/, "", key)
|
|
off = (index(active, " " key " ") > 0) ? 0 : 1 # off=1 -> comment the block
|
|
print; next
|
|
}
|
|
/#[[:space:]]*TRAEFIK_PORT_[0-9]+_END/ { off = 0; print; next }
|
|
{
|
|
if (off == 1 && $0 !~ /^[[:space:]]*#/) {
|
|
match($0, /^[[:space:]]*/)
|
|
indent = substr($0, RSTART, RLENGTH)
|
|
rest = substr($0, RLENGTH + 1)
|
|
print indent "# " rest
|
|
next
|
|
}
|
|
print
|
|
}
|
|
' "$file" | runFileWrite "$tmp" >/dev/null
|
|
runFileOp mv "$tmp" "$file"
|
|
}
|