Rocky container: Unterschied zwischen den Versionen

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen
Zeile 4: Zeile 4:
 
! Parameter !! Wert !! Erläuterung
 
! Parameter !! Wert !! Erläuterung
 
|-
 
|-
| '''VM Name || container || Name der VM
+
| '''VM Name''' || container || Name der VM
 
|-
 
|-
 
| '''Disk''' || 20GB || Vorgabe übernehmen
 
| '''Disk''' || 20GB || Vorgabe übernehmen
Zeile 12: Zeile 12:
 
| '''Ram''' || 4 GB || Speicher
 
| '''Ram''' || 4 GB || Speicher
 
|-
 
|-
| '''Netzwerk (NIC)''' || DMZ|| Interface-Zuweisung in VirtualBox
+
| '''Netzwerk (NIC)''' || DMZ || Interface-Zuweisung in VirtualBox
 
|-
 
|-
 
| '''Admin''' || root || Passwort: radler
 
| '''Admin''' || root || Passwort: radler
Zeile 22: Zeile 22:
 
| '''CIDR''' || 24 || Classless Inter-Domain Routing Präfixlänge
 
| '''CIDR''' || 24 || Classless Inter-Domain Routing Präfixlänge
 
|-
 
|-
| '''GW''' || 10.88.2XX.1 || GATEWAY  
+
| '''GW''' || 10.88.2XX.1 || GATEWAY
 
|-
 
|-
| '''NS''' || 10.88.2XX.21 || Resolver  
+
| '''NS''' || 10.88.2XX.21 || Resolver
 
|-
 
|-
 
| '''FQDN''' || container.it2XX.int || Fully Qualified Domain Name
 
| '''FQDN''' || container.it2XX.int || Fully Qualified Domain Name
 
|-
 
|-
| '''DOM''' || it2XX.int|| Domain Name
+
| '''DOM''' || it2XX.int || Domain Name
 
|}
 
|}
 
{{Vorlage:Rocky Setup}}
 
{{Vorlage:Rocky Setup}}
Zeile 36: Zeile 36:
 
Als Ausblick nach der klassischen Systemadministration wird auf der
 
Als Ausblick nach der klassischen Systemadministration wird auf der
 
Maschine '''container.it2XX.int''' ein kleines Container-Setup gezeigt:
 
Maschine '''container.it2XX.int''' ein kleines Container-Setup gezeigt:
Uptime Kuma als Monitoring-Tool, davor Caddy als Reverse Proxy. Beide
+
Uptime Kuma als Monitoring-Tool, davor Caddy als Reverse Proxy. Jeder
laufen als Podman-Container, verwaltet über '''podman-compose'''.
+
Dienst bekommt sein '''eigenes Verzeichnis mit eigener compose.yaml''' –
 +
das entspricht der Praxis, Container-Stacks unabhängig voneinander
 +
verwaltbar zu halten (eigenes Update, eigenes Down/Up, ohne andere
 +
Dienste zu berühren). Verwaltet werden die einzelnen Stacks über
 +
'''podman-compose'''.
  
 
=== Was ist Podman ===
 
=== Was ist Podman ===
Zeile 70: Zeile 74:
 
* <code>/etc/ssl/own.crt</code>
 
* <code>/etc/ssl/own.crt</code>
 
* <code>/etc/ssl/own.key</code>
 
* <code>/etc/ssl/own.key</code>
 +
 +
=== Verzeichnisstruktur ===
 +
 +
Jeder Container-Dienst bekommt ein eigenes Verzeichnis mit eigener
 +
Compose-Datei. Der Dateiname ist immer '''compose.yaml''' – das ist der
 +
aktuelle Standardname (der alte Name <code>docker-compose.yml</code>
 +
funktioniert zwar auch noch, wird aber nicht mehr verwendet).
 +
podman-compose sucht beim Aufruf automatisch nach dieser Datei im
 +
aktuellen Arbeitsverzeichnis.
 +
 +
<pre>
 +
/opt/monitoring/
 +
├── uptime-kuma/
 +
│  └── compose.yaml
 +
├── caddy/
 +
│  ├── compose.yaml
 +
│  └── Caddyfile
 +
└── hedgedoc/          (Beispiel für weiteren Dienst)
 +
    └── compose.yaml
 +
</pre>
 +
 +
;Merksatz
 +
Ein Verzeichnis = ein Dienst = ein eigenständiges Compose-Projekt.
 +
Jeder Dienst lässt sich einzeln starten, stoppen und aktualisieren,
 +
ohne die anderen zu beeinflussen.
  
 
=== Wie Container sich im Netzwerk finden: DNS über container_name ===
 
=== Wie Container sich im Netzwerk finden: DNS über container_name ===
  
Podman (wie Docker) legt für jedes in <code>networks:</code> definierte
+
Podman (wie Docker) legt für jedes Netzwerk ein eigenes internes DNS
Netz ein eigenes internes DNS auf. Jeder Container ist darin unter
+
an. Jeder Container ist darin unter seinem '''container_name'''
seinem '''container_name''' erreichbar – nicht unter <code>localhost</code>
+
erreichbar – nicht unter <code>localhost</code> und nicht über die
und nicht über die Host-IP.
+
Host-IP.
  
 
;Merksatz
 
;Merksatz
container_name = Hostname im internen Compose-Netz. Zwei Container im
+
container_name = Hostname im internen Netz. Zwei Container im selben
selben <code>networks:</code>-Eintrag erreichen sich gegenseitig per
+
Netzwerk erreichen sich gegenseitig per <code>ping container_name</code>
<code>ping container_name</code> bzw. <code>curl http://container_name:PORT</code>.
+
bzw. <code>curl http://container_name:PORT</code>.
  
Das bedeutet konkret für unser Setup: Caddy spricht Uptime Kuma nicht
+
'''Wichtige Besonderheit bei getrennten Verzeichnissen:''' Jedes
über <code>127.0.0.1:3001</code> an, sondern über <code>uptime-kuma:3001</code>
+
Compose-Projekt legt normalerweise sein eigenes, isoliertes Netzwerk
– beide hängen im Netz <code>monitoring</code>.
+
an. Liegen uptime-kuma und caddy in unterschiedlichen Verzeichnissen
 +
(= unterschiedliche Compose-Projekte), würden sie sich '''nicht'''
 +
automatisch finden. Die Lösung: Das Netzwerk wird einmalig '''manuell
 +
und projektübergreifend''' angelegt, und jede compose.yaml bindet sich
 +
darüber als <code>external</code> ein, statt ein eigenes zu erzeugen.
  
=== Container 1: Uptime Kuma ===
+
;Einmalig das gemeinsame Netzwerk anlegen
 +
*podman network create monitoring
 +
 
 +
=== Dienst 1: Uptime Kuma (/opt/monitoring/uptime-kuma/compose.yaml) ===
  
 
Uptime Kuma braucht keinen externen Port. Es lauscht intern auf Port
 
Uptime Kuma braucht keinen externen Port. Es lauscht intern auf Port
Zeile 95: Zeile 131:
  
 
<syntaxhighlight lang="yaml">
 
<syntaxhighlight lang="yaml">
 +
version: "3"
 +
 +
services:
 
   uptime-kuma:
 
   uptime-kuma:
 
     image: docker.io/louislam/uptime-kuma:1
 
     image: docker.io/louislam/uptime-kuma:1
Zeile 102: Zeile 141:
 
     networks:
 
     networks:
 
       - monitoring
 
       - monitoring
 +
 +
volumes:
 +
  uptime-kuma-data:
 +
 +
networks:
 +
  monitoring:
 +
    external: true
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Zeile 110: Zeile 156:
 
am Host-Netz, ungeschützt durch TLS).
 
am Host-Netz, ungeschützt durch TLS).
  
=== Container 2: Caddy (Reverse Proxy) ===
+
Der Eintrag <code>networks.monitoring.external: true</code> ist hier
 +
entscheidend: er sagt podman-compose "leg kein eigenes Netz an, nutze
 +
das bereits existierende <code>monitoring</code>-Netz".
 +
 
 +
=== Dienst 2: Caddy (/opt/monitoring/caddy/compose.yaml) ===
  
 
Caddy ist der einzige Container, der Ports nach außen (Host) öffnen
 
Caddy ist der einzige Container, der Ports nach außen (Host) öffnen
 
muss, weil er der einzige Kontaktpunkt von außen ist. Er terminiert
 
muss, weil er der einzige Kontaktpunkt von außen ist. Er terminiert
 
TLS mit dem vorhandenen Zertifikat und leitet intern per Klartext-HTTP
 
TLS mit dem vorhandenen Zertifikat und leitet intern per Klartext-HTTP
an <code>uptime-kuma:3001</code> weiter.
+
an die jeweiligen Backend-Dienste weiter.
  
 
<syntaxhighlight lang="yaml">
 
<syntaxhighlight lang="yaml">
 +
version: "3"
 +
 +
services:
 
   caddy:
 
   caddy:
 
     image: docker.io/library/caddy:2
 
     image: docker.io/library/caddy:2
Zeile 131: Zeile 184:
 
     networks:
 
     networks:
 
       - monitoring
 
       - monitoring
    depends_on:
+
 
      - uptime-kuma
+
volumes:
 +
  caddy-data:
 +
 
 +
networks:
 +
  monitoring:
 +
    external: true
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Zeile 141: Zeile 199:
 
caddy-data) ist das nicht nötig, das übernimmt Podman selbst.
 
caddy-data) ist das nicht nötig, das übernimmt Podman selbst.
  
=== Caddyfile ===
+
;Hinweis depends_on
 +
Da Caddy und Uptime Kuma in getrennten Compose-Projekten liegen, gibt
 +
es zwischen ihnen kein <code>depends_on</code> mehr (das funktioniert
 +
nur innerhalb desselben Projekts). Das ist unproblematisch: Caddy
 +
versucht bei jeder Anfrage erneut, den Upstream zu erreichen, und
 +
verkraftet einen kurzzeitig noch nicht gestarteten Backend-Dienst
 +
klaglos.
 +
 
 +
=== Caddyfile (/opt/monitoring/caddy/Caddyfile) ===
  
 
Die '''Caddyfile''' ist Caddys eigene Konfigurationsdatei (reiner Text,
 
Die '''Caddyfile''' ist Caddys eigene Konfigurationsdatei (reiner Text,
Zeile 147: Zeile 213:
 
wird und wohin intern weitergeleitet wird.
 
wird und wohin intern weitergeleitet wird.
  
;Im selben Verzeichnis wie die compose.yaml anlegen (z. B. /opt/monitoring/Caddyfile)
 
 
<pre>
 
<pre>
 
kuma.it2XX.int {
 
kuma.it2XX.int {
Zeile 158: Zeile 223:
 
* <code>kuma.it2XX.int {</code> – für welchen Hostnamen (Host-Header) der Block gilt
 
* <code>kuma.it2XX.int {</code> – für welchen Hostnamen (Host-Header) der Block gilt
 
* <code>tls ...</code> – welches Zertifikat/Key für diesen Host verwendet wird
 
* <code>tls ...</code> – welches Zertifikat/Key für diesen Host verwendet wird
* <code>reverse_proxy uptime-kuma:3001</code> – wohin die entschlüsselte Anfrage intern weitergeleitet wird (container_name als DNS-Name)
+
* <code>reverse_proxy uptime-kuma:3001</code> – wohin die entschlüsselte Anfrage intern weitergeleitet wird (container_name als DNS-Name, funktioniert nur weil beide Container im selben externen Netz <code>monitoring</code> hängen)
  
=== Einen zweiten Dienst dazugeben ===
+
=== Einen weiteren Dienst dazugeben ===
  
Soll z. B. HedgeDoc als zweiter Dienst hinzu, gilt immer dasselbe
+
Soll z. B. HedgeDoc als weiterer Dienst hinzu, gilt immer dasselbe
Schema:
+
Schema – wieder ein eigenes Verzeichnis:
  
# Container-Definition mit eigenem '''container_name''' in <code>compose.yaml</code>
+
# Neues Verzeichnis <code>/opt/monitoring/hedgedoc/</code> mit eigener <code>compose.yaml</code>
# Container hängt im '''selben''' <code>networks:</code>-Eintrag (<code>monitoring</code>)
+
# Container hängt über <code>external: true</code> im '''selben''' Netzwerk <code>monitoring</code>
 
# Kein <code>ports:</code>-Eintrag beim Backend-Dienst – nur Caddy exponiert Ports
 
# Kein <code>ports:</code>-Eintrag beim Backend-Dienst – nur Caddy exponiert Ports
 
# Eigener Host-Block in der Caddyfile, der per <code>container_name:internerPort</code> auf den Dienst zeigt
 
# Eigener Host-Block in der Caddyfile, der per <code>container_name:internerPort</code> auf den Dienst zeigt
  
 
<syntaxhighlight lang="yaml">
 
<syntaxhighlight lang="yaml">
 +
version: "3"
 +
 +
services:
 
   hedgedoc:
 
   hedgedoc:
 
     image: docker.io/linuxserver/hedgedoc:latest
 
     image: docker.io/linuxserver/hedgedoc:latest
Zeile 178: Zeile 246:
 
     networks:
 
     networks:
 
       - monitoring
 
       - monitoring
 +
 +
volumes:
 +
  hedgedoc-data:
 +
 +
networks:
 +
  monitoring:
 +
    external: true
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
Ergänzung in der Caddyfile:
  
 
<pre>
 
<pre>
Zeile 186: Zeile 263:
 
}
 
}
 
</pre>
 
</pre>
 
Nicht vergessen: neues Volume (<code>hedgedoc-data</code>) unter
 
<code>volumes:</code> deklarieren.
 
  
 
;Merksatz
 
;Merksatz
Ein neuer Dienst braucht drei Dinge: eigener container_name, gleiches
+
Ein neuer Dienst braucht vier Dinge: eigenes Verzeichnis, eigener
Netzwerk wie Caddy, eigener Host-Block in der Caddyfile mit
+
container_name, Anbindung an das externe Netz <code>monitoring</code>
<code>container_name:Port</code>. Der Port nach außen bleibt immer nur
+
via <code>external: true</code>, eigener Host-Block in der Caddyfile
80/443 bei Caddy – alles andere läuft intern.
+
mit <code>container_name:Port</code>. Der Port nach außen bleibt immer
 +
nur 80/443 bei Caddy – alles andere läuft intern.
  
=== compose.yaml (vollständig, Beispiel mit zwei Backend-Diensten) ===
+
=== Starten und Stoppen ===
 
 
<syntaxhighlight lang="yaml">
 
version: "3"
 
 
 
services:
 
  uptime-kuma:
 
    image: docker.io/louislam/uptime-kuma:1
 
    container_name: uptime-kuma
 
    volumes:
 
      - uptime-kuma-data:/app/data
 
    networks:
 
      - monitoring
 
 
 
  hedgedoc:
 
    image: docker.io/linuxserver/hedgedoc:latest
 
    container_name: hedgedoc
 
    volumes:
 
      - hedgedoc-data:/config
 
    networks:
 
      - monitoring
 
 
 
  caddy:
 
    image: docker.io/library/caddy:2
 
    container_name: caddy
 
    ports:
 
      - "80:80"
 
      - "443:443"
 
    volumes:
 
      - ./Caddyfile:/etc/caddy/Caddyfile:Z
 
      - /etc/ssl/own.crt:/etc/ssl/own.crt:Z
 
      - /etc/ssl/own.key:/etc/ssl/own.key:Z
 
      - caddy-data:/data
 
    networks:
 
      - monitoring
 
    depends_on:
 
      - uptime-kuma
 
      - hedgedoc
 
  
volumes:
+
Da jeder Dienst ein eigenes Verzeichnis und Compose-Projekt ist, wird
  uptime-kuma-data:
+
auch jeder Dienst einzeln aus seinem Verzeichnis heraus gestartet.
  hedgedoc-data:
+
Reihenfolge ist egal, solange das Netzwerk <code>monitoring</code>
  caddy-data:
+
bereits existiert.
 
 
networks:
 
  monitoring:
 
</syntaxhighlight>
 
 
 
=== Starten und Stoppen ===
 
  
;Stack starten
+
;Stack starten (pro Verzeichnis)
*cd /opt/monitoring
+
*cd /opt/monitoring/uptime-kuma && podman-compose up -d
*podman-compose up -d
+
*cd /opt/monitoring/caddy && podman-compose up -d
 +
*cd /opt/monitoring/hedgedoc && podman-compose up -d
  
 
;Status prüfen
 
;Status prüfen
*podman-compose ps
+
*podman ps
  
;Stack stoppen
+
;Einzelnen Dienst stoppen
*podman-compose down
+
*cd /opt/monitoring/caddy && podman-compose down
  
 
=== Test ===
 
=== Test ===
Zeile 270: Zeile 303:
 
=== Merksatz (Zusammenfassung) ===
 
=== Merksatz (Zusammenfassung) ===
 
podman-compose = ein YAML-File statt mehrerer podman-run-Befehle |
 
podman-compose = ein YAML-File statt mehrerer podman-run-Befehle |
container_name = DNS-Name im internen Netz | nur Caddy exponiert Ports
+
getrenntes Verzeichnis pro Dienst = unabhängige Compose-Projekte |
nach außen | jeder neue Dienst = eigener Block in compose.yaml +
+
gemeinsames Netz muss einmalig manuell angelegt und in jeder
eigener Host-Block in der Caddyfile
+
compose.yaml als external eingebunden werden | container_name = DNS-
 +
Name im internen Netz | nur Caddy exponiert Ports nach außen | jeder
 +
neue Dienst = eigenes Verzeichnis + eigener Host-Block in der Caddyfile

Version vom 5. Juli 2026, 11:12 Uhr

Installation

DATEN

Parameter Wert Erläuterung
VM Name container Name der VM
Disk 20GB Vorgabe übernehmen
CPU 4 Cores Kerne
Ram 4 GB Speicher
Netzwerk (NIC) DMZ Interface-Zuweisung in VirtualBox
Admin root Passwort: radler
User kit Passwort: kit
IP 10.88.2XX.39/24 Statische IP
CIDR 24 Classless Inter-Domain Routing Präfixlänge
GW 10.88.2XX.1 GATEWAY
NS 10.88.2XX.21 Resolver
FQDN container.it2XX.int Fully Qualified Domain Name
DOM it2XX.int Domain Name

Hostname

  • hostnamectl hostname FQDN

Netzwerk

  • nmcli con mod enp0s3 ipv4.addresses IP/CIDR
  • nmcli con mod enp0s3 ipv4.gateway GW
  • nmcli con mod enp0s3 ipv4.dns NS
  • nmcli con mod enp0s3 ipv4.method manual
  • nmcli con mod enp0s3 connection.autoconnect yes
  • nmcli con up enp0s3

Nameserver & Suchdomain

Der DNS wird bereits über nmcli gesetzt. Suchdomain ergänzen:

  • nmcli con mod enp0s3 ipv4.dns-search DOM
  • nmcli con up enp0s3

Tools die wir haben wollen

  • dnf install vim sudo git curl tcpdump nmap wget epel-release policycoreutils-python-utils tar

Kit Stamm-CA ziehen und in das System einbauen

Zertifikat und Key holen

Monitoring mit Uptime Kuma und Caddy (container.it2XX.int)

Als Ausblick nach der klassischen Systemadministration wird auf der Maschine container.it2XX.int ein kleines Container-Setup gezeigt: Uptime Kuma als Monitoring-Tool, davor Caddy als Reverse Proxy. Jeder Dienst bekommt sein eigenes Verzeichnis mit eigener compose.yaml – das entspricht der Praxis, Container-Stacks unabhängig voneinander verwaltbar zu halten (eigenes Update, eigenes Down/Up, ohne andere Dienste zu berühren). Verwaltet werden die einzelnen Stacks über podman-compose.

Was ist Podman

Podman ist eine Container-Engine, kompatibel zur Docker-CLI, aber ohne zentralen Root-Daemon.

Wichtigste Unterschiede zu Docker
  • Daemonless: Docker braucht einen dauerhaft laufenden Root-Daemon
 (dockerd). Fällt er aus oder wird kompromittiert, sind alle Container
 betroffen. Podman startet Container als direkte Kindprozesse ohne
 zentralen Daemon.
  • Rootless by Default: Podman-Container laufen standardmäßig ohne
 Root-Rechte. Ein Escape aus dem Container landet nicht automatisch
 bei Root auf dem Host.
  • Systemd-Integration: Podman-Container lassen sich nativ als
 systemd-Units verwalten (Quadlets), passt gut in RHEL/Rocky-Abläufe.
Merksatz

Docker = ein Daemon regiert alle Container (meist als Root) | Podman = jeder Container ein eigener Prozess, standardmäßig ohne Root-Rechte

podman-compose installieren

Über EPEL installieren
  • dnf install -y epel-release
  • dnf install -y podman-compose

Vorbereitung: Zertifikate

Die Zertifikate liegen bereits vor unter:

  • /etc/ssl/own.crt
  • /etc/ssl/own.key

Verzeichnisstruktur

Jeder Container-Dienst bekommt ein eigenes Verzeichnis mit eigener Compose-Datei. Der Dateiname ist immer compose.yaml – das ist der aktuelle Standardname (der alte Name docker-compose.yml funktioniert zwar auch noch, wird aber nicht mehr verwendet). podman-compose sucht beim Aufruf automatisch nach dieser Datei im aktuellen Arbeitsverzeichnis.

/opt/monitoring/
├── uptime-kuma/
│   └── compose.yaml
├── caddy/
│   ├── compose.yaml
│   └── Caddyfile
└── hedgedoc/          (Beispiel für weiteren Dienst)
    └── compose.yaml
Merksatz

Ein Verzeichnis = ein Dienst = ein eigenständiges Compose-Projekt. Jeder Dienst lässt sich einzeln starten, stoppen und aktualisieren, ohne die anderen zu beeinflussen.

Wie Container sich im Netzwerk finden: DNS über container_name

Podman (wie Docker) legt für jedes Netzwerk ein eigenes internes DNS an. Jeder Container ist darin unter seinem container_name erreichbar – nicht unter localhost und nicht über die Host-IP.

Merksatz

container_name = Hostname im internen Netz. Zwei Container im selben Netzwerk erreichen sich gegenseitig per ping container_name bzw. curl http://container_name:PORT.

Wichtige Besonderheit bei getrennten Verzeichnissen: Jedes Compose-Projekt legt normalerweise sein eigenes, isoliertes Netzwerk an. Liegen uptime-kuma und caddy in unterschiedlichen Verzeichnissen (= unterschiedliche Compose-Projekte), würden sie sich nicht automatisch finden. Die Lösung: Das Netzwerk wird einmalig manuell und projektübergreifend angelegt, und jede compose.yaml bindet sich darüber als external ein, statt ein eigenes zu erzeugen.

Einmalig das gemeinsame Netzwerk anlegen
  • podman network create monitoring

Dienst 1: Uptime Kuma (/opt/monitoring/uptime-kuma/compose.yaml)

Uptime Kuma braucht keinen externen Port. Es lauscht intern auf Port 3001 und wird ausschließlich über Caddy nach außen gereicht. Daten (SQLite-DB, Konfiguration) liegen in einem benannten Volume, damit sie Container-Neustarts und -Updates überleben.

version: "3"

services:
  uptime-kuma:
    image: docker.io/louislam/uptime-kuma:1
    container_name: uptime-kuma
    volumes:
      - uptime-kuma-data:/app/data
    networks:
      - monitoring

volumes:
  uptime-kuma-data:

networks:
  monitoring:
    external: true
Wichtig

Kein ports:-Eintrag nötig. Ein Backend-Dienst, der nur von Caddy angesprochen wird, muss nicht auf dem Host exponiert werden – das wäre sogar ein unnötiges Sicherheitsrisiko (Port läge dann offen am Host-Netz, ungeschützt durch TLS).

Der Eintrag networks.monitoring.external: true ist hier entscheidend: er sagt podman-compose "leg kein eigenes Netz an, nutze das bereits existierende monitoring-Netz".

Dienst 2: Caddy (/opt/monitoring/caddy/compose.yaml)

Caddy ist der einzige Container, der Ports nach außen (Host) öffnen muss, weil er der einzige Kontaktpunkt von außen ist. Er terminiert TLS mit dem vorhandenen Zertifikat und leitet intern per Klartext-HTTP an die jeweiligen Backend-Dienste weiter.

version: "3"

services:
  caddy:
    image: docker.io/library/caddy:2
    container_name: caddy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:Z
      - /etc/ssl/own.crt:/etc/ssl/own.crt:Z
      - /etc/ssl/own.key:/etc/ssl/own.key:Z
      - caddy-data:/data
    networks:
      - monitoring

volumes:
  caddy-data:

networks:
  monitoring:
    external: true
Hinweis SELinux

Das :Z an den Bind-Mounts (Caddyfile, Zertifikate) ist auf Rocky notwendig, damit Caddy trotz aktivem SELinux Lesezugriff über den passenden Kontext erhält. Bei benannten Volumes (uptime-kuma-data, caddy-data) ist das nicht nötig, das übernimmt Podman selbst.

Hinweis depends_on

Da Caddy und Uptime Kuma in getrennten Compose-Projekten liegen, gibt es zwischen ihnen kein depends_on mehr (das funktioniert nur innerhalb desselben Projekts). Das ist unproblematisch: Caddy versucht bei jeder Anfrage erneut, den Upstream zu erreichen, und verkraftet einen kurzzeitig noch nicht gestarteten Backend-Dienst klaglos.

Caddyfile (/opt/monitoring/caddy/Caddyfile)

Die Caddyfile ist Caddys eigene Konfigurationsdatei (reiner Text, kein YAML/JSON). Sie legt pro Domain fest, welches Zertifikat benutzt wird und wohin intern weitergeleitet wird.

kuma.it2XX.int {
    tls /etc/ssl/own.crt /etc/ssl/own.key
    reverse_proxy uptime-kuma:3001
}

Aufbau:

  • kuma.it2XX.int { – für welchen Hostnamen (Host-Header) der Block gilt
  • tls ... – welches Zertifikat/Key für diesen Host verwendet wird
  • reverse_proxy uptime-kuma:3001 – wohin die entschlüsselte Anfrage intern weitergeleitet wird (container_name als DNS-Name, funktioniert nur weil beide Container im selben externen Netz monitoring hängen)

Einen weiteren Dienst dazugeben

Soll z. B. HedgeDoc als weiterer Dienst hinzu, gilt immer dasselbe Schema – wieder ein eigenes Verzeichnis:

  1. Neues Verzeichnis /opt/monitoring/hedgedoc/ mit eigener compose.yaml
  2. Container hängt über external: true im selben Netzwerk monitoring
  3. Kein ports:-Eintrag beim Backend-Dienst – nur Caddy exponiert Ports
  4. Eigener Host-Block in der Caddyfile, der per container_name:internerPort auf den Dienst zeigt
version: "3"

services:
  hedgedoc:
    image: docker.io/linuxserver/hedgedoc:latest
    container_name: hedgedoc
    volumes:
      - hedgedoc-data:/config
    networks:
      - monitoring

volumes:
  hedgedoc-data:

networks:
  monitoring:
    external: true

Ergänzung in der Caddyfile:

notes.it2XX.int {
    tls /etc/ssl/own.crt /etc/ssl/own.key
    reverse_proxy hedgedoc:3000
}
Merksatz

Ein neuer Dienst braucht vier Dinge: eigenes Verzeichnis, eigener container_name, Anbindung an das externe Netz monitoring via external: true, eigener Host-Block in der Caddyfile mit container_name:Port. Der Port nach außen bleibt immer nur 80/443 bei Caddy – alles andere läuft intern.

Starten und Stoppen

Da jeder Dienst ein eigenes Verzeichnis und Compose-Projekt ist, wird auch jeder Dienst einzeln aus seinem Verzeichnis heraus gestartet. Reihenfolge ist egal, solange das Netzwerk monitoring bereits existiert.

Stack starten (pro Verzeichnis)
  • cd /opt/monitoring/uptime-kuma && podman-compose up -d
  • cd /opt/monitoring/caddy && podman-compose up -d
  • cd /opt/monitoring/hedgedoc && podman-compose up -d
Status prüfen
  • podman ps
Einzelnen Dienst stoppen
  • cd /opt/monitoring/caddy && podman-compose down

Test

Aufruf im Browser
https://kuma.it2XX.int
https://notes.it2XX.int

Beim ersten Aufruf fragt Uptime Kuma nach Anlegen eines Admin-Accounts. Danach lassen sich Monitore für ns, www, ldap, client und fw anlegen (Ping, TCP-Port, HTTP) und der Status live auf dem Dashboard verfolgen.

Merksatz (Zusammenfassung)

podman-compose = ein YAML-File statt mehrerer podman-run-Befehle | getrenntes Verzeichnis pro Dienst = unabhängige Compose-Projekte | gemeinsames Netz muss einmalig manuell angelegt und in jeder compose.yaml als external eingebunden werden | container_name = DNS- Name im internen Netz | nur Caddy exponiert Ports nach außen | jeder neue Dienst = eigenes Verzeichnis + eigener Host-Block in der Caddyfile