HTTPS ueber die blanke IP: Standard-Server statt abgelehntem Handshake

https://<IP>/cmk/ endete im Browser mit ERR_SSL_UNRECOGNIZED_NAME_ALERT,
waehrend dieselbe Adresse ueber http funktionierte. Die Ursache liegt
nicht beim Zertifikat: RFC 6066 laesst in der SNI-Erweiterung keine
IP-Adressen zu, der Browser schickt bei einer IP also gar keinen Namen.
nginx kann den Server-Block dann nicht ueber den Namen waehlen und
faellt auf den Standard-Server zurueck - bei NPM ist das der Block aus
/etc/nginx/conf.d/default.conf mit "ssl_reject_handshake on". Ueber HTTP
faellt das nicht auf, dort entscheidet der Host-Kopf, und der traegt die
IP.

Nachgeprueft am Image jc21/nginx-proxy-manager:2 (2.15.1): der Block
steht dort in Zeile 36, und nginx.conf liest conf.d/*.conf vor den
Proxy-Hosts ein - damit wird er zum Standard-Server, obwohl keiner der
Bloecke "default_server" gesetzt hat. Mit einem eigenen Block, der das
Kennzeichen ausdruecklich traegt, ist der Fall entschieden; Aufrufe mit
Namen gehen unveraendert an ihren Proxy-Host.

Neu ist "proxy default":

  proxy default                 Stand anzeigen
  proxy default --domain X      Proxy-Host X spiegeln
  proxy default --off           Spiegelung entfernen
  --restart                     Proxy Manager gleich neu starten

Gespiegelt wird ueber die API: Ziel, Zertifikat und die zusaetzlichen
Pfade des Proxy-Hosts landen in einem Standard-Server-Block in der
Zusatzkonfiguration. Fuehrt das Zertifikat die IP nicht als
Alternativnamen, sagt der Befehl das vorher - bei Lets Encrypt geht es
prinzipbedingt nicht.

Dabei aufgefallen: die Zusatzkonfiguration liegt im Datenverzeichnis des
Proxy Managers und gehoert dem Container. Ohne Schreibrecht scheiterte
bisher nur ein nacktes "touch" - jetzt sagt npm_conf_writable, woran es
liegt, und nennt den sudo-Aufruf. Das gilt auch fuer "npm-port".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-20 20:17:10 +02:00
co-authored by Claude Opus 5
parent 989256e082
commit 8782c6d5c7
3 changed files with 458 additions and 7 deletions
+65
View File
@@ -1224,6 +1224,8 @@ erzwingen, HTTP/2 und Websockets einschalten und den empfohlenen
| `proxy add …` | Proxy-Host anlegen (`--update` ersetzt einen vorhandenen) |
| `proxy show --domain X` | Einzelheiten samt zusätzlicher Pfade |
| `proxy del --id N` | Proxy-Host löschen |
| `proxy default --domain X` | HTTPS über die blanke IP ermöglichen (spiegelt X in einen Standard-Server) |
| `proxy default --off` | diese Spiegelung wieder entfernen |
Optionen von `proxy add`:
@@ -1459,6 +1461,68 @@ Einbinden:
Die ncurses-Oberfläche bietet denselben Ablauf unter *„Selbstsigniertes
Zertifikat erzeugen“*.
### 10.8 HTTPS über die blanke IP
Ruft man den Server als `https://172.0.250.82/cmk/` auf, endet das im Browser
mit **`ERR_SSL_UNRECOGNIZED_NAME_ALERT`** – über `http://` funktioniert
dieselbe Adresse. Das liegt nicht am Zertifikat.
Der Grund steckt in TLS: Der Browser teilt dem Server beim Verbindungsaufbau
mit, welchen Namen er sprechen will (*SNI*). Laut RFC 6066 dürfen dort **keine
IP-Adressen** stehen, also sendet der Browser bei einer IP gar nichts. nginx
kann den passenden Server-Block dann nicht über den Namen auswählen und fällt
auf seinen Standard-Server zurück. Bei NPM ist das dieser Block aus
`/etc/nginx/conf.d/default.conf`:
```nginx
server {
listen 443 ssl;
server_name localhost;
ssl_reject_handshake on; # <- genau das meldet der Browser
return 444;
}
```
Über HTTP fällt es nicht auf, weil nginx den Server-Block dort am `Host`-Kopf
erkennt – und der trägt die IP.
Abhilfe ist ein eigener Standard-Server, der diese namenlosen Aufrufe annimmt:
```bash
sudo ./scripts/cmk-manage.sh proxy default --domain checkmk.example.local --restart
```
Der Befehl liest den genannten Proxy-Host über die API aus und spiegelt ihn –
Ziel, Zertifikat und **alle zusätzlichen Pfade** – in einen Block mit
`default_server`, der in die Zusatzkonfiguration geschrieben wird. Aufrufe mit
Namen bleiben unberührt: nginx wählt weiterhin zuerst nach SNI aus, der
Standard-Server greift nur, wenn kein Name passt. Keiner der von NPM erzeugten
Blöcke setzt `default_server` selbst, deshalb gibt es darum keinen Streit.
| Befehl | Wirkung |
|---|---|
| `proxy default` | zeigt, ob eingerichtet, und welchen Proxy-Host es spiegelt |
| `proxy default --domain X` | Proxy-Host `X` spiegeln |
| `proxy default --off` | Spiegelung entfernen |
| `--restart` | den Proxy Manager gleich neu starten |
In der Oberfläche liegt das unter **Proxy-Hosts → HTTPS über die blanke IP
(ohne Namen) ermöglichen**.
Zwei Dinge sind zu beachten:
- Das **Zertifikat muss die IP als Alternativnamen führen**, sonst meldet der
Browser einen Namensfehler (anklickbar, aber unschön). `cmk-manage.sh cert`
und `proxy add --cert self` tragen die IP des Hosts von sich aus ein; bei
einem Let's-Encrypt-Zertifikat geht das prinzipbedingt nicht – dafür gibt es
keine Zertifikate auf IP-Adressen. Der Befehl prüft das und sagt es.
- Die Zusatzkonfiguration liegt im Datenverzeichnis des Proxy Managers, und das
gehört dem Container. Deshalb **mit `sudo`** aufrufen.
Die saubere Alternative bleibt ein Name: ein DNS-Eintrag oder eine Zeile in der
`hosts`-Datei der Clients genügt, damit der Browser SNI sendet und der
Proxy-Host ganz normal greift.
---
## 11. Proxy Manager lokal einrichten (Terminal-Browser)
@@ -2628,6 +2692,7 @@ Checkmk-Werksnotizen (Werks/Release Notes) lesen.
| Symptom | Ursache / Lösung |
|---|---|
| `ERR_SSL_UNRECOGNIZED_NAME_ALERT` beim Aufruf über `https://<IP>/` | Der Browser sendet bei einer IP kein SNI, nginx fällt auf seinen Standard-Server zurück und lehnt ab. `cmk-manage.sh proxy default --domain <name>` – siehe [Kapitel 10.8](#108-https-über-die-blanke-ip) |
| `Port 80/443 already in use` | Auf dem Host läuft bereits ein Webserver: `ss -tlnp \| grep ':80'` → `systemctl disable --now apache2 nginx httpd` |
| Nach Reboot laufen die Container nicht (Podman) | systemd-Unit fehlt: `./install.sh --with-systemd` bzw. `--quadlet`, danach `systemctl is-enabled checkmk-stack` |
| `omd restore`: *version is not installed* | passendes Image holen: `cmk-manage.sh image pull --edition <ed> --version <v>`, dann `up` |
+64
View File
@@ -1223,6 +1223,8 @@ HTTPS, enables HTTP/2 and websockets, and sets the recommended
| `proxy add …` | create a proxy host (`--update` replaces an existing one) |
| `proxy show --domain X` | details including additional paths |
| `proxy del --id N` | delete a proxy host |
| `proxy default --domain X` | enable HTTPS on the bare IP (mirrors X into a default server) |
| `proxy default --off` | remove that mirror again |
Options for `proxy add`:
@@ -1456,6 +1458,67 @@ Installing it:
The ncurses interface offers the same workflow under *"Selbstsigniertes
Zertifikat erzeugen"*.
### 10.8 HTTPS on the bare IP
Opening the server as `https://172.0.250.82/cmk/` ends in
**`ERR_SSL_UNRECOGNIZED_NAME_ALERT`** in the browser – while `http://` on the
very same address works. This is not a certificate problem.
The reason is in TLS: the browser tells the server which name it wants to talk
to (*SNI*) while the connection is set up. RFC 6066 does not allow **IP
addresses** there, so for an IP the browser sends nothing at all. nginx then
cannot select the matching server block by name and falls back to its default
server. With NPM that is this block from `/etc/nginx/conf.d/default.conf`:
```nginx
server {
listen 443 ssl;
server_name localhost;
ssl_reject_handshake on; # <- exactly what the browser reports
return 444;
}
```
Over HTTP it does not show, because there nginx picks the server block by the
`Host` header – and that carries the IP.
The remedy is a default server of your own that accepts those nameless calls:
```bash
sudo ./scripts/cmk-manage.sh proxy default --domain checkmk.example.local --restart
```
The command reads the named proxy host through the API and mirrors it – target,
certificate and **all additional paths** – into a block carrying
`default_server`, written to the custom configuration. Calls by name are
untouched: nginx still selects by SNI first, and the default server only
applies when no name matches. None of the blocks NPM generates sets
`default_server` itself, so there is no conflict over it.
| Command | Effect |
|---|---|
| `proxy default` | shows whether it is set up, and which proxy host it mirrors |
| `proxy default --domain X` | mirror proxy host `X` |
| `proxy default --off` | remove the mirror |
| `--restart` | restart the Proxy Manager right away |
In the GUI this lives under **Proxy-Hosts → HTTPS über die blanke IP (ohne
Namen) ermöglichen**.
Two things to keep in mind:
- The **certificate must carry the IP as a subject alternative name**, otherwise
the browser reports a name mismatch (clickable, but ugly). `cmk-manage.sh
cert` and `proxy add --cert self` add the host's IP by themselves; with a
Let's Encrypt certificate this is impossible by design – there are no
certificates for IP addresses. The command checks this and says so.
- The custom configuration lives in the Proxy Manager's data directory, which
belongs to the container. So run it **with `sudo`**.
The clean alternative is still a name: a DNS record or one line in the clients'
`hosts` file is enough for the browser to send SNI, and the proxy host applies
as usual.
---
## 11. Configuring the Proxy Manager locally (terminal browser)
@@ -2625,6 +2688,7 @@ release notes beforehand.
| Symptom | Cause / solution |
|---|---|
| `ERR_SSL_UNRECOGNIZED_NAME_ALERT` when opening `https://<IP>/` | browsers send no SNI for an IP, nginx falls back to its default server and rejects. `cmk-manage.sh proxy default --domain <name>` – see [chapter 10.8](#108-https-on-the-bare-ip) |
| `Port 80/443 already in use` | a web server is already running on the host: `ss -tlnp \| grep ':80'` → `systemctl disable --now apache2 nginx httpd` |
| Containers do not run after a reboot (Podman) | systemd unit missing: `./install.sh --with-systemd` or `--quadlet`, then `systemctl is-enabled checkmk-stack` |
| `omd restore`: *version is not installed* | fetch the matching image: `cmk-manage.sh image pull --edition <ed> --version <v>`, then `up` |
+329 -7
View File
@@ -2753,25 +2753,54 @@ NPM_CUSTOM_CONF_REL="nginx/custom/http.conf"
NPM_BLOCK_START="# >>> cmk-manage.sh: Admin-Port - nicht von Hand aendern >>>"
NPM_BLOCK_END="# <<< cmk-manage.sh: Admin-Port <<<"
npm_custom_conf_path() {
local base="${NPM_DATA_DIR:-$PROJECT_DIR/data/npm/data}"
case "$base" in /*) : ;; *) base="$PROJECT_DIR/${base#./}" ;; esac
printf '%s/%s\n' "$base" "$NPM_CUSTOM_CONF_REL"
# Die Zusatzkonfiguration liegt im Datenverzeichnis des Proxy Managers,
# und das gehoert dem Container - also root. Ohne Schreibrecht scheitert
# sonst erst "touch" mit einer nackten Fehlermeldung.
npm_conf_writable() { # datei
local f="$1" d; d="$(dirname "$f")"
if [ -e "$f" ]; then
[ -w "$f" ] && return 0
elif [ -d "$d" ]; then
[ -w "$d" ] && return 0
else
mkdir -p "$d" 2>/dev/null && return 0
fi
err "Keine Schreibrechte auf $f"
printf ' Das Verzeichnis gehoert dem Proxy-Manager-Container (root).
Bitte mit sudo aufrufen:
sudo %s %s\n' "$SELF" "${CMD_LINE:-<befehl>}" >&2
return 1
}
npm_data_dir_abs() {
local base="${NPM_DATA_DIR:-$PROJECT_DIR/data/npm/data}"
case "$base" in /*) : ;; *) base="$PROJECT_DIR/${base#./}" ;; esac
printf '%s\n' "$base"
}
npm_custom_conf_path() {
printf '%s/%s\n' "$(npm_data_dir_abs)" "$NPM_CUSTOM_CONF_REL"
}
NPM_DEF_START="# >>> cmk-manage.sh: HTTPS ohne SNI - nicht von Hand aendern >>>"
NPM_DEF_END="# <<< cmk-manage.sh: HTTPS ohne SNI <<<"
# Vorhandenen verwalteten Block entfernen, Fremdinhalte bleiben erhalten
npm_conf_strip_block() {
local f="$1"
npm_conf_strip_marked() {
local f="$1" st="$2" en="$3"
[ -f "$f" ] || return 0
awk -v s="$NPM_BLOCK_START" -v e="$NPM_BLOCK_END" '
awk -v s="$st" -v e="$en" '
$0 == s { skip=1; next }
$0 == e { skip=0; next }
!skip { print }
' "$f" > "$f.tmp" && mv "$f.tmp" "$f"
}
npm_conf_strip_block() { npm_conf_strip_marked "$1" "$NPM_BLOCK_START" "$NPM_BLOCK_END"; }
npm_conf_write_block() {
local f="$1" port="$2"
npm_conf_writable "$f" || return 1
mkdir -p "$(dirname "$f")"
touch "$f"
npm_conf_strip_block "$f"
@@ -3555,6 +3584,144 @@ proxy_location_json() { # spec -> JSON-Objekt auf stdout
}
# --- Proxy-Hosts ---------------------------------------------------------
# =====================================================================
# HTTPS ueber die blanke IP
#
# Ruft man den Server mit https://<IP>/ auf, sendet der Browser keinen
# SNI-Namen - RFC 6066 laesst dort keine IP-Adressen zu. nginx kann den
# passenden Server-Block dann nicht ueber den Namen auswaehlen und faellt
# auf den Standard-Server zurueck. Bei NPM ist das der Block aus
# /etc/nginx/conf.d/default.conf, und der antwortet mit
# "ssl_reject_handshake on" - im Browser als
# ERR_SSL_UNRECOGNIZED_NAME_ALERT.
#
# Ueber HTTP faellt das nicht auf: dort waehlt nginx den Server-Block
# anhand des Host-Kopfes aus, und der traegt die IP.
#
# Abhilfe ist ein eigener Block mit "default_server" in der
# Zusatzkonfiguration, die nginx nach den Proxy-Hosts einliest. Keiner
# der NPM-Bloecke setzt das Kennzeichen selbst, deshalb gibt es keinen
# Streit darum. Benannte Aufrufe gehen weiterhin an ihren Proxy-Host -
# der Standard-Server greift nur, wenn kein Name passt.
# =====================================================================
# Zertifikatspfade IM CONTAINER zu einer NPM-Zertifikats-ID
npm_cert_paths() { # id -> "fullchain|privkey|anbieter"
local cid="$1" o prov
o="$(npm_api GET "/api/nginx/certificates/$cid")" || return 1
prov="$(json_str "$o" provider)"
if [ "$prov" = letsencrypt ]; then
printf '/etc/letsencrypt/live/npm-%s/fullchain.pem|/etc/letsencrypt/live/npm-%s/privkey.pem|%s\n' \
"$cid" "$cid" "$prov"
else
printf '/data/custom_ssl/npm-%s/fullchain.pem|/data/custom_ssl/npm-%s/privkey.pem|%s\n' \
"$cid" "$cid" "${prov:-other}"
fi
}
# Deckt das Zertifikat die IP ab? Nur pruefbar, wenn die Datei hier liegt.
npm_cert_covers_ip() { # zertifikats-id ip
local cid="$1" ip="$2" f
f="$(npm_data_dir_abs)/custom_ssl/npm-$cid/fullchain.pem"
[ -r "$f" ] || return 0 # nicht pruefbar - dann auch nicht meckern
( set +o pipefail; openssl x509 -in "$f" -noout -text 2>/dev/null | grep -q "IP Address:$ip" )
}
# Einen Proxy-Host in einen Standard-Server-Block spiegeln
npm_default_write() { # conf objekt-json fullchain privkey domain
local f="$1" o="$2" full="$3" key="$4" dom="$5"
npm_conf_writable "$f" || return 1
local sch host port seg lp lsch lh lpo
sch="$(json_str "$o" forward_scheme)"; [ -n "$sch" ] || sch=http
host="$(json_str "$o" forward_host)"
port="$(json_num "$o" forward_port)"
mkdir -p "$(dirname "$f")"
touch "$f"
npm_conf_strip_marked "$f" "$NPM_DEF_START" "$NPM_DEF_END"
{
printf '%s\n' "$NPM_DEF_START"
cat <<EOF
# Standard-Server fuer HTTPS: greift, wenn der Browser keinen Namen
# mitschickt - das ist beim Aufruf ueber die blanke IP der Fall.
# Spiegelt den Proxy-Host "$dom".
# Erzeugt von scripts/cmk-manage.sh proxy default --domain $dom
server {
listen 443 ssl default_server;
EOF
if [ "${NPM_DISABLE_IPV6:-false}" != true ]; then
printf ' listen [::]:443 ssl default_server;\n'
fi
cat <<EOF
server_name _;
ssl_certificate $full;
ssl_certificate_key $key;
include conf.d/include/ssl-ciphers.conf;
access_log /data/logs/default_ssl_access.log standard;
error_log /data/logs/default_ssl_error.log warn;
client_max_body_size 0;
proxy_read_timeout 300s;
EOF
# Zusaetzliche Pfade zuerst - laengster Treffer gewinnt bei nginx
# ohnehin, aber so liest es sich wie im Proxy Manager.
while IFS= read -r seg; do
case "$seg" in *'"path"'*) : ;; *) continue ;; esac
lp="$(printf '%s' "$seg" | sed -n 's/.*"path":"\([^"]*\)".*/\1/p')"
lsch="$(printf '%s' "$seg" | sed -n 's/.*"forward_scheme":"\([^"]*\)".*/\1/p')"
lh="$(printf '%s' "$seg" | sed -n 's/.*"forward_host":"\([^"]*\)".*/\1/p')"
lpo="$(printf '%s' "$seg" | sed -n 's/.*"forward_port":\([0-9]*\).*/\1/p')"
[ -n "$lp" ] && [ -n "$lh" ] && [ -n "$lpo" ] || continue
[ -n "$lsch" ] || lsch=http
cat <<EOF
location $lp {
proxy_pass $lsch://$lh:$lpo;
proxy_http_version 1.1;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
}
EOF
done < <(printf '%s' "$o" | tr '}' '\n')
cat <<EOF
location / {
proxy_pass $sch://$host:$port;
proxy_http_version 1.1;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
}
}
EOF
printf '%s\n' "$NPM_DEF_END"
} >> "$f"
sed -i '/./,$!d' "$f"
}
npm_reload_hint() { # restart-flag
if [ -n "${1:-}" ] && container_running "$NPM_CONTAINER_NAME"; then
log "Starte '$NPM_CONTAINER_NAME' neu, damit nginx die Konfiguration liest ..."
if $RUNTIME restart "$NPM_CONTAINER_NAME" >/dev/null; then
ok "Proxy Manager neu gestartet."
else
warn "Neustart fehlgeschlagen - bitte manuell: $SELF restart"
fi
else
log "Wirksam nach: $SELF restart (bzw. Neustart des Proxy Managers)"
fi
}
cmd_proxy() {
local sub="${1:-list}"; [ $# -gt 0 ] && shift || true
@@ -3639,6 +3806,116 @@ cmd_proxy() {
echo
return 0 ;;
default|ip)
local dom="" off="" restart="" conf
while [ $# -gt 0 ]; do
case "$1" in
--domain) dom="$2"; shift 2 ;;
--off|--aus) off=1; shift ;;
--restart) restart=1; shift ;;
--help|-h)
cat <<EOF
HTTPS ueber die blanke IP ermoeglichen.
$SELF proxy default Stand anzeigen
$SELF proxy default --domain NAME Proxy-Host spiegeln
$SELF proxy default --off Spiegelung entfernen
Ruft man den Server als https://<IP>/ auf, schickt der Browser keinen
Namen mit (SNI kennt keine IP-Adressen). nginx kann den Proxy-Host dann
nicht ueber den Namen finden und faellt auf seinen Standard-Server
zurueck - der lehnt den Handshake ab: ERR_SSL_UNRECOGNIZED_NAME_ALERT.
Ueber HTTP faellt das nicht auf, dort entscheidet der Host-Kopf.
Dieser Befehl legt einen Standard-Server an, der denselben Weg nimmt wie
der genannte Proxy-Host - samt der zusaetzlichen Pfade. Aufrufe mit
Namen gehen weiterhin an ihren eigenen Proxy-Host.
EOF
return 0 ;;
*) dom="$1"; shift ;;
esac
done
conf="$(npm_custom_conf_path)"
if [ -n "$off" ]; then
if ! grep -qsF "$NPM_DEF_START" "$conf"; then
ok "Es ist kein Standard-Server eingetragen."
return 0
fi
npm_conf_strip_marked "$conf" "$NPM_DEF_START" "$NPM_DEF_END"
[ -s "$conf" ] || rm -f "$conf"
ok "Standard-Server entfernt: $conf"
npm_reload_hint "$restart"
return 0
fi
if [ -z "$dom" ]; then
printf '\n%sHTTPS ueber die blanke IP%s\n' "$C_BLD" "$C_RST"
if grep -qsF "$NPM_DEF_START" "$conf"; then
test_result ok "eingerichtet"
printf ' Datei : %s\n' "$conf"
printf ' Spiegelt: %s\n' \
"$(sed -n 's/^# Spiegelt den Proxy-Host "\(.*\)"\.$/\1/p' "$conf" | head -1)"
printf '\n Entfernen mit: %s proxy default --off\n\n' "$SELF"
else
test_result warn "nicht eingerichtet"
printf ' https://<IP>/ endet dann in
ERR_SSL_UNRECOGNIZED_NAME_ALERT, http://<IP>/ geht.\n'
printf '\n Einrichten mit: %s proxy default --domain <name-des-proxy-hosts>\n' "$SELF"
printf ' Vorhandene : %s proxy list\n\n' "$SELF"
fi
return 0
fi
npm_require_running || return 1
NPM_TOKEN="$(npm_api_token)" || return 1
# Proxy-Host zum Namen suchen
local all pid="" 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 - '$SELF proxy list' zeigt die vorhandenen."
local o cid
o="$(npm_api GET "/api/nginx/proxy-hosts/$pid")"
cid="$(json_num "$o" certificate_id)"
if [ -z "$cid" ] || [ "$cid" = 0 ]; then
die "Der Proxy-Host '$dom' hat kein Zertifikat.
Ohne Zertifikat gibt es nichts, was ohne SNI ausgeliefert werden koennte.
Erst eines zuweisen: $SELF proxy add --domain $dom --cert ... --update"
fi
local paths full key prov
paths="$(npm_cert_paths "$cid")" || die "Zertifikat $cid nicht abrufbar."
full="${paths%%|*}"; paths="${paths#*|}"
key="${paths%%|*}"; prov="${paths##*|}"
local ip; ip="$(primary_ip)"
if [ "$prov" = letsencrypt ]; then
warn "Das Zertifikat stammt von Lets Encrypt und lautet auf '$dom'.
Beim Aufruf ueber die IP meldet der Browser deshalb einen
Namensfehler (anklickbar, aber unschoen). Fuer den IP-Zugang ist
ein selbstsigniertes Zertifikat mit der IP als Alternativname
besser: $SELF cert --domain $dom --alt $ip"
elif [ -n "$ip" ] && ! npm_cert_covers_ip "$cid" "$ip"; then
warn "Das Zertifikat fuehrt die IP $ip nicht als Alternativnamen.
Der Browser meldet dann einen Namensfehler. Neu erzeugen mit:
$SELF cert --domain $dom --alt $ip
und dem Proxy-Host zuweisen."
fi
CMD_LINE="proxy default --domain $dom" npm_default_write "$conf" "$o" "$full" "$key" "$dom" || return 1
ok "Standard-Server geschrieben: $conf"
printf ' Spiegelt Proxy-Host %s (%s), Zertifikat %s (%s)\n' "$pid" "$dom" "$cid" "$prov"
if [ -n "$ip" ]; then printf ' Danach erreichbar unter: https://%s/\n' "$ip"; fi
npm_reload_hint "$restart"
return 0 ;;
del|delete|rm)
local pid=""
while [ $# -gt 0 ]; do
@@ -4970,6 +5247,7 @@ Ziel : ${PROXY_FORWARD_HOST:-127.0.0.1}:${PROXY_FORWARD_PORT:-5000}" \
list "Vorhandene Proxy-Hosts anzeigen" \
show "Einzelheiten eines Proxy-Hosts (mit Pfaden)" \
certs "Vorhandene Zertifikate anzeigen" \
ipzugang "HTTPS ueber die blanke IP (ohne Namen) ermoeglichen" \
del "Proxy-Host loeschen" \
status "Anmeldung pruefen" \
reset "Datenbank zuruecksetzen (Konto neu anlegen lassen)" \
@@ -4985,6 +5263,7 @@ Ziel : ${PROXY_FORWARD_HOST:-127.0.0.1}:${PROXY_FORWARD_PORT:-5000}" \
ui_text "Proxy-Host $d3" "$f3"; rm -f "$f3" ;;
certs) local f2; f2="$(mktemp)"; NO_COLOR=1 cmd_proxy certs >"$f2" 2>&1 || true
ui_text "Zertifikate" "$f2"; rm -f "$f2" ;;
ipzugang) gui_proxy_default || true ;;
del) gui_proxy_del || true ;;
status) ui_run "Anmeldung pruefen" bash -c "cd '$PROJECT_DIR' && NO_COLOR=1 '$SELF' proxy status" ;;
reset) gui_npm_reset || true ;;
@@ -4993,6 +5272,49 @@ Ziel : ${PROXY_FORWARD_HOST:-127.0.0.1}:${PROXY_FORWARD_PORT:-5000}" \
done
}
gui_proxy_default() {
local f rc=0
f="$(mktemp)"
NO_COLOR=1 cmd_proxy default >"$f" 2>&1 || true
ui_text "HTTPS ueber die blanke IP" "$f"; rm -f "$f"
local sel
sel="$(ui_menu "HTTPS ueber die blanke IP" \
"Ruft man den Server als https://<IP>/ auf, schickt der Browser keinen
Namen mit - SNI kennt keine IP-Adressen. nginx findet den Proxy-Host
dann nicht und lehnt den Handshake ab (ERR_SSL_UNRECOGNIZED_NAME_ALERT).
Ueber http://<IP>/ faellt das nicht auf, dort zaehlt der Host-Kopf.
Ein Standard-Server nimmt genau diese Aufrufe an und geht denselben Weg
wie der gewaehlte Proxy-Host, samt seiner zusaetzlichen Pfade.
Aufrufe mit Namen bleiben unberuehrt." \
ein "Einrichten - Proxy-Host spiegeln" \
aus "Entfernen" \
back "zurueck")" || return 0
case "$sel" in
back) return 0 ;;
aus) ui_run "Standard-Server entfernen" bash -c \
"cd '$PROJECT_DIR' && NO_COLOR=1 '$SELF' proxy default --off --restart" || true
return 0 ;;
esac
local dom
dom="$(ui_input "Einrichten" "Name des Proxy-Hosts, der gespiegelt werden soll:" \
"${PROXY_DOMAIN:-}")" || return 0
[ -n "$dom" ] || return 0
f="$(mktemp)"
NO_COLOR=1 cmd_proxy default --domain "$dom" --restart >"$f" 2>&1 || rc=$?
if [ "$rc" -eq 0 ]; then
ui_text "Standard-Server eingerichtet" "$f"
else
ui_text "Einrichten fehlgeschlagen" "$f"
fi
rm -f "$f"
return 0
}
gui_proxy_add() {
if ! npm_require_running 2>/dev/null; then
ui_msg "Proxy Manager laeuft nicht" \