Files
docker-podman-installation-…/README.md
T
duffyduckandClaude Opus 5 2d645bcc0b Fehler in der Oberflaeche abfangen, Backups planbar machen
Der Anlass: "Backup erstellen" bei fehlendem Container beendete die
ganze TUI mit einer Fehlerzeile in der Shell.

Ursachen waren zwei, beide behoben:
  1. die() in GUI-Pfaden. Neue Helfer gui_need_container/gui_need_sites
     melden das Problem im Dialog und kehren zurueck. Interaktives wie
     Shell und Terminal-Browser laeuft jetzt ueber gui_run_interactive
     in einer Subshell mit Weiter-mit-ENTER.
  2. "set -e". Schon ein Rueckgabewert != 0 aus einer Menuefunktion
     beendete das Skript, weil Menuezweige keine Bedingung sind. 47
     "|| return" auf "|| return 0" gestellt und 37 Menuezweige mit
     "|| true" abgesichert. Ausserdem schlug ein "clear" ohne TERM fehl
     und riss alles mit - drei Aufrufe abgesichert.
Jeder Hauptmenuepunkt wurde einzeln durchlaufen und kehrt sauber zurueck.

Neu: Backup-Jobs
  Der Menuepunkt heisst jetzt "Backup erstellen / planen" mit Untermenue
  (manuell erstellen, Jobs verwalten, Automatik ein/aus, Zeitplan
  anzeigen, Job sofort ausfuehren). Dieselben Jobs liegen auch in den
  Einstellungen unter "Backup-Jobs".

  Manuelle Backups nehmen weiterhin immer BACKUP_DIR aus der .env.
  Jeder Job hat dagegen sein eigenes Zielverzeichnis, seinen eigenen
  Zeitplan, eigene Optionen und eine eigene Aufbewahrung, nach der er
  sein Zielverzeichnis selbst aufraeumt.

  Vollstaendig auch per Parameter:
    job list | status | add | set | del | enable | disable
        | run | run-all | auto [on|off]
  mit --name --sites --cron --dir --keep --no-rrds --no-logs --stop
  --disabled.

  "job auto on" erzeugt aus den aktiven Jobs /etc/cron.d/checkmk-backup,
  eine Zeile je Job mit dessen eigenem Zeitplan. Ohne root werden die
  Zeilen ausgegeben statt kommentarlos zu scheitern. Der Schalter steht
  als BACKUP_AUTO in der .env, die Jobs in backup-jobs.conf.

Nebenbei behoben: "local f; f=... tmp" fuehrte tmp als Kommando aus,
wodurch job_put und job_remove nichts schrieben.

Dokumentiert als Abschnitt 15.1 in beiden Sprachfassungen.

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

1905 lines
74 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Checkmk im Container – Docker (Debian) & Podman (RHEL) mit NGINX Proxy Manager
*[English version: README_en.md](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](#1-überblick--architektur)
2. [Verzeichnisstruktur](#2-verzeichnisstruktur)
3. [Voraussetzungen & Ports](#3-voraussetzungen--ports)
4. [Installation auf Debian/Ubuntu (Docker)](#4-installation-auf-debianubuntu-docker)
5. [Installation auf RHEL/Rocky/Alma/Fedora (Podman)](#5-installation-auf-rhelrockyalmafedora-podman)
* [5.1 Unregistriertes RHEL: woher die Pakete kommen](#51-unregistriertes-rhel-woher-die-pakete-kommen)
6. [Autostart nach einem Neustart des Hosts (Podman)](#6-autostart-nach-einem-neustart-des-hosts-podman)
7. [Konfiguration (`.env`)](#7-konfiguration-env)
8. [Checkmk-Image beschaffen (Raw, Enterprise & Co.)](#8-checkmk-image-beschaffen-raw-enterprise--co)
9. [Erststart](#9-erststart)
10. [HTTPS einrichten – Let's Encrypt oder selbstsigniert](#10-https-einrichten--lets-encrypt-oder-selbstsigniert)
11. [Proxy Manager lokal einrichten (Terminal-Browser)](#11-proxy-manager-lokal-einrichten-terminal-browser)
12. [Adminoberfläche auf einen anderen Port legen](#12-adminoberfläche-auf-einen-anderen-port-legen)
13. [Firewall](#13-firewall)
14. [Verwaltung: `cmk-manage.sh` (CLI und ncurses-Oberfläche)](#14-verwaltung-cmk-managesh)
15. [Backup](#15-backup)
16. [Restore](#16-restore)
17. [Migration einer Direktinstallation (`migrate_creator.sh`)](#17-migration-einer-direktinstallation-migrate_creatorsh)
18. [Mehrere Sites in einem Container](#18-mehrere-sites-in-einem-container)
19. [Checkmk aktualisieren](#19-checkmk-aktualisieren)
20. [Fehlersuche](#20-fehlersuche)
21. [Sicherheitshinweise](#21-sicherheitshinweise)
22. [Deinstallation](#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`](#12-adminoberfläche-auf-einen-anderen-port-legen) änderbar) | nur Admin-Netz! |
| 5000/tcp | Checkmk Apache (Backend) | **nur localhost** – nicht freigeben. Ausnahme: bei abgeschaltetem Proxy Manager ([12.4](#124-proxy-manager-ganz-abschalten-externer-nginx)) 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)
```bash
# 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:
```bash
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](#18-mehrere-sites-in-einem-container)).
---
## 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.
>
> ```bash
> # 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](#51-unregistriertes-rhel-woher-die-pakete-kommen).
>
> **Rocky Linux, AlmaLinux, CentOS Stream und Fedora** brauchen nichts davon –
> dort einfach weiterlesen.
```bash
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](#51-unregistriertes-rhel-woher-die-pakete-kommen)
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:
```bash
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](#variante-b--podman-quadlet-ab-podman-44-ohne-compose))
> läuft der Stack ganz ohne Compose, direkt über systemd.
Starten:
```bash
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](#82-zwei-podman-fallstricke-genau-die-aus-der-praxis)
> 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:
```bash
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.
3. Kontrolle:
```bash
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:
```bash
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:
```bash
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.
```bash
# 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.
```bash
# 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](#6-autostart-nach-einem-neustart-des-hosts-podman)
> 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:
```bash
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:
```bash
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:
```bash
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.
```bash
sudo ./install.sh --quadlet
```
Das schreibt (mit den Werten aus der `.env`) nach `/etc/containers/systemd/`:
* `checkmk.container`
* `nginx-proxy-manager.container`
Danach:
```bash
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/](systemd/quadlet/).
### Variante C – rootless Podman (optional, erhöhter Aufwand)
```bash
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`)
```bash
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](#8-checkmk-image-beschaffen-raw-enterprise--co) |
| `CMK_EDITION`, `CMK_VERSION` | nur Vorgaben fuer den Image-Downloader |
| `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](#124-proxy-manager-ganz-abschalten-externer-nginx) |
| `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 |
### 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](#14-verwaltung-cmk-managesh)).
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 (Raw → Community,
Enterprise → Pro, Managed → Ultimate MT); 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.
> 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:
```bash
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:
```bash
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
```bash
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:
```bash
./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:
```bash
# 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 eine temporäre `.netrc` an `curl` übergeben und
erscheinen daher **nicht** in der Prozessliste. 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 liegt der Test unter
**Checkmk-Image beschaffen/auswählen → „Zugangsdaten prüfen"**.
### 8.5 Image holen – drei Wege
**a) Aus einer Registry (empfohlen)**
```bash
# 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)**
```bash
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:
```bash
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 per temporaerer `.netrc`-Datei an `curl` uebergeben und
tauchen damit **nicht** in der Prozessliste auf.
**c) Bereits heruntergeladene Datei einspielen**
Wer die Datei im Browser aus dem Kundenportal geladen hat:
```bash
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. `localhost/checkmk/check-mk-enterprise:2.3.0p23`) und traegt
ihn als `CMK_IMAGE` in die `.env` ein. Danach:
```bash
sudo ./scripts/cmk-manage.sh up
```
### 8.6 Nachsehen, was gilt
```bash
./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
```bash
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/ (Erstlogin: admin@example.com / changeme)
```
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 NGINX Proxy Manager vorbereiten
1. `http://<server>:81` aufrufen – bzw. den in `NPM_ADMIN_PORT` gesetzten Port
(siehe [Kapitel 12](#12-adminoberfläche-auf-einen-anderen-port-legen));
ist der Port im Netz gesperrt, hilft der Terminal-Browser aus
[Kapitel 11](#11-proxy-manager-lokal-einrichten-terminal-browser)
2. Erstanmeldung: **admin@example.com** / **changeme**
3. Sofort E-Mail-Adresse und Passwort ändern (wird beim ersten Login erzwungen)
### 10.2 Proxy-Host für Checkmk 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):
```nginx
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.3 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.4 Variante B – Selbstsigniertes Zertifikat (interne Umgebung)
Erzeugen:
```bash
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“*.
---
## 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.
```bash
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
```bash
# 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:
```bash
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 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.4](#104-variante-b--selbstsigniertes-zertifikat-interne-umgebung)
erzeugen, dann:
```bash
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:
```bash
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.4 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:
```bash
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:
```bash
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](#11-proxy-manager-lokal-einrichten-terminal-browser) 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:
```bash
# 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
```bash
./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:
```bash
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:
```bash
# 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:
```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](#variante-b--podman-quadlet-ab-podman-44-ohne-compose))
> 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
**firewalld (RHEL/Rocky/Alma):**
```bash
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'
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):**
```bash
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 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)
```bash
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 │
│ 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 │
│ browser Terminal-Browser (Proxy Manager lokal) │
│ cert Selbstsigniertes Zertifikat erzeugen │
│ 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.
Es wird `dialog` bevorzugt; ist nur `whiptail` vorhanden, wird dieses genutzt.
Eine Dateiauswahl mit Verzeichnisnavigation ist eingebaut.
### 14.2 Kommandozeile
```bash
./scripts/cmk-manage.sh --help
```
| Kommando | Wirkung |
|---|---|
| `up` / `down` / `restart` / `pull` | Stack steuern |
| `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 status\|list\|pull\|download\|load\|use` | Checkmk-Image beschaffen und auswaehlen |
| `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) |
| `cert …` | selbstsigniertes Zertifikat erzeugen |
| `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:
```bash
./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](#12-adminoberfläche-auf-einen-anderen-port-legen)).
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.
```bash
# 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:
```bash
./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:
```bash
# 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
```bash
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:
```cron
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
```bash
# 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
```bash
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:
```bash
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):
```bash
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:**
```bash
# 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:
```bash
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:
```bash
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](#8-checkmk-image-beschaffen-raw-enterprise--co).
### 17.5 Schritt 4 – Bundle importieren
Mit Oberfläche:
```bash
sudo ./scripts/cmk-manage.sh gui # -> "import"
```
Mit Parametern:
```bash
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
```bash
# 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:
```bash
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`.
```bash
# 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 |
|---|---|
| `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](#8-checkmk-image-beschaffen-raw-enterprise--co) |
| `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](#51-unregistriertes-rhel-woher-die-pakete-kommen) |
| `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](#variante-b--podman-quadlet-ab-podman-44-ohne-compose) |
| 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` |
| 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.3](#113-grenze-datei-upload) |
| `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 |
| 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:
```bash
./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.
* Standardzugang des Proxy Managers (`admin@example.com` / `changeme`) beim
ersten Login zwingend ändern.
* 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
```bash
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.