diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
new file mode 100644
index 0000000..807f408
--- /dev/null
+++ b/ARCHITECTURE.md
@@ -0,0 +1,207 @@
+
+# Architekturskizze — `demo-gymburgdorf`
+
+Diese Skizze zeigt, wie das `reference-ansible`-Repo am Beispiel der
+Inventory `demo-gymburgdorf` funktioniert: welche Hosts existieren,
+welche Rollen darauf laufen, wo welche Variablen hingehören und wie
+Secrets aus OpenBao gelookupt werden.
+
+## 1. Variablen-Hierarchie (Ansible Precedence)
+
+```mermaid
+flowchart TB
+ classDef rolelayer fill:#fef3c7,stroke:#92400e,color:#000
+ classDef grouplayer fill:#dbeafe,stroke:#1e40af,color:#000
+ classDef hostlayer fill:#dcfce7,stroke:#166534,color:#000
+ classDef vaultlayer fill:#fee2e2,stroke:#991b1b,color:#000
+
+ R["role defaults/main.yml
(niedrigste Precedence)
~180 Variablen über 12 Rollen
z.B. traefik_use_ssl: false
keycloak_admin_password: changeme"]:::rolelayer
+
+ GA["group_vars/all/
docker.yml → docker_registry_mirrors
vault.yml → vault_addr, vault_mount"]:::grouplayer
+
+ GT["group_vars/traefik_servers/
traefik.yml
traefik_use_ssl, traefik_cert_mode: acme
traefik_acme_dns_zone
traefik_acme_tsig_* (Vault-Lookup!)"]:::grouplayer
+
+ GB["group_vars/backend_servers/
traefik.yml → traefik_mode: backend"]:::grouplayer
+
+ HR["host_vars/reverseproxy/
traefik.yml → traefik_mode: dmz"]:::hostlayer
+
+ HA["host_vars/application/ (fehlt aktuell!)
FQDNs, OIDC-Clients, DB-Passwords
nextcloud_domain, authentik_domain, ..."]:::hostlayer
+
+ HS["host_vars/storage/ (fehlt aktuell!)
garage_s3_domain, garage_*_token
traefik_dmz_exposed_services (für DMZ)"]:::hostlayer
+
+ V["HashiCorp Vault / OpenBao
bao.digitalboard.ch
mount: demo-gymburgdorf
z.B. demo-gymburgdorf/data/acme-tsig"]:::vaultlayer
+
+ R --> GA --> GT --> GB --> HR
+ GB --> HA
+ GB --> HS
+ GT -.Lookup zur Laufzeit.-> V
+ HA -.Lookup zur Laufzeit.-> V
+ HS -.Lookup zur Laufzeit.-> V
+```
+
+Höhere Ebene überschreibt tiefere. `host_vars/reverseproxy/traefik_mode: dmz`
+schlägt also `group_vars/backend_servers/traefik_mode: backend` —
+möglich, weil `reverseproxy` *nicht* in `backend_servers` ist.
+
+## 2. Inventory-Topologie demo-gymburgdorf
+
+```mermaid
+flowchart LR
+ classDef dmz fill:#fee2e2,stroke:#991b1b,color:#000
+ classDef app fill:#dcfce7,stroke:#166534,color:#000
+ classDef stor fill:#dbeafe,stroke:#1e40af,color:#000
+ classDef turn fill:#fef9c3,stroke:#854d0e,color:#000
+
+ subgraph ALL["group: all_servers (alle Hosts)"]
+ direction LR
+ subgraph DMZ["DMZ-Segment 172.16.9.0/24"]
+ RP["reverseproxy
172.16.9.111
traefik_mode: dmz"]:::dmz
+ TURN["turn
172.16.9.112
(STUN/TURN)"]:::turn
+ end
+ subgraph BE["Backend-Segment 172.16.19.0/24
(group: backend_servers)"]
+ APP["application
172.16.19.101
traefik_mode: backend
+ nextcloud, opencloud,
collabora, drawio,
authentik, authentik_outpost_ldap"]:::app
+ ST["storage
172.16.19.102
traefik_mode: backend
+ garage (S3)"]:::stor
+ end
+ end
+
+ RP -.HTTP/HTTPS reverse proxy.-> APP
+ RP -.HTTP/HTTPS reverse proxy.-> ST
+```
+
+Gruppen-Mitgliedschaften (`hosts.yml`):
+
+- `traefik_servers` ⊇ `all_servers` → **alle 4 Hosts** bekommen Traefik
+ (DMZ-Modus für `reverseproxy`, Backend-Modus für `application`/`storage`).
+- `backend_servers = {application, storage}` → setzt
+ `traefik_mode: backend` via group_vars.
+- Service-Gruppen (`nextcloud_servers`, `garage_servers`, …) sind
+ Single-Host-Wrapper, mit denen `playbooks/site.yml` gezielt
+ deploybare Rollen targetet.
+
+## 3. Service-Layout & Variablen-Verortung
+
+```mermaid
+flowchart TB
+ classDef rp fill:#fee2e2,stroke:#991b1b,color:#000
+ classDef ap fill:#dcfce7,stroke:#166534,color:#000
+ classDef st fill:#dbeafe,stroke:#1e40af,color:#000
+ classDef ext fill:#e9d5ff,stroke:#6b21a8,color:#000
+
+ Internet((Internet))
+ DNS["DNS ns1.digitalboard.ch
RFC2136 TSIG (key: acme_update_key_demo_gymb)
dynamic zone: demo-gymb._acme.digitalboard.ch
CNAME-bridge: _acme-challenge.*.gymb.souveredu.ch"]:::ext
+ BAO["OpenBao
bao.digitalboard.ch
mount: demo-gymburgdorf"]:::ext
+
+ subgraph RP["reverseproxy — traefik dmz"]
+ TRDMZ["traefik (file provider)
📍 group_vars/traefik_servers/traefik.yml
→ acme, tsig, ssl
📍 host_vars/reverseproxy/traefik.yml
→ traefik_mode: dmz
📍 host_vars/reverseproxy/...
→ traefik_dmz_exposed_services"]:::rp
+ end
+
+ subgraph APP["application — backend"]
+ TRA["traefik (docker provider)
📍 group_vars/backend_servers
→ traefik_mode: backend"]:::ap
+ NC["nextcloud
📍 host_vars/application/nextcloud.yml
domain, postgres_pw, oidc, s3, ldap"]:::ap
+ OC["opencloud
📍 host_vars/application/opencloud.yml
oidc_issuer, ldap, s3"]:::ap
+ AK["authentik
📍 host_vars/application/authentik.yml
secret_key, postgres, ldap_apps, oidc_apps"]:::ap
+ AKO["authentik_outpost_ldap
📍 host_vars/application/authentik_outpost_ldap.yml
host, token"]:::ap
+ COL["collabora
📍 host_vars/application/collabora.yml
domain, allowed_domains"]:::ap
+ DRW["drawio
📍 host_vars/application/drawio.yml"]:::ap
+ end
+
+ subgraph ST["storage — backend"]
+ TRS["traefik (docker provider)"]:::st
+ GAR["garage (S3)
📍 host_vars/storage/garage.yml
s3_domain, rpc_secret,
admin_token, s3_keys"]:::st
+ end
+
+ Internet -->|HTTPS :443| TRDMZ
+ TRDMZ -->|HTTP backend| TRA
+ TRDMZ -->|HTTP backend| TRS
+ TRA --> NC & OC & AK & COL & DRW & AKO
+ TRS --> GAR
+
+ NC -. S3 .-> GAR
+ OC -. S3 .-> GAR
+ NC -. OIDC .-> AK
+ OC -. OIDC .-> AK
+ NC -. WOPI .-> COL
+ OC -. WOPI .-> COL
+ NC -. LDAP .-> AKO
+ OC -. LDAP .-> AKO
+ AKO -. RPC + token .-> AK
+
+ TRDMZ -. ACME DNS-01 TSIG .-> DNS
+ TRDMZ -. lookup acme-tsig .-> BAO
+ AK -. lookup secrets .-> BAO
+ NC -. lookup secrets .-> BAO
+ GAR -. lookup secrets .-> BAO
+```
+
+## 4. Deploy-Flow
+
+```mermaid
+sequenceDiagram
+ participant U as User (make)
+ participant M as Makefile
+ participant A as ansible-playbook
+ participant V as OpenBao
+ participant H as Hosts
+
+ U->>M: make bao
+ M->>V: bao login (OIDC)
+ V-->>M: VAULT_TOKEN
+ U->>M: make deploy_site_demo_gymburgdorf
+ M->>A: ansible-playbook site.yml -i inventories/demo-gymburgdorf/hosts.yml
+ A->>A: lade group_vars/all → group_vars/traefik_servers → group_vars/backend_servers → host_vars/*
+ A->>V: community.hashi_vault Lookups (acme-tsig, secrets)
+ V-->>A: secret values
+ A->>H: Play "base" → all_servers
+ A->>H: Play "traefik" → traefik_servers (dmz auf reverseproxy, backend auf application/storage)
+ A->>H: Play "garage" → storage
+ A->>H: Play "authentik / nextcloud / collabora / ..." → application
+```
+
+## 5. Variablen-Cheatsheet — wo gehört was hin?
+
+| Variable | Wohin in `demo-gymburgdorf/` | Warum |
+|---|---|---|
+| `vault_addr`, `vault_mount` | `group_vars/all/vault.yml` ✅ | Vault-Endpoint gilt site-weit |
+| `docker_registry_mirrors` | `group_vars/all/docker.yml` ✅ | Pulls aus Mirror auf allen Hosts |
+| `traefik_acme_*`, `traefik_use_ssl`, `traefik_cert_mode` | `group_vars/traefik_servers/traefik.yml` ✅ | Gilt für alle Traefik-Instanzen (dmz + backend) |
+| `traefik_mode: backend` | `group_vars/backend_servers/traefik.yml` ✅ | Default für app + storage |
+| `traefik_mode: dmz` | `host_vars/reverseproxy/traefik.yml` ✅ | Host-spezifischer Override |
+| `traefik_dmz_exposed_services` | **`host_vars/reverseproxy/`** | Liste, welche Backend-Services die DMZ proxyt (nur dort sinnvoll) |
+| `nextcloud_*`, `authentik_*`, `opencloud_*`, `collabora_*`, `drawio_*` | **`host_vars/application/.yml`** | Service läuft genau auf `application` |
+| `garage_*` | **`host_vars/storage/garage.yml`** | Service läuft genau auf `storage` |
+| Secrets (Passwords, Tokens, Keys) | Inline-Variable mit `lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/', url=vault_addr)` | Single source of truth; Pattern wie bei `_acme_tsig` |
+
+## 6. Traefik-Modi (zentral für die Architektur)
+
+**`traefik_mode: dmz`** (Public-facing Reverse Proxy auf `reverseproxy`):
+
+- Aggregiert Services von Backend-Servern via
+ `traefik_dmz_exposed_services` (Host-Variablen).
+- Nutzt **file provider** mit `services.yml` für statisches Routing.
+- Kein Docker-Socket gemountet — keine lokalen Container.
+- Routet zu `backend_host` auf anderen Maschinen.
+- Selektive Backend-Auswahl via `traefik_backend_servers_to_proxy`.
+
+**`traefik_mode: backend`** (Application/Storage Server):
+
+- Mountet Docker-Socket (`/var/run/docker.sock`).
+- Nutzt **docker provider** für Auto-Discovery lokaler Container.
+- Services mit Label `traefik.enable=true` werden automatisch exponiert.
+- Beide Modi unterstützen ACME (RFC2136 DNS Challenge) oder Self-Signed.
+
+## 7. Was im aktuellen `demo-gymburgdorf` noch fehlt
+
+Im Vergleich zur `vagrant`-Inventory (Referenz) fehlen für eine
+vollständige Deployment:
+
+- `host_vars/application/main.yml` — Backbone-Vars für den Host
+ (FQDN-Pattern, gemeinsame Defaults).
+- `host_vars/application/{nextcloud,opencloud,authentik,authentik_outpost_ldap,collabora,drawio}.yml`
+ — die service-spezifischen Konfigurationen.
+- `host_vars/storage/{main.yml,garage.yml}` — Garage-Cluster-Setup.
+- `host_vars/reverseproxy/<…>.yml` mit `traefik_dmz_exposed_services`
+ — sonst routet die DMZ nichts.
+
+Die `vagrant`-Inventory ist das Template: dieselbe Struktur auf
+`application`/`storage` mappen, FQDNs auf `*.gymb.souveredu.ch`
+umstellen, Secrets durch Bao-Lookups ersetzen.
diff --git a/Makefile b/Makefile
index 6cc2944..67b2a75 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,7 @@
export BAO_ADDR=https://bao.digitalboard.ch
+# macOS fork-safety: Objective-C runtime is not fork-safe; Ansible forks
+# per host. Without this, hashi_vault lookups crash workers.
+export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
install:
ansible-galaxy collection install -r requirements.yml -p collections
@@ -17,7 +20,7 @@ ping_demo:
deploy_site_demo_gymburgdorf:
echo "deploying demo site gymburgdorf"
- ansible-playbook playbooks/site.yml -i inventories/demo-gymburgdorf/hosts.yml
+ ansible-playbook playbooks/site.yml -i inventories/demo-gymburgdorf/hosts.yml --diff
deploy_site_demo_mbazürich:
echo "deploying demo site mbazürich"
@@ -30,4 +33,4 @@ deploy_site_demo_phbern:
deploy_site_demo:
make deploy_site_demo_gymburgdorf
make deploy_site_demo_mbazürich
- make deploy_site_demo_phbern
\ No newline at end of file
+ make deploy_site_demo_phbern
diff --git a/inventories/demo-gymburgdorf/group_vars/all/ansible.yml b/inventories/demo-gymburgdorf/group_vars/all/ansible.yml
new file mode 100644
index 0000000..e425179
--- /dev/null
+++ b/inventories/demo-gymburgdorf/group_vars/all/ansible.yml
@@ -0,0 +1,2 @@
+---
+ansible_python_interpreter: /usr/bin/python3
diff --git a/inventories/demo-gymburgdorf/group_vars/traefik_servers/traefik.yml b/inventories/demo-gymburgdorf/group_vars/traefik_servers/traefik.yml
index a0f587e..c42dc79 100644
--- a/inventories/demo-gymburgdorf/group_vars/traefik_servers/traefik.yml
+++ b/inventories/demo-gymburgdorf/group_vars/traefik_servers/traefik.yml
@@ -5,7 +5,7 @@ traefik_cert_mode: "acme"
traefik_log_level: DEBUG
traefik_network: proxy
-traefik_acme_dns_zone: "gymb._acme.digitalboard.ch"
+traefik_acme_dns_zone: "demo-gymb._acme.digitalboard.ch"
traefik_acme_dns_nameserver: "{{ _acme_tsig.server }}"
traefik_acme_tsig_algorithm: "hmac-sha256"
traefik_acme_tsig_key: "{{ _acme_tsig.tsig_key }}"
diff --git a/inventories/demo-gymburgdorf/host_vars/application/authentik.yml b/inventories/demo-gymburgdorf/host_vars/application/authentik.yml
new file mode 100644
index 0000000..aba8775
--- /dev/null
+++ b/inventories/demo-gymburgdorf/host_vars/application/authentik.yml
@@ -0,0 +1,53 @@
+---
+# Bao secret expected at /data/authentik with keys:
+# secret_key, postgres_password, admin_password,
+# ldap_outpost_token,
+# nextcloud_oidc_secret
+_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
+
+authentik_domain: "auth.gymb.souveredu.ch"
+authentik_secret_key: "{{ _authentik.secret_key }}"
+authentik_postgres_password: "{{ _authentik.postgres_password }}"
+
+# LDAP outpost (provider for nextcloud)
+authentik_ldap_apps:
+ - slug: ldap
+ name: LDAP
+ base_dn: "dc=gymb,dc=souveredu,dc=ch"
+ search_group: admins
+
+authentik_ldap_outpost:
+ name: "ldap-outpost"
+ token: "{{ _authentik.ldap_outpost_token }}"
+ config:
+ authentik_host: "https://auth.gymb.souveredu.ch/"
+ log_level: "info"
+
+# OIDC clients
+authentik_oidc_apps:
+ - slug: nextcloud
+ name: Nextcloud
+ client_id: nextcloud
+ client_secret: "{{ _authentik.nextcloud_oidc_secret }}"
+ redirect_uris:
+ - url: "https://cloud.gymb.souveredu.ch/apps/user_oidc/code"
+ matching_mode: strict
+ signing_key_name: "authentik Self-signed Certificate"
+ flows:
+ authorization_slug: default-provider-authorization-implicit-consent
+ invalidation_slug: default-provider-invalidation-flow
+ scopes: [openid, email, profile, offline_access]
+
+authentik_groups:
+ - name: admins
+ - name: users
+
+authentik_local_users:
+ - username: akadmin
+ name: "Authentik Admin"
+ email: "admin@gymb.souveredu.ch"
+ password: "{{ _authentik.admin_password }}"
+ is_active: true
+ groups:
+ - authentik Admins
+ - admins
diff --git a/inventories/demo-gymburgdorf/host_vars/application/authentik_outpost_ldap.yml b/inventories/demo-gymburgdorf/host_vars/application/authentik_outpost_ldap.yml
new file mode 100644
index 0000000..c02b660
--- /dev/null
+++ b/inventories/demo-gymburgdorf/host_vars/application/authentik_outpost_ldap.yml
@@ -0,0 +1,7 @@
+---
+# Same token as authentik_ldap_outpost.token above — outpost uses it to
+# authenticate against the authentik server it talks to.
+_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
+
+authentik_outpost_ldap_host: "https://auth.gymb.souveredu.ch"
+authentik_outpost_ldap_token: "{{ _authentik.ldap_outpost_token }}"
diff --git a/inventories/demo-gymburgdorf/host_vars/application/collabora.yml b/inventories/demo-gymburgdorf/host_vars/application/collabora.yml
new file mode 100644
index 0000000..b02760c
--- /dev/null
+++ b/inventories/demo-gymburgdorf/host_vars/application/collabora.yml
@@ -0,0 +1,8 @@
+---
+collabora_domain: "office.gymb.souveredu.ch"
+
+collabora_allowed_domains:
+ - "cloud.gymb.souveredu.ch"
+
+collabora_frame_ancestors:
+ - "cloud.gymb.souveredu.ch"
diff --git a/inventories/demo-gymburgdorf/host_vars/application/drawio.yml b/inventories/demo-gymburgdorf/host_vars/application/drawio.yml
new file mode 100644
index 0000000..beef6a5
--- /dev/null
+++ b/inventories/demo-gymburgdorf/host_vars/application/drawio.yml
@@ -0,0 +1,2 @@
+---
+drawio_domain: "draw.gymb.souveredu.ch"
diff --git a/inventories/demo-gymburgdorf/host_vars/application/main.yml b/inventories/demo-gymburgdorf/host_vars/application/main.yml
new file mode 100644
index 0000000..49248a6
--- /dev/null
+++ b/inventories/demo-gymburgdorf/host_vars/application/main.yml
@@ -0,0 +1,3 @@
+---
+# application host runs: authentik, authentik-ldap-outpost,
+# nextcloud, collabora, drawio
diff --git a/inventories/demo-gymburgdorf/host_vars/application/nextcloud.yml b/inventories/demo-gymburgdorf/host_vars/application/nextcloud.yml
new file mode 100644
index 0000000..a1719f4
--- /dev/null
+++ b/inventories/demo-gymburgdorf/host_vars/application/nextcloud.yml
@@ -0,0 +1,90 @@
+---
+# Bao secret /data/nextcloud expected to contain:
+# postgres_password, admin_password
+_nextcloud: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/nextcloud', url=vault_addr) }}"
+_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
+
+nextcloud_domain: "cloud.gymb.souveredu.ch"
+nextcloud_postgres_password: "{{ _nextcloud.postgres_password }}"
+nextcloud_admin_user: admin
+nextcloud_admin_password: "{{ _nextcloud.admin_password }}"
+
+nextcloud_enable_notify_push: true
+
+# Collabora integration
+nextcloud_enable_collabora: true
+nextcloud_collabora_domain: "office.gymb.souveredu.ch"
+
+# Draw.io integration
+nextcloud_enable_drawio: true
+nextcloud_drawio_url: "https://draw.gymb.souveredu.ch"
+
+nextcloud_apps_to_install:
+ - groupfolders
+ - richdocuments
+ - spreed
+ - user_ldap
+ - user_oidc
+ - whiteboard
+ - drawio
+ - files_lock
+ - notify_push
+
+# S3 primary storage via Garage
+nextcloud_use_s3_storage: true
+nextcloud_s3_key: "{{ lookup('digitalboard.core.garage_credentials', 'nextcloud', host='storage')['key_id'] }}"
+nextcloud_s3_secret: "{{ lookup('digitalboard.core.garage_credentials', 'nextcloud', host='storage')['secret_key'] }}"
+nextcloud_s3_bucket: "nextcloud"
+nextcloud_s3_host: "{{ hostvars['storage']['garage_s3_domain'] }}"
+nextcloud_s3_port: 443
+nextcloud_s3_ssl: true
+nextcloud_s3_usepath_style: true
+
+# Share the LDAP docker network with the authentik LDAP outpost
+nextcloud_extra_networks:
+ - ldap
+
+# LDAP backend (Authentik LDAP outpost)
+nextcloud_ldap_enabled: true
+nextcloud_ldap_config:
+ ldapHost: "ldap://authentik-outpost-ldap-ldap-1"
+ ldapPort: "3389"
+ ldapAgentName: "cn=akadmin,ou=users,dc=gymb,dc=souveredu,dc=ch"
+ ldapAgentPassword: "{{ _authentik.admin_password }}"
+ ldapBase: "dc=gymb,dc=souveredu,dc=ch"
+ ldapBaseUsers: "ou=users,dc=gymb,dc=souveredu,dc=ch"
+ ldapTLS: "0"
+ turnOffCertCheck: "1"
+ ldapUserFilter: "(&(objectClass=user)(cn=*))"
+ ldapUserFilterObjectclass: "user"
+ ldapLoginFilter: "(&(objectClass=user)(cn=%uid))"
+ ldapLoginFilterUsername: "1"
+ ldapUserDisplayName: "cn"
+ ldapEmailAttribute: "mail"
+ ldapExpertUsernameAttr: "cn"
+ ldapExpertUUIDUserAttr: "uid"
+ ldapExpertUUIDGroupAttr: "uid"
+ ldapBaseGroups: "ou=groups,dc=gymb,dc=souveredu,dc=ch"
+ ldapGroupFilter: "(&(objectClass=group))"
+ ldapGroupFilterObjectclass: "group"
+ ldapGroupDisplayName: "cn"
+ ldapGroupMemberAssocAttr: "member"
+ ldapAdminGroup: "admins"
+ ldapCacheTTL: "600"
+ ldapPagingSize: "500"
+ ldapExperiencedAdmin: "1"
+ ldapConfigurationActive: "1"
+
+# OIDC providers for login (Authentik)
+nextcloud_oidc_providers:
+ - identifier: authentik
+ display_name: "Login with Authentik"
+ client_id: nextcloud
+ client_secret: "{{ _authentik.nextcloud_oidc_secret }}"
+ discovery_url: "https://auth.gymb.souveredu.ch/application/o/nextcloud/.well-known/openid-configuration"
+ scope: "openid email profile"
+ unique_uid: true
+ mapping:
+ uid: preferred_username
+ display_name: name
+ email: email
diff --git a/inventories/demo-gymburgdorf/host_vars/reverseproxy/traefik.yml b/inventories/demo-gymburgdorf/host_vars/reverseproxy/traefik.yml
index 35f8874..c43e6be 100644
--- a/inventories/demo-gymburgdorf/host_vars/reverseproxy/traefik.yml
+++ b/inventories/demo-gymburgdorf/host_vars/reverseproxy/traefik.yml
@@ -1 +1,28 @@
-traefik_mode: dmz
\ No newline at end of file
+---
+traefik_mode: dmz
+
+traefik_dmz_exposed_services:
+ - name: authentik
+ domain: auth.gymb.souveredu.ch
+ port: 443
+ protocol: https
+ - name: nextcloud
+ domain: cloud.gymb.souveredu.ch
+ port: 443
+ protocol: https
+ - name: collabora
+ domain: office.gymb.souveredu.ch
+ port: 443
+ protocol: https
+ - name: drawio
+ domain: draw.gymb.souveredu.ch
+ port: 443
+ protocol: https
+ - name: garage-webui
+ domain: console.s3.gymb.souveredu.ch
+ port: 443
+ protocol: https
+ - name: garage-s3
+ domain: s3.gymb.souveredu.ch
+ port: 443
+ protocol: https
diff --git a/inventories/demo-gymburgdorf/host_vars/storage/garage.yml b/inventories/demo-gymburgdorf/host_vars/storage/garage.yml
new file mode 100644
index 0000000..bc392c9
--- /dev/null
+++ b/inventories/demo-gymburgdorf/host_vars/storage/garage.yml
@@ -0,0 +1,27 @@
+---
+# Bao secret /data/garage expected to contain:
+# rpc_secret, admin_token, metrics_token, webui_password
+_garage: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/garage', url=vault_addr) }}"
+
+garage_s3_domain: "s3.gymb.souveredu.ch"
+garage_webui_domain: "console.s3.gymb.souveredu.ch"
+garage_use_ssl: true
+garage_webui_enabled: true
+garage_webui_username: "admin"
+garage_webui_password: "{{ _garage.webui_password }}"
+
+garage_rpc_secret: "{{ _garage.rpc_secret }}"
+garage_admin_token: "{{ _garage.admin_token }}"
+garage_metrics_token: "{{ _garage.metrics_token }}"
+
+# Initial cluster bootstrap (single-node)
+garage_bootstrap_enabled: true
+garage_bootstrap_zone: "burgdorf1"
+garage_bootstrap_capacity: "100G"
+
+# Buckets and keys consumed by nextcloud
+garage_s3_keys:
+ - name: nextcloud
+ buckets:
+ - name: nextcloud
+ permissions: ["read", "write"]
diff --git a/inventories/demo-gymburgdorf/host_vars/storage/main.yml b/inventories/demo-gymburgdorf/host_vars/storage/main.yml
new file mode 100644
index 0000000..75e487d
--- /dev/null
+++ b/inventories/demo-gymburgdorf/host_vars/storage/main.yml
@@ -0,0 +1,2 @@
+---
+# storage host runs: garage (S3 + WebUI)
diff --git a/inventories/demo-gymburgdorf/hosts.yml b/inventories/demo-gymburgdorf/hosts.yml
index 648b2cf..220784b 100644
--- a/inventories/demo-gymburgdorf/hosts.yml
+++ b/inventories/demo-gymburgdorf/hosts.yml
@@ -32,10 +32,6 @@ all:
hosts:
application:
- opencloud_servers:
- hosts:
- application:
-
collabora_servers:
hosts:
application:
@@ -45,5 +41,9 @@ all:
application:
authentik_servers:
+ hosts:
+ application:
+
+ authentik_outpost_ldap_servers:
hosts:
application:
\ No newline at end of file
diff --git a/playbooks/site.yml b/playbooks/site.yml
index d46b5b7..ba9f7ca 100644
--- a/playbooks/site.yml
+++ b/playbooks/site.yml
@@ -71,6 +71,18 @@
roles:
- digitalboard.core.drawio
+- name: Deploy send service
+ hosts: send_servers
+ become: yes
+ roles:
+ - digitalboard.core.send
+
+- name: Deploy openforms service
+ hosts: openforms_servers
+ become: yes
+ roles:
+ - digitalboard.core.openforms
+
- name: Deploy opencloud service
hosts: opencloud_servers
become: yes