Molecule 7/7: ansible_remote_tmp fix
Test & Deploy Hugo Docker CMS / test-and-deploy (push) Has been cancelled

This commit is contained in:
jonnybravo
2026-09-08 14:51:34 +02:00
parent b21172b2ab
commit a3de448b17
4 changed files with 229 additions and 1 deletions
+169
View File
@@ -0,0 +1,169 @@
# Hugo Docker CMS
Hugo-basiertes CMS im Docker-Stack mit Caddy als TLS-Reverse-Proxy.
Markdown-Dateien einfach in `content/` ablegen – Hugo rendert sie automatisch.
## Architektur
```
Port 5443
Browser ── HTTPS ──→ Caddy ── HTTP ──→ Hugo (live-reload)
:2-alpine hugomods/hugo:latest
self-signed markdown → HTML
```
| Komponente | Image | Aufgabe |
|---|---|---|
| Hugo | `hugomods/hugo:latest` (0.165+) | Rendert .md-Dateien, live-reload via --watch |
| Caddy | `caddy:2-alpine` | HTTPS-Terminierung, Reverse-Proxy → Hugo:1313 |
## Verzeichnisstruktur
```
hugo_docker/
├── docker-compose.yml # Hugo + Caddy Stack
├── Caddyfile # TLS + Reverse-Proxy
├── content/ # ← .md-Dateien hier ablegen (Host-Mount)
├── crt/ # Self-signed Zertifikate
├── site/ # Hugo-Config, Layouts, CSS
│ ├── hugo.toml
│ ├── entrypoint.sh # Auto-Frontmatter + Hugo-Server
│ ├── assets/css/main.css # Modernes CSS (oklch, dark mode, grid)
│ └── layouts/ # HTML-Templates
├── ansible/
│ ├── deploy.yml # Playbook
│ ├── tasks.yml # Geteilte Tasks (DRY)
│ ├── templates/ # Caddyfile.j2, hugo.toml.j2
│ └── molecule/default/ # CI-Tests (Ubuntu Docker)
└── .gitea/workflows/
└── deploy.yml # CI: Molecule-Test → Deploy
```
## Schnellstart (lokal)
```bash
# Zertifikate generieren (nur einmal)
python3 -c "
import sys; sys.path.insert(0,'../Python_Skripte/create_selfsign')
from selfsign_ca import generate_and_save_cert
generate_and_save_cert(cert_common_name='localhost', cert_name='localhost')
"
# Container starten
docker compose up -d
# HTTPS aufrufen
curl -k https://localhost:5443/
```
## Nutzung
```bash
# Neue Seite anlegen – .md-Datei in content/ werfen
cat > content/mein-artikel.md << 'EOF'
---
title: "Mein Artikel"
date: "2026-09-08"
---
Inhalt im **Markdown**-Format.
EOF
# Kein Neustart nötig – Hugo erkennt Änderungen automatisch
docker compose restart hugo # nur bei komplett neuen Dateien
```
## Frontmatter
Der Entrypoint (`site/entrypoint.sh`) fügt **automatisch** fehlendes YAML-Frontmatter
in .md-Dateien ein – extrahiert Titel aus der ersten `#`-Überschrift, Datum aus
dem Datei-Änderungsdatum.
Hugo benötigt diesen `---`-Block:
```yaml
---
title: "Meine Seite"
date: "2026-09-08"
---
```
Mit dem Entrypoint kannst du **beliebige** .md-Dateien in `content/` werfen.
## Deployment (Ansible)
Auf entfernten Host ausrollen:
```bash
cd ansible
ansible-playbook -i "ras-dan-01," deploy.yml
```
Variablen (optional):
```bash
ansible-playbook -i "ras-dan-01," deploy.yml \
-e "target_hostname=ras-dan-01 target_port=5443"
```
Das Playbook legt alles unter `~/.docker/hugo/` auf dem Ziel-Host ab,
rendert Templates mit Hostname/Port und startet die Container.
## Zertifikate
Generiert mit `Python_Skripte/create_selfsign/selfsign_ca.py` (lokales Tool).
Jedes Zertifikat enthält eine **SAN (Subject Alternative Name)** Extension –
Pflicht für moderne Browser.
```bash
# CA systemweit vertrauen (optional, für Browser ohne Warnung)
sudo cp crt/ca.crt /etc/ca-certificates/trust-source/anchors/hugo-docker-ca.crt
sudo update-ca-trust
# Firefox / qutebrowser (NSS-Store)
certutil -A -d sql:$HOME/.pki/nssdb/ -t "CT,," \
-n "Hugo Docker CA" -i crt/ca.crt
```
## CI/CD (Gitea Actions)
Workflow in `.gitea/workflows/deploy.yml` – läuft auf Runner mit Label `shell`:
```
Push auf main
→ molecule test (Ubuntu Docker)
→ syntax, create, prepare, converge, idempotence, verify, destroy
→ ansible-playbook deploy auf ras-dan-01
```
**Voraussetzungen auf dem Runner:**
- Docker + Docker Compose
- molecule + molecule-plugins[docker] (vorinstalliert)
- ansible-core (vorinstalliert)
- SSH-Agent mit Key für ras-dan-01
## CSS-Features
Modernes Theme in `site/assets/css/main.css`:
- `oklch()`-Farbraum mit `light-dark()` – automatisch hell/dunkel
- CSS Grid Layout (Header – Main – Footer)
- TOC (Table of Contents) als aufklappbares `<details>`-Element
- Code-Highlighting mit Catppuccin-Mocha-Theme
- Responsive (max-width: 840px)
## Hugo-Version
- Image: `hugomods/hugo:latest` (aktuell 0.165.0, August 2026)
- `hugo.toml` verwendet `locale` statt `languageCode` (v0.158+)
- Goldmark-Renderer mit `unsafe: true` (HTML in Markdown erlaubt)
## Troubleshooting
| Problem | Lösung |
|---|---|
| Neue .md-Dateien erscheinen nicht | `docker compose restart hugo` (Entrypoint läuft nur beim Start) |
| Browser zeigt Zertifikatswarnung | CA in NSS-Store importieren (s.o.) |
| Caddy startet nicht | `docker compose logs caddy` – TLS-Zertifikate prüfen unter `crt/` |
| Zertifikatsfehler "no SAN" | Zertifikate mit `selfsign_ca.py` neu generieren (SAN ist jetzt enthalten) |
| Molecule-Test schlägt fehl | `ansible_remote_tmp: /tmp/.ansible` in molecule.yml prüfen |
+4 -1
View File
@@ -1,7 +1,10 @@
services:
hugo:
image: hugomods/hugo:latest # Hugo 0.165.0 (2026)
image: hugomods/hugo:latest
entrypoint: /src/entrypoint.sh
environment:
HOST_UID: "1000"
HOST_GID: "1000"
volumes:
- ./site:/src # Hugo-Config, Layouts, Assets, Entrypoint
- ./content:/src/content # HIER .md-Dateien ablegen
+53
View File
@@ -0,0 +1,53 @@
import log
import os
import subprocess
import time
def copy_files_scp(scr: str = "/home/jonnybravo/Dokumente/",
dest: str = 'ras-dan-01:/home/jonnybravo/.docker/hugo/content/',
container: str = "hugo"):
dest_host = dest.split(":")[0]
list_all_files_md = [os.path.join(scr, a) for a in os.listdir(scr) if a.endswith(".md")]
for file in list_all_files_md:
cmd = ["scp", "-o", "StrictHostKeyChecking=no", file, dest ]
#print(cmd)
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
log.log(f"SCP FEHLER: {result.stderr.strip() or result.stdout.strip()}", status="ERROR")
return False
else:
log.log(f"Datei {file} wurde kopiert !", status="SUCCESS")
if container == "":
log.log("Es wird kein Container neugestartet", status="INFO")
else:
log.log(f"Der {container} wird auf {dest_host} via SSH neugestartet !", status="INFO")
docker_cmd = ["ssh", "-o", "StrictHostKeyChecking=no", dest_host,
"docker", "compose", "-f", ".docker/hugo/docker-compose.yml", "restart", container]
result_docker = subprocess.run(docker_cmd, capture_output=True, text=True)
if result_docker.returncode != 0:
log.log(f"Der {container} konnte nicht gestartet werden: {result_docker.stderr.strip() or result_docker.stdout.strip()}", status="ERROR")
return False
else:
log.log(f"Der {container} konnte neu gestartet werden !", status="SUCCESS")
# Warten bis Hugo antwortet (max 15s)
deadline = time.time() + 15
while time.time() < deadline:
check = subprocess.run(
["ssh", "-o", "StrictHostKeyChecking=no", dest_host,
"curl", "-sk", "--max-time", "2", "-o", "/dev/null", "-w", "%{http_code}",
"https://localhost:5443/"],
capture_output=True, text=True,
)
if check.stdout.strip() == "200":
log.log("Hugo ist bereit und antwortet mit 200", status="SUCCESS")
break
time.sleep(1)
else:
log.log("Warnung: Hugo antwortet nicht innerhalb von 15s", status="WARN")
return True
if __name__ == "__main__":
copy_files_scp()
+3
View File
@@ -22,6 +22,9 @@ for md in "$CONTENT_DIR"/*.md; do
cat "$md"
} > "$tmp" && mv "$tmp" "$md"
# Besitzer zurückgeben an Host-User
chown "${HOST_UID}:${HOST_GID}" "$md" 2>/dev/null || true
echo "[frontmatter] $title"
fi
done