From a3de448b17ab4476e3b48ee896d588d157b0d9e1 Mon Sep 17 00:00:00 2001 From: jonnybravo Date: Tue, 8 Sep 2026 14:51:34 +0200 Subject: [PATCH] Molecule 7/7: ansible_remote_tmp fix --- README.md | 169 +++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 5 +- scp_copy.py | 53 ++++++++++++++ site/entrypoint.sh | 3 + 4 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 README.md create mode 100644 scp_copy.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2a4a64 --- /dev/null +++ b/README.md @@ -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 `
`-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 | \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 01b81ac..06801b2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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 diff --git a/scp_copy.py b/scp_copy.py new file mode 100644 index 0000000..07c7c8b --- /dev/null +++ b/scp_copy.py @@ -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() + diff --git a/site/entrypoint.sh b/site/entrypoint.sh index 27b4c4e..e5f93f4 100755 --- a/site/entrypoint.sh +++ b/site/entrypoint.sh @@ -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