Nginx und Let's Encrypt als wiederverwendbarer Polycrate-Block
Fabian Peter 10 Minuten Lesezeit

Nginx und Let’s Encrypt als wiederverwendbarer Polycrate-Block

Nginx und Let’s Encrypt als wiederverwendbaren Polycrate-Block bauen und teilen
Ganze Serie lesen (24 Artikel)

Diese Serie zeigt Schritt für Schritt, wie Ansible mit Polycrate zu einer strukturierten, teilbaren und compliance-fähigen Automatisierungsplattform wird – von den Grundlagen bis zu Enterprise-Szenarien.

  1. Polycrate installieren und den ersten Ansible-Block in 15 Minuten bauen
  2. Blöcke, Actions und Workspaces: Das Baukasten-Prinzip von Polycrate
  3. Linux-Server auf Autopilot: System-Management mit Polycrate und Ansible
  4. Nginx und Let's Encrypt als wiederverwendbarer Polycrate-Block
  5. Docker-Stacks auf Linux-Servern mit Polycrate verwalten
  6. Viele Server, eine Wahrheit: Multi-Server-Management mit Polycrate-Inventories
  7. Windows-Automatisierung mit Polycrate: Ansible und WinRM ohne Schmerzen
  8. Windows-Software-Deployment ohne SCCM: Chocolatey und Ansible
  9. Hybrid-Automatisierung: Windows und Linux im selben Polycrate-Workspace
  10. Kubernetes-Apps aus dem PolyHub: Von der Idee zum Deployment in Minuten
  11. Eigene Kubernetes-App als Polycrate-Block: Eine Schritt-für-Schritt-Anleitung
  12. Multi-Cluster Kubernetes mit Polycrate: Warum ein Cluster, ein Workspace
  13. SSH-Sessions und kubectl-Debugging: Polycrate als Operations-Werkzeug
  14. Helm-Charts als Polycrate-Block: Mehr Kontrolle über Chart-Deployments
  15. Policy as Code: Compliance-Anforderungen mit Polycrate automatisieren
  16. Workspace-Verschlüsselung: Secrets DSGVO-konform verwalten – ohne externes Tooling
  17. IoT und Edge Computing: Raspberry Pi und Edge-Nodes mit Polycrate verwalten
  18. Enterprise-Automatisierung: Blöcke bauen, versionieren und im Team teilen
  19. Polycrate MCP: KI-Assistenten mit Live-Infrastruktur-Kontext verbinden
  20. Polycrate vs. plain Ansible: Was du gewinnst – und warum es sich lohnt
  21. Das Polycrate-Ökosystem: PolyHub, API, MCP und die Zukunft der Automatisierung
  22. Dein erster produktiver Polycrate-Workspace: Eine Checkliste für den Start
  23. Auditierbare Operations: SSH-Sessions und CLI-Aktivitäten mit Polycrate API
  24. Polycrate API für Teams: Zentrales Monitoring und Remote-Triggering

TL;DR

  • Du baust einen wiederverwendbaren Polycrate-Block, der Nginx und Let’s Encrypt (via community.general.certbot) automatisiert auf einem Linux-Server bereitstellt – inkl. generischer nginx.conf als Jinja2-Template.
  • Der Block parametrisiert Domain, Kontakt-E-Mail und Upstream-Port über block.config.* und kann in jedem Workspace mit anderen Werten eingesetzt werden – ohne Code-Kopie oder Wiki-Bastelei.
  • Polycrate containerisiert Ansible und die gesamte Toolchain: kein lokales Ansible, kein Python-Chaos, keine individuellen Setups – der gleiche Block läuft auf jeder Developer-Workstation identisch.
  • Über eine Registry (from: cargo.ayedo.cloud/ayedo/infra/nginx-letsencrypt:1.0.0 in workspace.poly) teilst du den Block mit Kolleg:innen: vor dem Push muss name in der block.poly die volle OCI-Referenz ohne Tag sein; polycrate blocks push verwendet genau diesen Namen plus version als Tag – Sharing statt Screenshots.
  • ayedo unterstützt Teams dabei, solche standardisierten, teilbaren Automationsblöcke aufzubauen – von der Konzeption der Block-Struktur bis zum Betrieb einer Registry und Integration in bestehende Prozesse.

Das eigentliche Problem: Die vergessene Nginx-Config

Viele Admins kennen das Szenario: Auf web01.acme-corp.com läuft seit Jahren ein Nginx, die nginx.conf wurde “damals schnell” angepasst, Let’s Encrypt irgendwo mit certbot eingerichtet – und niemand weiß mehr genau, wie.

  • Warum ist der Upstream-Port 8081?
  • Wieso wird hier eine Subdomain umgeleitet?
  • Welche certbot-Option war das nochmal?

Dokumentation, wenn überhaupt, liegt in einem Wiki-Eintrag, der längst nicht mehr zur Realität passt. Automatisierung besteht aus einzelnen Shell-Snippets, die nur auf genau diesem Server jemals ausprobiert wurden.

Mit plain Ansible lässt sich das besser machen, aber du kennst die Hürden:

  • Lokale Ansible-Installation, Python-Versionen, Collections managen
  • Rollen und Playbooks pflegen, verteilen, versionieren
  • Kollegen müssen Ansible-CLI, Inventories und Variablenstruktur verstehen

In diesem Beitrag zeige ich dir, wie du aus genau diesem Setup einen wiederverwendbaren Polycrate-Block machst, den deine Kolleg:innen einfach verwenden können – ohne die Implementierung kennen zu müssen.


Von der Server-Config zum wiederverwendbaren Block

Polycrate setzt direkt auf Ansible auf, löst aber zwei typische Probleme:

  1. Dependency-Problem:
    Ansible läuft in einem Container. Keine lokale Installation, kein Python-Zoo, keine unterschiedlichen Versionsstände im Team. Der Block bringt alles mit, was er braucht.

  2. Sharable Automation:
    Dein Nginx-Setup ist kein fragiler Wiki-Artikel mehr, sondern ein versionierter Block, der in einer Registry liegt. Was du baust, können andere sofort nutzen – mit ihren eigenen Domains und Ports.

Wir konzentrieren uns auf einen konkreten Block:

  • Installiert Nginx und certbot auf Ubuntu 22.04
  • Holt ein Let’s-Encrypt-Zertifikat für eine Domain
  • Deployt eine nginx.conf auf Basis eines Jinja2-Templates
  • Parametrisiert:
    • block.config.domain
    • block.config.email
    • block.config.upstream_port

Block-Struktur: Verzeichnis & block.poly

Ausgangspunkt ist ein bestehender Polycrate-Workspace, z.B.:

# workspace.poly
name: acme-corp-automation
organization: acme

Unser Block liegt in ./blocks/nginx-letsencrypt/ und enthält:

  • block.poly
  • nginx-letsencrypt.yml (Ansible-Playbook)
  • nginx.conf.j2 (Jinja2-Template)

Verzeichnislayout (Überblick)

So hängen Workspace-Root und Block-Ordner zusammen (Beispiel-Workspace-Name acme-corp-automation):

acme-corp-automation/                 # Workspace-Root
├── workspace.poly                    # Workspace-Konfiguration, u. a. Block-Instanzen
├── inventory.yml                   # Zentrales Ansible-Inventory (alle Blöcke)
├── blocks/
│   └── nginx-letsencrypt/            # Lokaler Block (Ordnername = Template-Name in from:)
│       ├── block.poly                # Block-Definition, Version, config, actions
│       ├── nginx-letsencrypt.yml     # Ansible-Playbook (Action deploy)
│       └── nginx.conf.j2             # Jinja2-Template für Nginx
└── …                                 # weitere typische Einträge (z. B. artifacts/, secrets.poly)

Später, wenn du den Block für eine Registry mit vollem OCI-name auslieferst, liegt derselbe Inhalt typischerweise unter einem Pfad, der den Registry-Namen spiegelt, z. B. blocks/registry.acme-corp.com/infra/nginx/ (siehe Abschnitt Registry).

Vollständige block.poly

name: nginx-letsencrypt
version: 1.0.0
kind: generic

config:
  domain: ""
  email: ""
  upstream_port: 8080

actions:
  - name: deploy
    playbook: nginx-letsencrypt.yml

Wichtige Punkte:

  • version: 1.0.0 – wir versionieren den Block explizit.
  • config definiert die Parameter, die später im Workspace gesetzt werden:
    • domain – FQDN wie www.acme-corp.com
    • email – Kontakt-E-Mail für Let’s Encrypt
    • upstream_port – Port des Backends, auf das Nginx proxyt (z.B. eine App auf 8080)
  • actions beschreibt, welche Playbooks verfügbar sind.
    Mit polycrate run nginx-letsencrypt deploy führen wir das Playbook aus.

Weitere Details zur Block-Struktur findest du in den offiziellen Block-Konzepte.


nginx.conf als Jinja2-Template

Das Herzstück für Wiederverwendbarkeit ist die Nginx-Konfiguration als Template. Statt fixem Domainnamen und Port verwenden wir die Polycrate-Variablen.

Vollständiges nginx.conf.j2

# nginx.conf für {{ block.config.domain }} – generiert durch Polycrate

server {
    listen 80;
    server_name {{ block.config.domain }};

    # HTTP → HTTPS Redirect
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name {{ block.config.domain }};

    ssl_certificate     /etc/letsencrypt/live/{{ block.config.domain }}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/{{ block.config.domain }}/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # Optionales HSTS – bei Bedarf anpassen
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    location / {
        proxy_pass http://127.0.0.1:{{ block.config.upstream_port }};
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Was hier passiert:

  • {{ block.config.domain }} und {{ block.config.upstream_port }} stammen direkt aus block.config im Block – und werden letztlich im Workspace gesetzt.
  • Die Zertifikats-Pfade zeigen auf die Standardverzeichnisse von certbot (/etc/letsencrypt/live/...).
  • Die Konfiguration ist idempotent aus Ansible heraus deploybar – Änderungen am Template führen zu einem konsistenten Zustand.

Ansible-Playbook für Nginx + Let’s Encrypt

Jetzt verbinden wir alles in einem Playbook. Wichtiger Hinweis in Polycrate: Die Playbooks laufen im Container, aber die Ziel-Hosts sind echte Server aus dem Inventory, nicht localhost.

Inventory im Workspace

Im Workspace-Root liegt die inventory.yml (Polycrate setzt ANSIBLE_INVENTORY automatisch):

# inventory.yml
all:
  hosts:
    web01.acme-corp.com:
      ansible_user: ubuntu
      ansible_become: true

Vollständiges Playbook nginx-letsencrypt.yml

---
- name: Nginx mit Let's Encrypt bereitstellen
  hosts: all
  become: true

  vars:
    domain_name: "{{ block.config.domain }}"
    contact_email: "{{ block.config.email }}"
    upstream_port: "{{ block.config.upstream_port }}"

  pre_tasks:
    - name: Domain muss gesetzt sein
      ansible.builtin.assert:
        that:
          - domain_name | length > 0
          - contact_email | length > 0
        fail_msg: "block.config.domain und block.config.email müssen im Workspace gesetzt sein."

  tasks:
    - name: APT-Cache aktualisieren (Ubuntu/Debian)
      ansible.builtin.apt:
        update_cache: true
        cache_valid_time: 3600

    - name: Nginx und Certbot installieren
      ansible.builtin.apt:
        name:
          - nginx
          - certbot
          - python3-certbot
        state: present

    - name: Standard-Site deaktivieren
      ansible.builtin.file:
        path: /etc/nginx/sites-enabled/default
        state: absent
      notify: reload nginx

    - name: TLS-Zertifikat von Let's Encrypt holen (Standalone)
      community.general.certbot:
        email: "{{ contact_email }}"
        domains:
          - "{{ domain_name }}"
        authenticator: standalone
        agree_tos: true
        installer: none
        state: present
      register: certbot_result

    - name: Certbot-Output anzeigen (Debug)
      ansible.builtin.debug:
        var: certbot_result

    - name: Nginx-Konfiguration deployen
      ansible.builtin.template:
        src: nginx.conf.j2
        dest: "/etc/nginx/sites-available/{{ domain_name }}"
        owner: root
        group: root
        mode: "0644"
      notify: reload nginx

    - name: Site aktivieren
      ansible.builtin.file:
        src: "/etc/nginx/sites-available/{{ domain_name }}"
        dest: "/etc/nginx/sites-enabled/{{ domain_name }}"
        state: link
      notify: reload nginx

  handlers:
    - name: reload nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded
        enabled: true

Erläuterungen:

  • hosts: all – alle Hosts aus inventory.yml. Keine connection: local, weil wir echte Server verwalten.
  • community.general.certbot stammt aus der Collection community.general. Polycrate kann diese im Container installieren, ohne dein lokales System zu berühren (siehe Ansible-Integration).
  • Wir nutzen den standalone-Authenticator:
    • Certbot startet kurz einen eigenen Webserver auf Port 80.
    • Danach deployen wir die HTTPS-Nginx-Konfiguration.
  • Über vars binden wir die Polycrate-Variablen (block.config.*) an Ansible-Variablen, was das Lesen im Playbook vereinfacht.

Den Block im Workspace nutzen

Nach dem Build und polycrate blocks push nutzen Workspaces denselben Block wie in den anderen Beiträgen dieser Reihe: vollständige OCI-Referenz unter cargo.ayedo.cloud (nicht nur der kurze Template-Name).

Block im Workspace referenzieren

# workspace.poly
name: acme-corp-automation
organization: acme

blocks:
  - name: webserver
    from: cargo.ayedo.cloud/ayedo/infra/nginx-letsencrypt:1.0.0
    config:
      domain: "www.acme-corp.com"
      email: "admin@acme-corp.com"
      upstream_port: 8080
  • name: webserver ist der Instanzname im Workspace.
  • Der Block liegt in der Registry unter cargo.ayedo.cloud. Ein vorheriges polycrate blocks pull ist nicht nötig: Fehlt der Block lokal, erkennt Polycrate das beim Aufruf von polycrate run … und fragt, ob der Block aus der Registry automatisch installiert werden soll. Danach liegt die entpackte Struktur unter blocks/cargo.ayedo.cloud/ayedo/infra/nginx-letsencrypt/. In from: steht die vollständige Referenz inkl. Tag (Block Sharing per OCI statt nur lokalem Ordner blocks/nginx-letsencrypt/).
  • Unter config überschreiben wir die Default-Werte aus block.poly.

Aktion ausführen

polycrate run webserver deploy

Polycrate:

  • Startet einen Container mit Ansible und allen benötigten Tools.
  • Lädt inventory.yml aus dem Workspace-Root.
  • Setzt Variablen wie block.config.* und führt das Playbook im Container aus.
  • Verändert den Ziel-Host via SSH – der Container selbst bleibt ephemeral.

Mit plain Ansible sähe das z.B. so aus:

ansible-playbook -i inventory.yml nginx-letsencrypt.yml \
  -e "domain_name=www.acme-corp.com contact_email=admin@acme-corp.com upstream_port=8080"

Und du müsstest sicherstellen, dass:

  • Ansible lokal installiert ist
  • Die richtige Python-Version läuft
  • Die Collection community.general vorhanden ist

Mit Polycrate sind diese Abhängigkeiten Teil des Blocks bzw. des Workspaces und laufen im Container.


Den Webserver-Block in eine Registry pushen

Jetzt kommt das Sharing-Argument: Statt einen Wiki-Eintrag zu schreiben, veröffentlichst du deinen Block in einer Registry.

Wichtig: Blöcke mit rein lokalen Namen wie nginx-letsencrypt oder nginx lassen sich nicht in eine Registry pushen. polycrate blocks push erwartet, dass name in der block.poly bereits die vollständige OCI-Referenz ohne Versions-Tag ist (Host und Pfad wie bei einem Container-Image-Namen ohne :tag). Die Version steht separat im Feld version: und wird beim Push zum OCI-Tag.

Angenommen, ihr betreibt eine interne Polycrate-/OCI-Registry unter registry.acme-corp.com.

block.poly für die Registry anpassen

Vor dem Push trägst du den Registry-Namen ein und versionierst wie gewohnt:

name: registry.acme-corp.com/infra/nginx
version: 1.0.0
kind: generic

config:
  domain: ""
  email: ""
  upstream_port: 8080

actions:
  - name: deploy
    playbook: nginx-letsencrypt.yml

Empfehlenswert: Das Block-Verzeichnis spiegelt den Namen, z. B. blocks/registry.acme-corp.com/infra/nginx/ (siehe Best Practices).

Block pushen

polycrate blocks push registry.acme-corp.com/infra/nginx

Es gibt nur dieses eine Argument – den Block-Namen exakt wie in block.poly (name, ohne Tag). Kein zweites Argument für „Ziel-URL“; Host, Pfad und Tag leitet Polycrate aus name und version ab.

Was passiert:

  • Polycrate verpackt den Block (inkl. block.poly, Playbook, Template) als OCI-Artifact.
  • Der Artifact landet als registry.acme-corp.com/infra/nginx:1.0.0 in eurer Registry (name + version als Tag).
  • Für ein Folge-Release erhöhst du version in der block.poly (z. B. 1.1.0) und pushst erneut.

Im Workspace: Version pinnen

Wenn andere den Block einbinden, referenzieren sie ihn mit from: inklusive Tag – nach Best Practices pinnt man die Block-Version beim Instanziieren im Workspace explizit, z. B. from: registry.acme-corp.com/infra/nginx:1.0.0 (siehe Registry-Dokumentation).


Kollege nutzt den Block in seinem Workspace

Dein Kollege hat einen anderen Workspace, z.B. für ein internes Portal. Er möchte denselben Nginx-/Let’s-Encrypt-Block nutzen, aber mit anderen Werten.

workspace.poly beim Kollegen

# workspace.poly im Workspace des Kollegen
name: acme-portal-automation
organization: acme

blocks:
  - name: portal-web
    from: registry.acme-corp.com/infra/nginx:1.0.0
    config:
      domain: "portal.acme-corp.com"
      email: "ops@acme-corp.com"
      upstream_port: 9000

Er muss weder:

  • Das Playbook lesen
  • Die Nginx-Template-Syntax verstehen
  • Certbot-Optionen kennen

Er setzt nur die Konfiguration.

Erster polycrate run beim Kollegen

polycrate run portal-web deploy

Beim ersten Aufruf erkennt Polycrate, dass der Block registry.acme-corp.com/infra/nginx:1.0.0 noch nicht lokal installiert ist, und fragt:

Block 'registry.acme-corp.com/infra/nginx:1.0.0' ist nicht installiert.
Möchten Sie den Block jetzt aus der Registry ziehen? [y/N]

Mit y zieht Polycrate den Block, legt ihn im Workspace an und führt die Action aus. Ab diesem Punkt ist der Webserver-Block Teil seines Workspaces – vollständig versioniert und testbar.

Was vorher ein Wiki-Eintrag mit “Bitte so machen” war, ist jetzt ein Block mit:

  • Klarem Verhalten (Playbook)
  • Interface über block.config.*
  • Versionierung und Verteilung über eine Registry

Häufige Fragen

Muss ich Ansible lokal installieren, um diesen Block zu nutzen?

Nein. Polycrate führt Ansible immer im Container aus. Der Container enthält:

  • Eine definierte Ansible-Version
  • Die benötigten Collections (z.B. community.general für certbot)
  • Eine konsistente Toolchain für alle im Team

Du brauchst lokal nur Polycrate und Zugang zur Registry. Das eliminiert das typische Dependency-Problem mit unterschiedlichen Python-/Ansible-Versionen auf Entwickler- und Admin-Maschinen.

Wie gehe ich mit mehreren Domains oder Staging-Umgebungen um?

Das Block-Modell ist exakt dafür gemacht:

  • Eine Block-Implementierung (nginx-letsencrypt).
  • Mehrere Block-Instanzen im Workspace mit verschiedenen config-Werten, z.B.:
blocks:
  - name: web-prod
    from: registry.acme-corp.com/infra/nginx:1.0.0
    config:
      domain: "www.acme-corp.com"
      email: "admin@acme-corp.com"
      upstream_port: 8080

  - name: web-staging
    from: registry.acme-corp.com/infra/nginx:1.0.0
    config:
      domain: "staging.acme-corp.com"
      email: "admin@acme-corp.com"
      upstream_port: 8081

Du führst dann z.B. polycrate run web-staging deploy aus. Das Ansible-Playbook bleibt unverändert; nur die Parameter unterscheiden sich.

Wie sicher ist das Teilen eines solchen Blocks?

Der Block selbst enthält nur:

  • Struktur (block.poly)
  • Playbooks, Templates, Skripte

Vertrauliche Daten wie Passwörter gehören in den Workspace – z.B. in verschlüsselte Secrets. Polycrate unterstützt dich hier mit integrierter Workspace-Verschlüsselung auf Basis von age (siehe Workspace-Verschlüsselung).

Du kannst also:

  • Den Block öffentlich oder intern teilen
  • Im Workspace sensible Daten verschlüsselt halten
  • Trotzdem gemeinsam auf dieselbe Automatisierung aufsetzen

Weitere Fragen? Siehe unsere FAQ


Von der Routine zur Reproduzierbarkeit

Mit diesem Beispiel hast du gesehen, wie du aus einer einmaligen Server-Konfiguration eine wiederverwendbare, versionierte Automatisierung machst:

  • Nginx + Let’s Encrypt als Polycrate-Block
  • Parametrisiert über block.config.domain, block.config.email und block.config.upstream_port
  • Vollständig automatisiert per Ansible im Container
  • Geteilt über eine Registry, damit Kolleg:innen den Block nutzen können, ohne die Interna zu kennen

Genau hier liegt die Stärke von Polycrate in heterogenen Umgebungen: Du kannst bewährte Setups – ob Webserver, Windows-Policies oder IoT-Deployments – als strukturierte Blöcke kapseln, im Team teilen und über Workspaces sicher betreiben. Die Guardrails des Block-Modells verhindern Playbook-Wildwuchs, die Container-Ausführung löst das Dependency-Problem, und die Registry macht aus Einzelwissen gemeinsame Infrastruktur.

ayedo unterstützt Teams dabei, diese Art von wiederverwendbaren Bausteinen systematisch aufzubauen: vom Design der Block-Schnittstellen über die Einrichtung der Registry bis zur Integration in bestehende CI/CD- und Compliance-Prozesse. Wenn du sehen möchtest, wie ein solcher Webserver-Block in deiner Umgebung konkret aussehen kann, führt der nächste Schritt über unsere Webserver-Block Demo

Ähnliche Artikel