- testwebserver/: eigenstaendiger Python-Webserver (python:3.12-alpine, kein Build), Port/TLS/Text in .env, zeigt Client-IP und loggt jeden Zugriff - start.sh: erkennt Docker/Podman (inkl. rootless Port-Grenze), prueft Port-Konflikte, erzeugt bei TLS=yes ein selbstsigniertes Zertifikat, Befehle up/down/restart/logs/ps/test/firewall - firewall-check.sh: erkennt auch HTTP-Dienste ohne TLS als erreichbar - .gitignore: testwebserver/.env versionieren, testwebserver/certs/ ausschliessen - README: Abschnitt Testwebserver Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
103 lines
4.9 KiB
Bash
Executable File
103 lines
4.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# Testwebserver starten/stoppen - erkennt Docker oder Podman selbst (wie ../setup.sh).
|
|
#
|
|
# ./start.sh starten (= up)
|
|
# ./start.sh down stoppen und entfernen
|
|
# ./start.sh restart neu starten (z.B. nach Aenderung der .env)
|
|
# ./start.sh logs Zugriffe live ansehen (jede Anfrage mit Client-IP)
|
|
# ./start.sh ps Status
|
|
# ./start.sh test lokal aufrufen und Adresse fuer den Test von aussen anzeigen
|
|
# ./start.sh firewall ../firewall-check.sh fuer diesen Port (Optionen werden durchgereicht)
|
|
#
|
|
# Port, TLS und Text stehen in .env. Erkennung uebersteuern: CONTAINER_ENGINE=docker|podman
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")"
|
|
|
|
info() { echo -e "\e[1;32m==>\e[0m $*"; }
|
|
warn() { echo -e "\e[1;33m!!\e[0m $*" >&2; }
|
|
die() { echo -e "\e[1;31mFEHLER:\e[0m $*" >&2; exit 1; }
|
|
env_get() { grep "^$1=" .env 2>/dev/null | cut -d= -f2- || true; }
|
|
|
|
PORT=$(env_get PORT); PORT=${PORT:-8080}
|
|
TLS=$(env_get TLS); TLS=${TLS:-no}
|
|
[[ $PORT =~ ^[0-9]+$ ]] || die "PORT in .env ist keine Zahl: $PORT"
|
|
SCHEME=http; [[ ${TLS,,} =~ ^(yes|true|1)$ ]] && SCHEME=https
|
|
|
|
ENGINE="${CONTAINER_ENGINE:-}"
|
|
if [ -z "$ENGINE" ]; then
|
|
if command -v docker >/dev/null 2>&1 && ! docker --version 2>/dev/null | grep -qi podman; then ENGINE=docker
|
|
elif command -v podman >/dev/null 2>&1; then ENGINE=podman
|
|
else die "Weder Docker noch Podman gefunden"; fi
|
|
fi
|
|
case "$ENGINE" in
|
|
docker)
|
|
if docker compose version >/dev/null 2>&1; then DC=(docker compose)
|
|
elif command -v docker-compose >/dev/null 2>&1; then DC=(docker-compose)
|
|
else die "Docker Compose fehlt"; fi ;;
|
|
podman)
|
|
if command -v podman-compose >/dev/null 2>&1; then DC=(podman-compose)
|
|
elif podman compose version >/dev/null 2>&1; then DC=(podman compose)
|
|
else die "podman-compose fehlt (RHEL: EPEL aktivieren, dnf install podman-compose)"; fi
|
|
# Rootless Podman darf nur Ports ab ip_unprivileged_port_start (meist 1024) belegen
|
|
if [ "$(podman info --format '{{.Host.Security.Rootless}}' 2>/dev/null)" = true ]; then
|
|
min=$(cat /proc/sys/net/ipv4/ip_unprivileged_port_start 2>/dev/null || echo 1024)
|
|
[ "$PORT" -ge "$min" ] || die "Rootless Podman kann Port $PORT nicht belegen (erst ab $min). Hoeheren Port in .env oder: sudo ./start.sh"
|
|
fi ;;
|
|
*) die "CONTAINER_ENGINE muss docker oder podman sein" ;;
|
|
esac
|
|
|
|
make_cert() {
|
|
[ "$SCHEME" = https ] || return 0
|
|
[ -s certs/server.crt ] && [ -s certs/server.key ] && return 0
|
|
command -v openssl >/dev/null || die "TLS=yes braucht openssl auf dem Host (RHEL: dnf install openssl)"
|
|
info "Erzeuge selbstsigniertes Zertifikat (certs/)"
|
|
mkdir -p certs
|
|
openssl req -x509 -newkey rsa:2048 -nodes -days 825 -subj "/CN=$(uname -n)" \
|
|
-keyout certs/server.key -out certs/server.crt 2>/dev/null
|
|
chmod 644 certs/server.key # Container liest als anderer Benutzer; reiner Testschluessel
|
|
}
|
|
|
|
my_ip() { ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<NF;i++) if($i=="src") print $(i+1)}' | head -1; }
|
|
|
|
cmd_test() {
|
|
local code
|
|
code=$(curl -sk --max-time 5 -o /dev/null -w '%{http_code}' "$SCHEME://127.0.0.1:$PORT/health" || true)
|
|
if [ "$code" = 200 ]; then info "Lokal OK: $SCHEME://127.0.0.1:$PORT"
|
|
else warn "Lokal keine Antwort ($SCHEME://127.0.0.1:$PORT, Code ${code:-000}) - laeuft er? ./start.sh ps / logs"; fi
|
|
echo "Von einem anderen Rechner testen: curl -k $SCHEME://$(my_ip):$PORT/ (oder im Browser)"
|
|
echo "Kommt nichts an, zeigt './start.sh logs' keinen Zugriff -> Firewall: sudo ./start.sh firewall"
|
|
}
|
|
|
|
port_free() {
|
|
# Belegt, aber nicht von uns? Dann klar melden statt kryptischer Engine-Fehlermeldung.
|
|
local used
|
|
used=$(ss -Hltnp "sport = :$PORT" 2>/dev/null) || return 0
|
|
[ -z "$used" ] && return 0
|
|
# Unser eigener, schon laufender Container auf genau diesem Port ist kein Konflikt
|
|
"$ENGINE" ps --format '{{.Names}} {{.Ports}}' 2>/dev/null | grep testwebserver | grep -q ":$PORT->" && return 0
|
|
local who; who=$(echo "$used" | grep -o 'users:(("[^"]*' | head -1 | cut -d'"' -f2 || true)
|
|
die "Port $PORT ist schon belegt${who:+ (Prozess: $who)}. Anderen PORT in .env eintragen."
|
|
}
|
|
|
|
mkdir -p certs # wird immer gemountet, auch ohne TLS
|
|
case "${1:-up}" in
|
|
up)
|
|
port_free
|
|
make_cert
|
|
info "Starte Testwebserver mit $ENGINE (${DC[*]}) auf Port $PORT ($SCHEME)"
|
|
"${DC[@]}" up -d
|
|
sleep 2
|
|
cmd_test ;;
|
|
down) "${DC[@]}" down ;;
|
|
restart) make_cert; "${DC[@]}" down; port_free; "${DC[@]}" up -d; sleep 2; cmd_test ;;
|
|
logs) "${DC[@]}" logs -f ;;
|
|
ps) "${DC[@]}" ps ;;
|
|
test) cmd_test ;;
|
|
firewall)
|
|
shift
|
|
[ -x ../firewall-check.sh ] || die "../firewall-check.sh nicht gefunden"
|
|
extra=(); [ "$SCHEME" = http ] && extra=(--tcp)
|
|
../firewall-check.sh --port "$PORT" "${extra[@]}" "$@" ;;
|
|
*) sed -n '2,13p' "$0"; exit 2 ;;
|
|
esac
|