Files
docker-podman-installation-…/README.md
T
duffyduckandClaude Opus 5 06ae4807ba Firewall: Ports auch wieder zumachen
"firewall open" kannte nur eine Richtung. Wer die Event Console wieder
abschaltet oder einen Eintrag aus FW_EXTRA_PORTS streicht, behielt die
Freigabe - der Port stand offen, ohne dass noch etwas dahinter lauscht.

"firewall close" bietet an, was offen ist, zu diesem Aufbau gehoert und
gerade nicht gebraucht wird. Dazu zaehlen die bekannten Ports des Stacks
und alles, was "firewall open --apply" selbst geoeffnet hat; das merkt
sich firewall-opened.conf, damit ein gestrichener FW_EXTRA_PORTS-Eintrag
nicht in Vergessenheit geraet.

Drei Sicherungen, weil hier das Aussperren droht:

  - SSH wird nie geschlossen: Port 22, der Port aus "sshd -T" und der
    Port der laufenden Sitzung aus SSH_CONNECTION
  - fremde Freigaben bleiben unberuehrt - wer 3306 fuer seine Datenbank
    offen hat, behaelt sie
  - Sammelregeln wie "80,443/tcp" werden gemeldet statt geloescht, sonst
    faellt ein noch gebrauchter Port mit weg

Bei ufw wird bewusst nicht nach Regelnummern geloescht. Die Nummern
verschieben sich beim ersten Loeschen, und da je Port ein eigener
Aufruf erzeugt wird, haette der naechste die falsche Regel getroffen -
im Test waere so eine 443er-Freigabe gefallen. Geloescht wird ueber die
Regelangabe, bei nftables ueber den Handle, bei iptables mit derselben
Angabe, mit der die Regel eingetragen wurde.

Nebenbei: fw_state_del liess die Datei stehen, wenn der letzte Eintrag
entfernt wurde - "grep -v" liefert dann 1. Unter "set -e" brach damit
ausserdem der Ablauf ab, noch vor dem Neuladen der Firewall.

In der Oberflaeche liegt das unter Einstellungen > Firewall als
"Nicht mehr benoetigte Ports schliessen".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 20:40:02 +02:00

117 KiB
Raw Blame History

Checkmk im Container – Docker (Debian) & Podman (RHEL) mit NGINX Proxy Manager

English version: README_en.md

Vollständige, produktionstaugliche Container-Installation von Checkmk mit NGINX Proxy Manager als HTTPS-Terminierung (Let's Encrypt oder selbstsigniert), inklusive Werkzeugen für Backup, Restore und die Migration bestehender Sites von einer Direktinstallation – ohne dass die Agents neu eingerichtet werden müssen.


Inhaltsverzeichnis

  1. Überblick & Architektur
  2. Verzeichnisstruktur
  3. Voraussetzungen & Ports
  4. Installation auf Debian/Ubuntu (Docker)
  5. Installation auf RHEL/Rocky/Alma/Fedora (Podman)
  6. Autostart nach einem Neustart des Hosts (Podman)
  7. Konfiguration (.env)
  8. Checkmk-Image beschaffen (Raw, Enterprise & Co.)
  9. Erststart
  10. HTTPS einrichten – Let's Encrypt oder selbstsigniert
  11. Proxy Manager lokal einrichten (Terminal-Browser)
  12. Adminoberfläche auf einen anderen Port legen
  13. Firewall
  14. Verwaltung: cmk-manage.sh (CLI und ncurses-Oberfläche)
  15. Backup
  16. Restore
  17. Migration einer Direktinstallation (migrate_creator.sh)
  18. Mehrere Sites in einem Container
  19. Checkmk aktualisieren
  20. Fehlersuche
  21. Sicherheitshinweise
  22. Deinstallation

1. Überblick & Architektur

                    Internet / LAN
                          |
                     :80  :443  :81
                          |
        +-----------------------------------+
        |  NGINX Proxy Manager (Container)  |   network_mode: host
        |  - Let's Encrypt ODER self-signed |
        |  - Weboberfläche auf Port 81      |
        +-----------------------------------+
                          |  http://127.0.0.1:5000
                          v
        +-----------------------------------+
        |  Checkmk / OMD (Container)        |   network_mode: host
        |  :5000  Web-GUI (Apache)          |
        |  :8000  Agent-Receiver            |   <-- Agents (cmk-agent-ctl)
        |  :6557  Livestatus (optional)     |
        +-----------------------------------+
                          |
             Bind-Mount: ./data/checkmk/sites  ->  /omd/sites

Bewusste Entwurfsentscheidungen

Punkt Umsetzung Grund
Checkmk im Host-Netzwerk network_mode: host, keine ports:-Angaben Agents, SNMP-Traps, ICMP und der Agent-Receiver arbeiten ohne NAT; die Quell-IP der überwachten Hosts bleibt erhalten
NGINX Proxy Manager ebenfalls im Host-Netzwerk network_mode: host erreicht das Checkmk-Backend direkt über 127.0.0.1:5000; kein Bridge-Netz, keine host-gateway-Tricks nötig – funktioniert unter Docker und Podman identisch
Keine Named Volumes ausschließlich Bind-Mounts nach ./data/ alle Daten liegen sichtbar im Projektverzeichnis, einfach zu sichern, zu kopieren und zu prüfen
Eine Compose-Datei für beides docker compose und podman-compose identische Bedienung auf Debian und RHEL
:Z an den Bind-Mounts SELinux-Relabeling nötig unter RHEL; unter Debian/Docker wirkungslos (kein Fehler)

2. Verzeichnisstruktur

.
├── README.md                        # deutsche Dokumentation
├── README_en.md                     # englische Fassung
├── docker-compose.yml               # für Docker UND Podman
├── .env.example                     # Vorlage -> .env
├── install.sh                       # Installation Docker (Debian) / Podman (RHEL)
│
├── scripts/
│   ├── cmk-manage.sh                # Stack, Backup, Restore, Import + ncurses-GUI
│   ├── migrate_creator.sh           # -> auf den QUELLSERVER kopieren
│   └── lib/
│       └── common.sh                # gemeinsame Funktionen + TUI-Helfer
│
├── containers/
│   └── browser/
│       └── Containerfile        # Werkzeug-Image: Textbrowser, curl, jq, openssl
│
├── systemd/
│   ├── checkmk-stack.service.example # Compose-basierte Unit (Autostart)
│   └── quadlet/
│       ├── checkmk.container         # Podman-Quadlet (Alternative)
│       └── nginx-proxy-manager.container
│
├── data/                            # ALLE Nutzdaten (Bind-Mounts)
│   ├── checkmk/sites/               # -> /omd/sites   (komplette OMD-Sites)
│   └── npm/
│       ├── data/                    # -> /data            (NPM-Konfiguration/DB)
│       ├── letsencrypt/             # -> /etc/letsencrypt (Zertifikate)
│       └── custom-certs/            # selbstsignierte Zertifikate zum Hochladen
│
├── backups/                         # Backups und Migrations-Bundles (*.tar.gz)
└── images/                          # heruntergeladene Checkmk-Image-Tarballs

3. Voraussetzungen & Ports

  • 64-Bit-Linux, mind. 2 CPU-Kerne, 4 GB RAM (Empfehlung: 4 Kerne, 8 GB)
  • Plattenplatz: Faustregel 1 GB je 100 überwachte Hosts und Jahr, plus Backups
  • root-Rechte
  • Ausgehender Internetzugang für den Image-Download

Belegte Ports (Host-Netzwerk!)

Port Dienst Erreichbar von
80/tcp NGINX Proxy Manager – HTTP, Let's-Encrypt-Challenge Internet/LAN
443/tcp NGINX Proxy Manager – HTTPS Internet/LAN
81/tcp NGINX Proxy Manager – Adminoberfläche (Vorgabe; per npm-port änderbar) nur Admin-Netz!
5000/tcp Checkmk Apache (Backend) nur localhost – nicht freigeben. Ausnahme: bei abgeschaltetem Proxy Manager (12.4) nur für die IP des externen Proxys
8000/tcp Checkmk Agent-Receiver (TLS-registrierte Agents) überwachte Hosts
6557/tcp Livestatus (nur bei CMK_LIVESTATUS_TCP=on) verteilte Sites

Wichtig: Da beide Container im Host-Netzwerk laufen, dürfen die Ports 80, 443 und 81 auf dem Host nicht bereits belegt sein (z. B. durch einen installierten Apache/NGINX). Prüfen mit ss -tlnp | grep -E ':(80|81|443|5000)\b'.


4. Installation auf Debian/Ubuntu (Docker)

# Projekt an den gewünschten Ort legen
sudo mkdir -p /opt/checkmk-stack
sudo cp -r ./* ./.env.example /opt/checkmk-stack/
cd /opt/checkmk-stack

# Docker CE + Compose-Plugin installieren, Projekt vorbereiten
sudo ./install.sh --with-systemd

install.sh erledigt dabei:

  1. Docker-Repository von download.docker.com einbinden (GPG-Key + Sources-Liste)
  2. docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin, docker-compose-plugin installieren
  3. dialog, openssl, tar, curl installieren (für die ncurses-Oberfläche)
  4. systemctl enable --now docker
  5. Verzeichnisse unter data/ und backups/ anlegen, .env aus .env.example erzeugen
  6. optional die systemd-Unit checkmk-stack.service einrichten

Anschließend:

sudo $EDITOR /opt/checkmk-stack/.env     # mindestens CMK_PASSWORD und CMK_SITE_ID

# Image festlegen (Raw geht ohne Anmeldung, Enterprise siehe Kapitel 8)
sudo ./scripts/cmk-manage.sh image pull --edition raw --version 2.3.0-latest

sudo ./scripts/cmk-manage.sh up
sudo ./scripts/cmk-manage.sh status

Unter Docker sorgt bereits restart: unless-stopped dafür, dass die Container nach einem Reboot wieder starten (der Docker-Daemon startet sie). Die systemd-Unit ist trotzdem sinnvoll, weil sie zusätzlich alle Sites startet (siehe Kapitel 18).


5. Installation auf RHEL/Rocky/Alma/Fedora (Podman)

Auf Red-Hat-Systemen steht Docker nicht zur Verfügung – hier wird Podman verwendet. Die Compose-Datei ist dieselbe.

Schritt 0 bei RHEL: Subskription prüfen

Ein nicht registriertes RHEL installiert überhaupt keine Pakete – weder podman noch git, dialog oder tar. dnf meldet dann nur „This system is not registered with an entitlement server". Das ist der häufigste Grund, warum install.sh auf einem frischen RHEL nicht durchläuft.

# Ist das System registriert?
sudo subscription-manager status      # -> "Overall Status: Current" = in Ordnung
sudo dnf repolist                     # -> darf nicht leer sein

# Falls nicht: kostenloses Konto auf https://developers.redhat.com anlegen
# (Developer Subscription for Individuals, bis zu 16 Systeme) und dann:
sudo subscription-manager register --username <benutzer>

RHEL 9 nutzt Simple Content Access, ein subscription-manager attach ist nicht mehr nötig. Ohne Konto geht es auch per Installations-DVD oder durch den Wechsel auf Rocky/Alma – alle drei Wege stehen ausführlich in Abschnitt 5.1.

Rocky Linux, AlmaLinux, CentOS Stream und Fedora brauchen nichts davon – dort einfach weiterlesen.

sudo mkdir -p /opt/checkmk-stack
sudo cp -r ./* ./.env.example /opt/checkmk-stack/
cd /opt/checkmk-stack

sudo ./install.sh --with-systemd

install.sh installiert dabei:

  1. prüft zuerst, ob überhaupt ein nutzbares Repository vorhanden ist, und nennt andernfalls die drei Wege aus Abschnitt 5.1
  2. podman, tar, openssl
  3. dialog für die ncurses-Oberfläche – schlägt das fehl, wird newt (whiptail) genommen; beides unterstützen die Skripte
  4. podman-compose – in dieser Reihenfolge versucht: Distributions-Repository → EPEL → pip3 install podman-compose
  5. richtet die systemd-Unit ein (bei Podman immer, siehe nächstes Kapitel)

Manuell entspricht das:

sudo dnf install -y podman podman-compose tar openssl
sudo dnf install -y dialog || sudo dnf install -y newt   # dialog: AppStream, newt: BaseOS

# Falls podman-compose nicht im Repo ist - EPEL nachrüsten:
sudo dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
sudo dnf install -y podman-compose

EPEL setzt eine funktionierende Subskription voraus. Das Paket epel-release konfiguriert nur die EPEL-Quelle; seine Abhängigkeiten und alles, was danach daraus installiert wird, kommen weiterhin aus Red Hats BaseOS/AppStream. Auf einem nicht registrierten System scheitert deshalb schon der Befehl oben – EPEL ist kein Ersatz für die Registrierung.

Bleibt podman-compose deswegen unerreichbar, ist das kein Hindernis: mit Quadlet (Kapitel 6, Variante B) läuft der Stack ganz ohne Compose, direkt über systemd.

Starten:

sudo $EDITOR /opt/checkmk-stack/.env

# Image beschaffen - bei Enterprise mit Zugangsdaten, siehe Kapitel 8
sudo ./scripts/cmk-manage.sh image pull --edition enterprise --version 2.3.0p23 \
     --user <benutzer> --password <kennwort>

sudo ./scripts/cmk-manage.sh up          # nutzt automatisch podman-compose
sudo ./scripts/cmk-manage.sh status

Auf RHEL unbedingt Kapitel 8.2 lesen: kurze Image-Namen und podman import statt podman load sind die beiden Ursachen fuer „Image unbekannt“.

5.1 Unregistriertes RHEL: woher die Pakete kommen

Ein frisch installiertes Red Hat Enterprise Linux ohne Subskription liefert gar nichts aus:

$ sudo dnf install -y podman
This system is not registered with an entitlement server.
You can use "rhc" or "subscription-manager" to register.
Error: There are no enabled repositories in "/etc/yum.repos.d".

Das betrifft alle Pakete – podman, git, dialog, tar. Es gibt drei Wege, und install.sh erkennt die Lage inzwischen selbst und nennt sie.

Nur RHEL selbst ist betroffen. Rocky Linux, AlmaLinux, CentOS Stream und Fedora brauchen keine Registrierung – dort funktioniert dnf sofort.

Weg 1 – kostenlose Developer-Subskription (empfohlen)

Red Hat vergibt die Developer Subscription for Individuals kostenlos. Sie gilt für bis zu 16 Systeme, physisch oder virtuell, und deckt neben Entwicklung und Test ausdrücklich auch kleine Produktivnutzung ab. Sie wird an die Person vergeben, nicht an die Firma.

  1. Kostenloses Konto auf https://developers.redhat.com anlegen
  2. Auf dem Server registrieren:
sudo subscription-manager register --username <benutzer>
# Kennwort wird abgefragt; alternativ --password <kennwort>

RHEL 9 nutzt Simple Content Access – die Repositories sind damit sofort freigeschaltet, ein subscription-manager attach ist nicht mehr nötig.

  1. Kontrolle:
sudo subscription-manager status      # -> Overall Status: Current
sudo dnf repolist                     # -> rhel-9-for-x86_64-baseos-rpms u.a.
sudo dnf install -y git podman

Fehlen einzelne Repositories:

sudo subscription-manager repos --list-enabled
sudo subscription-manager repos --enable=rhel-9-for-x86_64-appstream-rpms

Bei einem Firmenkonto mit Aktivierungsschlüssel stattdessen:

sudo subscription-manager register --org <org-id> --activationkey <schluessel>

Weg 2 – Installations-DVD als lokales Repository (ohne Konto, offline)

Funktioniert ohne jede Registrierung und ohne Internet. Voraussetzung ist die DVD-ISO (rhel-9.x-x86_64-dvd.iso, mehrere GB) – die kleine boot.iso enthält keine Pakete.

# ISO dauerhaft einhängen
sudo mkdir -p /mnt/rhel
sudo mount -o loop,ro /pfad/rhel-9.8-x86_64-dvd.iso /mnt/rhel

# beim Booten automatisch einhängen
echo '/pfad/rhel-9.8-x86_64-dvd.iso /mnt/rhel iso9660 loop,ro,nofail 0 0' \
  | sudo tee -a /etc/fstab

# Repository-Datei anlegen
sudo tee /etc/yum.repos.d/rhel-local.repo >/dev/null <<'REPO'
[rhel-local-baseos]
name=RHEL local - BaseOS
baseurl=file:///mnt/rhel/BaseOS
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release

[rhel-local-appstream]
name=RHEL local - AppStream
baseurl=file:///mnt/rhel/AppStream
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
REPO

sudo dnf clean all
sudo dnf repolist
sudo dnf install -y podman tar openssl dialog git

Grenze: Das lokale Repository enthält exakt den Stand der ISO – es gibt keine Sicherheitsupdates. Für einen dauerhaft betriebenen Monitoring-Server ist das kein Zustand; als Überbrückung, bis die Registrierung steht, ist es in Ordnung.

Weg 3 – auf Rocky Linux oder AlmaLinux wechseln

Beide sind binärkompatible Nachbauten von RHEL, dauerhaft kostenfrei und ohne Registrierung. Dieses Projekt läuft dort unverändert – install.sh erkennt sie als RHEL-Familie.

# Rocky Linux
sudo dnf install -y git
sudo git clone https://github.com/rocky-linux/rocky-tools.git
sudo bash rocky-tools/migrate2rocky/migrate2rocky.sh -r

# AlmaLinux
curl -O https://raw.githubusercontent.com/AlmaLinux/almalinux-deploy/master/almalinux-deploy.sh
sudo bash almalinux-deploy.sh

Vorher ein Backup bzw. einen Snapshot anlegen. Die Umstellung tauscht die Basispakete im laufenden System aus.

Was dieses Projekt tatsächlich braucht

Paket Wofür Repository
podman Container-Runtime AppStream
tar Backups und Migrations-Bundles BaseOS
openssl selbstsignierte Zertifikate BaseOS
dialog ncurses-Oberfläche AppStream
newt (whiptail) Ersatz, falls dialog fehlt BaseOS
curl Image-Download BaseOS
podman-compose Compose-Unterstützung EPEL oder pip3
git nur zum Klonen dieses Projekts AppStream

dialog ist optional: fehlt es, nutzen die Skripte automatisch whiptail aus dem Paket newt, das in BaseOS liegt. install.sh versucht genau diese Reihenfolge und bricht deswegen nicht mehr ab.

git wird nicht zwingend gebraucht – das Projekt lässt sich genauso als ZIP oder per scp auf den Server bringen.

EPEL hilft hier nicht: Das EPEL-Repository setzt die Basis-Repositories von Red Hat voraus. Ohne Subskription oder lokales Repository lässt sich auch epel-release nicht installieren – und damit kein podman-compose. In dem Fall ist der Quadlet-Weg aus Kapitel 6 die Lösung: er kommt ganz ohne Compose aus.

5.2 SELinux

Die Bind-Mounts sind in docker-compose.yml mit :Z versehen, Podman setzt dadurch automatisch den Kontext container_file_t. Falls Zugriffe dennoch scheitern:

sudo semanage fcontext -a -t container_file_t "/opt/checkmk-stack/data(/.*)?"
sudo restorecon -Rv /opt/checkmk-stack/data
sudo ausearch -m avc -ts recent          # AVC-Meldungen prüfen

6. Autostart nach einem Neustart des Hosts (Podman)

Das ist bei Podman der wichtigste Unterschied zu Docker: Podman hat keinen Daemon. Die Angabe restart: unless-stopped in der Compose-Datei wirkt deshalb nicht über einen Reboot hinweg. Der Autostart muss über systemd erfolgen. Es gibt zwei erprobte Wege.

Variante A – Compose-basierte systemd-Unit (empfohlen, identisch zu Docker)

Wird von ./install.sh --with-systemd automatisch erzeugt und aktiviert. Manuell:

sudo tee /etc/systemd/system/checkmk-stack.service >/dev/null <<'EOF'
[Unit]
Description=Checkmk + NGINX Proxy Manager (Container-Stack)
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/checkmk-stack
EnvironmentFile=/opt/checkmk-stack/.env
TimeoutStartSec=0
ExecStart=/bin/sh -c '/usr/bin/podman-compose up -d'
ExecStartPost=/opt/checkmk-stack/scripts/cmk-manage.sh start-all-sites
ExecStop=/bin/sh -c '/usr/bin/podman-compose down'

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now checkmk-stack.service
sudo systemctl status checkmk-stack.service

Prüfen, dass es einen Reboot übersteht:

sudo systemctl is-enabled checkmk-stack     # -> enabled
sudo reboot
# nach dem Neustart:
sudo podman ps
sudo /opt/checkmk-stack/scripts/cmk-manage.sh status

ExecStartPost ruft start-all-sites auf. Das ist nötig, weil der Checkmk-Entrypoint nur die in CMK_SITE_ID eingetragene Site startet – bei mehreren Sites blieben die übrigen sonst gestoppt.

Variante B – Podman-Quadlet (ab Podman 4.4, ohne Compose)

Quadlet erzeugt aus einfachen Beschreibungsdateien echte systemd-Units. Vorteil: kein podman-compose nötig, saubere Abhängigkeiten, natives Podman.

sudo ./install.sh --quadlet

Das schreibt (mit den Werten aus der .env) nach /etc/containers/systemd/:

  • checkmk.container
  • nginx-proxy-manager.container

Danach:

sudo systemctl daemon-reload
sudo systemctl start checkmk nginx-proxy-manager
sudo systemctl status checkmk

Die Units werden durch WantedBy=multi-user.target default.target beim Systemstart automatisch aktiviert – ein separates systemctl enable ist bei Quadlet nicht nötig (und auch nicht möglich, da die Units generiert werden).

Vorlagen liegen unter systemd/quadlet/.

Variante C – rootless Podman (optional, erhöhter Aufwand)

sudo ./install.sh --rootless
sudo loginctl enable-linger checkmk           # Dienstbenutzer
# Unit als Benutzer-Unit:
mkdir -p ~/.config/systemd/user
cp systemd/checkmk-stack.service.example ~/.config/systemd/user/checkmk-stack.service
systemctl --user daemon-reload
systemctl --user enable --now checkmk-stack

--rootless setzt net.ipv4.ip_unprivileged_port_start=80, damit die Ports 80/443 ohne root gebunden werden dürfen. loginctl enable-linger sorgt dafür, dass die Benutzer-Units auch ohne Anmeldung nach einem Reboot starten.

Hinweis: Im rootless-Betrieb werden die UIDs der Site-Benutzer über User-Namespaces abgebildet. Die Dateien unter data/checkmk/sites gehören dann Subordinate-UIDs (z. B. 165536). Das ist normal, erschwert aber die Arbeit mit den Dateien vom Host aus. Für Migrationen wird der rootful Betrieb empfohlen.


7. Konfiguration (.env)

cp .env.example .env
chmod 600 .env
$EDITOR .env

Die wichtigsten Schalter:

Variable Bedeutung
CMK_RUNTIME leer = automatische Erkennung, sonst docker oder podman
CMK_IMAGE das tatsaechlich verwendete Image, immer vollqualifiziert – siehe Kapitel 8
CMK_EDITION, CMK_VERSION nur Vorgaben fuer den Image-Downloader
CMK_IMAGE_SOURCE auto/registry/download – woher das Image geholt wird
CMK_REGISTRY_USER/-PASSWORD Anmeldung an registry.checkmk.com (Enterprise)
CMK_DOWNLOAD_USER/-PASSWORD Anmeldung am Checkmk-Downloadportal
CMK_SITE_ID Site, die der Container anlegt bzw. beim Start hochfährt
CMK_PASSWORD Startpasswort für den Benutzer cmkadmin (nur bei Neuanlage)
CMK_LIVESTATUS_TCP on öffnet Port 6557 für verteilte Überwachung
MAIL_RELAY_HOST SMTP-Relay für Benachrichtigungen
TZ Zeitzone, z. B. Europe/Berlin
NPM_ENABLED on/off – soll der Proxy-Manager-Container überhaupt laufen? Siehe 12.4
NPM_ADMIN_PORT Port der Proxy-Manager-Oberfläche (Vorgabe 81) – nur über npm-port bzw. das Menü ändern
NPM_ADMIN_URL Startseite des Terminal-Browsers; leer = automatisch aus NPM_ADMIN_PORT
BACKUP_DIR Ablage für manuelle Backups (Vorgabe ./backups); geplante Jobs haben eigene Pfade
BACKUP_AUTO on/off – sollen die Backup-Jobs per cron laufen?
CERT_DOMAIN, CERT_DAYS Vorgaben für selbstsignierte Zertifikate
FW_ROLE single/central/remote – Rolle im verteilten Monitoring, steuert die Firewall-Prüfung
FW_EC_SYSLOG, FW_EC_SNMPTRAP, FW_EC_TCP Event Console: Syslog (514), SNMP-Traps (162/udp), Status über TCP (6558)
FW_AGENT läuft auf diesem Host ein Checkmk-Agent im Pull-Betrieb? (6556)
FW_EXTRA_PORTS weitere Ports für die Prüfung, z. B. 3000/tcp=Grafana

7.1 Wer liest die .env – und warum gibt es sie zusätzlich zum Skript?

Die .env ist die einzige Konfigurationsdatei. Es gibt bewusst keine zweite Konfiguration im Verwaltungsskript:

                    .env  (einzige Quelle der Wahrheit)
                      |
      +---------------+----------------+------------------+
      |               |                |                  |
docker-compose    systemd-Unit    cmk-manage.sh      migrate_creator.sh
(Variablen-       (EnvironmentFile)  (source)         (unabhaengig, laeuft
 ersetzung)                                            auf dem Quellserver)
  • Gelesen wird sie von compose, von der systemd-Unit und vom Skript.
  • Geschrieben wird sie durch das Skript – entweder gezielt (image … setzt CMK_IMAGE, import --set-default-site setzt CMK_SITE_ID, npm-port setzt NPM_ADMIN_PORT) oder über das Einstellungsmenü bzw. config set (siehe Kapitel 14). Ein Editor ist damit nicht mehr nötig, bleibt aber als Menüpunkt erhalten.
  • Das Skript selbst haelt nur Rueckfallwerte fuer den Fall, dass ein Schluessel in der .env fehlt (in scripts/lib/common.sh, Funktion load_env). Es ueberschreibt niemals einen gesetzten Wert.

Kurz: die .env sagt was laeuft, das Skript macht etwas damit. Doppelt gepflegt werden muss nichts.


8. Checkmk-Image beschaffen (Raw, Enterprise & Co.)

8.1 Welche Edition liegt wo?

Das ist die haeufigste Stolperfalle: die Enterprise-Edition liegt nicht auf Docker Hub. Im Namensraum checkmk auf Docker Hub gibt es ausschliesslich:

Edition (CMK_EDITION) Bezugsquelle Anmeldung
raw (bis 2.4) docker.io/checkmk/check-mk-raw nein
community (ab 2.5, Nachfolger von raw) docker.io/checkmk/check-mk-community nein
cloud docker.io/checkmk/check-mk-cloud nein
managed (bis 2.4) docker.io/checkmk/check-mk-managed nein
pro (ab 2.5, Nachfolger von enterprise) docker.io/checkmk/check-mk-pro nein
ultimate, ultimatemt (ab 2.5) docker.io/checkmk/check-mk-ultimate[mt] nein
enterprise (2.0 – 2.4) registry.checkmk.com/enterprise/check-mk-enterprise oder Image-Tarball aus dem Kundenportal ja
free (historisch, bis 2.1) docker.io/checkmk/check-mk-free nein

Ab Checkmk 2.5 wurden die Editionen umbenannt; diese Images liegen wieder offen auf Docker Hub. Wer also eine 2.5 oder neuer einsetzt, nimmt einfach pro. Fuer 2.2/2.3/2.4-Enterprise fuehrt nur der Weg ueber registry.checkmk.com oder den Tarball.

Vorsicht bei den Namen

Die Umbenennung ist die zweite grosse Stolperfalle. checkmk.com zeigt nur noch die neuen Namen, die Dateien und Repositories tragen bis 2.4 aber die alten. Konkret für 2.3.0p9 – geprüft am Versionsarchiv:

Auswahl auf checkmk.com --edition hier tatsächlicher Dateiname
Community raw check-mk-raw-docker-2.3.0p9.tar.gz
Pro enterprise check-mk-enterprise-docker-2.3.0p9.tar.gz
Ultimate cloud check-mk-cloud-docker-2.3.0p9.tar.gz
Ultimate MT managed check-mk-managed-docker-2.3.0p9.tar.gz

Wer auf der Website „Pro" wählt und daraus check-mk-pro-docker-2.3.0p9.tar.gz ableitet, bekommt ein HTTP 404 – diese Datei gibt es für 2.3 nicht.

Das Skript nimmt einem das ab: es liest den echten Dateinamen aus dem Versionsarchiv und probiert zusätzlich beide Namensvarianten durch. In der Oberfläche steht in der Editionsauswahl jeweils beides.

Frei herunterladbar heisst nicht lizenzfrei – der Lizenzschluessel wird anschliessend in Checkmk selbst hinterlegt.

8.2 Zwei Podman-Fallstricke (genau die aus der Praxis)

1. Kurze Image-Namen. Podman kennt keine Vorgabe-Registry. Kurze Namen wie checkmk/check-mk-enterprise:2.3.0p23 werden ueber unqualified-search-registries aus /etc/containers/registries.conf aufgeloest – auf RHEL steht dort registry.access.redhat.com an erster Stelle. Podman sucht das Image also bei Red Hat, findet es nicht und meldet image not known bzw. fragt interaktiv nach. Deshalb steht in .env und docker-compose.yml konsequent der vollqualifizierte Name:

CMK_IMAGE=registry.checkmk.com/enterprise/check-mk-enterprise:2.3.0p23

Aktuelle Auflösungsreihenfolge ansehen:

grep -A3 unqualified-search-registries /etc/containers/registries.conf

2. import statt load. Ein heruntergeladener Image-Tarball wird mit load eingespielt:

Kommando Erwartet Ergebnis
podman import datei.tar.gz ein Dateisystem-Archiv (rootfs) Image ohne Entrypoint, ohne Umgebung, ohne Tag → unbrauchbar, „Image unbekannt“
podman load -i datei.tar.gz ein Image-Archiv (docker save/OCI) vollstaendiges Image inkl. Metadaten und Tag ✔

Ein mit import erzeugtes Fehl-Image wieder loswerden:

podman images | grep '<none>'
podman rmi <image-id>

cmk-manage.sh image load prueft das Archiv vorher auf manifest.json bzw. oci-layout und weist ein falsches Archiv mit genau diesem Hinweis ab.

8.3 Zugangsdaten in der .env hinterlegen

CMK_EDITION=enterprise
CMK_VERSION=2.3.0p23

# Bezugsweg 1 - private Registry
CMK_REGISTRY=registry.checkmk.com
CMK_REGISTRY_USER=<benutzer-aus-dem-kundenportal>
CMK_REGISTRY_PASSWORD=<kennwort>

# Bezugsweg 2 - Tarball vom Downloadportal
CMK_DOWNLOAD_BASEURL=https://download.checkmk.com/checkmk
CMK_DOWNLOAD_USER=<benutzer>
CMK_DOWNLOAD_PASSWORD=<kennwort>

Die Zugangsdaten stammen aus dem Checkmk-Kundenportal (portal.checkmk.com). Die .env sollte deshalb chmod 600 haben – install.sh setzt das.

8.4 Zugangsdaten vorab prüfen

Bevor ein mehrere Gigabyte grosser Download an einer falschen Anmeldung scheitert, lässt sich beides in Sekunden testen:

./scripts/cmk-manage.sh image test --edition enterprise --version 2.3.0p23

Geprüft wird ohne jeden Download und ohne dass eine Anmeldung gespeichert wird:

Prüfung Was sie beantwortet
Registry erreichbar Netzwerk, Proxy, DNS
Anmeldung akzeptiert stimmen Benutzer und Kennwort?
Zugriff auf das Repository hat das Konto die nötige Berechtigung (Subskription)?
Downloadportal liegt der Image-Tarball dort und wird die Anmeldung akzeptiert?

Beispiel mit korrekten Zugangsdaten aus der .env:

Registry registry.checkmk.com
  [  OK  ] erreichbar (HTTP 401)
  [  OK  ] Anmeldung akzeptiert
  [  OK  ] Zugriff auf 'enterprise/check-mk-enterprise' vorhanden

Downloadportal download.checkmk.com
  [  OK  ] Datei erreichbar (HTTP 200)
           https://download.checkmk.com/checkmk/2.3.0p23/check-mk-enterprise-2.3.0p23.docker.tar.gz

[  OK  ] Zugangsweg nutzbar.

Bei falschem Kennwort:

Registry registry.checkmk.com
  [  OK  ] erreichbar (HTTP 401)
  [FEHLER] Anmeldung abgelehnt (HTTP 401)
           Benutzername/Kennwort des Checkmk-Kundenportals pruefen

Nützliche Unterscheidungen, die der Test trifft:

  • Anmeldung akzeptiert, aber kein Zugriff auf das Repository – die Zugangsdaten stimmen, der Subskription fehlt aber die Berechtigung für diese Edition.
  • Anmeldung akzeptiert, aber HTTP 404 im Downloadportal – Benutzer und Kennwort sind richtig, nur Version oder Dateiname passen nicht. Dann die exakte Version angeben (kein -latest) oder CMK_DOWNLOAD_URL setzen.
  • Bei den frei verfügbaren Editionen (raw, pro, cloud …) meldet der Test „öffentliches Repository – keine Anmeldung nötig" und prüft trotzdem, ob das Repository wirklich abrufbar ist.

Optionen:

# Zugangsdaten einmalig angeben, ohne sie in die .env zu schreiben
./scripts/cmk-manage.sh image test --edition enterprise --version 2.3.0p23 \
     --user <benutzer> --password <kennwort>

# nur einen Bezugsweg prüfen
./scripts/cmk-manage.sh image test --only registry
./scripts/cmk-manage.sh image test --only download

Die Zugangsdaten werden über curl --config - von der Standardeingabe übergeben und erscheinen daher nicht in der Prozessliste.

Kennwörter mit Sonderzeichen: Bis dahin lief das über eine temporäre .netrc-Datei. Deren Format trennt die Felder durch Leerzeichen – ein Kennwort mit Leerzeichen, # oder Anführungszeichen kam dadurch still verstümmelt an, und die Anmeldung schlug scheinbar grundlos fehl. Gegen einen Testserver nachgemessen: bei einem Kennwort mit Leerzeichen, #, " und $ liefert der neue Weg HTTP 200, der alte HTTP 401. Fehlt curl, weicht der Test für die Registry auf podman login bzw. docker login aus – auch dann in eine Wegwerfdatei, die gespeicherte Anmeldung des Systems bleibt unberührt.

In der ncurses-Oberfläche ist der Test an zwei Stellen erreichbar:

  • Hauptmenü → image → „Zugangsdaten prüfen"
  • Einstellungen → „Checkmk-Image und Zugangsdaten" → „>> Zugangsdaten jetzt prüfen" – also direkt dort, wo Benutzer und Kennwort eingetragen werden

Nach dem Ändern eines Zugangsdaten-Feldes fragt das Menü ausserdem von sich aus, ob gleich geprüft werden soll.

8.5 Verfügbare Versionen auflisten

Statt Versionsnummern zu raten:

./scripts/cmk-manage.sh image versions --edition enterprise --filter 2.3.0p

Abgefragt werden bis zu drei Quellen:

Quelle --source Zugangsdaten
Versionsarchiv von checkmk.com web nein
Registry (Docker Hub bzw. registry.checkmk.com) registry nur für Enterprise
Downloadportal (Verzeichnis-Listing) download ja

Registry und Downloadportal führen nicht dasselbe. Die Registry hält in der Regel nur die jüngsten Patchstände vor – bei 2.4.0 etwa p31 aufwärts, dazu 2.4.0-latest und die täglichen Bauten. Ältere Stände sind dort herausgerollt. Das Downloadportal ist dagegen ein Archiv und hat sie weiterhin.

Das ist genau dann entscheidend, wenn eine bestimmte Version gebraucht wird – bei einer Migration nämlich, weil omd restore exakt die Version der Quell-Site verlangt (Kapitel 17.4). Für solche Fälle ist der Tarball der richtige Weg, nicht die Registry. image why weist von sich aus darauf hin, wenn ein Tag in der Registry fehlt, die Version im Archiv aber vorhanden ist.

Ohne --source werden alle drei versucht – so kommt auch ohne hinterlegte Zugangsdaten eine brauchbare Liste zustande:

Versionsarchiv  https://checkmk.com/download/archive
  (oeffentlich, keine Zugangsdaten noetig)
  2.3.0p50
  2.3.0p49
  2.3.0p48
  ...

Uebernehmen
  aus der Registry :  ./scripts/cmk-manage.sh image pull     --edition enterprise --version <version>
  als Tarball      :  ./scripts/cmk-manage.sh image download --edition enterprise --version <version>
  nur eintragen    :  ./scripts/cmk-manage.sh config set CMK_VERSION <version>

Weitere Optionen: --limit N (Vorgabe 25), --all, --filter TEXT und --bare für die nackte Liste ohne Rahmen – praktisch zum Weiterverarbeiten:

./scripts/cmk-manage.sh image versions --source web --filter 2.3.0p --bare | head -1

In der Oberfläche gibt es den Punkt image → „Verfügbare Versionen auflisten"; beim Holen eines Images muss die Version ohnehin nicht mehr abgetippt werden – dort erscheint eine Auswahlliste.

8.6 Image holen – ein Kommando, drei Wege

Stehen Edition und Version fest, genügt:

sudo ./scripts/cmk-manage.sh image get

Woher geholt wird, steuert CMK_IMAGE_SOURCE:

Wert Wirkung
auto (Vorgabe) erst die Registry, dann das Downloadportal
registry nur aus der Registry
download nur als Tarball vom Downloadportal

Einmalig abweichen: image get --source download.

auto ist die sinnvolle Vorgabe, weil Registries nur die jüngsten Patchstände vorhalten – eine ältere, für eine Migration nötige Version liegt dann nur noch im Downloadportal. Der Wechsel geschieht automatisch, ohne Rückfrage.

Beim up wird automatisch geholt. Fehlt das Image lokal und sind Edition und Version gesetzt, beschafft up es zuerst über diesen Weg – sonst versucht compose einen nackten Pull, der bei einer nur im Archiv vorhandenen Version scheitern muss:

[ INFO ] Das Image ist lokal nicht vorhanden - hole es (auto) ...
[ INFO ] Bezugsweg 'auto': zuerst die Registry ...
[ WARN ] Aus der Registry nicht zu bekommen - versuche das Downloadportal.

Mit up --no-fetch bleibt das aus.

In der Oberfläche liegt das unter image → „Image holen". Dort wird nur noch der Bezugsweg abgefragt – der eingestellte ist gekennzeichnet. Wer Edition oder Version ändern will, wählt dort „Etwas anderes waehlen" oder gleich den Assistenten.

Die Einzelschritte

In der Oberfläche geht das als Assistent: image → „Image beschaffen" führt in einem Durchgang durch Edition, Version und Bezugsweg, setzt danach CMK_EDITION, CMK_VERSION und CMK_IMAGE und fragt nicht erneut nach Zugangsdaten, die schon in der .env stehen. Nur wenn sie für den gewählten Weg fehlen, werden sie erfragt – auf Wunsch gleich gespeichert. Derselbe Assistent liegt auch unter Einstellungen → Checkmk-Image und Zugangsdaten → „>> Image beschaffen".

Auf der Kommandozeile bleiben die Einzelschritte:

a) Aus einer Registry (empfohlen)

Für die Enterprise-Edition entspricht das genau diesen beiden Schritten – das Skript erledigt sie in einem Aufruf und trägt das Ergebnis in die .env ein:

podman login registry.checkmk.com          # bzw. docker login
podman pull registry.checkmk.com/enterprise/check-mk-enterprise:2.3.0p9
# frei verfuegbar, ohne Anmeldung
sudo ./scripts/cmk-manage.sh image pull --edition raw --version 2.3.0-latest

# Enterprise mit Anmeldung an registry.checkmk.com
sudo ./scripts/cmk-manage.sh image pull --edition enterprise --version 2.3.0p23 \
     --user <benutzer> --password <kennwort>

b) Image-Tarball vom Downloadportal (mit Zugangsdaten)

sudo ./scripts/cmk-manage.sh image download --edition enterprise --version 2.3.0p23 \
     --user <benutzer> --password <kennwort>

Der Downloader probiert die ueblichen Dateinamen unter <CMK_DOWNLOAD_BASEURL>/<version>/ durch (check-mk-enterprise-<version>.docker.tar.gz und check-mk-enterprise-docker-<version>.tar.gz). Falls Checkmk das Schema geaendert hat, laesst sich die vollstaendige URL direkt vorgeben:

sudo ./scripts/cmk-manage.sh image download \
     --url 'https://download.checkmk.com/checkmk/2.3.0p23/check-mk-enterprise-2.3.0p23.docker.tar.gz' \
     --user <benutzer> --password <kennwort>

Die Zugangsdaten werden über curl --config - übergeben und erscheinen daher nicht in der Prozessliste.

c) Bereits heruntergeladene Datei einspielen

Wer die Datei im Browser aus dem Kundenportal geladen hat:

sudo ./scripts/cmk-manage.sh image load --file /root/check-mk-enterprise-2.3.0p23.docker.tar.gz

In allen drei Faellen ermittelt das Skript den tatsaechlichen Image-Namen (bei load z. B. docker.io/checkmk/check-mk-enterprise:2.4.0p9) und traegt ihn als CMK_IMAGE in die .env ein. Danach:

sudo ./scripts/cmk-manage.sh up

8.7 CMK_IMAGE gegenüber CMK_EDITION/CMK_VERSION

Diese drei Werte haben unterschiedliche Aufgaben, und das ist eine häufige Verwechslung:

Wert Wer liest ihn Wozu
CMK_IMAGE compose und die systemd-Units das Image, das tatsächlich gestartet wird
CMK_EDITION nur cmk-manage.sh image … Vorgabe für den Downloader
CMK_VERSION nur cmk-manage.sh image … Vorgabe für den Downloader

CMK_IMAGE lässt sich nicht aus Edition und Version ableiten – je nach Bezugsweg sieht dieselbe Version völlig anders aus:

docker.io/checkmk/check-mk-raw:2.3.0-latest                 (Docker Hub)
registry.checkmk.com/enterprise/check-mk-enterprise:2.3.0p9 (Registry)
docker.io/checkmk/check-mk-enterprise:2.4.0p9               (aus Tarball geladen)

Der Name nach image download überrascht. Der Tarball trägt intern den unqualifizierten Namen checkmk/check-mk-enterprise:<version>, und Podman ergänzt daraus beim Einspielen docker.io/ – obwohl es das Image dort gar nicht gibt. Das ist richtig und stört nicht: das Image liegt lokal, up verwendet es. Nur pullen ließe es sich unter diesem Namen nicht. Fehlt es später einmal, holt image get es wieder über das Downloadportal – nicht über podman pull.

Deshalb hält CMK_IMAGE fest, was wirklich gilt. Gesetzt wird der Wert von image pull, image download, image load und image use – von Hand muss man dort nichts eintragen. In der Oberfläche sind die drei Werte deshalb nicht einzeln editierbar: der Assistent setzt sie gemeinsam. Auf der Kommandozeile bleiben sie einzeln setzbar (config set …).

Nur eintragen, ohne etwas herunterzuladen. Aus Edition und Version lässt sich die Referenz bilden – ein Download ist dafür nicht nötig:

./scripts/cmk-manage.sh image use --edition enterprise --version 2.4.0p9
# -> CMK_IMAGE=registry.checkmk.com/enterprise/check-mk-enterprise:2.4.0p9
#    CMK_EDITION=enterprise
#    CMK_VERSION=2.4.0p9

Das Image selbst holt die Runtime beim nächsten up. Im Assistenten heißt dieser Weg „Nur eintragen – geholt wird beim nächsten Start". Braucht die Registry eine Anmeldung (Enterprise), muss die einmal erfolgt sein – entweder über den Weg „Registry holen" oder mit podman login registry.checkmk.com.

Alle vier Wege des Assistenten setzen CMK_IMAGE – sie unterscheiden sich nur darin, ob dabei schon etwas geholt wird. Deshalb bleiben die drei Werte von selbst stimmig, und die Abweichungswarnung tritt im normalen Betrieb gar nicht mehr auf.

Auf der Kommandozeile übernehmen image pull und image download mit --remember die Edition und Version gleich mit in die .env:

./scripts/cmk-manage.sh image pull --edition enterprise --version 2.3.0p9 --remember

Daraus folgt: Edition oder Version zu ändern, startet keine andere Ausgabe. Erst image pull (bzw. download/load) schreibt das Ergebnis nach CMK_IMAGE, und erst up erstellt den Container neu.

Damit das nicht unbemerkt auseinanderläuft, prüft das Skript die drei Werte gegeneinander – in image status, in status und im Einstellungsmenü direkt nach dem Ändern von Edition oder Version:

[ WARN ] CMK_IMAGE passt nicht zu den eingestellten Vorgaben.

  verwendet wird : docker.io/checkmk/check-mk-raw:2.3.0-latest
  Edition        : eingestellt "enterprise", im Image steckt "raw"

Compose und die systemd-Units verwenden ausschliesslich CMK_IMAGE.
...
    ./scripts/cmk-manage.sh image pull --edition enterprise --version 2.3.0-latest
    ./scripts/cmk-manage.sh up

Aus einem Tarball geladene Images (localhost/…) gelten dabei als stimmig, solange Name und Tag passen.

Wenn das Holen fehlschlägt, bleibt CMK_IMAGE unverändert – das ist Absicht, denn das alte Image läuft ja weiter. Der Assistent sagt das dann auch ausdrücklich („Image wurde NICHT geholt") statt nur auf die Abweichung hinzuweisen. Es bleibt trotzdem ein Zustand, in dem Edition und Version etwas anderes behaupten als das benutzte Image. Dafür gibt es zwei Auswege – beide im Menü unter den drei Werten:

Weg Richtung Wirkung
Assistent starten – führt durch Edition, Version und Bezugsweg
Image aus den Vorgaben setzen Edition/Version → Image bildet die Referenz und trägt sie ein, ohne etwas zu laden; der Menüeintrag zeigt gleich, was dabei herauskommt
Vorgaben aus dem Image ableiten Image → Edition/Version schreibt Edition und Version aus CMK_IMAGE zurück; am Betrieb ändert sich nichts

Auf der Kommandozeile ist das zweite:

./scripts/cmk-manage.sh image use "$CMK_IMAGE" --remember

8.8 Registry-Pfad herausfinden

„Login Succeeded" heisst noch nicht, dass der Pfad stimmt. Meldet der Pull unable to copy from source docker://…, existiert das Repository unter diesem Namen nicht oder die Subskription deckt es nicht ab:

./scripts/cmk-manage.sh image repos --edition enterprise

Das fragt zuerst den Katalog (/v2/_catalog) ab – den sperren allerdings viele Registries – und probiert danach die üblichen Pfade durch:

Uebliche Pfade fuer "raw" durchprobiert
  STATUS TAGS     PFAD
  200 = nutzbar, 404 = gibt es nicht, 401/403 = kein Zugriff
  401    -        raw/check-mk-raw  (kein Zugriff - oder gibt es nicht)
  200    2394     checkmk/check-mk-raw
  ...
[  OK  ] Nutzbar: docker.io/checkmk/check-mk-raw

Scheitert ein image pull gegen eine private Registry, läuft diese Prüfung automatisch an und zeigt gleich, was dort wirklich liegt.

401 heisst nicht zwingend „vorhanden". Viele Registries – Docker Hub zum Beispiel – antworten auch auf nicht existierende Repositories mit 401, um deren Existenz nicht zu verraten. Verlässlich ist nur 200 = nutzbar und 404 = gibt es nicht.

Führt kein Pfad zum Ziel, bleibt der Tarball-Weg. Er ist für Enterprise ohnehin der dokumentierte und funktioniert unabhängig von der Registry:

./scripts/cmk-manage.sh image download --edition enterprise --version 2.4.0p9

8.9 Nachsehen, was gilt

./scripts/cmk-manage.sh image status     # konfiguriertes + lokale Images
./scripts/cmk-manage.sh image list       # nur lokale Checkmk-Images
./scripts/cmk-manage.sh image use localhost/checkmk/check-mk-enterprise:2.3.0p23

image status warnt ausdruecklich, wenn CMK_IMAGE ein kurzer Name ohne Registry ist.

In der ncurses-Oberflaeche liegt derselbe Ablauf unter dem Menuepunkt „Checkmk-Image beschaffen/auswaehlen“ (Edition auswaehlen → Version → Zugangsdaten → holen).


9. Erststart

sudo ./scripts/cmk-manage.sh up
sudo ./scripts/cmk-manage.sh status

Ausgabe (Beispiel):

Container
  checkmk                  läuft
  nginx-proxy-manager      läuft

Sites im Container
  SITE                 VERSION            STATUS
  cmk                  2.3.0p23.cre       läuft

Zugang
  Checkmk (direkt)        : http://10.0.0.5:5000/cmk/
  Checkmk (über Proxy)    : https://<FQDN>/cmk/
  Agent-Receiver          : 10.0.0.5:8000
  NGINX Proxy Manager     : http://10.0.0.5:81/

Der Port der Adminoberfläche folgt NPM_ADMIN_PORT aus der .env; die Ausgabe zeigt immer den tatsächlich eingestellten Wert.

Anmeldung an Checkmk: Benutzer cmkadmin, Passwort aus CMK_PASSWORD.


10. HTTPS einrichten – Let's Encrypt oder selbstsigniert

10.1 Das Administratorkonto

Die früher üblichen Standardzugangsdaten admin@example.com / changeme gibt es seit Version 2.15 nicht mehr. Der Container legt das erste Konto nur noch an, wenn beim ersten Start INITIAL_ADMIN_EMAIL und INITIAL_ADMIN_PASSWORD gesetzt sind – sonst erscheint im Browser ein Einrichtungsassistent. Nachgelesen in backend/setup.js von v2.15.1 und am laufenden Container überprüft.

Deshalb stehen die Werte in der .env und werden von docker-compose.yml durchgereicht:

NPM_ADMIN_EMAIL=admin@example.com
NPM_ADMIN_PASSWORD=ein-ordentliches-kennwort

Beides vor dem ersten Start setzen. Dann ist das Konto sofort da – und damit auch die REST-Schnittstelle nutzbar, über die Kapitel 10.2 den Proxy-Host anlegt.

Ist der Stack schon gelaufen und das Konto von Hand über den Assistenten angelegt worden, wirken die Variablen nicht mehr (die Datenbank ist nicht mehr leer). Dann einfach die selbst vergebenen Zugangsdaten eintragen – das Skript meldet sich damit an.

Wenn die Anmeldung fehlt

Fehlen die Zugangsdaten, sagt das Skript je nach Lage, was zu tun ist – es sieht dafür nach, ob data/npm/data/database.sqlite schon existiert:

Lage Weg
noch keine Datenbank config set NPM_ADMIN_EMAIL … und …_PASSWORD …, dann up – der Container legt das Konto selbst an
Datenbank vorhanden Konto im Browser anlegen (cmk-manage.sh browser), dieselben Daten anschließend mit config set eintragen

Wer lieber sauber neu beginnt – in der Oberfläche unter Einstellungen → NGINX Proxy Manager → „>> Datenbank zurücksetzen" oder auch im Proxy-Hosts-Menü, auf der Kommandozeile:

sudo ./scripts/cmk-manage.sh npm-reset

Das legt die Datenbank beiseite (umbenannt, nicht gelöscht), sodass der Container beim nächsten up das Konto aus NPM_ADMIN_EMAIL/NPM_ADMIN_PASSWORD neu anlegt. Proxy-Hosts, Weiterleitungen und Zugriffslisten sind damit weg – die Zertifikate bleiben. Das Kommando zeigt vorher genau das an und fragt nach. Die Proxy-Hosts lassen sich mit proxy add in einem Aufruf neu anlegen.

10.2 Proxy-Host anlegen – ohne Browser

Die Weboberfläche lässt sich im Terminal-Browser nur mühsam bedienen; Formulare mit Datei-Upload funktionieren dort gar nicht. Da der Proxy Manager ohnehin lokal läuft, ist die Schnittstelle der verlässlichere Weg:

# Checkmk unter checkmk.example.com veröffentlichen, mit selbstsigniertem Zertifikat
sudo ./scripts/cmk-manage.sh proxy add --domain checkmk.example.com --cert self

# oder mit Let's Encrypt (Port 80 muss aus dem Internet erreichbar sein)
sudo ./scripts/cmk-manage.sh proxy add --domain checkmk.example.com --cert letsencrypt

# auf einen anderen Zielport statt 5000
sudo ./scripts/cmk-manage.sh proxy add --domain checkmk.example.com --forward-port 8080

Das Kommando erledigt in einem Zug: Zertifikat erzeugen (bzw. bei Let's Encrypt anfordern), in den Proxy Manager hochladen, Proxy-Host anlegen, HTTPS erzwingen, HTTP/2 und Websockets einschalten und den empfohlenen advanced_config-Abschnitt setzen.

Kommando Wirkung
proxy status Anmeldung prüfen, Anzahl Hosts und Zertifikate
proxy list vorhandene Proxy-Hosts
proxy certs vorhandene Zertifikate mit Ablaufdatum
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 edit --id N … vorhandenen Proxy-Host ändern – nur die angegebenen Felder
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:

Option Vorgabe Bedeutung
--domain FQDN PROXY_DOMAIN öffentlicher Name
--forward-host H 127.0.0.1 Weiterleitungsziel
--forward-port P 5000 Zielport – frei wählbar, nicht auf Checkmk festgelegt
--scheme http|https http Schema zum Ziel
--cert self|letsencrypt|none self Zertifikat
--update – vorhandenen Eintrag ersetzen
--advanced TEXT siehe unten eigener nginx-Abschnitt
--location /P=HOST:PORT – weiterer Dienst unter einem Pfad, mehrfach angebbar – siehe 10.3
--no-force-ssl, --no-http2, --no-websockets, --no-block-exploits – Abschalter

Der advanced_config-Abschnitt

Ohne --advanced setzt proxy add diesen Block – dieselben vier Zeilen, die man sonst im Reiter Advanced von Hand einträgt:

client_max_body_size 0;
proxy_read_timeout 300s;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Wozu die vier:

Zeile Grund
client_max_body_size 0 hebt die Größenbegrenzung auf – sonst scheitern große Agent-Uploads und Bakery-Pakete
proxy_read_timeout 300s lange laufende Checkmk-Ansichten laufen sonst in eine Zeitüberschreitung
X-Forwarded-Proto Checkmk erzeugt sonst http://-Verweise hinter dem HTTPS-Proxy
X-Forwarded-For im Checkmk-Zugriffsprotokoll steht sonst nur die Proxy-Adresse statt der echten Client-IP

Ersetzen (nicht ergänzen) lässt sich der Block mit --advanced:

sudo ./scripts/cmk-manage.sh proxy add --domain checkmk.example.com \
     --advanced 'client_max_body_size 0;
proxy_read_timeout 600s;'

Mit --advanced '' bleibt das Feld leer. Der Assistent in der Oberfläche verwendet immer die Vorgabe oben; wer etwas anderes braucht, nimmt die Kommandozeile oder passt den Eintrag anschließend im Proxy Manager an.

In der Oberfläche liegt derselbe Ablauf unter proxy → „Proxy-Host anlegen" (Name → Zielport → Zertifikat) sowie unter Einstellungen → NGINX Proxy Manager → „>> Proxy-Hosts anlegen/verwalten".

Ein selbstsigniertes Zertifikat wird bei wiederholtem Aufruf wiederverwendet statt jedes Mal neu angelegt – sonst sammeln sich im Proxy Manager Dutzende Einträge gleichen Namens an.

10.3 Mehrere Dienste hinter einem Port (Pfade statt Namen)

Der typische Fall: von außen ist nur ein Port erreichbar, auf dem Server laufen aber mehrere Oberflächen – Checkmk, Grafana, vielleicht noch etwas. Statt für jeden Dienst einen eigenen Namen zu brauchen, lassen sie sich über den Pfad unterscheiden:

https://10.0.0.5/cmk/      ->  Checkmk   (127.0.0.1:5000)
https://10.0.0.5/grafana   ->  Grafana   (127.0.0.1:3000)
https://10.0.0.5/sonstwas  ->  ein weiterer Dienst

Genau dafür ist der Proxy Manager da. In einem Aufruf:

sudo ./scripts/cmk-manage.sh proxy add \
     --domain 10.0.0.5 \
     --forward-port 5000 \
     --cert self \
     --location /grafana=127.0.0.1:3000 \
     --location /sonstwas=127.0.0.1:8080
  • --domain darf eine IP-Adresse sein – ein DNS-Name ist nicht nötig. (Die Schnittstelle akzeptiert alles außer einer Handvoll Sonderzeichen.)
  • --forward-port ist das Ziel für alles, was nicht von einem Pfad abgedeckt ist – hier Checkmk.
  • --location ist beliebig oft angebbar. Schreibweise /pfad=host:port, wahlweise mit Schema (https://host:port) und mit einem Pfad, der beim Ziel vorangestellt wird (/alt=host:3000/basis).

Anzeigen lässt sich das Ergebnis mit:

./scripts/cmk-manage.sh proxy show --domain 10.0.0.5

In der Oberfläche fragt der Assistent nach dem Zertifikat, ob weitere Dienste unter demselben Namen liegen sollen, und nimmt dann Pfad und Ziel im Wechsel auf, bis man ein Feld leer lässt.

Die Pfadliste ist vollständig zu verstehen. proxy add --update ersetzt den Eintrag mitsamt allen Pfaden. Wer später einen Pfad ergänzt, gibt die bereits vorhandenen also wieder mit an – proxy show zeigt, welche das sind.

Was die Dienste selbst wissen müssen

Ein Dienst hinter einem Unterpfad erzeugt sonst Verweise auf /, die ins Leere gehen. Checkmk ist davon nicht betroffen – es liegt ohnehin unter /<site>/. Andere brauchen eine Einstellung:

Grafana (/etc/grafana/grafana.ini bzw. GF_*-Umgebungsvariablen):

[server]
domain = 10.0.0.5
root_url = %(protocol)s://%(domain)s/grafana/
serve_from_sub_path = true

Als Container:

environment:
  GF_SERVER_ROOT_URL: https://10.0.0.5/grafana/
  GF_SERVER_SERVE_FROM_SUB_PATH: "true"

Bleibt das aus, lädt Grafana zwar, sucht sein JavaScript aber unter https://10.0.0.5/public/... statt /grafana/public/... – die Seite bleibt weiß. Dasselbe gilt sinngemäß für jeden anderen Dienst: er muss seinen Basispfad kennen.

Warum überhaupt der Proxy Manager

Alle Container laufen im Host-Netzwerk, die Dienste hören also direkt auf ihren Ports (Checkmk 5000, Grafana 3000, …). Nach außen geben Sie davon keinen frei – nur 443. Der Proxy Manager verteilt dahinter nach Pfad und erledigt zugleich die HTTPS-Terminierung mit einem Zertifikat für alle Dienste.

         Internet / LAN
               |
             :443  (einziger offener Port)
               |
     NGINX Proxy Manager
        |        |        |
   /cmk/     /grafana  /sonstwas
     |          |          |
  :5000      :3000      :8080     (nur auf localhost)

10.4 Wenn doch die Weboberfläche

  1. http://<server>:81 aufrufen – bzw. den in NPM_ADMIN_PORT gesetzten Port (siehe Kapitel 12); ist der Port im Netz gesperrt, hilft der Terminal-Browser aus Kapitel 11
  2. Anmelden mit NPM_ADMIN_EMAIL / NPM_ADMIN_PASSWORD

10.5 Proxy-Host im Browser anlegen

Hosts → Proxy Hosts → Add Proxy Host

Feld Wert
Domain Names checkmk.example.com (bzw. der interne Name)
Scheme http
Forward Hostname / IP 127.0.0.1
Forward Port 5000
Block Common Exploits ein
Websockets Support ein (für die Livedaten der Oberfläche)

Reiter Advanced (empfohlen, damit Checkmk die echte Client-IP sieht und große Agent-Uploads funktionieren):

client_max_body_size 0;
proxy_read_timeout 300s;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

10.6 Variante A – Let's Encrypt (öffentlich erreichbarer Server)

Voraussetzungen: der DNS-Name zeigt öffentlich auf diesen Server und Port 80 ist aus dem Internet erreichbar (HTTP-01-Challenge).

Im Proxy-Host, Reiter SSL:

  • SSL Certificate → Request a new SSL Certificate
  • Force SSL ein
  • HTTP/2 Support ein
  • HSTS Enabled nach Bedarf
  • E-Mail-Adresse angeben, Nutzungsbedingungen bestätigen → Save

Die Erneuerung übernimmt der Proxy Manager automatisch; die Zertifikate liegen im Bind-Mount data/npm/letsencrypt/ und sind damit im Projektverzeichnis gesichert.

Bei interner DNS-Zone ohne öffentlichen Zugang: DNS-Challenge verwenden (SSL → Use a DNS Challenge → Provider auswählen, API-Token hinterlegen).

10.7 Variante B – Selbstsigniertes Zertifikat (interne Umgebung)

Erzeugen:

sudo ./scripts/cmk-manage.sh cert \
     --domain checkmk.intern.example \
     --alt 10.0.0.5 --alt checkmk \
     --days 3650

Ergebnis in data/npm/custom-certs/checkmk.intern.example/:

  • privkey.pem – privater Schlüssel
  • fullchain.pem – Zertifikat (mit SAN für alle angegebenen Namen/IPs)

Einbinden:

  1. SSL Certificates → Add SSL Certificate → Custom
  2. Name vergeben, privkey.pem als Certificate Key, fullchain.pem als Certificate hochladen
  3. Im Proxy-Host unter SSL dieses Zertifikat auswählen, Force SSL und HTTP/2 aktivieren

Damit die Checkmk-Agents und Browser dem Zertifikat vertrauen, muss fullchain.pem auf den Clients als vertrauenswürdiges Zertifikat installiert werden (Windows: Computerzertifikate → Vertrauenswürdige Stammzertifizierungsstellen; Linux: /usr/local/share/ca-certificates/ + update-ca-certificates). Für die reine Agent-Kommunikation über Port 8000 ist das nicht nötig – dort verwendet Checkmk eine eigene, site-interne CA.

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:

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:

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.

10.9 Einen Proxy-Host ändern

proxy add --update schreibt den Eintrag vollständig neu – wer damit nur den Port ändern will, verliert unbeabsichtigt die Pfade und die erweiterte Konfiguration. Dafür gibt es proxy edit: angegeben wird nur, was sich ändern soll, alles Übrige bleibt unangetastet.

./scripts/cmk-manage.sh proxy edit --id 3 --forward-port 5001
./scripts/cmk-manage.sh proxy edit --domain checkmk.example.local --cert self
./scripts/cmk-manage.sh proxy edit --id 3 --location /grafana=127.0.0.1:3000
./scripts/cmk-manage.sh proxy edit --id 3 --del-location /grafana
./scripts/cmk-manage.sh proxy edit --id 3          # nur ansehen

Der Eintrag wird über --id oder --domain gewählt.

Option Ändert
--rename NAME den Domainnamen
--forward-host HOST, --forward-port PORT das Weiterleitungsziel
--scheme http|https wie der Proxy das Ziel anspricht
--cert self|letsencrypt|none|ID das Zertifikat
--advanced 'TEXT' die erweiterte nginx-Konfiguration (\n trennt Zeilen)
--force-ssl, --http2, --websockets, --block-exploits jeweils on/off
--enable, --disable den Eintrag ein- oder ausschalten
--location /pfad=host:port einen Pfad hinzufügen oder ersetzen
--del-location /pfad einen Pfad entfernen

Zwei Dinge sind dabei zu wissen:

  • Pfade kennt die Schnittstelle nur als Ganzes. --location und --del-location lesen deshalb den Bestand, ändern den einen Eintrag und schreiben die Liste zurück. Hatte ein ersetzter Pfad eine eigene erweiterte Konfiguration, wird das vorher gesagt.
  • Der Proxy Manager biegt manches still zurecht: ohne Zertifikat schaltet er http2_support und ssl_forced von sich aus ab. proxy edit vergleicht danach, was gespeichert wurde, und meldet eine Abweichung – sonst sucht man den Fehler später an der falschen Stelle.

In der Oberfläche liegt dasselbe unter Proxy-Hosts → Proxy-Host bearbeiten; dort sind die Felder mit den aktuellen Werten vorbelegt, und die Schalter stehen als Auswahlliste bereit.

Wurde der Standard-Server für den IP-Zugang eingerichtet (Kapitel 10.8), spiegelt er einen Stand von vorher. Nach inhaltlichen Änderungen neu schreiben – proxy edit erinnert daran.


11. Proxy Manager lokal einrichten (Terminal-Browser)

Wenn Port 81 aus dem Netz nicht erreichbar ist, muss die Adminoberfläche des NGINX Proxy Managers auf der Maschine selbst bedient werden. Dafür startet cmk-manage.sh browser einen weiteren Container im Host-Netzwerk – der erreicht 127.0.0.1:81 genauso wie der Proxy Manager selbst.

sudo ./scripts/cmk-manage.sh browser

Das ist bewusst kein Dienst in der docker-compose.yml: ein Browser ist ein interaktives Programm mit Terminal, kein Hintergrunddienst. Er wird mit run --rm -it gestartet und verschwindet beim Beenden wieder rückstandslos.

11.1 Warum kein lynx

Die Adminoberfläche des Proxy Managers ist eine JavaScript-Anwendung. Klassische Textbrowser können sie nicht darstellen – man sieht eine leere Seite. Es gibt deshalb zwei Engines, die einen vollwertigen Browser im Terminal rendern:

Engine Basis JavaScript Proxy Manager bedienbar
browsh Firefox ja ja – Vorgabe, gepflegt
carbonyl Chromium ja ja – schönere Darstellung, Stand 2023
links (links2) Textbrowser nein nein
w3m Textbrowser nein nein
lynx Textbrowser nein nein
shell Bash + curl/jq/openssl – für Diagnose und die API

Die Textbrowser sind trotzdem eingebaut, weil sie für schnelle Prüfungen praktisch sind. Wählt man sie, warnt das Skript ausdrücklich.

11.2 Bedienung

# Vorgabe: browsh auf http://127.0.0.1:81
sudo ./scripts/cmk-manage.sh browser

# andere Engine oder andere Seite
sudo ./scripts/cmk-manage.sh browser --engine carbonyl
sudo ./scripts/cmk-manage.sh browser --engine links --url http://127.0.0.1:5000/cmk/

# Shell mit Netzwerkwerkzeugen im Host-Netzwerk
sudo ./scripts/cmk-manage.sh browser --engine shell

Tastenbelegung in browsh:

Taste Wirkung
Strg+L Adresszeile
Strg+T neuer Tab
Strg+W Tab schließen
Strg+Q beenden

Beim ersten Aufruf einer Textbrowser- oder shell-Engine baut das Skript ein kleines Werkzeug-Image (Debian slim mit links2, w3m, lynx, curl, jq, openssl, rund 170 MB). Vorab bauen – auch ohne Terminal, etwa im Installationsskript:

sudo ./scripts/cmk-manage.sh browser --build-only

browsh und carbonyl werden dagegen als fertige Images geladen; die Namen stehen in der .env (BROWSH_IMAGE, CARBONYL_IMAGE) und sind vollqualifiziert, damit Podman sie nicht bei registry.access.redhat.com sucht.

In der ncurses-Oberfläche liegt alles unter „Terminal-Browser (Proxy Manager lokal bedienen)".

11.3 Schwarzes Fenster: die Startseite antwortet nicht

Bleibt nach Starting Browsh … / Waiting for Firefox to connect… alles schwarz, liegt es fast immer daran, dass auf der Startseite nichts antwortet – nicht am Browser. Ein Terminal-Browser zeigt in dem Fall keine Fehlerseite, sondern gar nichts. Dass Browsh selbst läuft, merkt man daran, dass Strg+Q noch ins Menü zurückführt.

Das Skript prüft die Startseite deshalb vorher und nennt die Ursache:

[ WARN ] Auf http://127.0.0.1:81 antwortet nichts.
Ein Terminal-Browser zeigt dann nur eine schwarze Seite.

Das ist die Oberflaeche des NGINX Proxy Managers.
Er ist abgeschaltet (NPM_ENABLED=off):
    ./scripts/cmk-manage.sh npm-enable on

Trotzdem starten? [j/N]

Unterschieden werden:

Lage Meldung
Proxy Manager abgeschaltet Hinweis auf npm-enable on
Container fehlt oder gestoppt Hinweis auf up
Container läuft, antwortet aber nicht Hinweis auf logs und npm-port
Checkmk-Oberfläche (Port 5000) tot Hinweis auf up bzw. sites
externe Adresse Hinweis auf den Netzzugang des Hosts

Mit --no-check lässt sich die Prüfung überspringen. In der Oberfläche erscheint dieselbe Diagnose als Dialog mit der Wahl, trotzdem zu starten oder im Menü eine andere Startseite einzugeben.

11.4 Grenze: Datei-Upload

Ein Terminal-Browser kann keinen Dateiauswahl-Dialog des Betriebssystems öffnen. Für Let's Encrypt ist das egal (dort werden nur Formularfelder ausgefüllt), aber das Hochladen eines selbstsignierten Zertifikats (SSL Certificates → Custom) funktioniert so nicht zuverlässig.

Für genau diesen Fall führt der Weg über die REST-Schnittstelle des Proxy Managers. Zertifikat wie in Kapitel 10.7 erzeugen, dann:

NPM=http://127.0.0.1:81
CERTDIR=./data/npm/custom-certs/checkmk.intern.example

# 1) Anmelden und Token holen
TOKEN=$(curl -s -X POST "$NPM/api/tokens" \
  -H 'Content-Type: application/json' \
  -d '{"identity":"admin@example.com","secret":"<kennwort>"}' | jq -r .token)

# 2) Zertifikatseintrag anlegen (provider "other" = eigenes Zertifikat)
CERT_ID=$(curl -s -X POST "$NPM/api/nginx/certificates" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"provider":"other","nice_name":"checkmk-selfsigned","domain_names":["checkmk.intern.example"]}' \
  | jq -r .id)

# 3) Schlüssel und Zertifikat hochladen
curl -s -X POST "$NPM/api/nginx/certificates/$CERT_ID/upload" \
  -H "Authorization: Bearer $TOKEN" \
  -F "certificate=@$CERTDIR/fullchain.pem" \
  -F "certificate_key=@$CERTDIR/privkey.pem"

# 4) Proxy-Host für Checkmk anlegen
curl -s -X POST "$NPM/api/nginx/proxy-hosts" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d "{\"domain_names\":[\"checkmk.intern.example\"],
       \"forward_scheme\":\"http\",
       \"forward_host\":\"127.0.0.1\",
       \"forward_port\":5000,
       \"certificate_id\":$CERT_ID,
       \"ssl_forced\":true,
       \"http2_support\":true,
       \"block_exploits\":true,
       \"allow_websocket_upgrade\":true,
       \"advanced_config\":\"client_max_body_size 0;\",
       \"enabled\":true,
       \"meta\":{}}"

curl und jq sind im Werkzeug-Image enthalten, falls der Host sie nicht hat:

sudo ./scripts/cmk-manage.sh browser --engine shell

Beim allerersten Login erzwingt der Proxy Manager das Ändern von E-Mail-Adresse und Kennwort. Das geht am einfachsten im Browser (cmk-manage.sh browser); danach funktioniert die API mit den neuen Daten.

11.5 Alternative: SSH-Tunnel

Falls SSH auf die Maschine möglich ist, ist der Tunnel der bequemste Weg – dann bedient man die Oberfläche im gewohnten Browser:

ssh -N -L 8081:127.0.0.1:81 benutzer@checkmk-server
# danach lokal:  http://127.0.0.1:8081

Das ändert nichts an der Firewall: Port 81 bleibt von außen dicht, der Zugriff läuft durch die bestehende SSH-Verbindung.


12. Adminoberfläche auf einen anderen Port legen

Die Weboberfläche des NGINX Proxy Managers hört im Image fest auf Port 81 (listen 81 default; in /etc/nginx/conf.d/production.conf). Eine Umgebungsvariable dafür gibt es in den veröffentlichten 2.x-Versionen noch nicht – im Entwicklungszweig ist NPM_ADMIN_PORT bereits vorbereitet, in Version 2.15.1 aber noch nicht enthalten. Und weil beide Container im Host-Netzwerk laufen, lässt sich der Port auch nicht per Port-Mapping verschieben.

Ist Port 81 im Netz gesperrt, hilft deshalb:

sudo ./scripts/cmk-manage.sh npm-port 10443

12.1 Was dabei passiert

nginx bindet innerhalb seines http{}-Blocks einen offiziellen Erweiterungspunkt ein:

include /data/nginx/custom/http.conf;

/data ist unser Bind-Mount ./data/npm/data. Dort legt das Kommando einen zusätzlichen Server an, der auf dem gewünschten Port lauscht und an die Oberfläche auf 127.0.0.1:81 weiterreicht:

./data/npm/data/nginx/custom/http.conf

# >>> cmk-manage.sh: Admin-Port - nicht von Hand aendern >>>
server {
    listen 10443;
    listen [::]:10443;
    server_name _;
    client_max_body_size 0;
    location / {
        proxy_pass http://127.0.0.1:81;
        ...
    }
}
# <<< cmk-manage.sh: Admin-Port <<<

Nur der Bereich zwischen den beiden Markierungen wird verwaltet – eigene Ergänzungen in derselben Datei bleiben unangetastet. Anschließend startet das Skript den Proxy-Manager-Container neu, damit nginx die Datei liest, und trägt NPM_ADMIN_PORT sowie NPM_ADMIN_URL in die .env ein. Der Terminal-Browser aus Kapitel 11 startet dann automatisch auf dem neuen Port.

12.2 Wichtig: Port 81 bleibt lokal bestehen

Der eingebaute Server auf Port 81 lässt sich so nicht abschalten – er lauscht weiter auf allen Adressen. Das ist unkritisch, solange die Firewall ihn sperrt, und genau so ist die Empfehlung:

# firewalld
sudo firewall-cmd --permanent --add-port=10443/tcp
sudo firewall-cmd --permanent --remove-port=81/tcp 2>/dev/null
sudo firewall-cmd --reload

# ufw
sudo ufw allow 10443/tcp
sudo ufw delete allow 81/tcp 2>/dev/null

12.3 Stand ansehen und zurücksetzen

./scripts/cmk-manage.sh npm-port          # aktuellen Stand anzeigen
sudo ./scripts/cmk-manage.sh npm-port 81  # zurück auf die Vorgabe

Bei 81 wird der verwaltete Block wieder entfernt; ist die Datei danach leer, verschwindet sie ganz. Es gilt dann wieder ausschließlich die Konfiguration aus dem Image.

Das Kommando lehnt Ports ab, die im Stack schon vergeben sind (80, 443, 5000, 8000, 6557), prüft den Zahlenbereich und warnt, wenn auf dem Wunschport bereits ein anderer Dienst lauscht.

Sobald eine NPM-Version mit NPM_ADMIN_PORT erscheint, wird dieser Umweg überflüssig – dann genügt die Umgebungsvariable. Bis dahin ist der Erweiterungspunkt der Weg, der ohne Änderung am Image auskommt.

12.4 Proxy Manager ganz abschalten (externer NGINX)

Wer die HTTPS-Terminierung schon anderweitig löst – etwa mit einem NGINX auf einem vorgelagerten System – braucht den Container gar nicht. Dafür gibt es einen Schalter:

sudo ./scripts/cmk-manage.sh npm-enable off    # abschalten
sudo ./scripts/cmk-manage.sh npm-enable on     # wieder einschalten
./scripts/cmk-manage.sh npm-enable             # Stand anzeigen

In der Oberfläche steht er unter Einstellungen → NGINX Proxy Manager → „Proxy Manager betreiben", in der .env heißt er NPM_ENABLED.

Was „aus" bedeutet: Der Container wird gestoppt und entfernt, und bei up gar nicht erst angelegt – compose bekommt dann nur noch den Checkmk-Dienst genannt. Es wird also weder ein Image geladen noch ein Container gebaut:

NPM_ENABLED=off  ->  docker compose up -d checkmk
NPM_ENABLED=on   ->  docker compose up -d checkmk nginx-proxy-manager

Die Daten bleiben. Konfiguration, Datenbank und Zertifikate liegen in den Bind-Mounts ./data/npm/data und ./data/npm/letsencrypt, nicht im Container. Vor dem Abschalten zeigt das Kommando beides mit Größe an; beim späteren Einschalten wird die vorhandene Konfiguration samt Zertifikaten unverändert wieder aufgenommen.

Was danach zu tun ist: Der externe Proxy leitet auf Port 5000 dieses Hosts weiter. Der war bisher nur für localhost gedacht und muss jetzt – möglichst eng begrenzt – für den Proxy erreichbar sein:

# firewalld
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=<proxy-ip> port port=5000 protocol=tcp accept'
sudo firewall-cmd --reload

# ufw
sudo ufw allow from <proxy-ip> to any port 5000 proto tcp

Im externen NGINX:

location / {
    proxy_pass http://<checkmk-host>:5000;
    proxy_set_header Host               $host;
    proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto  $scheme;
    client_max_body_size 0;
    proxy_read_timeout 300s;
}

Das passende Kommando samt Beispielkonfiguration gibt npm-enable off direkt mit aus.

Der Agent-Receiver bleibt davon unberührt. Die Agents sprechen Port 8000 dieses Hosts direkt an, nicht den Proxy – der muss also weiterhin für die überwachten Systeme erreichbar sein.

Bei Quadlet (Kapitel 6, Variante B) entfernt install.sh --quadlet die Unit nginx-proxy-manager.container, solange der Schalter auf off steht. Schaltet man ihn später ein, genügt ein erneutes sudo ./install.sh --quadlet.


13. Firewall

RHEL und Rocky bringen firewalld ab Werk mit, und dort ist in der Regel nur SSH freigegeben. Ein Stack, der sauber läuft, ist von außen trotzdem nicht erreichbar – die Agents kommen nicht durch, und im Browser passiert nichts. Deshalb prüft der Manager das auf Wunsch selbst:

./scripts/cmk-manage.sh firewall                 # Prüfbericht
./scripts/cmk-manage.sh firewall open            # Kommandos nur anzeigen
sudo ./scripts/cmk-manage.sh firewall open --apply
sudo ./scripts/cmk-manage.sh firewall open --apply --source 10.0.0.0/24

Erkannt werden firewalld, ufw, nftables und iptables – in dieser Reihenfolge, die erste aktive gewinnt. Bei firewalld werden alle aktiven Zonen ausgewertet, nicht nur die Standardzone: hängen zwei Netzwerkkarten in verschiedenen Zonen, zählt ein Port als offen, sobald ihn eine davon freigibt. Neben einzelnen Ports werden auch Dienstnamen (http, https, ssh) und Rich Rules berücksichtigt.

Welche Ports gebraucht werden, hängt an der Konfiguration. Ports werden durchweg als nummer/protokoll geführt – Syslog und SNMP-Traps laufen über UDP, und eine Freigabe für TCP nützt ihnen nichts.

Immer:

Port Zweck Nötig
80/tcp HTTP, Prüfung durch Let's Encrypt nur mit NPM_ENABLED=on
443/tcp HTTPS für Checkmk und weitere Dienste nur mit NPM_ENABLED=on
NPM_ADMIN_PORT/tcp (81) Adminoberfläche des Proxy Managers nur aus dem Adminnetz
5000/tcp Checkmk direkt nur mit NPM_ENABLED=off, sonst geschlossen lassen
8000/tcp Agent-Receiver (registrierte Agents) immer

Verteiltes Monitoring – über FW_ROLE gesteuert:

Port Zweck Nötig
6557/tcp Livestatus – die Zentrale fragt diese Site ab bei FW_ROLE=remote, sonst nur mit CMK_LIVESTATUS_TCP=on
443/tcp Konfigurationsabgleich und Automations-API der Zentrale bei FW_ROLE=remote

Die Zentrale (FW_ROLE=central) baut die Verbindungen selbst auf und braucht eingehend nichts zusätzlich – dafür muss ausgehend 6557/tcp und 443/tcp zu den Remote-Sites erlaubt sein. Darauf weist der Bericht hin. Ebenso auf den häufigsten Stolperstein: FW_ROLE=remote bei CMK_LIVESTATUS_TCP=off – dann ist der Port zwar offen, aber es lauscht niemand.

Event Console und Agent – jeweils eigener Schalter, weil das nicht jeder Aufbau braucht:

Port Zweck Schalter
514/udp, 514/tcp Syslog-Meldungen annehmen FW_EC_SYSLOG=off|udp|tcp|beide
162/udp SNMP-Traps annehmen FW_EC_SNMPTRAP=on
6558/tcp Status und Ereignisse der Event Console über TCP FW_EC_TCP=on
6556/tcp Checkmk-Agent dieses Hosts (Pull-Betrieb) FW_AGENT=on

Alles Weitere – Grafana, NSCA, was sonst auf dem Rechner liegt – kommt in FW_EXTRA_PORTS:

./scripts/cmk-manage.sh config set FW_EXTRA_PORTS "3000/tcp=Grafana,5667/tcp=NSCA"

Der Bericht markiert auch den umgekehrten Fall: Ist 5000 offen, obwohl der Proxy Manager läuft, steht dort „offen – sollte zu sein". Ohne Prüfbefund endet firewall mit Rückgabewert 1, lässt sich also in eigenen Skripten auswerten.

Portbereiche in bestehenden Regeln werden aufgelöst: Wer 6556-6558/tcp (firewalld, nftables) oder 6556:6558/tcp (ufw, iptables) freigegeben hat, bekommt alle drei Ports als offen gemeldet. Bei ufw zählt eine Regel ohne Protokollangabe – ufw allow 514 – für TCP und UDP, so wie ufw sie auch anlegt.

--source begrenzt jede erzeugte Regel auf ein Quellnetz. Für 8000, 6557 und 514 ist das sinnvoll (nur die überwachten Hosts bzw. die Zentrale), für Port 80 nicht: Let's Encrypt prüft die Domain von außen, eine Begrenzung lässt die Ausstellung scheitern. Darauf weist der Bericht hin.

Wieder zumachen

firewall open kennt nur eine Richtung. Schaltet man die Event Console wieder ab oder streicht einen Eintrag aus FW_EXTRA_PORTS, bleibt die Freigabe stehen – der Port ist offen, ohne dass noch etwas dahinter lauscht. Dafür gibt es die Gegenrichtung:

./scripts/cmk-manage.sh firewall close            # Kommandos nur anzeigen
sudo ./scripts/cmk-manage.sh firewall close --apply

Angeboten wird nur, was offen ist, zu diesem Aufbau gehört und gerade nicht gebraucht wird. Dazu zählen die Ports aus der Tabelle oben und alles, was firewall open --apply selbst geöffnet hat – das merkt sich das Werkzeug in firewall-opened.conf, damit ein gestrichener FW_EXTRA_PORTS-Eintrag nicht in Vergessenheit gerät.

Drei Sicherungen sind eingebaut:

SSH bleibt offen Port 22, der Port, auf dem sshd wirklich lauscht (aus sshd -T), und der Port der laufenden Sitzung (SSH_CONNECTION)
Fremde Freigaben bleiben Wer 3306 für seine Datenbank offen hat, behält sie – geschlossen wird nur, was dieser Aufbau kennt
Sammelregeln bleiben Eine Regel wie 80,443/tcp deckt mehrere Ports ab; sie wird nicht angefasst, sondern gemeldet

Bei ufw wird dabei bewusst nicht nach Regelnummern gelöscht: die verschieben sich beim ersten Löschen, der nächste Aufruf träfe die falsche Regel. Stattdessen wird über die Regelangabe gelöscht (ufw delete allow 514/udp), bei nftables über den Handle und bei iptables mit derselben Regelangabe, mit der sie eingetragen wurde.

In der Oberfläche liegt das unter Einstellungen → Firewall → Nicht mehr benötigte Ports schließen.

Docker und ufw: Veröffentlichte Container-Ports umgehen ufw sonst über die DOCKER-USER-Kette. Hier nicht – beide Container laufen im Host-Netz, es gelten die Hostregeln unverändert.

In der Oberfläche steckt derselbe Bericht unter Firewall prüfen, samt Rückfrage, ob die fehlenden Freigaben gleich gesetzt werden sollen. Die Schalter liegen unter Einstellungen → Firewall: was offen sein muss, und dort stehen auch zwei Aktionen:

Menüpunkt was er tut
>> Firewall jetzt prüfen derselbe Bericht wie firewall check
>> Firewall-Regeln übernehmen (Ports öffnen) fragt erst nach einem Quellnetz, zeigt danach die Kommandos, die genau so ausgeführt werden, und setzt sie nach Bestätigung

Die Reihenfolge ist Absicht: das Quellnetz ändert die Kommandos, deshalb wird es vor der Anzeige erfragt – was im Fenster steht, wird auch ausgeführt. Ohne root wird über sudo neu aufgerufen. Zum Schluss zeigt die Oberfläche den Stand danach, damit man nicht raten muss, ob es gewirkt hat.

Sind die FW_*-Schlüssel in einer älteren .env noch nicht vorhanden, steht im Menü <leer> – es gelten dann die Vorgaben (single, alles aus). Sobald ein Wert gesetzt wird, landet der Schlüssel in der .env.

Von Hand

firewalld (RHEL/Rocky/Alma):

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-port=8000/tcp          # Agent-Receiver
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.0.0/24 port port=81 protocol=tcp accept'

# Verteiltes Monitoring: Livestatus nur fuer die Zentrale
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.0.5/32 port port=6557 protocol=tcp accept'

# Event Console: Syslog und SNMP-Traps (UDP!)
sudo firewall-cmd --permanent --add-service=syslog          # 514/udp
sudo firewall-cmd --permanent --add-service=snmptrap        # 162/udp
sudo firewall-cmd --permanent --add-port=6558/tcp           # Status ueber TCP

sudo firewall-cmd --reload

# Bei abweichendem Admin-Port (z.B. 10443) stattdessen dessen Nummer freigeben -
# das passende Kommando gibt "cmk-manage.sh npm-port <port>" direkt aus.

ufw (Debian/Ubuntu):

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 8000/tcp
sudo ufw allow from 10.0.0.0/24 to any port 81 proto tcp
sudo ufw allow from 10.0.0.5 to any port 6557 proto tcp     # Livestatus fuer die Zentrale
sudo ufw allow 514/udp                                      # Event Console: Syslog
sudo ufw allow 162/udp                                      # Event Console: SNMP-Traps
sudo ufw enable

Port 5000 bleibt geschlossen – der Zugriff erfolgt ausschließlich über den Proxy. Port 81 nur aus dem Administrationsnetz freigeben.


14. Verwaltung: cmk-manage.sh

Das Skript ist gleichzeitig Kommandozeilenwerkzeug und ncurses-Oberfläche.

14.1 ncurses-Oberfläche (wie im Midnight Commander)

sudo ./scripts/cmk-manage.sh gui
 ┌──────────────── Checkmk Stack Manager ─────────────────┐
 │ Projekt : /opt/checkmk-stack                           │
 │ Runtime : podman     Standard-Site: cmk                │
 │ Backups : /opt/checkmk-stack/backups                   │
 │                                                        │
 │   status    Status von Containern und Sites            │
 │   stack     Stack steuern (Start/Stop/Logs/Update)     │
 │   backup    Backup erstellen / planen                  │
 │   restore   Backup wiederherstellen                    │
 │   import    Site von Direktinstallation importieren    │
 │   manage    Backups verwalten (Liste/Details/Löschen)  │
 │   sites     Sites im Container verwalten               │
 │   image     Checkmk-Image beschaffen/auswählen         │
 │   proxy     Proxy-Hosts anlegen/verwalten (HTTPS)      │
 │   browser   Terminal-Browser (Proxy Manager lokal)     │
 │   cert      Selbstsigniertes Zertifikat erzeugen       │
 │   firewall  Firewall prüfen (benötigte Ports)          │
 │   config    Einstellungen (.env) - menügeführt         │
 │   shell     Root-Shell im Checkmk-Container            │
 │   quit      Beenden                                    │
 │                  <  OK  >   <Cancel>                   │
 └────────────────────────────────────────────────────────┘

Bedienung: Pfeiltasten, Leertaste markiert in Auswahllisten (z. B. mehrere Sites für ein Backup), Enter bestätigt, ESC/Cancel geht zurück. Die Fenstergröße richtet sich nach Terminalgröße, Textlänge und Anzahl der Einträge – in einem größeren Terminal sind entsprechend mehr Einträge auf einmal sichtbar. Das gilt für alle Fenster, auch in migrate_creator.sh: sämtliche Dialoge laufen über drei gemeinsame Stellen in scripts/lib/common.sh, die die Größe selbst berechnen.

14.4 Rahmen erscheinen als q, x, l, m (PuTTY)

Sieht die Oberfläche so aus –

lqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk
x  Projekt : /opt/checkmk-stack         x

– dann fehlt auf dem Server eine UTF-8-Locale. Ohne sie zeichnen dialog und whiptail die Rahmen über die alte VT100-Umschaltung ESC(0. Terminals im UTF-8-Modus – PuTTY in der Vorgabe – ignorieren diese Umschaltung und zeigen stattdessen die rohen Buchstaben.

Nachgemessen: bei LC_ALL=C schickt whiptail eine ESC(0-Umschaltung und 91 rohe q; mit UTF-8-Locale keine einzige.

Das Skript behebt das auf zwei Wegen selbst.

1. UTF-8-Locale. Beim Start der Oberfläche setzt es LC_CTYPE auf die erste verfügbare UTF-8-Locale (C.UTF-8, en_US.UTF-8, …). Nur LC_CTYPE, damit Sortierung und Zahlenformat unberührt bleiben. Ist LC_ALL auf einen Nicht-UTF-8-Wert gesetzt, wird es dabei entfernt – sonst würde es LC_CTYPE aushebeln. 2. Unicode statt VT100. Das allein genügt nicht: ncurses benutzt die VT100-Umschaltung auch mit UTF-8-Locale, solange das terminfo sie anbietet – bei TERM=xterm der Fall. Deshalb wird zusätzlich NCURSES_NO_UTF8_ACS=1 gesetzt, womit ncurses echte Unicode-Rahmenzeichen zeichnet. Mit dialog unter LANG=C.UTF-8 und TERM=xterm gemessen:

ESC(0 UTF-8-Rahmenbytes rohe q
ohne Schalter 38 0 182
mit Schalter 0 220 0

whiptail braucht das nicht – es zeichnet bei UTF-8-Locale von sich aus Unicode. Wer den umgekehrten Fall hat – ein Terminal, das ESC(0 beherrscht, aber kein UTF-8 – stellt mit CMK_TUI_ACS=1 das alte Verhalten wieder her.

Prüfen lässt sich das mit:

./scripts/cmk-manage.sh selftest      # Abschnitt "Zeichensatz fuer die Oberflaeche"

Meldet die Prüfung, dass keine UTF-8-Locale vorhanden ist, fehlt das Sprachpaket:

sudo dnf install -y glibc-langpack-en     # RHEL/Rocky/Alma
sudo apt-get install -y locales           # Debian/Ubuntu

Einstellungen in PuTTY

Damit es auch auf der Gegenseite passt:

PuTTY-Bereich Einstellung
Window → Translation Remote character set: UTF-8
Window → Translation Handling of line drawing characters: Use Unicode line drawing code points
Connection → Data Terminal-type string: xterm-256color (Vorgabe ist nur xterm)
Window → Appearance eine Schrift mit Rahmenzeichen, z. B. Consolas oder DejaVu Sans Mono

Wer die Sitzung dauerhaft so haben möchte, speichert sie in PuTTY unter Session → Saved Sessions.

Wenn es trotzdem nicht passt: nachsehen statt raten

./scripts/cmk-manage.sh tui-check

Das gibt zwei Testzeilen aus:

  • Zeile A – echte UTF-8-Rahmenzeichen (┌──┐)
  • Zeile B – die alte VT100-Umschaltung ESC(0 mit den Buchstaben lqk

Daran lässt sich die Ursache ablesen:

Beobachtung Bedeutung
A Linien, B Linien alles in Ordnung
A Linien, B zeigt lqqqk das Terminal macht die VT100-Umschaltung nicht mit – der PuTTY-Fall, siehe Einstellungen oben
A zeigt Kauderwelsch das Terminal läuft nicht im UTF-8-Modus
beide zeigen Buchstaben die Schrift hat keine Rahmenzeichen

Das Kommando nennt zu jeder Beobachtung gleich die passende Abhilfe.

dialog statt whiptail installieren ist auf dieser Seite der wirksamste Griff – es geht mit dem Zeichensatz zuverlässiger um und kann als einziges auch einfache ASCII-Rahmen:

sudo dnf install -y dialog        # RHEL/Rocky/Alma
sudo apt-get install -y dialog    # Debian/Ubuntu

Das Skript bevorzugt dialog, sobald es vorhanden ist. Danach lassen sich notfalls einfache Rahmen erzwingen:

CMK_TUI_ASCII=1 ./scripts/cmk-manage.sh gui

Ohne dialog sagt das Skript das ausdrücklich – whiptail kennt keine solche Option.

14.5 Selbstprüfung

./scripts/cmk-manage.sh selftest

Prüft die Skripte auf die Fallstricke, die sich hier als wiederkehrend erwiesen haben:

Prüfung Warum
Syntax aller vier Skripte Tippfehler fallen sofort auf
Dialoge gehen über die gemeinsamen Stellen sonst hätte ein neues Fenster wieder eine feste Größe
keine fest eingetragenen Fenstergrößen dito
kein [ … ] && VAR=… liefert 1, wenn die Bedingung nicht zutrifft, und beendet unter set -e das Skript – dreimal die Ursache eines stillen Abbruchs
Einstellungstabelle vollständig jeder Schlüssel hat sechs Felder und steht in .env.example

Wer eigene Menüpunkte ergänzt, sollte den Aufruf danach einmal machen. Es wird dialog bevorzugt; ist nur whiptail vorhanden, wird dieses genutzt. Eine Dateiauswahl mit Verzeichnisnavigation ist eingebaut.

14.2 Kommandozeile

./scripts/cmk-manage.sh --help
Kommando Wirkung
up [--no-fetch] / down / restart / pull Stack steuern; up holt ein fehlendes Image selbst
status Container, Sites, Zugangsadressen
logs [-f] Container-Logs
sites Sites im Container auflisten
site-start SITE / site-stop SITE einzelne Site steuern
start-all-sites alle Sites starten (wird von systemd aufgerufen)
backup … Backup als .tar.gz-Bundle
list / verify / prune --keep N Backups verwalten
job list|add|set|del|run|auto geplante Backups (eigene Zielpfade je Job)
restore … Backup zurückspielen
import … Migrations-Bundle einspielen
image get Image über den eingestellten Bezugsweg holen
image status|list|versions|repos|why|test|pull|download|load|use Checkmk-Image beschaffen, auswählen und Fehler erklären
browser [--engine …] Terminal-Browser im Container – Proxy Manager lokal bedienen
config list|get|set|edit Einstellungen der .env anzeigen und ändern
npm-port [PORT] Port der Proxy-Manager-Oberfläche setzen/anzeigen
npm-enable [on|off] Proxy Manager ein-/ausschalten (Daten bleiben erhalten)
npm-reset Datenbank beiseitelegen, damit das Konto neu entsteht
proxy status|list|certs|add|del Proxy-Hosts über die API anlegen und verwalten
cert … selbstsigniertes Zertifikat erzeugen
firewall [check|open|close] prüfen, öffnen und nicht mehr Benötigtes wieder schließen (firewalld, ufw, nftables, iptables)
shell Root-Shell im Checkmk-Container
omd … beliebiges omd-Kommando im Container

Globale Optionen: --env-file DATEI, -y/--yes (keine Rückfragen, z. B. für Cronjobs), -v/--verbose.

14.3 Einstellungen ändern – ohne Editor

Sämtliche Werte der .env lassen sich über das Menü pflegen. In der Oberfläche: Einstellungen (.env) – menügeführt. Die Werte sind nach Bereichen gruppiert:

 ┌──────────────────── Einstellungen ─────────────────────┐
 │ Alle Werte der Datei .env - direkt hier änderbar.      │
 │ Datei: /opt/checkmk-stack/.env                         │
 │                                                        │
 │   runtime   Runtime und Zeitzone                       │
 │   image     Checkmk-Image und Zugangsdaten             │
 │   checkmk   Checkmk-Site und Container                 │
 │   npm       NGINX Proxy Manager                        │
 │   browser   Terminal-Browser                           │
 │   paths     Verzeichnisse                              │
 │   cert      Selbstsignierte Zertifikate                │
 │   show      Alle Werte auflisten                       │
 │   editor    Datei .env im Editor öffnen                │
 │   back      zurück                                     │
 └────────────────────────────────────────────────────────┘

Jeder Eintrag zeigt seinen aktuellen Wert und öffnet beim Bestätigen die passende Eingabe: Freitext, Zahl, Auswahlliste oder Kennwortfeld (Kennwörter erscheinen in der Übersicht als ******** und bleiben unverändert, wenn man das Feld leer lässt). Der Editor bleibt als Menüpunkt erhalten.

Dieselben Werte über die Kommandozeile:

./scripts/cmk-manage.sh config list                  # alles mit aktuellen Werten
./scripts/cmk-manage.sh config list --category npm   # nur ein Bereich
./scripts/cmk-manage.sh config get CMK_SITE_ID
./scripts/cmk-manage.sh config set CMK_SITE_ID prod
./scripts/cmk-manage.sh config set NPM_ADMIN_PORT 10443

Geprüft wird beim Setzen, nicht erst beim nächsten Start:

Schlüssel Prüfung
NPM_ADMIN_PORT Zahl 1–65535, nicht 80/443/5000/8000/6557, Warnung wenn belegt
CMK_SITE_ID nur Buchstaben, Ziffern, _; höchstens 16 Zeichen
CMK_IMAGE, NPM_IMAGE, … muss vollqualifiziert sein (Podman-Fallstrick)
CMK_RUNTIME muss auf diesem System installiert sein
CERT_DAYS u. a. Zahlenfelder
URL-Felder müssen mit http:// oder https:// beginnen

Werte mit Leerzeichen werden automatisch in Anführungszeichen gesetzt, damit die .env weiterhin von compose, systemd und der Shell gelesen werden kann. Ändert man NPM_ADMIN_PORT, zieht das Skript die nginx-Zusatzdatei automatisch mit (siehe Kapitel 12). Bei Werten, die erst nach dem Neuerstellen der Container greifen, weist das Menü ausdrücklich darauf hin.


15. Backup

Backups werden mit omd backup erstellt und als Bundle verpackt:

cmkbackup_<site>_<version>_<zeitstempel>.tar.gz
└── cmkbundle/
    ├── MANIFEST              Site, Version, Quelle, Prüfsumme …
    ├── INFO.txt              lesbare Zusammenfassung
    ├── site.tar.gz           das eigentliche omd-Backup
    └── site.tar.gz.sha256

Dadurch weiß das Restore-/Import-Werkzeug immer, welche Site und welche Checkmk-Version im Archiv steckt, und kann die Integrität prüfen.

# eine Site
sudo ./scripts/cmk-manage.sh backup --site cmk

# alle Sites, ohne Logdateien, mit Kennzeichnung
sudo ./scripts/cmk-manage.sh backup --all --no-logs --label vor-update

# konsistentestes Backup: Site wird kurz gestoppt
sudo ./scripts/cmk-manage.sh backup --site cmk --stop

# ohne Performance-Daten (deutlich kleiner)
sudo ./scripts/cmk-manage.sh backup --site cmk --no-rrds --dir /mnt/nas/checkmk

Auflisten und prüfen:

./scripts/cmk-manage.sh list
./scripts/cmk-manage.sh verify --file backups/cmkbackup_cmk_2.3.0p23.cre_20260820-030000.tar.gz
./scripts/cmk-manage.sh prune --keep 7

15.1 Geplante Backups (Backup-Jobs)

Manuelle Backups gehen immer nach BACKUP_DIR aus der .env. Geplante Jobs bringen dagegen ihr eigenes Zielverzeichnis mit – so lässt sich täglich auf eine NAS-Freigabe und wöchentlich woanders hin sichern.

Im Menü: backup → „Backup erstellen / planen"

 ┌──────────── Backup erstellen / planen ─────────────────┐
 │ Manuelle Backups gehen immer nach:                     │
 │   /opt/checkmk-stack/backups   (Einstellung BACKUP_DIR)│
 │                                                        │
 │ Geplante Jobs haben ihr eigenes Zielverzeichnis.       │
 │ Automatische Ausfuehrung: aus                          │
 │                                                        │
 │   manuell   Backup jetzt erstellen                     │
 │   jobs      Backup-Jobs verwalten                      │
 │   auto      Automatische Ausfuehrung ein/aus           │
 │   status    Zeitplan und Jobs anzeigen                 │
 │   jetzt     Einen Job sofort ausfuehren                │
 │   back      zurueck                                    │
 └────────────────────────────────────────────────────────┘

Dieselben Jobs liegen auch in den Einstellungen → „Backup-Jobs".

Job anlegen

Im Menü führt ein Dialog durch Sites, Zeitplan (täglich / wöchentlich / monatlich / freier Cron-Ausdruck), Zielverzeichnis, Aufbewahrung und Optionen. Dasselbe per Parameter:

# täglich 02:15, alle Sites, ohne Logs, 14 Backups aufbewahren
sudo ./scripts/cmk-manage.sh job add --name nachts \
     --cron "15 2 * * *" --no-logs --keep 14

# sonntags 03:30, nur zwei Sites, auf die NAS, ohne RRDs, 8 aufbewahren
sudo ./scripts/cmk-manage.sh job add --name nas-woche \
     --cron "30 3 * * 0" --sites prod,test \
     --dir /mnt/nas/checkmk --no-rrds --no-logs --keep 8

Alle Kommandos:

Kommando Wirkung
job list angelegte Jobs anzeigen
job status Zeitplan, Cron-Datei und Schalter
job add --name N --cron "…" Job anlegen
job set NAME … Job ändern (nicht genannte Felder bleiben)
job del NAME Job löschen (die Backups bleiben)
job enable|disable NAME Job ein-/ausschalten
job run NAME Job sofort ausführen
job run-all alle aktiven Jobs ausführen
job auto on|off automatische Ausführung ein/aus

Optionen von job add / job set:

Option Bedeutung
--sites ALL|a,b zu sichernde Sites (Vorgabe ALL)
--cron "15 2 * * *" Zeitplan, fünf Cron-Felder
--dir VERZ Zielverzeichnis dieses Jobs (Vorgabe BACKUP_DIR)
--keep N wie viele Backups im Ziel bleiben (0 = alle)
--no-rrds, --no-logs, --stop wie bei backup
--disabled anlegen, aber noch nicht einplanen

Automatik ein- und ausschalten

sudo ./scripts/cmk-manage.sh job auto on     # einplanen
sudo ./scripts/cmk-manage.sh job auto off    # Zeitplan entfernen

on schreibt aus allen aktiven Jobs die Datei /etc/cron.d/checkmk-backup – je Job eine Zeile mit seinem eigenen Zeitplan:

15 2 * * * root /opt/checkmk-stack/scripts/cmk-manage.sh -y job run nachts    >>/var/log/cmk-backup.log 2>&1
30 3 * * 0 root /opt/checkmk-stack/scripts/cmk-manage.sh -y job run nas-woche >>/var/log/cmk-backup.log 2>&1

Dafür werden root-Rechte gebraucht. Ohne root gibt das Kommando die Zeilen aus, damit man sie selbst übernehmen kann. off entfernt die Datei wieder; die Jobs selbst bleiben erhalten. Der Schalter steht als BACKUP_AUTO in der .env.

Nach jedem Lauf räumt der Job sein eigenes Zielverzeichnis auf --keep auf – ein separater prune-Eintrag ist nicht nötig.

Wo die Jobs liegen

In backup-jobs.conf im Projektverzeichnis, eine Zeile je Job:

name|sites|cron|verzeichnis|optionen|aufbewahren|aktiv
nachts|ALL|15 2 * * *|/opt/checkmk-stack/backups|--no-logs|14|on
nas-woche|prod,test|30 3 * * 0|/mnt/nas/checkmk|--no-rrds --no-logs|8|on

Die Datei ist bewusst lesbar und versionierbar, gehört aber nicht ins Repository (sie steht in .gitignore, weil sie systemspezifische Pfade enthält).


16. Restore

# Einfachster Fall: Site existiert nicht mehr
sudo ./scripts/cmk-manage.sh restore --file backups/cmkbackup_cmk_2.3.0p23.cre_20260820-030000.tar.gz

# Vorhandene Site überschreiben (laufende Prozesse beenden)
sudo ./scripts/cmk-manage.sh restore --file backups/… --reuse --kill

# Unter anderem Namen zurückspielen (z. B. für einen Test)
sudo ./scripts/cmk-manage.sh restore --file backups/… --as-site test

Ablauf des Skripts:

  1. Archivstruktur und SHA256-Prüfsumme kontrollieren
  2. prüfen, ob die Checkmk-Version des Backups im Container vorhanden ist
  3. bei vorhandener Site Rückfrage/--reuse, Site stoppen
  4. Archiv in den Container kopieren und omd restore ausführen
  5. TMPFS der Site abschalten (im Container nicht nutzbar)
  6. Site starten und Hinweise ausgeben

--as-site ändert den Site-Namen – registrierte Agents zeigen dann ins Leere und müssten neu registriert werden. Für eine Migration also nicht verwenden.

Ein rohes omd backup-Archiv (ohne Bundle-Hülle) wird ebenfalls akzeptiert; der Site-Name wird dann aus dem Archiv gelesen.


17. Migration einer Direktinstallation (migrate_creator.sh)

Ziel: eine bestehende Checkmk-Installation auf Blech/VM in den Container übernehmen – ohne die Agents anzufassen.

17.1 Warum die Agents weiterlaufen

Ein omd backup enthält die komplette Site inklusive etc/ssl (site-eigene CA und Zertifikate der registrierten Agents), etc/check_mk (Regeln, Hosts, Passwörter) und der Monitoring-Historie. Wird die Site unter demselben Namen wiederhergestellt und ist der Server unter derselben IP-Adresse erreichbar, dann

  • finden Push-/Pull-Agents (cmk-agent-ctl) ihre Registrierung wieder,
  • bleibt die TLS-Verbindung zum Agent-Receiver auf Port 8000 gültig,
  • stimmen alle URLs (https://<ip>/<site>/check_mk/…) weiterhin,
  • bleiben Performance-Daten und Historie erhalten.

Voraussetzung ist deshalb, dass das Zielsystem die IP des Quellservers übernimmt (bzw. der DNS-Name darauf umgestellt wird) – das ist im geplanten Vorgehen ohnehin so.

17.2 Schritt 1 – Skript auf den Quellserver kopieren

scp scripts/migrate_creator.sh root@alt-server:/root/
ssh root@alt-server 'chmod +x /root/migrate_creator.sh'

Das Skript ist eigenständig – es braucht auf dem Quellserver nur bash, tar und omd (für die Oberfläche zusätzlich dialog oder whiptail).

17.3 Schritt 2 – Bundle auf dem Quellserver erzeugen

Vorhandene Sites anzeigen:

sudo ./migrate_creator.sh --list
SITE                 VERSION            STATUS       GROESSE
prod                 2.3.0p23.cre       laeuft       4.7 GiB
test                 2.3.0p23.cre       gestoppt     318.2 MiB

Mit Oberfläche (Sites per Leertaste auswählen):

sudo ./migrate_creator.sh --gui

Der Dialog fragt nacheinander ab: Sites → Optionen (Site stoppen, RRDs/Logs auslassen) → Zielverzeichnis → Kennzeichnung → optionale Übertragung per scp.

Mit Parametern:

# eine Site, Site während des Backups stoppen (konsistenteste Variante)
sudo ./migrate_creator.sh --site prod --stop --out /var/tmp

# alle Sites, ohne Logs, direkt auf das Zielsystem übertragen
sudo ./migrate_creator.sh --all --no-logs \
     --scp root@10.0.0.5:/opt/checkmk-stack/backups/

Ergebnis:

/var/tmp/cmkmigrate_prod_2.3.0p23.cre_20260820-101500.tar.gz

Das Bundle enthält zusätzlich zum omd-Backup ein MANIFEST mit Site-Name, Checkmk-Version, Quell-Hostname, Quell-IP-Adressen, Quell-Betriebssystem und SHA256-Prüfsumme sowie ein Verzeichnis siteinfo/ mit omd config show, omd status und der IP-Konfiguration des Altsystems zur späteren Kontrolle.

17.4 Schritt 3 – Zielsystem auf die richtige Version bringen

omd restore kann eine Site nur wiederherstellen, wenn genau deren Checkmk-Version im Zielsystem installiert ist. Im Container kommt die Version aus dem Image – also muss der Image-Tag passen:

tar -xzOf backups/cmkmigrate_prod_*.tar.gz cmkbundle/MANIFEST | grep CMK_VERSION
# CMK_VERSION=2.3.0p23.cre   ->  Version 2.3.0p23, Endung .cre = Raw Edition

# passendes Image holen und als CMK_IMAGE eintragen lassen
sudo ./scripts/cmk-manage.sh image pull --edition raw --version 2.3.0p23
sudo ./scripts/cmk-manage.sh up

Bei einer Enterprise-Quelle (.cee) entsprechend:

sudo ./scripts/cmk-manage.sh image pull --edition enterprise --version 2.3.0p23 \
     --user <benutzer> --password <kennwort>
# oder, wenn die Registry nicht erreichbar ist:
sudo ./scripts/cmk-manage.sh image download --edition enterprise --version 2.3.0p23 \
     --user <benutzer> --password <kennwort>

Das Import-Skript prüft das selbst und bricht mit einer entsprechenden Meldung ab, wenn die Version fehlt.

Edition beachten: die Endung der Version verrät sie – .cre = Raw, .cee = Enterprise, .cce = Cloud, .cme = Managed. Das Import-Skript liest sie aus dem Manifest und nennt im Fehlerfall direkt das passende image pull-Kommando. Enterprise-Images gibt es nicht auf Docker Hub – siehe Kapitel 8.

17.5 Schritt 4 – Bundle importieren

Mit Oberfläche:

sudo ./scripts/cmk-manage.sh gui      # -> "import"

Mit Parametern:

sudo ./scripts/cmk-manage.sh import \
     --file backups/cmkmigrate_prod_2.3.0p23.cre_20260820-101500.tar.gz \
     --set-default-site

Das Skript

  1. erkennt das Migrations-Bundle und zeigt Quell-Host und Quell-IP an,
  2. warnt, wenn die IP dieses Hosts von der Quell-IP abweicht (dann müssten die Agents nachgeführt werden),
  3. prüft Prüfsumme, Version und Edition,
  4. fragt bei bereits vorhandener Site nach (--reuse überschreibt),
  5. führt omd restore unter dem unveränderten Site-Namen aus,
  6. setzt auf Wunsch CMK_SITE_ID in der .env (--set-default-site), damit der Container die Site auch nach einem Reboot automatisch startet,
  7. startet die Site und gibt die nächsten Schritte aus.

17.6 Schritt 5 – Umschalten und kontrollieren

# 1) Alten Server abschalten bzw. dessen Site stoppen (kein Doppel-Monitoring!)
ssh root@alt-server 'omd stop prod'

# 2) Zielsystem auf die IP/den DNS-Namen des Altsystems umstellen
#    (statische IP übernehmen oder DNS-Eintrag umbiegen)

# 3) Container neu erstellen, falls CMK_SITE_ID geändert wurde
sudo ./scripts/cmk-manage.sh up
sudo ./scripts/cmk-manage.sh status

# 4) Kontrolle in Checkmk
sudo ./scripts/cmk-manage.sh omd su prod
   OMD[prod]:~$ cmk -O                # Konfiguration aktivieren
   OMD[prod]:~$ omd status
   OMD[prod]:~$ exit

Danach in der Oberfläche prüfen:

  • Monitor → All hosts – melden sich die Agents wieder?
  • Bei TLS-Agents: der Service „Check_MK Agent“ darf keine Registrierungsfehler melden.
  • Ein Agent lässt sich vom überwachten Host aus testen mit cmk-agent-ctl status – dort muss die Site prod mit dem Zielserver und „Connection: TLS“ erscheinen.

17.7 Checkliste Migration

  • migrate_creator.sh auf den Quellserver kopiert
  • Bundle erzeugt (möglichst mit --stop)
  • Bundle auf das Zielsystem kopiert (backups/)
  • passendes Image geholt (image pull/image download), CMK_IMAGE gesetzt, Stack neu erstellt
  • import --set-default-site ausgeführt, Site läuft
  • Alte Site gestoppt / alter Server abgeschaltet
  • IP bzw. DNS auf das Zielsystem umgestellt
  • Ports 80/443/8000 in der Firewall offen
  • Proxy-Host im NGINX Proxy Manager mit Zertifikat eingerichtet
  • Agents melden sich, cmk -O ausgeführt
  • Backup des neuen Systems eingerichtet (Cron)

18. Mehrere Sites in einem Container

Der Checkmk-Entrypoint legt beim Start nur die Site aus CMK_SITE_ID an und startet auch nur diese. Weitere Sites (z. B. mehrere importierte) existieren im Bind-Mount, werden aber nach einem Neustart nicht automatisch hochgefahren.

Deshalb:

sudo ./scripts/cmk-manage.sh start-all-sites

Dieses Kommando wird von der systemd-Unit (ExecStartPost) bzw. der Quadlet-Unit automatisch nach dem Containerstart ausgeführt und startet alle vorhandenen Sites.

Empfehlung: Für sauber getrennte Umgebungen lieber je Site ein eigenes Projektverzeichnis mit eigener .env betreiben. Da beide Container im Host-Netzwerk laufen, kann pro Host allerdings nur ein Checkmk-Container die Ports 5000/8000 belegen – für echte Mehrfachinstanzen dann getrennte Hosts oder eine Bridge-Netzwerk-Variante verwenden.


19. Checkmk aktualisieren

Da /omd/sites ein Bind-Mount ist, überleben die Daten den Austausch des Images. Die Checkmk-Software selbst steckt im Image unter /omd/versions.

# 1) IMMER zuerst sichern
sudo ./scripts/cmk-manage.sh backup --all --label vor-update

# 2) neues Image holen (traegt CMK_IMAGE automatisch in die .env ein)
sudo ./scripts/cmk-manage.sh image pull --edition raw --version 2.3.0p28

# 3) Container neu erstellen
sudo ./scripts/cmk-manage.sh up

# 4) Site aktualisieren (interaktiv, Konflikte bestätigen)
sudo ./scripts/cmk-manage.sh omd stop cmk
sudo ./scripts/cmk-manage.sh omd update cmk
sudo ./scripts/cmk-manage.sh omd start cmk

Bei einem Versionssprung (z. B. 2.2 → 2.3) unbedingt vorher die Checkmk-Werksnotizen (Werks/Release Notes) lesen.


20. Fehlersuche

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
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
Import bricht mit Editions-Warnung ab Enterprise-Backup benötigt ein Enterprise-Image, siehe Kapitel 8
manifest unknown beim Pull Das Repository ist da, das Tag nicht. cmk-manage.sh image why nennt die vorhandenen Tags des Zweigs
repository name unknown / Login Succeeded, aber Pull scheitert Der Repository-Pfad stimmt nicht. cmk-manage.sh image repos --edition enterprise zeigt, was die Registry anbietet; sonst über den Tarball gehen
image not known / Podman sucht bei registry.access.redhat.com kurzer Image-Name. CMK_IMAGE vollqualifiziert setzen: cmk-manage.sh image use docker.io/… bzw. registry.checkmk.com/enterprise/…
checkmk/check-mk-enterprise nicht auf Docker Hub gefunden richtig so – Enterprise liegt nur auf registry.checkmk.com oder als Tarball vor; ab 2.5 heißt die Edition pro und liegt frei auf Docker Hub
Tarball mit podman import eingespielt, Image „unbekannt“ import erzeugt ein Image ohne Metadaten. Fehl-Image mit podman rmi <id> entfernen und cmk-manage.sh image load --file … verwenden (nutzt load)
Download des Image-Tarballs schlägt fehl (401/404) Zugangsdaten des Kundenportals prüfen, exakte Version angeben (kein -latest), notfalls image download --url '<vollständige URL>'
Proxy zeigt 502 Bad Gateway Checkmk-Container läuft nicht oder Weiterleitung nicht auf 127.0.0.1:5000 gesetzt: ./scripts/cmk-manage.sh status, curl -I http://127.0.0.1:5000/
Let's Encrypt schlägt fehl Port 80 aus dem Internet nicht erreichbar oder DNS falsch; Alternative: DNS-Challenge oder selbstsigniertes Zertifikat
Agents melden sich nach der Migration nicht Site-Name geändert (--as-site), IP nicht übernommen oder Port 8000 blockiert; auf dem Agent prüfen: cmk-agent-ctl status
Permission denied auf data/ unter RHEL SELinux: restorecon -Rv /opt/checkmk-stack/data, :Z an den Mounts prüfen
podman-compose nicht gefunden EPEL aktivieren oder auf Quadlet umstellen (./install.sh --quadlet)
This system is not registered with an entitlement server RHEL ohne Subskription – dnf liefert dann gar keine Pakete. Registrieren, Installations-DVD als Repository einbinden oder auf Rocky/Alma wechseln: Abschnitt 5.1
epel-release lässt sich nicht installieren EPEL setzt Red Hats Basis-Repositories voraus und ersetzt die Registrierung nicht. Ohne Subskription führt der Quadlet-Weg ohne podman-compose zum Ziel: Kapitel 6, Variante B
Proxy-Manager-Container startet nicht mehr mit Schalter steht auf off: cmk-manage.sh npm-enable on. Prüfen mit cmk-manage.sh npm-enable
Adminoberfläche aus dem LAN nicht erreichbar Port 81 gesperrt. Auf einen freien Port legen: cmk-manage.sh npm-port 10443 und in der Firewall freigeben
Nach npm-port antwortet der neue Port nicht Proxy Manager wurde nicht neu gestartet: cmk-manage.sh restart; Datei prüfen: data/npm/data/nginx/custom/http.conf
cmk-manage.sh bricht mit „CMK_RUNTIME … ist nicht installiert" ab wird nur noch gewarnt und selbst gesucht; sauber setzen mit config set CMK_RUNTIME auto
Browser bleibt schwarz, „Waiting for Firefox to connect…" Die Startseite antwortet nicht – meist läuft der Proxy Manager nicht. Das Skript meldet das jetzt vorab, siehe Kapitel 11.3
Proxy-Manager-Oberfläche im Browser leer / nur Textfragmente Textbrowser ohne JavaScript verwendet. cmk-manage.sh browser --engine browsh (bzw. carbonyl) nehmen
Selbstsigniertes Zertifikat lässt sich im Terminal-Browser nicht hochladen Datei-Dialoge gibt es dort nicht – Upload über die API, siehe Kapitel 11.4
browser meldet „braucht ein echtes Terminal" Aufruf aus Pipe/Skript. Direkt auf der Konsole oder per SSH aufrufen; nur der Bau geht headless mit --build-only
Menüpunkt bricht mit einer Fehlermeldung in die Shell ab behoben: fehlende Container, Sites oder Backups werden jetzt als Dialog gemeldet, die Oberfläche bleibt offen
job auto on meldet fehlende Rechte /etc/cron.d/ braucht root: mit sudo aufrufen, oder die ausgegebenen Zeilen selbst übernehmen
Proxy Manager verlangt beim ersten Aufruf ein neues Konto seit 2.15 normal. NPM_ADMIN_EMAIL/NPM_ADMIN_PASSWORD vor dem ersten Start setzen; ist das Konto schon angelegt, dessen Daten dort eintragen
Im Terminal-Browser erscheint bei Proxy-Hosts ein JSON-Fehler Die Oberfläche ist dafür zu aufwendig. Proxy-Hosts stattdessen über cmk-manage.sh proxy add anlegen (Kapitel 10.2)
TUI startet nicht dialog installieren: apt-get install -y dialog bzw. dnf install -y dialog
Site startet nicht, tmp-Fehler ./scripts/cmk-manage.sh omd config <site> set TMPFS off, danach Site starten

Nützliche Kommandos:

./scripts/cmk-manage.sh logs -f                  # Container-Logs
./scripts/cmk-manage.sh omd status cmk           # Dienste der Site
./scripts/cmk-manage.sh shell                    # Root-Shell im Container
docker exec -it checkmk omd su cmk               # bzw. podman exec …

21. Sicherheitshinweise

  • CMK_PASSWORD sofort nach der Installation in der Oberfläche ändern und aus der .env entfernen (wird nur bei der Neuanlage ausgewertet); chmod 600 .env ist gesetzt.
  • NPM_ADMIN_PASSWORD vor dem ersten Start auf ein eigenes Kennwort setzen – daraus wird das Administratorkonto des Proxy Managers erzeugt.
  • Port 81 (Adminoberfläche) nur aus dem Administrationsnetz erreichbar machen, Port 5000 gar nicht nach außen öffnen.
  • Backups enthalten alle Passwörter und Zertifikate der Site – verschlüsselt ablegen bzw. Zugriffsrechte eng fassen (chmod 700 backups).
  • Regelmäßig ./scripts/cmk-manage.sh pull + up für Sicherheitsupdates der Images einplanen.
  • Host-Netzwerk bedeutet: der Container teilt sich den Netzwerk-Stack des Hosts. Es gibt keine zusätzliche Netzwerkisolierung – die Absicherung erfolgt über die Firewall des Hosts.

22. Deinstallation

sudo ./scripts/cmk-manage.sh down

# systemd
sudo systemctl disable --now checkmk-stack.service
sudo rm -f /etc/systemd/system/checkmk-stack.service
# bzw. Quadlet
sudo rm -f /etc/containers/systemd/checkmk.container \
           /etc/containers/systemd/nginx-proxy-manager.container
sudo systemctl daemon-reload

# Images entfernen (Namen aus "cmk-manage.sh image list")
docker image rm docker.io/checkmk/check-mk-raw:2.3.0-latest docker.io/jc21/nginx-proxy-manager:2
# podman image rm …

# ggf. gespeicherte Registry-Anmeldung entfernen
podman logout registry.checkmk.com   # bzw. docker logout

# Daten (ACHTUNG: löscht die komplette Überwachung!)
sudo rm -rf /opt/checkmk-stack/data

Lizenz / Hinweise

Dieses Projekt enthält lediglich Konfiguration und Hilfsskripte. Checkmk (Raw Edition, GPLv2) und NGINX Proxy Manager (MIT) unterliegen den Lizenzbedingungen der jeweiligen Hersteller.