308 lines
11 KiB
Bash
Executable File
308 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# =====================================================================
|
|
# install.sh - Installation des Checkmk-/NGINX-Proxy-Manager-Stacks
|
|
#
|
|
# Debian/Ubuntu : Docker CE + Compose-Plugin
|
|
# RHEL/Rocky/Alma/CentOS/Fedora : Podman + podman-compose
|
|
#
|
|
# Zusaetzlich: dialog (ncurses-Oberflaeche), openssl, tar, curl
|
|
# =====================================================================
|
|
set -euo pipefail
|
|
|
|
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
. "$PROJECT_DIR/scripts/lib/common.sh"
|
|
|
|
WITH_SYSTEMD=""
|
|
WITH_QUADLET=""
|
|
SKIP_RUNTIME=""
|
|
ROOTLESS=""
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
install.sh - Installation des Checkmk-Container-Stacks
|
|
|
|
OPTIONEN
|
|
--with-systemd systemd-Unit einrichten, damit der Stack nach einem
|
|
Neustart des Hosts automatisch wieder startet
|
|
(Vorgabe bei Podman)
|
|
--quadlet statt der Compose-Unit Podman-Quadlet-Dateien
|
|
(/etc/containers/systemd/) einrichten
|
|
--rootless Podman rootless vorbereiten (linger + Ports ab 80)
|
|
--skip-runtime Docker/Podman nicht installieren (nur Projekt einrichten)
|
|
-h, --help Hilfe
|
|
EOF
|
|
}
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--with-systemd) WITH_SYSTEMD=1; shift ;;
|
|
--quadlet) WITH_QUADLET=1; WITH_SYSTEMD=1; shift ;;
|
|
--rootless) ROOTLESS=1; shift ;;
|
|
--skip-runtime) SKIP_RUNTIME=1; shift ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) die "Unbekannte Option: $1" ;;
|
|
esac
|
|
done
|
|
|
|
[ "$(id -u)" -eq 0 ] || die "Bitte als root ausfuehren: sudo ./install.sh"
|
|
|
|
# ---------------------------------------------------------------------
|
|
# Distribution erkennen
|
|
# ---------------------------------------------------------------------
|
|
[ -r /etc/os-release ] || die "/etc/os-release nicht lesbar - Distribution unbekannt."
|
|
# shellcheck disable=SC1091
|
|
. /etc/os-release
|
|
OS_ID="${ID:-unknown}"
|
|
OS_LIKE="${ID_LIKE:-}"
|
|
OS_NAME="${PRETTY_NAME:-$OS_ID}"
|
|
|
|
FAMILY=""
|
|
case "$OS_ID" in
|
|
debian|ubuntu|linuxmint|raspbian|pop) FAMILY=debian ;;
|
|
rhel|centos|rocky|almalinux|fedora|ol|oracle|scientific) FAMILY=rhel ;;
|
|
*)
|
|
case " $OS_LIKE " in
|
|
*debian*) FAMILY=debian ;;
|
|
*rhel*|*fedora*|*centos*) FAMILY=rhel ;;
|
|
esac
|
|
;;
|
|
esac
|
|
[ -n "$FAMILY" ] || die "Nicht unterstuetzte Distribution: $OS_NAME"
|
|
|
|
printf '\n%s=== Checkmk Container-Stack - Installation ===%s\n\n' "$C_BLD" "$C_RST"
|
|
log "System : $OS_NAME"
|
|
log "Familie : $FAMILY"
|
|
log "Projektpfad : $PROJECT_DIR"
|
|
|
|
# ---------------------------------------------------------------------
|
|
# Runtime installieren
|
|
# ---------------------------------------------------------------------
|
|
install_debian() {
|
|
log "Installiere Docker CE aus dem offiziellen Docker-Repository ..."
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
apt-get update -qq
|
|
apt-get install -y ca-certificates curl gnupg tar dialog openssl
|
|
|
|
if [ "$OS_ID" = debian ] || [ "$OS_ID" = ubuntu ]; then
|
|
install -m 0755 -d /etc/apt/keyrings
|
|
if [ ! -f /etc/apt/keyrings/docker.asc ]; then
|
|
curl -fsSL "https://download.docker.com/linux/$OS_ID/gpg" -o /etc/apt/keyrings/docker.asc
|
|
chmod a+r /etc/apt/keyrings/docker.asc
|
|
fi
|
|
local codename="${VERSION_CODENAME:-}"
|
|
[ -n "$codename" ] || codename="$(. /etc/os-release && echo "${UBUNTU_CODENAME:-stable}")"
|
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/$OS_ID $codename stable" \
|
|
>/etc/apt/sources.list.d/docker.list
|
|
apt-get update -qq
|
|
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
else
|
|
warn "Abgeleitete Distribution ($OS_NAME) - verwende die Distributionspakete."
|
|
apt-get install -y docker.io docker-compose
|
|
fi
|
|
|
|
systemctl enable --now docker
|
|
ok "Docker installiert: $(docker --version)"
|
|
}
|
|
|
|
install_rhel() {
|
|
log "Installiere Podman ..."
|
|
local PM=dnf
|
|
command -v dnf >/dev/null 2>&1 || PM=yum
|
|
$PM install -y podman tar dialog openssl || die "Podman-Installation fehlgeschlagen."
|
|
|
|
# podman-compose besorgen (Reihenfolge: Distro-Repo -> EPEL -> pip)
|
|
if ! command -v podman-compose >/dev/null 2>&1; then
|
|
log "Suche podman-compose ..."
|
|
if ! $PM install -y podman-compose 2>/dev/null; then
|
|
if [ "$OS_ID" != fedora ]; then
|
|
local rel; rel="${VERSION_ID%%.*}"
|
|
log "Aktiviere EPEL ${rel} ..."
|
|
$PM install -y "https://dl.fedoraproject.org/pub/epel/epel-release-latest-${rel}.noarch.rpm" 2>/dev/null || true
|
|
$PM install -y podman-compose 2>/dev/null || true
|
|
fi
|
|
fi
|
|
fi
|
|
if ! command -v podman-compose >/dev/null 2>&1; then
|
|
log "Versuche podman-compose per pip ..."
|
|
$PM install -y python3-pip 2>/dev/null || true
|
|
pip3 install --quiet podman-compose 2>/dev/null || true
|
|
fi
|
|
|
|
if command -v podman-compose >/dev/null 2>&1; then
|
|
ok "podman-compose vorhanden: $(podman-compose --version 2>&1 | head -n1)"
|
|
else
|
|
warn "podman-compose konnte nicht installiert werden.
|
|
Alternative: Installation ueber Quadlet ( ./install.sh --quadlet ),
|
|
dafuer wird kein Compose benoetigt."
|
|
fi
|
|
ok "Podman installiert: $(podman --version)"
|
|
|
|
# SELinux: Bind-Mounts brauchen den passenden Kontext (:Z ist im Compose gesetzt)
|
|
if command -v getenforce >/dev/null 2>&1 && [ "$(getenforce)" = "Enforcing" ]; then
|
|
log "SELinux ist aktiv - die Bind-Mounts sind im Compose mit ':Z' versehen."
|
|
fi
|
|
}
|
|
|
|
if [ -z "$SKIP_RUNTIME" ]; then
|
|
case "$FAMILY" in
|
|
debian) install_debian ;;
|
|
rhel) install_rhel ;;
|
|
esac
|
|
else
|
|
log "Runtime-Installation uebersprungen (--skip-runtime)."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------
|
|
# Projekt vorbereiten
|
|
# ---------------------------------------------------------------------
|
|
log "Bereite Projektverzeichnis vor ..."
|
|
mkdir -p "$PROJECT_DIR/data/checkmk/sites" \
|
|
"$PROJECT_DIR/data/npm/data" \
|
|
"$PROJECT_DIR/data/npm/letsencrypt" \
|
|
"$PROJECT_DIR/data/npm/custom-certs" \
|
|
"$PROJECT_DIR/backups"
|
|
chmod +x "$PROJECT_DIR"/scripts/*.sh "$PROJECT_DIR/install.sh" 2>/dev/null || true
|
|
|
|
if [ ! -f "$PROJECT_DIR/.env" ]; then
|
|
cp "$PROJECT_DIR/.env.example" "$PROJECT_DIR/.env"
|
|
chmod 600 "$PROJECT_DIR/.env"
|
|
ok ".env aus .env.example erzeugt - bitte Passwort und Site-Namen anpassen!"
|
|
else
|
|
log ".env ist bereits vorhanden - bleibt unveraendert."
|
|
fi
|
|
|
|
load_env "$PROJECT_DIR/.env"
|
|
detect_runtime
|
|
ok "Verwendete Runtime: $RUNTIME"
|
|
|
|
# Podman: Autostart nach Reboot ohne systemd-Unit funktioniert nicht ->
|
|
# Unit standardmaessig einrichten.
|
|
if [ "$RUNTIME" = podman ] && [ -z "$WITH_SYSTEMD" ]; then
|
|
warn "Podman hat keinen Daemon: ohne systemd-Unit starten die Container
|
|
nach einem Reboot NICHT automatisch. Die Unit wird jetzt eingerichtet."
|
|
WITH_SYSTEMD=1
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------
|
|
# Rootless-Vorbereitung (optional)
|
|
# ---------------------------------------------------------------------
|
|
if [ -n "$ROOTLESS" ]; then
|
|
log "Bereite rootless-Betrieb vor ..."
|
|
echo 'net.ipv4.ip_unprivileged_port_start=80' >/etc/sysctl.d/99-checkmk-rootless.conf
|
|
sysctl -q --system || true
|
|
ok "Unprivilegierte Ports ab 80 erlaubt."
|
|
warn "Zusaetzlich noetig: loginctl enable-linger <benutzer>
|
|
und die Unit als '--user'-Unit einrichten (siehe README)."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------
|
|
# systemd
|
|
# ---------------------------------------------------------------------
|
|
install_compose_unit() {
|
|
local compose_bin
|
|
detect_compose
|
|
compose_bin="${COMPOSE_CMD[*]}"
|
|
|
|
log "Richte systemd-Unit 'checkmk-stack.service' ein ..."
|
|
cat >/etc/systemd/system/checkmk-stack.service <<EOF
|
|
[Unit]
|
|
Description=Checkmk + NGINX Proxy Manager (Container-Stack)
|
|
Documentation=file://$PROJECT_DIR/README.md
|
|
Wants=network-online.target
|
|
After=network-online.target
|
|
$([ "$RUNTIME" = docker ] && echo "Requires=docker.service" || true)
|
|
$([ "$RUNTIME" = docker ] && echo "After=docker.service" || true)
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
RemainAfterExit=yes
|
|
WorkingDirectory=$PROJECT_DIR
|
|
EnvironmentFile=$PROJECT_DIR/.env
|
|
TimeoutStartSec=0
|
|
ExecStart=/bin/sh -c '$compose_bin up -d'
|
|
ExecStartPost=$PROJECT_DIR/scripts/cmk-manage.sh start-all-sites
|
|
ExecStop=/bin/sh -c '$compose_bin down'
|
|
ExecReload=/bin/sh -c '$compose_bin up -d'
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
systemctl daemon-reload
|
|
systemctl enable checkmk-stack.service
|
|
ok "Unit aktiviert. Steuerung: systemctl start|stop|status checkmk-stack"
|
|
}
|
|
|
|
install_quadlet_units() {
|
|
log "Richte Podman-Quadlet-Units ein (/etc/containers/systemd/) ..."
|
|
[ -d /etc/containers/systemd ] || mkdir -p /etc/containers/systemd
|
|
local f
|
|
for f in "$PROJECT_DIR"/systemd/quadlet/*.container; do
|
|
sed -e "s|__PROJECT_DIR__|$PROJECT_DIR|g" \
|
|
-e "s|__CMK_IMAGE__|${CMK_IMAGE_REPO:-checkmk/check-mk-raw}:${CMK_IMAGE_TAG:-2.3.0-latest}|g" \
|
|
-e "s|__NPM_IMAGE__|${NPM_IMAGE:-jc21/nginx-proxy-manager:2}|g" \
|
|
-e "s|__CMK_SITE_ID__|${CMK_SITE_ID:-cmk}|g" \
|
|
-e "s|__CMK_CONTAINER_NAME__|${CMK_CONTAINER_NAME:-checkmk}|g" \
|
|
-e "s|__NPM_CONTAINER_NAME__|${NPM_CONTAINER_NAME:-nginx-proxy-manager}|g" \
|
|
"$f" >"/etc/containers/systemd/$(basename "$f")"
|
|
done
|
|
systemctl daemon-reload
|
|
ok "Quadlet-Units geschrieben. Start: systemctl start checkmk nginx-proxy-manager"
|
|
log "Die Units starten durch 'WantedBy=multi-user.target' automatisch nach einem Reboot."
|
|
}
|
|
|
|
if [ -n "$WITH_SYSTEMD" ]; then
|
|
if [ -n "$WITH_QUADLET" ]; then
|
|
[ "$RUNTIME" = podman ] || die "--quadlet ist nur mit Podman moeglich."
|
|
install_quadlet_units
|
|
else
|
|
install_compose_unit
|
|
fi
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------
|
|
# Firewall-Hinweise
|
|
# ---------------------------------------------------------------------
|
|
print_firewall_hint() {
|
|
if command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then
|
|
cat <<'EOF'
|
|
|
|
Firewall (firewalld) - empfohlene Regeln:
|
|
firewall-cmd --permanent --add-service=http
|
|
firewall-cmd --permanent --add-service=https
|
|
firewall-cmd --permanent --add-port=8000/tcp # Agent-Receiver
|
|
# Admin-Oberflaeche des Proxy Managers nur aus dem Admin-Netz:
|
|
firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.0.0/24 port port=81 protocol=tcp accept'
|
|
# Checkmk-Port 5000 NICHT nach aussen oeffnen (nur ueber den Proxy)
|
|
firewall-cmd --reload
|
|
EOF
|
|
elif command -v ufw >/dev/null 2>&1; then
|
|
cat <<'EOF'
|
|
|
|
Firewall (ufw) - empfohlene Regeln:
|
|
ufw allow 80/tcp
|
|
ufw allow 443/tcp
|
|
ufw allow 8000/tcp # Agent-Receiver
|
|
ufw allow from 10.0.0.0/24 to any port 81 proto tcp # Proxy-Manager-Admin
|
|
# Port 5000 (Checkmk direkt) bleibt zu - Zugriff nur ueber den Proxy
|
|
EOF
|
|
fi
|
|
}
|
|
print_firewall_hint
|
|
|
|
cat <<EOF
|
|
|
|
${C_BLD}Installation abgeschlossen.${C_RST}
|
|
|
|
Naechste Schritte:
|
|
1) Konfiguration anpassen:
|
|
\$EDITOR $PROJECT_DIR/.env (CMK_SITE_ID, CMK_PASSWORD, TZ ...)
|
|
2) Stack starten:
|
|
$PROJECT_DIR/scripts/cmk-manage.sh up
|
|
3) NGINX Proxy Manager oeffnen:
|
|
http://$(primary_ip):81 Erstlogin: admin@example.com / changeme
|
|
4) Verwaltung / Backup / Migration - ncurses-Oberflaeche:
|
|
$PROJECT_DIR/scripts/cmk-manage.sh gui
|
|
|
|
Alles Weitere steht in der README.md.
|
|
EOF
|