Proxy-Host bearbeiten, ohne den Rest zu verlieren
Aendern ging bisher nur ueber "proxy add --update", und das schreibt den
Eintrag vollstaendig neu: wer den Port aendern wollte, verlor still die
zusaetzlichen Pfade und die erweiterte Konfiguration, weil die Nutzlast
aus Vorgaben zusammengesetzt wird.
Die Schnittstelle des Proxy Managers arbeitet als Patch - ein PUT mit
nur einem Feld aendert auch nur dieses; an einem laufenden NPM 2.15.1
nachgemessen. Darauf setzt "proxy edit" auf: angegeben wird, was sich
aendern soll, alles Uebrige bleibt unberuehrt.
proxy edit --id 3 --forward-port 5001
proxy edit --domain checkmk.example.local --cert self
proxy edit --id 3 --location /grafana=127.0.0.1:3000
proxy edit --id 3 --del-location /grafana
Dazu Ziel, Schema, Name, Zertifikat, erweiterte Konfiguration, die vier
Schalter und ein/aus. Ohne Angabe wird nur der Stand gezeigt. In der
Oberflaeche liegt dasselbe unter "Proxy-Host bearbeiten", mit den
aktuellen Werten vorbelegt.
Pfade kennt die Schnittstelle nur als Ganzes, sie werden deshalb gelesen,
geaendert und zurueckgeschrieben. Das an "}" aufzuteilen geht nicht:
"advanced_config" darf nginx-Bloecke mit geschweiften Klammern und
maskierte Anfuehrungszeichen enthalten. Dafuer gibt es jetzt json_raw
und json_split_array, die die Verschachtelung mitzaehlen und
Zeichenketten erkennen. "proxy show" liest die Pfade ebenfalls darueber.
Zwei Fehler kamen dabei ans Licht:
- NPM_CODE wurde in npm_api gesetzt, aber npm_api wird fast immer in
einer Kommandoersetzung aufgerufen - also in einer Subshell. Der
HTTP-Code kam nie beim Aufrufer an; unter "set -u" brach das Skript
im Fehlerpfad sogar ab, statt den Fehler zu zeigen. Betraf auch
"proxy add" und das Anlegen von Zertifikaten. Der Code wird jetzt
zusaetzlich abgelegt und mit npm_code gelesen.
- Der Proxy Manager schaltet ohne Zertifikat http2_support und
ssl_forced von sich aus ab. Das blieb unbemerkt; jetzt wird nach dem
Schreiben verglichen und eine Abweichung gemeldet.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+510
-15
@@ -21,6 +21,7 @@ SELF="$SCRIPT_DIR/cmk-manage.sh"
|
||||
BUNDLE_DIRNAME="cmkbundle"
|
||||
ASSUME_YES=""
|
||||
VERBOSE=""
|
||||
NPM_TOKEN=""
|
||||
ENVFILE_OPT=""
|
||||
|
||||
# =====================================================================
|
||||
@@ -3470,7 +3471,10 @@ EOF
|
||||
printf '%s' "$tok"
|
||||
}
|
||||
|
||||
# npm_api METHODE PFAD [JSON] -> Antwort auf stdout, HTTP-Code in NPM_CODE
|
||||
# npm_api METHODE PFAD [JSON] -> Antwort auf stdout, HTTP-Code via npm_code
|
||||
NPM_CODE_FILE="${TMPDIR:-/tmp}/.cmk-manage-npmcode.$$"
|
||||
trap 'rm -f "$NPM_CODE_FILE"' EXIT
|
||||
|
||||
npm_api() {
|
||||
local method="$1" path="$2" data="${3:-}"
|
||||
local base; base="$(npm_api_base)"
|
||||
@@ -3479,9 +3483,20 @@ npm_api() {
|
||||
[ -n "$data" ] && a+=(-H 'Content-Type: application/json' -d "$data")
|
||||
local out; out="$(curl "${a[@]}" "$base$path" 2>/dev/null)" || out=$'\n000'
|
||||
NPM_CODE="${out##*$'\n'}"
|
||||
# Wird npm_api in einer Kommandoersetzung aufgerufen - und das ist der
|
||||
# Regelfall, weil die Antwort gebraucht wird -, laeuft sie in einer
|
||||
# Subshell. Die Zuweisung oben ist dann beim Rueckkehren wieder weg.
|
||||
# Deshalb zusaetzlich ablegen; gelesen wird mit npm_code.
|
||||
printf '%s' "$NPM_CODE" > "$NPM_CODE_FILE" 2>/dev/null || true
|
||||
printf '%s' "${out%$'\n'*}"
|
||||
}
|
||||
|
||||
# HTTP-Code des letzten API-Aufrufs - auch nach einer Kommandoersetzung
|
||||
npm_code() {
|
||||
local c; c="$(cat "$NPM_CODE_FILE" 2>/dev/null || true)"
|
||||
printf '%s' "${c:-${NPM_CODE:-000}}"
|
||||
}
|
||||
|
||||
npm_require_running() {
|
||||
npm_enabled || { err "Der NGINX Proxy Manager ist abgeschaltet (NPM_ENABLED=off)."
|
||||
log "Einschalten: $SELF npm-enable on"; return 1; }
|
||||
@@ -3516,7 +3531,7 @@ npm_cert_selfsigned() { # domain
|
||||
body="$(npm_api POST /api/nginx/certificates \
|
||||
"{\"provider\":\"other\",\"nice_name\":\"$domain\",\"domain_names\":[\"$domain\"]}")"
|
||||
id="$(json_num "$body" id)"
|
||||
[ -n "$id" ] || { err "Zertifikatseintrag konnte nicht angelegt werden (HTTP $NPM_CODE)."
|
||||
[ -n "$id" ] || { err "Zertifikatseintrag konnte nicht angelegt werden (HTTP $(npm_code))."
|
||||
printf ' %s\n' "$body" >&2; return 1; }
|
||||
fi
|
||||
log "Lade Schluessel und Zertifikat hoch (ID $id) ..." >&2
|
||||
@@ -3538,7 +3553,7 @@ npm_cert_letsencrypt() { # domain
|
||||
"{\"provider\":\"letsencrypt\",\"domain_names\":[\"$domain\"],\"meta\":{}}")"
|
||||
local id; id="$(json_num "$body" id)"
|
||||
if [ -z "$id" ]; then
|
||||
err "Let's Encrypt hat kein Zertifikat ausgestellt (HTTP $NPM_CODE)."
|
||||
err "Let's Encrypt hat kein Zertifikat ausgestellt (HTTP $(npm_code))."
|
||||
local m; m="$(json_str "$body" message)"
|
||||
[ -n "$m" ] && printf ' Antwort: %s\n' "$m" >&2
|
||||
cat >&2 <<EOF
|
||||
@@ -3584,6 +3599,99 @@ proxy_location_json() { # spec -> JSON-Objekt auf stdout
|
||||
}
|
||||
|
||||
# --- Proxy-Hosts ---------------------------------------------------------
|
||||
# ---------------------------------------------------------------------
|
||||
# Zwei kleine JSON-Helfer, die mehr koennen als ein sed-Ausdruck
|
||||
#
|
||||
# "advanced_config" darf geschweifte Klammern enthalten (nginx-Bloecke),
|
||||
# und Zeichenketten duerfen maskierte Anfuehrungszeichen tragen. Ein
|
||||
# Aufteilen an "}" wuerde daran zerbrechen. Diese beiden zaehlen die
|
||||
# Verschachtelung mit und achten auf Zeichenketten.
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
# Text fuer eine JSON-Zeichenkette absichern. Anfuehrungszeichen werden
|
||||
# maskiert, echte Zeilenumbrueche werden zu \n - ein vom Benutzer selbst
|
||||
# getipptes \n bleibt, was es ist: ein Zeilenumbruch fuer nginx.
|
||||
json_str_escape() {
|
||||
printf '%s' "$1" | sed 's/"/\\"/g' | awk '{ if (NR>1) printf "\\n"; printf "%s", $0 }'
|
||||
}
|
||||
|
||||
# Rohen Wert eines Schluessels der obersten Ebene ausschneiden
|
||||
json_raw() { # json schluessel
|
||||
printf '%s' "$1" | awk -v key="$2" '
|
||||
{ s = s $0 }
|
||||
function cut(s, p, n, c, k, ch, d2, q2, e2) {
|
||||
c = substr(s, p, 1)
|
||||
if (c == "{" || c == "[") {
|
||||
d2 = 0; q2 = 0; e2 = 0
|
||||
for (k = p; k <= n; k++) {
|
||||
ch = substr(s, k, 1)
|
||||
if (q2) { if (e2) e2 = 0; else if (ch == "\\") e2 = 1; else if (ch == "\"") q2 = 0; continue }
|
||||
if (ch == "\"") { q2 = 1; continue }
|
||||
if (ch == "{" || ch == "[") d2++
|
||||
else if (ch == "}" || ch == "]") { d2--; if (d2 == 0) return substr(s, p, k - p + 1) }
|
||||
}
|
||||
return substr(s, p)
|
||||
}
|
||||
if (c == "\"") {
|
||||
e2 = 0
|
||||
for (k = p + 1; k <= n; k++) {
|
||||
ch = substr(s, k, 1)
|
||||
if (e2) { e2 = 0; continue }
|
||||
if (ch == "\\") { e2 = 1; continue }
|
||||
if (ch == "\"") return substr(s, p, k - p + 1)
|
||||
}
|
||||
return substr(s, p)
|
||||
}
|
||||
for (k = p; k <= n; k++) {
|
||||
ch = substr(s, k, 1)
|
||||
if (ch == "," || ch == "}" || ch == "]") return substr(s, p, k - p)
|
||||
}
|
||||
return substr(s, p)
|
||||
}
|
||||
END {
|
||||
t = "\"" key "\""; tl = length(t); n = length(s)
|
||||
d = 0; q = 0; e = 0
|
||||
for (i = 1; i <= n; i++) {
|
||||
c = substr(s, i, 1)
|
||||
if (q) { if (e) e = 0; else if (c == "\\") e = 1; else if (c == "\"") q = 0; continue }
|
||||
if (c == "\"") {
|
||||
if (d == 1 && substr(s, i, tl) == t) {
|
||||
j = i + tl
|
||||
while (j <= n && index(" \t:", substr(s, j, 1)) > 0) j++
|
||||
print cut(s, j, n); exit
|
||||
}
|
||||
q = 1; continue
|
||||
}
|
||||
if (c == "{" || c == "[") d++
|
||||
else if (c == "}" || c == "]") d--
|
||||
}
|
||||
}'
|
||||
}
|
||||
|
||||
# JSON-Wahrheitswert eines Schluessels als on/off (fuer Auswahllisten)
|
||||
json_bool_on() { # json schluessel
|
||||
case "$(json_raw "$1" "$2")" in true) printf 'on' ;; *) printf 'off' ;; esac
|
||||
}
|
||||
|
||||
# Ein JSON-Feld in seine Elemente zerlegen, je Element eine Zeile
|
||||
json_split_array() { # array-text
|
||||
printf '%s' "$1" | awk '
|
||||
{ s = s $0 }
|
||||
END {
|
||||
n = length(s); d = 0; q = 0; e = 0; start = 0
|
||||
for (i = 1; i <= n; i++) {
|
||||
c = substr(s, i, 1)
|
||||
if (q) { if (e) e = 0; else if (c == "\\") e = 1; else if (c == "\"") q = 0; continue }
|
||||
if (c == "\"") { q = 1; continue }
|
||||
if (c == "[" || c == "{") { d++; if (d == 2 && start == 0) start = i; continue }
|
||||
if (c == "]" || c == "}") {
|
||||
d--
|
||||
if (d == 1 && start > 0) { print substr(s, start, i - start + 1); start = 0 }
|
||||
}
|
||||
}
|
||||
}'
|
||||
}
|
||||
|
||||
# =====================================================================
|
||||
# HTTPS ueber die blanke IP
|
||||
#
|
||||
@@ -3795,14 +3903,15 @@ cmd_proxy() {
|
||||
printf ' Ziel : %s://%s:%s\n' "$(json_str "$o" forward_scheme)" "$(json_str "$o" forward_host)" "$(json_num "$o" forward_port)"
|
||||
printf ' Zertifikat : %s\n' "$(json_num "$o" certificate_id)"
|
||||
printf '\n %sZusaetzliche Pfade%s\n' "$C_BLD" "$C_RST"
|
||||
local n
|
||||
n="$(printf '%s' "$o" | grep -o '"path":"[^"]*"' | wc -l || true)"
|
||||
if [ "${n:-0}" -eq 0 ]; then
|
||||
printf ' (keine - alles geht an das Ziel oben)\n'
|
||||
else
|
||||
printf '%s' "$o" | tr '}' '\n' \
|
||||
| sed -n 's/.*"path":"\([^"]*\)".*"forward_host":"\([^"]*\)","forward_port":\([0-9]*\).*/ \1 -> \2:\3/p'
|
||||
fi
|
||||
local el n=0
|
||||
while IFS= read -r el; do
|
||||
[ -n "$el" ] || continue
|
||||
n=$((n+1))
|
||||
printf ' %-20s -> %s://%s:%s\n' "$(json_str "$el" path)" \
|
||||
"$(json_str "$el" forward_scheme)" "$(json_str "$el" forward_host)" \
|
||||
"$(json_num "$el" forward_port)"
|
||||
done < <(json_split_array "$(json_raw "$o" locations)")
|
||||
if [ "$n" -eq 0 ]; then printf ' (keine - alles geht an das Ziel oben)\n'; fi
|
||||
echo
|
||||
return 0 ;;
|
||||
|
||||
@@ -3916,6 +4025,237 @@ EOF
|
||||
npm_reload_hint "$restart"
|
||||
return 0 ;;
|
||||
|
||||
edit|set)
|
||||
local pid="" dom="" cert="" adv="" advset="" rename=""
|
||||
local fhost="" fport="" scheme="" enabled=""
|
||||
local fssl="" h2="" ws="" blk=""
|
||||
local -a addloc=() delloc=()
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--id) pid="$2"; shift 2 ;;
|
||||
--domain) dom="$2"; shift 2 ;;
|
||||
--rename) rename="$2"; shift 2 ;;
|
||||
--forward-host) fhost="$2"; shift 2 ;;
|
||||
--forward-port) fport="$2"; shift 2 ;;
|
||||
--scheme) scheme="$2"; shift 2 ;;
|
||||
--advanced) adv="$2"; advset=1; shift 2 ;;
|
||||
--cert) cert="$2"; shift 2 ;;
|
||||
--force-ssl) fssl="$2"; shift 2 ;;
|
||||
--http2) h2="$2"; shift 2 ;;
|
||||
--websockets) ws="$2"; shift 2 ;;
|
||||
--block-exploits) blk="$2"; shift 2 ;;
|
||||
--enable) enabled=true; shift ;;
|
||||
--disable) enabled=false; shift ;;
|
||||
--location) addloc+=("$2"); shift 2 ;;
|
||||
--del-location) delloc+=("$2"); shift 2 ;;
|
||||
--help|-h)
|
||||
cat <<EOF
|
||||
|
||||
Einen vorhandenen Proxy-Host aendern. Angegeben wird nur, was sich
|
||||
aendern soll - alles andere bleibt, wie es ist.
|
||||
|
||||
$SELF proxy edit --id 3 --forward-port 5001
|
||||
$SELF proxy edit --domain checkmk.example.local --cert self
|
||||
$SELF proxy edit --id 3 --location /grafana=127.0.0.1:3000
|
||||
$SELF proxy edit --id 3 --del-location /grafana
|
||||
|
||||
Auswahl
|
||||
--id N | --domain NAME
|
||||
|
||||
Aenderungen
|
||||
--rename NAME Domainname ersetzen
|
||||
--forward-host HOST Weiterleitungsziel (Host)
|
||||
--forward-port PORT Weiterleitungsziel (Port)
|
||||
--scheme http|https Schema zum Ziel
|
||||
--cert self|letsencrypt|none|ID
|
||||
--advanced 'TEXT' erweiterte nginx-Konfiguration
|
||||
--force-ssl on|off HTTP auf HTTPS umleiten
|
||||
--http2 on|off
|
||||
--websockets on|off
|
||||
--block-exploits on|off
|
||||
--enable | --disable Proxy-Host ein-/ausschalten
|
||||
--location /pfad=host:port hinzufuegen oder ersetzen
|
||||
--del-location /pfad entfernen
|
||||
|
||||
Ohne Aenderung wird nur der aktuelle Stand gezeigt.
|
||||
EOF
|
||||
return 0 ;;
|
||||
*) die "Unbekannte Option fuer 'proxy edit': $1" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
npm_require_running || return 1
|
||||
NPM_TOKEN="$(npm_api_token)" || return 1
|
||||
|
||||
if [ -z "$pid" ]; then
|
||||
[ -n "$dom" ] || die "--id oder --domain angeben. ('$SELF proxy list' zeigt die IDs)"
|
||||
local all i
|
||||
all="$(npm_api GET /api/nginx/proxy-hosts)"
|
||||
for i in $(json_ids "$all"); do
|
||||
if ( set +o pipefail; npm_api GET "/api/nginx/proxy-hosts/$i" | grep -qF "\"$dom\"" ); then
|
||||
pid="$i"; break
|
||||
fi
|
||||
done
|
||||
[ -n "$pid" ] || die "Kein Proxy-Host fuer '$dom' gefunden."
|
||||
fi
|
||||
case "$pid" in ''|*[!0-9]*) die "'$pid' ist keine gueltige ID." ;; esac
|
||||
|
||||
local o; o="$(npm_api GET "/api/nginx/proxy-hosts/$pid")"
|
||||
[ -n "$(json_num "$o" id)" ] || die "Proxy-Host $pid gibt es nicht."
|
||||
|
||||
# Nichts angegeben -> nur zeigen
|
||||
if [ -z "$rename$fhost$fport$scheme$advset$cert$fssl$h2$ws$blk$enabled" ] \
|
||||
&& [ "${#addloc[@]}" -eq 0 ] && [ "${#delloc[@]}" -eq 0 ]; then
|
||||
cmd_proxy show --id "$pid"
|
||||
printf ' Aendern mit: %s proxy edit --id %s --forward-port 5001
|
||||
Alle Moeglichkeiten: %s proxy edit --help\n\n' "$SELF" "$pid" "$SELF"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local -a parts=() changed=()
|
||||
if [ -n "$rename" ]; then
|
||||
parts+=("\"domain_names\":[\"$(json_str_escape "$rename")\"]")
|
||||
changed+=("Domain -> $rename")
|
||||
fi
|
||||
if [ -n "$fhost" ]; then
|
||||
parts+=("\"forward_host\":\"$(json_str_escape "$fhost")\""); changed+=("Ziel-Host -> $fhost")
|
||||
fi
|
||||
if [ -n "$fport" ]; then
|
||||
valid_port "$fport" || die "--forward-port: keine gueltige Portnummer."
|
||||
parts+=("\"forward_port\":$fport"); changed+=("Ziel-Port -> $fport")
|
||||
fi
|
||||
if [ -n "$scheme" ]; then
|
||||
case "$scheme" in http|https) : ;; *) die "--scheme: http oder https" ;; esac
|
||||
parts+=("\"forward_scheme\":\"$scheme\""); changed+=("Schema -> $scheme")
|
||||
fi
|
||||
if [ -n "$advset" ]; then
|
||||
parts+=("\"advanced_config\":\"$(json_str_escape "$adv")\"")
|
||||
changed+=("erweiterte Konfiguration ersetzt")
|
||||
fi
|
||||
local b
|
||||
for b in "fssl:--force-ssl:ssl_forced:HTTPS erzwingen" \
|
||||
"h2:--http2:http2_support:HTTP/2" \
|
||||
"ws:--websockets:allow_websocket_upgrade:WebSockets" \
|
||||
"blk:--block-exploits:block_exploits:Exploit-Sperre"; do
|
||||
local var opt rest key label val
|
||||
var="${b%%:*}"; rest="${b#*:}"
|
||||
opt="${rest%%:*}"; rest="${rest#*:}"
|
||||
key="${rest%%:*}"; label="${rest#*:}"
|
||||
eval "val=\"\${$var}\""
|
||||
[ -n "$val" ] || continue
|
||||
case "$(fw_lc "$val")" in
|
||||
on|true|1|ja|yes) val=true ;;
|
||||
off|false|0|nein|no) val=false ;;
|
||||
*) die "$opt: on oder off" ;;
|
||||
esac
|
||||
parts+=("\"$key\":$val"); changed+=("$label -> $val")
|
||||
done
|
||||
if [ -n "$enabled" ]; then
|
||||
parts+=("\"enabled\":$enabled")
|
||||
changed+=("Proxy-Host $([ "$enabled" = true ] && echo eingeschaltet || echo ausgeschaltet)")
|
||||
fi
|
||||
|
||||
if [ -n "$cert" ]; then
|
||||
local certid="" cdom
|
||||
cdom="${rename:-$(printf '%s' "$o" | sed -n 's/.*"domain_names"[[:space:]]*:[[:space:]]*\[[[:space:]]*"\([^"]*\)".*/\1/p')}"
|
||||
case "$cert" in
|
||||
self) certid="$(npm_cert_selfsigned "$cdom")" || return 1 ;;
|
||||
letsencrypt) certid="$(npm_cert_letsencrypt "$cdom")" || return 1 ;;
|
||||
none) certid=0 ;;
|
||||
*[!0-9]*) die "--cert: self | letsencrypt | none | <ID>" ;;
|
||||
*) certid="$cert" ;;
|
||||
esac
|
||||
parts+=("\"certificate_id\":$certid")
|
||||
changed+=("Zertifikat -> $certid")
|
||||
if [ "$certid" = 0 ]; then
|
||||
parts+=("\"ssl_forced\":false" "\"http2_support\":false")
|
||||
changed+=("HTTPS erzwingen -> false (ohne Zertifikat nicht moeglich)")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Pfade: die API ersetzt das ganze Feld, also aus dem Bestand neu bauen
|
||||
if [ "${#addloc[@]}" -gt 0 ] || [ "${#delloc[@]}" -gt 0 ]; then
|
||||
local cur; cur="$(json_raw "$o" locations)"
|
||||
local -a keep=()
|
||||
local el elpath spec p drop
|
||||
while IFS= read -r el; do
|
||||
[ -n "$el" ] || continue
|
||||
elpath="$(json_str "$el" path)"
|
||||
drop=""
|
||||
for p in ${delloc[@]+"${delloc[@]}"}; do
|
||||
case "$p" in /*) : ;; *) p="/$p" ;; esac
|
||||
if [ "$p" = "$elpath" ]; then drop=1; changed+=("Pfad $elpath entfernt"); fi
|
||||
done
|
||||
for spec in ${addloc[@]+"${addloc[@]}"}; do
|
||||
p="${spec%%=*}"; case "$p" in /*) : ;; *) p="/$p" ;; esac
|
||||
if [ "$p" = "$elpath" ]; then
|
||||
drop=1
|
||||
if [ -n "$(json_str "$el" advanced_config)" ]; then
|
||||
warn "Der Pfad $elpath hatte eine eigene erweiterte Konfiguration.
|
||||
Beim Ersetzen geht sie verloren."
|
||||
fi
|
||||
fi
|
||||
done
|
||||
[ -n "$drop" ] || keep+=("$el")
|
||||
done < <(json_split_array "$cur")
|
||||
|
||||
for spec in ${addloc[@]+"${addloc[@]}"}; do
|
||||
local lj; lj="$(proxy_location_json "$spec")" || return 1
|
||||
keep+=("$lj")
|
||||
changed+=("Pfad ${spec%%=*} -> ${spec#*=}")
|
||||
done
|
||||
|
||||
local joined=""
|
||||
for el in ${keep[@]+"${keep[@]}"}; do
|
||||
if [ -n "$joined" ]; then joined="$joined,$el"; else joined="$el"; fi
|
||||
done
|
||||
parts+=("\"locations\":[$joined]")
|
||||
fi
|
||||
|
||||
local payload="{" first=1 x
|
||||
for x in "${parts[@]}"; do
|
||||
if [ -n "$first" ]; then payload="$payload$x"; first=""; else payload="$payload,$x"; fi
|
||||
done
|
||||
payload="$payload}"
|
||||
|
||||
log "Aendere Proxy-Host $pid ..."
|
||||
local body; body="$(npm_api PUT "/api/nginx/proxy-hosts/$pid" "$payload")"
|
||||
case "$(npm_code)" in
|
||||
200|201) : ;;
|
||||
*) err "Aenderung fehlgeschlagen (HTTP $(npm_code))."
|
||||
local m; m="$(json_str "$body" message)"
|
||||
if [ -n "$m" ]; then printf ' Antwort: %s\n' "$m" >&2; fi
|
||||
return 1 ;;
|
||||
esac
|
||||
ok "Proxy-Host $pid geaendert."
|
||||
for x in "${changed[@]}"; do printf ' %s\n' "$x"; done
|
||||
|
||||
# Der Proxy Manager biegt manches still zurecht - ohne Zertifikat
|
||||
# etwa HTTP/2 und die HTTPS-Umleitung. Das darf nicht unbemerkt
|
||||
# bleiben, sonst sucht man den Fehler spaeter an der falschen Stelle.
|
||||
local k want got
|
||||
for x in "${parts[@]}"; do
|
||||
k="${x%%:*}"; k="${k#\"}"; k="${k%\"}"
|
||||
case "$k" in locations|domain_names|advanced_config) continue ;; esac
|
||||
want="${x#*:}"
|
||||
got="$(json_raw "$body" "$k")"
|
||||
[ -n "$got" ] || continue
|
||||
[ "$got" != "$want" ] || continue
|
||||
warn "'$k': gesendet wurde $want, gespeichert ist $got."
|
||||
if [ "$(json_raw "$body" certificate_id)" = 0 ]; then
|
||||
printf ' Ohne Zertifikat laesst der Proxy Manager das nicht zu.
|
||||
Erst eines zuweisen: %s proxy edit --id %s --cert self\n' "$SELF" "$pid"
|
||||
fi
|
||||
done
|
||||
echo
|
||||
cmd_proxy show --id "$pid"
|
||||
if grep -qsF "$NPM_DEF_START" "$(npm_custom_conf_path)"; then
|
||||
log "Der Standard-Server fuer den IP-Zugang spiegelt einen Stand von vorher.
|
||||
Nach inhaltlichen Aenderungen neu schreiben:
|
||||
$SELF proxy default --domain <name> --restart"
|
||||
fi
|
||||
return 0 ;;
|
||||
|
||||
del|delete|rm)
|
||||
local pid=""
|
||||
while [ $# -gt 0 ]; do
|
||||
@@ -3926,8 +4266,8 @@ EOF
|
||||
NPM_TOKEN="$(npm_api_token)" || return 1
|
||||
confirm "Proxy-Host mit der ID $pid wirklich loeschen?" || die "Abgebrochen."
|
||||
npm_api DELETE "/api/nginx/proxy-hosts/$pid" >/dev/null
|
||||
case "$NPM_CODE" in 200|201|204) ok "Proxy-Host $pid geloescht." ;;
|
||||
*) die "Loeschen fehlgeschlagen (HTTP $NPM_CODE)." ;; esac
|
||||
case "$(npm_code)" in 200|201|204) ok "Proxy-Host $pid geloescht." ;;
|
||||
*) die "Loeschen fehlgeschlagen (HTTP $(npm_code))." ;; esac
|
||||
return 0 ;;
|
||||
|
||||
add)
|
||||
@@ -3996,7 +4336,7 @@ EOF
|
||||
fi
|
||||
local newid; newid="$(json_num "$body" id)"
|
||||
if [ -z "$newid" ]; then
|
||||
err "Der Proxy-Host konnte nicht angelegt werden (HTTP $NPM_CODE)."
|
||||
err "Der Proxy-Host konnte nicht angelegt werden (HTTP $(npm_code))."
|
||||
local m; m="$(json_str "$body" message)"
|
||||
[ -n "$m" ] && printf ' Antwort: %s\n' "$m" >&2
|
||||
return 1
|
||||
@@ -4019,7 +4359,7 @@ EOF
|
||||
return 0 ;;
|
||||
|
||||
*) die "Unbekanntes Unterkommando 'proxy $sub'.
|
||||
Moeglich: status | list | show | certs | add | del" ;;
|
||||
Moeglich: status | list | show | certs | add | edit | del | default" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -5245,6 +5585,7 @@ Konto: ${NPM_ADMIN_EMAIL:-<nicht gesetzt>}
|
||||
Ziel : ${PROXY_FORWARD_HOST:-127.0.0.1}:${PROXY_FORWARD_PORT:-5000}" \
|
||||
anlegen "Proxy-Host anlegen (Assistent)" \
|
||||
list "Vorhandene Proxy-Hosts anzeigen" \
|
||||
edit "Proxy-Host bearbeiten (Ziel, Pfade, Zertifikat ...)" \
|
||||
show "Einzelheiten eines Proxy-Hosts (mit Pfaden)" \
|
||||
certs "Vorhandene Zertifikate anzeigen" \
|
||||
ipzugang "HTTPS ueber die blanke IP (ohne Namen) ermoeglichen" \
|
||||
@@ -5254,6 +5595,7 @@ Ziel : ${PROXY_FORWARD_HOST:-127.0.0.1}:${PROXY_FORWARD_PORT:-5000}" \
|
||||
back "zurueck")" || return 0
|
||||
case "$sel" in
|
||||
anlegen) gui_proxy_add || true ;;
|
||||
edit) gui_proxy_edit || true ;;
|
||||
list) local f; f="$(mktemp)"; NO_COLOR=1 cmd_proxy list >"$f" 2>&1 || true
|
||||
ui_text "Proxy-Hosts" "$f"; rm -f "$f" ;;
|
||||
show) local d3; d3="$(ui_input "Einzelheiten" "Name oder ID des Proxy-Hosts:" "${PROXY_DOMAIN:-}")" || continue
|
||||
@@ -5272,6 +5614,159 @@ Ziel : ${PROXY_FORWARD_HOST:-127.0.0.1}:${PROXY_FORWARD_PORT:-5000}" \
|
||||
done
|
||||
}
|
||||
|
||||
# Proxy-Host auswaehlen -> ID auf stdout
|
||||
gui_pick_proxy() { # titel
|
||||
if ! npm_require_running >/dev/null 2>&1; then
|
||||
ui_msg "Proxy Manager" "Der Proxy Manager laeuft nicht oder ist abgeschaltet." >&2
|
||||
return 1
|
||||
fi
|
||||
NPM_TOKEN="$(npm_api_token 2>/dev/null)" || {
|
||||
ui_msg "Proxy Manager" "Anmeldung fehlgeschlagen.
|
||||
|
||||
Zugangsdaten pruefen unter Einstellungen > NGINX Proxy Manager,
|
||||
oder die Datenbank zuruecksetzen." >&2
|
||||
return 1
|
||||
}
|
||||
local all i o dom
|
||||
local -a items=()
|
||||
all="$(npm_api GET /api/nginx/proxy-hosts)"
|
||||
for i in $(json_ids "$all"); do
|
||||
o="$(npm_api GET "/api/nginx/proxy-hosts/$i")"
|
||||
dom="$(printf '%s' "$o" | sed -n 's/.*"domain_names"[[:space:]]*:[[:space:]]*\[[[:space:]]*"\([^"]*\)".*/\1/p')"
|
||||
items+=("$i" "${dom:-?} -> $(json_str "$o" forward_host):$(json_num "$o" forward_port)")
|
||||
done
|
||||
if [ "${#items[@]}" -eq 0 ]; then
|
||||
ui_msg "Proxy-Hosts" "Es gibt noch keinen Proxy-Host.
|
||||
|
||||
Anlegen unter: Proxy-Host anlegen (Assistent)" >&2
|
||||
return 1
|
||||
fi
|
||||
ui_menu "${1:-Proxy-Host waehlen}" "Welchen Eintrag?" "${items[@]}"
|
||||
}
|
||||
|
||||
# Einen vorhandenen Proxy-Host bearbeiten
|
||||
gui_proxy_edit() {
|
||||
local pid
|
||||
pid="$(gui_pick_proxy "Proxy-Host bearbeiten")" || return 0
|
||||
[ -n "$pid" ] || return 0
|
||||
# gui_pick_proxy lief in einer Kommandoersetzung, sein Token ist mit der
|
||||
# Subshell verschwunden - hier neu holen.
|
||||
NPM_TOKEN="$(npm_api_token)" || { ui_msg "Proxy Manager" "Anmeldung fehlgeschlagen."; return 0; }
|
||||
|
||||
while :; do
|
||||
local o dom
|
||||
o="$(npm_api GET "/api/nginx/proxy-hosts/$pid")"
|
||||
if [ -z "$(json_num "$o" id)" ]; then
|
||||
ui_msg "Proxy-Host" "Der Eintrag $pid ist nicht mehr da."; return 0
|
||||
fi
|
||||
dom="$(printf '%s' "$o" | sed -n 's/.*"domain_names"[[:space:]]*:[[:space:]]*\[[[:space:]]*"\([^"]*\)".*/\1/p')"
|
||||
|
||||
local sel
|
||||
sel="$(ui_menu "Proxy-Host $pid bearbeiten" \
|
||||
"Name : $dom
|
||||
Ziel : $(json_str "$o" forward_scheme)://$(json_str "$o" forward_host):$(json_num "$o" forward_port)
|
||||
Zertifikat : $(json_num "$o" certificate_id) Aktiv: $(json_raw "$o" enabled)
|
||||
|
||||
Jede Aenderung wirkt sofort; alles Uebrige bleibt unangetastet." \
|
||||
ziel "Weiterleitungsziel (Host und Port)" \
|
||||
schema "Schema zum Ziel (http/https)" \
|
||||
name "Domainname aendern" \
|
||||
cert "Zertifikat zuweisen oder entfernen" \
|
||||
pfad "Pfad hinzufuegen oder ersetzen" \
|
||||
pfadweg "Pfad entfernen" \
|
||||
schalter "Schalter (HTTPS erzwingen, HTTP/2, WebSockets, Sperre)" \
|
||||
anaus "Proxy-Host ein- oder ausschalten" \
|
||||
adv "Erweiterte nginx-Konfiguration" \
|
||||
zeigen "Aktuellen Stand anzeigen" \
|
||||
back "zurueck")" || return 0
|
||||
|
||||
local -a args=()
|
||||
case "$sel" in
|
||||
back) return 0 ;;
|
||||
zeigen) local f; f="$(mktemp)"
|
||||
NO_COLOR=1 cmd_proxy show --id "$pid" >"$f" 2>&1 || true
|
||||
ui_text "Proxy-Host $pid" "$f"; rm -f "$f"; continue ;;
|
||||
ziel) local h pt
|
||||
h="$(ui_input "Weiterleitungsziel" "Host:" "$(json_str "$o" forward_host)")" || continue
|
||||
[ -n "$h" ] || continue
|
||||
pt="$(ui_input "Weiterleitungsziel" "Port:" "$(json_num "$o" forward_port)")" || continue
|
||||
[ -n "$pt" ] || continue
|
||||
args=(--forward-host "$h" --forward-port "$pt") ;;
|
||||
schema) local sc
|
||||
sc="$(ui_menu "Schema zum Ziel" "Wie spricht der Proxy das Ziel an?" \
|
||||
http "unverschluesselt (der Regelfall im eigenen Netz)" \
|
||||
https "verschluesselt")" || continue
|
||||
args=(--scheme "$sc") ;;
|
||||
name) local nn
|
||||
nn="$(ui_input "Domainname" "Neuer Name:" "$dom")" || continue
|
||||
[ -n "$nn" ] || continue
|
||||
args=(--rename "$nn") ;;
|
||||
cert) local cc
|
||||
cc="$(ui_menu "Zertifikat" "Was soll ausgeliefert werden?" \
|
||||
self "selbstsigniert (fuer das eigene Netz)" \
|
||||
letsencrypt "Lets Encrypt (Server muss oeffentlich erreichbar sein)" \
|
||||
none "keines - nur HTTP")" || continue
|
||||
args=(--cert "$cc") ;;
|
||||
pfad) local sp
|
||||
sp="$(ui_input "Pfad" "Pfad und Ziel, z.B. /grafana=127.0.0.1:3000" "")" || continue
|
||||
[ -n "$sp" ] || continue
|
||||
args=(--location "$sp") ;;
|
||||
pfadweg)
|
||||
local el
|
||||
local -a pitems=()
|
||||
while IFS= read -r el; do
|
||||
[ -n "$el" ] || continue
|
||||
pitems+=("$(json_str "$el" path)" "-> $(json_str "$el" forward_host):$(json_num "$el" forward_port)")
|
||||
done < <(json_split_array "$(json_raw "$o" locations)")
|
||||
if [ "${#pitems[@]}" -eq 0 ]; then
|
||||
ui_msg "Pfade" "Dieser Proxy-Host hat keine zusaetzlichen Pfade."; continue
|
||||
fi
|
||||
local dp
|
||||
dp="$(ui_menu "Pfad entfernen" "Welchen Pfad?" "${pitems[@]}")" || continue
|
||||
ui_yesno "Pfad entfernen" "Pfad $dp wirklich entfernen?" || continue
|
||||
args=(--del-location "$dp") ;;
|
||||
schalter)
|
||||
local cur
|
||||
cur="$(ui_checklist "Schalter" "Mit der Leertaste umschalten:" \
|
||||
force-ssl "HTTP auf HTTPS umleiten" "$(json_bool_on "$o" ssl_forced)" \
|
||||
http2 "HTTP/2" "$(json_bool_on "$o" http2_support)" \
|
||||
websockets "WebSockets durchreichen" "$(json_bool_on "$o" allow_websocket_upgrade)" \
|
||||
block-exploits "Bekannte Angriffsmuster sperren" "$(json_bool_on "$o" block_exploits)")" || continue
|
||||
local o1 o2 o3 o4
|
||||
case " $cur " in *" force-ssl "*|*'"force-ssl"'*) o1=on ;; *) o1=off ;; esac
|
||||
case " $cur " in *" http2 "*|*'"http2"'*) o2=on ;; *) o2=off ;; esac
|
||||
case " $cur " in *" websockets "*|*'"websockets"'*) o3=on ;; *) o3=off ;; esac
|
||||
case " $cur " in *" block-exploits "*|*'"block-exploits"'*) o4=on ;; *) o4=off ;; esac
|
||||
args=(--force-ssl "$o1" --http2 "$o2" --websockets "$o3" --block-exploits "$o4") ;;
|
||||
anaus) if [ "$(json_bool_on "$o" enabled)" = on ]; then
|
||||
ui_yesno "Ausschalten" "Proxy-Host $pid ausschalten?" || continue
|
||||
args=(--disable)
|
||||
else
|
||||
ui_yesno "Einschalten" "Proxy-Host $pid einschalten?" || continue
|
||||
args=(--enable)
|
||||
fi ;;
|
||||
adv) local a1 curadv
|
||||
curadv="$(json_raw "$o" advanced_config)"
|
||||
curadv="${curadv#\"}"; curadv="${curadv%\"}"
|
||||
a1="$(ui_input "Erweiterte Konfiguration" \
|
||||
"nginx-Anweisungen fuer diesen Proxy-Host.
|
||||
Mehrere Anweisungen durch \\\\n trennen." "$curadv")" || continue
|
||||
args=(--advanced "$a1") ;;
|
||||
esac
|
||||
|
||||
[ "${#args[@]}" -gt 0 ] || continue
|
||||
local f2 rc=0
|
||||
f2="$(mktemp)"
|
||||
NO_COLOR=1 cmd_proxy edit --id "$pid" "${args[@]}" >"$f2" 2>&1 || rc=$?
|
||||
if [ "$rc" -eq 0 ]; then
|
||||
ui_text "Proxy-Host $pid geaendert" "$f2"
|
||||
else
|
||||
ui_text "Aenderung fehlgeschlagen" "$f2"
|
||||
fi
|
||||
rm -f "$f2"
|
||||
done
|
||||
}
|
||||
|
||||
gui_proxy_default() {
|
||||
local f rc=0
|
||||
f="$(mktemp)"
|
||||
|
||||
Reference in New Issue
Block a user