Merge branch 'feature/updater' into feature/store-i18n

Conflicts resolved:
- sys-front-inj-matomo: inject.yml keeps the store-i18n split; the cached
  failed site list load (5b7284c4a4) is ported into resolve_site.yml next
  to its token guard, and test_site_cache.py reads that file.
- web-app-bluesky: platform_administrator from store-i18n with the
  prefix-free handle and its i8- reserved variant from feature/updater;
  the broker CONFIG keeps siteTitle, storePath and chooseHandlePath.
- web-app-stalwart README: the managed Quick Setup section is dropped,
  the docs role renders it.
- README.md: the role overview is regenerated from the merged tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 5.5 committed 2026-10-25 14:19:41 +01:00
commit 9df6619903
25 files changed
+1046 -239

No files matched your search

+148 -150
View File
@@ -60,157 +60,155 @@ Every invokable role in the tested lifecycle envelope, with its upstream homepag
| Name | Status | Description | More | Integrated with |
|---|---|---|---|---|
| [Agent Broker](roles/svc-ai-agent-broker/) | beta | Per-user Hermes and OpenClaw agents started on demand behind an OpenAI-compatible endpoint | [🛠️](roles/svc-ai-agent-broker/README.md#quick-setup) | [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [OpenClaw](roles/web-app-openclaw/) |
| [Akaunting](roles/web-app-akaunting/) | beta | Self-hosted platform for online accounting, bookkeeping, and business finance management | [🌐](https://akaunting.com/) [🎬](https://www.youtube.com/watch?v=UTVe_Zob_k0) [🛠️](roles/web-app-akaunting/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [API](roles/web-svc-api/) | alpha | Public REST API serving role data, history and translations of Infinito.Nexus for every ref of core and its forks | [🌐](https://fastapi.tiangolo.com/) [🛠️](roles/web-svc-api/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Asset Mirror (Privacy Proxy)](roles/web-svc-mirror/) | alpha | Nginx-based privacy proxy that mirrors whitelisted third-party assets under a first-party domain | [🛠️](roles/web-svc-mirror/README.md#quick-setup) | [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Assets Server](roles/web-svc-asset/) | beta | Nginx-based server for hosting static assets copied from a source directory to the web data path | [🛠️](roles/web-svc-asset/README.md#quick-setup) | [File Server](roles/web-svc-file/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Backup Docker Volumes](roles/svc-bkp-volume-2-local/) | beta | Scheduled deduplicating backup system for Docker container volumes to a local directory, with consistent SQL dumps | [🛠️](roles/svc-bkp-volume-2-local/README.md#quick-setup) | [Backup Host Secrets](roles/svc-bkp-secrets-2-local/) |
| [Backup Host Secrets](roles/svc-bkp-secrets-2-local/) | beta | Scheduled deduplicating backup of host secrets, CA, ACME credentials, and node identity to the local backup directory | [🛠️](roles/svc-bkp-secrets-2-local/README.md#quick-setup) | |
| [Backup NFS](roles/svc-bkp-nfs-2-local/) | beta | Scheduled backup job for hard-linked differential rsync snapshots of an NFS export into the local backup tree | [🛠️](roles/svc-bkp-nfs-2-local/README.md#quick-setup) | [NFS Server](roles/svc-storage-nfs-server/) |
| [Backup Remote Server](roles/svc-bkp-remote-2-local/) | beta | Scheduled pull-style backup replicating remote hosts onto this host over SSH and rsync as hard-linked snapshots | [🛠️](roles/svc-bkp-remote-2-local/README.md#quick-setup) | [Backup to External Device](roles/svc-bkp-local-2-device/) |
| [Backup to External Device](roles/svc-bkp-local-2-device/) | beta | Plug-triggered systemd backup for hard-link deduplicated snapshots of the local backup tree onto a swappable USB device | [🛠️](roles/svc-bkp-local-2-device/README.md#quick-setup) | |
| [Base](roles/dsk-base/) | beta | Shared premise of every desktop role, the login account its files belong to | [🛠️](roles/dsk-base/README.md#quick-setup) | [Workstation User](roles/user-workstation/) |
| [Baserow](roles/web-app-baserow/) | beta | Self-hosted no-code database platform with a spreadsheet-like interface for building and collaborating on data | [🌐](https://baserow.io/) [🎬](https://www.youtube.com/watch?v=5yFMfP96_4M) [🛠️](roles/web-app-baserow/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [BigBlueButton](roles/web-app-bigbluebutton/) | beta | Self-hosted web conferencing platform for virtual classrooms, online meetings, and real-time collaboration | [🌐](https://bigbluebutton.org/) [🎬](https://www.youtube.com/watch?v=YRkQB6MJllI) [🛠️](roles/web-app-bigbluebutton/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Collabora](roles/web-svc-collabora/), [Corporate Design](roles/web-svc-design/), [Coturn](roles/web-svc-coturn/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Universal Logout](roles/web-svc-logout/) |
| [Blender](roles/dsk-blender/) | alpha | Blender workstation installation wired to the agents on the host through the Model Context Protocol | [🌐](https://www.blender.org) [🛠️](roles/dsk-blender/README.md#quick-setup) | [Base](roles/dsk-base/), [Claude Code](roles/dsk-gnt-claude/), [Code](roles/dsk-code/) |
| [Bluesky](roles/web-app-bluesky/) | beta | Self-hosted decentralized social network on the open AT Protocol, with its own Personal Data Server | [🌐](https://bsky.social/) [🛠️](roles/web-app-bluesky/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [BookWyrm](roles/web-app-bookwyrm/) | beta | Self-hosted federated reading platform for book reviews and reading tracking across the Fediverse | [🌐](https://joinbookwyrm.com/) [🛠️](roles/web-app-bookwyrm/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Bridgy Fed](roles/web-app-bridgy-fed/) | beta | Federation bridge connecting ActivityPub (Fediverse), the AT Protocol (Bluesky), and the IndieWeb | [🌐](https://fed.brid.gy/) [🛠️](roles/web-app-bridgy-fed/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Checkmk](roles/web-app-checkmk/) | beta | Open-source IT and application monitoring server behind SSO with native LDAP user management | [🌐](https://checkmk.com/) [🎬](https://www.youtube.com/watch?v=opO-SOgOJ1I) [🛠️](roles/web-app-checkmk/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Chess](roles/web-app-chess/) | beta | Federated chess server for playing and following rule-validated games over ActivityPub across the Fediverse | [🌐](https://castling.club/) [🛠️](roles/web-app-chess/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Claude Code](roles/dsk-gnt-claude/) | alpha | Terminal coding agent from Anthropic, pointed at the platform's own model gateway instead of the vendor API | [🌐](https://code.claude.com/) [🛠️](roles/dsk-gnt-claude/README.md#quick-setup) | [Base](roles/dsk-base/), [LiteLLM Gateway](roles/svc-ai-litellm/) |
| [Code](roles/dsk-code/) | alpha | Visual Studio Code workstation editor in a selectable flavor, carrying the extensions of the agents the host deploys | [🌐](https://github.com/microsoft/vscode) [🛠️](roles/dsk-code/README.md#quick-setup) | [Base](roles/dsk-base/), [Claude Code](roles/dsk-gnt-claude/), [Codex](roles/dsk-gnt-codex/) |
| [Codex](roles/dsk-gnt-codex/) | alpha | Terminal coding agent from OpenAI, pointed at the platform's own model gateway instead of the vendor API | [🌐](https://github.com/openai/codex) [🛠️](roles/dsk-gnt-codex/README.md#quick-setup) | [Base](roles/dsk-base/), [LiteLLM Gateway](roles/svc-ai-litellm/) |
| [Collabora](roles/web-svc-collabora/) | beta | Self-hosted online office backend for real-time in-browser editing of documents, spreadsheets, and presentations | [🌐](https://www.collaboraonline.com/) [🎬](https://www.youtube.com/watch?v=8pqkclWG2BY) [🛠️](roles/web-svc-collabora/README.md#quick-setup) | [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Content Delivery Network](roles/web-svc-cdn/) | beta | Nginx-based content delivery network for serving shared static assets to internal web applications | [🛠️](roles/web-svc-cdn/README.md#quick-setup) | [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Corporate Design](roles/web-svc-design/) | beta | Corporate design configuration owner and `design` service flag, redirecting its hostname to the CDN | [🛠️](roles/web-svc-design/README.md#quick-setup) | [Content Delivery Network](roles/web-svc-cdn/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Coturn](roles/web-svc-coturn/) | beta | Free and open-source TURN/STUN relay server for NAT traversal in WebRTC and real-time communication | [🌐](https://github.com/coturn/coturn) [🛠️](roles/web-svc-coturn/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Prometheus](roles/web-app-prometheus/) |
| [Cursor](roles/dsk-gnt-cursor/) | alpha | AI-first code editor installed on the workstation, whose endpoint override stays an operator step | [🌐](https://cursor.com/) [🛠️](roles/dsk-gnt-cursor/README.md#quick-setup) | [Base](roles/dsk-base/) |
| [Dashboard](roles/web-app-dashboard/) | beta | Self-hosted portal for unified access to all deployed applications via a customizable tile and menu interface | [🛠️](roles/web-app-dashboard/README.md#quick-setup) | [Assets Server](roles/web-svc-asset/), [Content Delivery Network](roles/web-svc-cdn/), [Corporate Design](roles/web-svc-design/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Simple Icons](roles/web-svc-simpleicons/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Decidim](roles/web-app-decidim/) | beta | Open-source participatory democracy platform for public consultations, civic processes, and community voting | [🌐](https://decidim.org/) [🎬](https://www.youtube.com/watch?v=luSdPZ-wUIY) [🛠️](roles/web-app-decidim/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Discourse](roles/web-app-discourse/) | beta | Open-source discussion and community forum platform with moderation, notifications, and plugin support | [🌐](https://www.discourse.org/) [🎬](https://www.youtube.com/watch?v=z3qp_uB46FA) [🛠️](roles/web-app-discourse/README.md#quick-setup) | [Assets Server](roles/web-svc-asset/), [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [BigBlueButton](roles/web-app-bigbluebutton/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Jitsi Meet](roles/web-app-jitsi/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Mastodon](roles/web-app-mastodon/), [Matomo](roles/web-app-matomo/), [Matrix](roles/web-app-matrix/), [Mattermost](roles/web-app-mattermost/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Translation Gateway](roles/web-svc-translate/), [Universal Logout](roles/web-svc-logout/) |
| [Docker Registry](roles/svc-registry-docker/) | beta | Cluster-local container image registry for serving custom-built images to Docker Swarm worker nodes | [🌐](https://distribution.github.io/distribution/) [🛠️](roles/svc-registry-docker/README.md#quick-setup) | [Docker Swarm](roles/svc-swarm-node/) |
| [Docker Registry Cache](roles/svc-registry-cache/) | beta | Cluster-local pull-through cache for shared Docker Hub base-image pulls, cutting duplicate transfers and rate limits | [🛠️](roles/svc-registry-cache/README.md#quick-setup) | [Docker Swarm](roles/svc-swarm-node/) |
| [Docker Swarm](roles/svc-swarm-node/) | beta | Container orchestration cluster for scheduling services across pooled manager and worker nodes | [🛠️](roles/svc-swarm-node/README.md#quick-setup) | |
| [Docker Swarm Manager](roles/svc-swarm-manager/) | beta | Marker role tagging a host as the Docker Swarm manager node, with the init logic delegated to svc-swarm-node | [🛠️](roles/svc-swarm-manager/README.md#quick-setup) | [Docker Swarm](roles/svc-swarm-node/) |
| [Agent Broker](roles/svc-ai-agent-broker/) | beta | Per-user Hermes and OpenClaw agents started on demand behind an OpenAI-compatible endpoint | [🛠️](roles/svc-ai-agent-broker/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [OpenClaw](roles/web-app-openclaw/) |
| [API](roles/web-svc-api/) | alpha | Public REST API serving role data, history and translations of Infinito.Nexus for every ref of core and its forks | [🌐](https://fastapi.tiangolo.com/) [🛠️](roles/web-svc-api/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Asset Mirror (Privacy Proxy)](roles/web-svc-mirror/) | alpha | Nginx-based privacy proxy that mirrors whitelisted third-party assets under a first-party domain | [🛠️](roles/web-svc-mirror/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Assets Server](roles/web-svc-asset/) | beta | Nginx-based server for hosting static assets copied from a source directory to the web data path | [🛠️](roles/web-svc-asset/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [File Server](roles/web-svc-file/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Backup Docker Volumes](roles/svc-bkp-volume-2-local/) | beta | Scheduled deduplicating backup system for Docker container volumes to a local directory, with consistent SQL dumps | [🛠️](roles/svc-bkp-volume-2-local/README.md#quick-setup) | [Backup Host Secrets](roles/svc-bkp-secrets-2-local/), [Documentation](roles/web-app-docs/) |
| [Backup Host Secrets](roles/svc-bkp-secrets-2-local/) | beta | Scheduled deduplicating backup of host secrets, CA, ACME credentials, and node identity to the local backup directory | [🛠️](roles/svc-bkp-secrets-2-local/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Backup NFS](roles/svc-bkp-nfs-2-local/) | beta | Scheduled backup job for hard-linked differential rsync snapshots of an NFS export into the local backup tree | [🛠️](roles/svc-bkp-nfs-2-local/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [NFS Server](roles/svc-storage-nfs-server/) |
| [Backup Remote Server](roles/svc-bkp-remote-2-local/) | beta | Scheduled pull-style backup replicating remote hosts onto this host over SSH and rsync as hard-linked snapshots | [🛠️](roles/svc-bkp-remote-2-local/README.md#quick-setup) | [Backup to External Device](roles/svc-bkp-local-2-device/), [Documentation](roles/web-app-docs/) |
| [Backup to External Device](roles/svc-bkp-local-2-device/) | beta | Plug-triggered systemd backup for hard-link deduplicated snapshots of the local backup tree onto a swappable USB device | [🛠️](roles/svc-bkp-local-2-device/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Base](roles/dsk-base/) | beta | Shared premise of every desktop role, the login account its files belong to | [🛠️](roles/dsk-base/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Workstation User](roles/user-workstation/) |
| [Baserow](roles/web-app-baserow/) | beta | Self-hosted no-code database platform with a spreadsheet-like interface for building and collaborating on data | [🌐](https://baserow.io/) [🎬](https://www.youtube.com/watch?v=5yFMfP96_4M) [🛠️](roles/web-app-baserow/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [BigBlueButton](roles/web-app-bigbluebutton/) | beta | Self-hosted web conferencing platform for virtual classrooms, online meetings, and real-time collaboration | [🌐](https://bigbluebutton.org/) [🎬](https://www.youtube.com/watch?v=YRkQB6MJllI) [🛠️](roles/web-app-bigbluebutton/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Collabora](roles/web-svc-collabora/), [Corporate Design](roles/web-svc-design/), [Coturn](roles/web-svc-coturn/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Universal Logout](roles/web-svc-logout/) |
| [Blender](roles/dsk-blender/) | alpha | Blender workstation installation wired to the agents on the host through the Model Context Protocol | [🌐](https://www.blender.org) [🛠️](roles/dsk-blender/README.md#quick-setup) | [Base](roles/dsk-base/), [Claude Code](roles/dsk-gnt-claude/), [Code](roles/dsk-code/), [Documentation](roles/web-app-docs/) |
| [Bluesky](roles/web-app-bluesky/) | beta | Self-hosted decentralized social network on the open AT Protocol, with its own Personal Data Server | [🌐](https://bsky.social/) [🛠️](roles/web-app-bluesky/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [BookWyrm](roles/web-app-bookwyrm/) | beta | Self-hosted federated reading platform for book reviews and reading tracking across the Fediverse | [🌐](https://joinbookwyrm.com/) [🛠️](roles/web-app-bookwyrm/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Bridgy Fed](roles/web-app-bridgy-fed/) | beta | Federation bridge connecting ActivityPub (Fediverse), the AT Protocol (Bluesky), and the IndieWeb | [🌐](https://fed.brid.gy/) [🛠️](roles/web-app-bridgy-fed/README.md#quick-setup) | [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Checkmk](roles/web-app-checkmk/) | beta | Open-source IT and application monitoring server behind SSO with native LDAP user management | [🌐](https://checkmk.com/) [🎬](https://www.youtube.com/watch?v=opO-SOgOJ1I) [🛠️](roles/web-app-checkmk/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Chess](roles/web-app-chess/) | beta | Federated chess server for playing and following rule-validated games over ActivityPub across the Fediverse | [🌐](https://castling.club/) [🛠️](roles/web-app-chess/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Claude Code](roles/dsk-gnt-claude/) | alpha | Terminal coding agent from Anthropic, pointed at the platform's own model gateway instead of the vendor API | [🌐](https://code.claude.com/) [🛠️](roles/dsk-gnt-claude/README.md#quick-setup) | [Base](roles/dsk-base/), [Documentation](roles/web-app-docs/), [LiteLLM Gateway](roles/svc-ai-litellm/) |
| [Code](roles/dsk-code/) | alpha | Visual Studio Code workstation editor in a selectable flavor, carrying the extensions of the agents the host deploys | [🌐](https://github.com/microsoft/vscode) [🛠️](roles/dsk-code/README.md#quick-setup) | [Base](roles/dsk-base/), [Claude Code](roles/dsk-gnt-claude/), [Codex](roles/dsk-gnt-codex/), [Documentation](roles/web-app-docs/) |
| [Codex](roles/dsk-gnt-codex/) | alpha | Terminal coding agent from OpenAI, pointed at the platform's own model gateway instead of the vendor API | [🌐](https://github.com/openai/codex) [🛠️](roles/dsk-gnt-codex/README.md#quick-setup) | [Base](roles/dsk-base/), [Documentation](roles/web-app-docs/), [LiteLLM Gateway](roles/svc-ai-litellm/) |
| [Collabora](roles/web-svc-collabora/) | beta | Self-hosted online office backend for real-time in-browser editing of documents, spreadsheets, and presentations | [🌐](https://www.collaboraonline.com/) [🎬](https://www.youtube.com/watch?v=8pqkclWG2BY) [🛠️](roles/web-svc-collabora/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Content Delivery Network](roles/web-svc-cdn/) | beta | Nginx-based content delivery network for serving shared static assets to internal web applications | [🛠️](roles/web-svc-cdn/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Corporate Design](roles/web-svc-design/) | beta | Corporate design configuration owner and `design` service flag, redirecting its hostname to the CDN | [🛠️](roles/web-svc-design/README.md#quick-setup) | [Content Delivery Network](roles/web-svc-cdn/), [Documentation](roles/web-app-docs/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Coturn](roles/web-svc-coturn/) | beta | Free and open-source TURN/STUN relay server for NAT traversal in WebRTC and real-time communication | [🌐](https://github.com/coturn/coturn) [🛠️](roles/web-svc-coturn/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Documentation](roles/web-app-docs/), [Prometheus](roles/web-app-prometheus/) |
| [Cursor](roles/dsk-gnt-cursor/) | alpha | AI-first code editor installed on the workstation, whose endpoint override stays an operator step | [🌐](https://cursor.com/) [🛠️](roles/dsk-gnt-cursor/README.md#quick-setup) | [Base](roles/dsk-base/), [Documentation](roles/web-app-docs/) |
| [Dashboard](roles/web-app-dashboard/) | beta | Self-hosted portal for unified access to all deployed applications via a customizable tile and menu interface | [🛠️](roles/web-app-dashboard/README.md#quick-setup) | [Assets Server](roles/web-svc-asset/), [Content Delivery Network](roles/web-svc-cdn/), [Corporate Design](roles/web-svc-design/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Simple Icons](roles/web-svc-simpleicons/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Decidim](roles/web-app-decidim/) | beta | Open-source participatory democracy platform for public consultations, civic processes, and community voting | [🌐](https://decidim.org/) [🎬](https://www.youtube.com/watch?v=luSdPZ-wUIY) [🛠️](roles/web-app-decidim/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Discourse](roles/web-app-discourse/) | beta | Open-source discussion and community forum platform with moderation, notifications, and plugin support | [🌐](https://www.discourse.org/) [🎬](https://www.youtube.com/watch?v=z3qp_uB46FA) [🛠️](roles/web-app-discourse/README.md#quick-setup) | [Assets Server](roles/web-svc-asset/), [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [BigBlueButton](roles/web-app-bigbluebutton/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Jitsi Meet](roles/web-app-jitsi/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Mastodon](roles/web-app-mastodon/), [Matomo](roles/web-app-matomo/), [Matrix](roles/web-app-matrix/), [Mattermost](roles/web-app-mattermost/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Translation Gateway](roles/web-svc-translate/), [Universal Logout](roles/web-svc-logout/) |
| [Docker Registry](roles/svc-registry-docker/) | beta | Cluster-local container image registry for serving custom-built images to Docker Swarm worker nodes | [🌐](https://distribution.github.io/distribution/) [🛠️](roles/svc-registry-docker/README.md#quick-setup) | [Docker Swarm](roles/svc-swarm-node/), [Documentation](roles/web-app-docs/) |
| [Docker Registry Cache](roles/svc-registry-cache/) | beta | Cluster-local pull-through cache for shared Docker Hub base-image pulls, cutting duplicate transfers and rate limits | [🛠️](roles/svc-registry-cache/README.md#quick-setup) | [Docker Swarm](roles/svc-swarm-node/), [Documentation](roles/web-app-docs/) |
| [Docker Swarm](roles/svc-swarm-node/) | beta | Container orchestration cluster for scheduling services across pooled manager and worker nodes | [🛠️](roles/svc-swarm-node/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Docker Swarm Manager](roles/svc-swarm-manager/) | beta | Marker role tagging a host as the Docker Swarm manager node, with the init logic delegated to svc-swarm-node | [🛠️](roles/svc-swarm-manager/README.md#quick-setup) | [Docker Swarm](roles/svc-swarm-node/), [Documentation](roles/web-app-docs/) |
| [Documentation](roles/web-app-docs/) | beta | Infinito.Nexus documentation for the latest commit and every release, built on demand with Sphinx | [🌐](https://www.sphinx-doc.org/) [🛠️](roles/web-app-docs/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Elasticsearch](roles/svc-db-elasticsearch/) | beta | Central search and analytics engine with per-consumer index namespaces isolating tenants in a shared Docker deployment | [🌐](https://www.elastic.co/elasticsearch) [🛠️](roles/svc-db-elasticsearch/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Tor Onion Service](roles/svc-net-tor/) |
| [ERPNext](roles/web-app-erpnext/) | beta | Self-hosted open-source ERP suite for finance, CRM, inventory, manufacturing, HR, sales, and projects | [🌐](https://erpnext.com/) [🎬](https://www.youtube.com/watch?v=JlqE-BfDEUY) [🛠️](roles/web-app-erpnext/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [EspoCRM](roles/web-app-espocrm/) | beta | Open-source CRM platform for managing sales, customer interactions, and business processes across teams | [🌐](https://www.espocrm.com/) [🎬](https://www.youtube.com/watch?v=TH6yJPTPLO0) [🛠️](roles/web-app-espocrm/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Fediwall](roles/web-app-fediwall/) | beta | Self-hosted Fediverse wall for showing recent public posts by hashtag or account in a live masonry grid | [🌐](https://github.com/defnull/fediwall) [🛠️](roles/web-app-fediwall/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Friendica](roles/web-app-friendica/), [Mastodon](roles/web-app-mastodon/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Fider](roles/web-app-fider/) | beta | Open-source community feedback platform for collecting, voting on, and prioritizing feature requests and ideas | [🌐](https://www.fider.io/) [🛠️](roles/web-app-fider/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [File Server](roles/web-svc-file/) | beta | Static file server over HTTPS with directory listing, .well-known handling, and automatic TLS certificates | [🛠️](roles/web-svc-file/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Firewall ruleset](roles/svc-net-firewall/) | beta | nftables packet filter whose rules each role owns as its own table, replaced atomically and reloaded at boot | [🌐](https://www.netfilter.org/projects/nftables/) [🎬](https://www.youtube.com/watch?v=EGKhIljDPCw) [🛠️](roles/svc-net-firewall/README.md#quick-setup) | |
| [Flowise](roles/web-app-flowise/) | beta | Low-code visual builder for creating, testing, and publishing LLM and RAG workflows as HTTP endpoints | [🌐](https://flowiseai.com/) [🎬](https://www.youtube.com/watch?v=h_0TJTY6Ulg) [🛠️](roles/web-app-flowise/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [Ollama](roles/svc-ai-ollama/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Qdrant](roles/svc-db-qdrant/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Friendica](roles/web-app-friendica/) | beta | Decentralized, federated social-networking platform for peer-to-peer communication and community building | [🌐](https://friendi.ca/) [🛠️](roles/web-app-friendica/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Funkwhale](roles/web-app-funkwhale/) | beta | Self-hosted, federated platform for sharing, hosting, and streaming your own music and audio library | [🌐](https://www.funkwhale.audio/) [🛠️](roles/web-app-funkwhale/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Typesense](roles/svc-db-typesense/), [Universal Logout](roles/web-svc-logout/) |
| [FusionDirectory](roles/web-app-fusiondirectory/) | beta | Web-based LDAP administration interface for managing users, groups, and directory objects | [🌐](https://www.fusiondirectory.org/) [🎬](https://www.youtube.com/watch?v=dThpssnXGyk) [🛠️](roles/web-app-fusiondirectory/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Gitea](roles/web-app-gitea/) | beta | Lightweight self-hosted Git service for code collaboration, version control, and repository management | [🌐](https://about.gitea.com/) [🛠️](roles/web-app-gitea/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [GitLab](roles/web-app-gitlab/) | beta | Self-hosted DevOps platform for Git source-code management, CI/CD pipelines, and issue tracking | [🌐](https://about.gitlab.com/) [🎬](https://www.youtube.com/watch?v=7q9Y1Cv-ib0) [🛠️](roles/web-app-gitlab/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Hermes Agent](roles/web-app-hermes/), [Jenkins](roles/web-app-jenkins/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Matrix](roles/web-app-matrix/), [Mattermost](roles/web-app-mattermost/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Hermes Agent](roles/web-app-hermes/) | beta | Kernel-isolated agent runtime serving an OpenAI-compatible API, routed to models through the shared LLM gateway | [🌐](https://hermes-agent.nousresearch.com/) [🛠️](roles/web-app-hermes/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Kata & gVisor](roles/svc-virt-kata/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Home Assistant](roles/web-app-homeassistant/) | beta | Smart-home automation hub with device integrations, dashboards and a built-in MCP server for AI agent access | [🌐](https://www.home-assistant.io/) [🛠️](roles/web-app-homeassistant/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Flowise](roles/web-app-flowise/), [Hermes Agent](roles/web-app-hermes/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [HTML Server](roles/web-svc-html/) | beta | NGINX vhost for serving static HTML websites over HTTPS with automatic Let's Encrypt certificates | [🛠️](roles/web-svc-html/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Hugo](roles/web-app-hugo/) | beta | Static site generator building HTML from an upstream Git repository at build time and serving it via nginx | [🌐](https://gohugo.io/) [🛠️](roles/web-app-hugo/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Imprint](roles/web-svc-legal/) | beta | NGINX-served static page rendering a legal imprint (Impressum) from a Jinja2 template | [🛠️](roles/web-svc-legal/README.md#quick-setup) | [HTML Server](roles/web-svc-html/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Intel Driver](roles/drv-intel/) | alpha | Intel VA-API media driver for hardware-accelerated video decode and encode across Linux distributions | [🌐](https://github.com/intel/media-driver) [🛠️](roles/drv-intel/README.md#quick-setup) | |
| [Jellyfin](roles/web-app-jellyfin/) | beta | Self-hosted media server for streaming and organizing movies, TV, music, and photos, with OIDC and LDAP login | [🌐](https://jellyfin.org/) [🎬](https://www.youtube.com/watch?v=0t3lSJL3B_Q) [🛠️](roles/web-app-jellyfin/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Jenkins](roles/web-app-jenkins/) | beta | Open-source automation server for CI/CD pipelines, builds, and plugin-driven deployment workflows | [🌐](https://www.jenkins.io/) [🎬](https://www.youtube.com/watch?v=rNy00_gOo8o) [🛠️](roles/web-app-jenkins/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Gitea](roles/web-app-gitea/), [GitLab](roles/web-app-gitlab/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Mattermost](roles/web-app-mattermost/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Jitsi Meet](roles/web-app-jitsi/) | beta | Self-hosted WebRTC platform for end-to-end-encryptable video conferencing with federated authentication | [🌐](https://jitsi.org/) [🎬](https://www.youtube.com/watch?v=TB7LlM4erx8) [🛠️](roles/web-app-jitsi/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Universal Logout](roles/web-svc-logout/) |
| [Joomla](roles/web-app-joomla/) | beta | Open-source content management system for building websites, intranets, and online applications without writing code | [🌐](https://www.joomla.org/) [🎬](https://www.youtube.com/watch?v=mXFSIC_zM2o) [🛠️](roles/web-app-joomla/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Jupyter](roles/svc-ai-jupyter/) | alpha | Kernel backend that runs the code a chat writes, in a container instead of in the browser sandbox | [🌐](https://jupyter.org/) [🛠️](roles/svc-ai-jupyter/README.md#quick-setup) | |
| [Kata & gVisor](roles/svc-virt-kata/) | beta | Kernel-isolating container runtimes that sandbox untrusted workloads in a microVM or a userspace kernel | [🌐](https://katacontainers.io/) [🛠️](roles/svc-virt-kata/README.md#quick-setup) | |
| [Keycloak](roles/web-app-keycloak/) | beta | Self-hosted identity and access management platform for single sign-on, multi-factor authentication, and user federation | [🌐](https://www.keycloak.org/) [🛠️](roles/web-app-keycloak/README.md#quick-setup) | [Content Delivery Network](roles/web-svc-cdn/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/) |
| [KIX](roles/web-app-kix/) | beta | Open-source ITSM and helpdesk platform (OTRS fork) for ticketing, CMDB, knowledge base, and reporting | [🌐](https://www.kixdesk.com/en/) [🎬](https://www.youtube.com/watch?v=D62emos1FQ8) [🛠️](roles/web-app-kix/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [LAM](roles/web-app-lam/) | beta | Web interface for administering LDAP directories: managing users, groups, and other directory objects | [🌐](https://www.ldap-account-manager.org/) [🛠️](roles/web-app-lam/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [LibreTranslate](roles/web-svc-libretranslate/) | beta | Self-hosted open-source machine translation API for translating and detecting text across languages | [🌐](https://libretranslate.com/) [🛠️](roles/web-svc-libretranslate/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [LibreTranslate Engine](roles/svc-ai-libretranslate-engine/) | beta | Machine translation engine without a web surface, for pipelines that call it directly | [🌐](https://libretranslate.com/) [🛠️](roles/svc-ai-libretranslate-engine/README.md#quick-setup) | |
| [LID Switch Driver](roles/drv-lid-switch/) | alpha | Power-aware systemd logind configuration for predictable laptop lid-close behavior across battery, AC, and docked states | [🛠️](roles/drv-lid-switch/README.md#quick-setup) | |
| [Listmonk](roles/web-app-listmonk/) | beta | Self-hosted platform for newsletters and mailing lists with subscriber segmentation and campaign analytics | [🌐](https://listmonk.app/) [🛠️](roles/web-app-listmonk/README.md#quick-setup) | [Assets Server](roles/web-svc-asset/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [LiteLLM Admin UI](roles/web-app-litellm/) | beta | Browser-facing admin interface for the shared LLM gateway, published on its own domain behind the front proxy | [🌐](https://docs.litellm.ai/) [🛠️](roles/web-app-litellm/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [LiteLLM Gateway](roles/svc-ai-litellm/) | beta | OpenAI-compatible LLM gateway routing a single /v1 endpoint to local and hosted model backends with per-consumer keys | [🌐](https://docs.litellm.ai/) [🛠️](roles/svc-ai-litellm/README.md#quick-setup) | [LM Studio](roles/svc-ai-lmstudio/), [Ollama](roles/svc-ai-ollama/), [PostgreSQL](roles/svc-db-postgres/), [System One](roles/svc-ai-s1/) |
| [LittleJS](roles/web-app-littlejs/) | alpha | Self-hosted HTML5 game sandbox for browsing and running lightweight engine demos and games in the browser | [🌐](https://killedbyapixel.github.io/LittleJS/) [🎬](https://youtu.be/chuBzGjv7Ms) [🛠️](roles/web-app-littlejs/README.md#quick-setup) | [Content Delivery Network](roles/web-svc-cdn/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [LM Studio](roles/svc-ai-lmstudio/) | beta | Headless local model server for open LLMs with an OpenAI-compatible API on the container network | [🌐](https://lmstudio.ai/) [🛠️](roles/svc-ai-lmstudio/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/) |
| [LTEngine](roles/svc-ai-ltengine/) | alpha | LLM-backed translation engine speaking the LibreTranslate API, for pipelines that call it directly | [🌐](https://github.com/LibreTranslate/LTEngine) [🛠️](roles/svc-ai-ltengine/README.md#quick-setup) | |
| [Magento](roles/web-app-magento/) | alpha | Self-hosted e-commerce platform for catalog management, checkout, promotions, and multi-store online retail | [🌐](https://business.adobe.com/products/commerce/magento/open-source.html) [🎬](https://www.youtube.com/watch?v=nFdz9DZrdFc) [🛠️](roles/web-app-magento/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [MariaDB](roles/svc-db-mariadb/) | beta | Shared relational database server for applications needing central SQL storage, run in Docker | [🌐](https://mariadb.org/) [🎬](https://www.youtube.com/watch?v=YsIJB15fq_c) [🛠️](roles/svc-db-mariadb/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Tor Onion Service](roles/svc-net-tor/) |
| [Mastodon](roles/web-app-mastodon/) | beta | Self-hosted federated social network for microblogging, real-time timelines, and community moderation | [🌐](https://joinmastodon.org/) [🛠️](roles/web-app-mastodon/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Matomo](roles/web-app-matomo/) | beta | Self-hosted, privacy-first web analytics platform for real-time visitor tracking and site metrics | [🌐](https://matomo.org/) [🎬](https://www.youtube.com/watch?v=Qc2kooLNDiU) [🛠️](roles/web-app-matomo/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [MariaDB](roles/svc-db-mariadb/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Matrix](roles/web-app-matrix/) | beta | Federated, end-to-end-encrypted messaging platform with a web client and protocol bridges to external chat networks | [🌐](https://matrix.org/) [🎬](https://www.youtube.com/watch?v=3AVsNqH_-9M) [🛠️](roles/web-app-matrix/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Coturn](roles/web-svc-coturn/), [Dashboard](roles/web-app-dashboard/), [GitLab](roles/web-app-gitlab/), [Jitsi Meet](roles/web-app-jitsi/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [n8n](roles/web-app-n8n/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Mattermost](roles/web-app-mattermost/) | beta | Open-source, self-hosted team messaging platform for real-time collaboration via channels, threads, and integrations | [🌐](https://mattermost.com/) [🎬](https://www.youtube.com/watch?v=szfZfQFUSnU) [🛠️](roles/web-app-mattermost/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Content Delivery Network](roles/web-svc-cdn/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [GitLab](roles/web-app-gitlab/), [Hermes Agent](roles/web-app-hermes/), [Jenkins](roles/web-app-jenkins/), [Jitsi Meet](roles/web-app-jitsi/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [MCP Adapter](roles/svc-ai-mcp-adapter/) | alpha | Reusable per-provider MCP adapter exposing a narrow allowlisted read surface | [🌐](https://modelcontextprotocol.io/) [🛠️](roles/svc-ai-mcp-adapter/README.md#quick-setup) | |
| [MediaWiki](roles/web-app-mediawiki/) | beta | Collaborative wiki platform for user-driven documentation with an extensible extension ecosystem and content management | [🌐](https://www.mediawiki.org/) [🎬](https://www.youtube.com/watch?v=-JnIjpRvgNY) [🛠️](roles/web-app-mediawiki/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Discourse](roles/web-app-discourse/), [Keycloak](roles/web-app-keycloak/), [LibreTranslate](roles/web-svc-libretranslate/), [LiteLLM Gateway](roles/svc-ai-litellm/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [PeerTube](roles/web-app-peertube/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Memcached](roles/svc-db-memcached/) | beta | Central in-memory caching engine with per-consumer key-prefix isolation, usable centrally or as an embedded sidecar | [🌐](https://memcached.org/) [🛠️](roles/svc-db-memcached/README.md#quick-setup) | [Tor Onion Service](roles/svc-net-tor/) |
| [Meta](roles/web-app-meta/) | alpha | Interactive graph visualization of all Infinito.Nexus roles and their dependencies for architecture transparency | [🛠️](roles/web-app-meta/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Mini-QR](roles/web-app-mini-qr/) | beta | Self-hosted browser tool for generating QR codes from text or URLs with privacy-friendly local rendering | [🌐](https://github.com/lyqht/mini-qr) [🛠️](roles/web-app-mini-qr/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Mobilizon](roles/web-app-mobilizon/) | beta | Federated, self-hosted platform for organizing events and building communities and groups | [🌐](https://joinmobilizon.org/) [🎬](https://framatube.org/w/2mtugeJXaihsQnTHVWHf2E) [🛠️](roles/web-app-mobilizon/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Moodle](roles/web-app-moodle/) | beta | Open-source learning management system for creating, managing, and delivering online courses and e-learning | [🌐](https://moodle.org/) [🎬](https://www.youtube.com/watch?v=3ORsUGVNxGs) [🛠️](roles/web-app-moodle/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [BigBlueButton](roles/web-app-bigbluebutton/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Hermes Agent](roles/web-app-hermes/), [Jitsi Meet](roles/web-app-jitsi/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Matrix](roles/web-app-matrix/), [Nextcloud](roles/web-app-nextcloud/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [n8n](roles/web-app-n8n/) | beta | Self-hosted low-code automation platform for connecting services and building workflow integrations visually | [🌐](https://n8n.io/) [🎬](https://youtu.be/4cQWJViybAQ) [🛠️](roles/web-app-n8n/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Nextcloud](roles/web-app-nextcloud/) | beta | Self-hosted cloud platform for file sync, sharing, real-time collaboration, and team workspaces under your own domain | [🌐](https://nextcloud.com/) [🎬](https://youtu.be/3jcYJGQgenI?si=FDmoMSrAb9_WvviC) [🛠️](roles/web-app-nextcloud/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [BigBlueButton](roles/web-app-bigbluebutton/), [Collabora](roles/web-svc-collabora/), [Corporate Design](roles/web-svc-design/), [Coturn](roles/web-svc-coturn/), [Dashboard](roles/web-app-dashboard/), [Discourse](roles/web-app-discourse/), [GitLab](roles/web-app-gitlab/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [MariaDB](roles/svc-db-mariadb/), [Mastodon](roles/web-app-mastodon/), [Matomo](roles/web-app-matomo/), [Matrix](roles/web-app-matrix/), [Mattermost](roles/web-app-mattermost/), [OnlyOffice](roles/web-svc-onlyoffice/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [OpenProject](roles/web-app-openproject/), [PeerTube](roles/web-app-peertube/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/), [XWiki](roles/web-app-xwiki/), [Zammad](roles/web-app-zammad/) |
| [NFS Client](roles/svc-storage-nfs-client/) | beta | Client-side NFS setup for mounting a remote server export on every swarm node, with a deploy-time reachability probe | [🛠️](roles/svc-storage-nfs-client/README.md#quick-setup) | [NFS Server](roles/svc-storage-nfs-server/) |
| [NFS Server](roles/svc-storage-nfs-server/) | beta | Kernel-level NFS server for exporting a shared directory tree with IP-restricted access for swarm-node hosts | [🛠️](roles/svc-storage-nfs-server/README.md#quick-setup) | [Backup NFS](roles/svc-bkp-nfs-2-local/) |
| [Odoo ERP](roles/web-app-odoo/) | beta | Open-source ERP suite for CRM, sales, accounting, inventory, HR, and website management | [🌐](https://www.odoo.com/) [🎬](https://www.youtube.com/watch?v=FCmFgHVzd3E) [🛠️](roles/web-app-odoo/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Nextcloud](roles/web-app-nextcloud/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Ollama](roles/svc-ai-ollama/) | beta | Self-hosted model server for running open LLMs locally behind a simple HTTP API | [🌐](https://ollama.com/) [🛠️](roles/svc-ai-ollama/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/) |
| [OnlyOffice](roles/web-svc-onlyoffice/) | beta | Document server backend for real-time in-browser editing of documents, spreadsheets, and presentations | [🌐](https://www.onlyoffice.com/) [🎬](https://www.youtube.com/watch?v=uiFxnRK_aWM) [🛠️](roles/web-svc-onlyoffice/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Tor Onion Service](roles/svc-net-tor/) |
| [Open WebUI](roles/web-app-openwebui/) | beta | Self-hosted chat interface for interacting with local and private AI models via backends such as Ollama | [🌐](https://openwebui.com/) [🛠️](roles/web-app-openwebui/README.md#quick-setup) | [Agent Broker](roles/svc-ai-agent-broker/), [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Qdrant](roles/svc-db-qdrant/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [OpenBao](roles/web-app-openbao/) | beta | Identity-based secrets, PKI and encryption manager with OIDC login, group-mapped policies and static-seal auto-unseal | [🌐](https://openbao.org/) [🎬](https://www.youtube.com/watch?v=hPBT-kSS-68) [🛠️](roles/web-app-openbao/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [OpenClaw](roles/web-app-openclaw/) | beta | Self-hosted personal AI agent gateway with a browser control UI, sandboxed in a Kata microVM or gVisor runtime | [🌐](https://openclaw.ai/) [🛠️](roles/web-app-openclaw/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Kata & gVisor](roles/svc-virt-kata/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [OpenCloud](roles/web-app-opencloud/) | beta | Self-hosted platform for file sync, sharing, and collaboration with Keycloak SSO and central LDAP directory | [🌐](https://opencloud.eu/) [🎬](https://www.youtube.com/watch?v=Cg48rFNY0R4) [🛠️](roles/web-app-opencloud/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [OpenLDAP](roles/svc-db-openldap/) | beta | Self-hosted LDAP directory service for centralized user, group, and schema management with TLS-secured access | [🌐](https://www.openldap.org/) [🛠️](roles/svc-db-openldap/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Tor Onion Service](roles/svc-net-tor/) |
| [OpenProject](roles/web-app-openproject/) | beta | Self-hosted platform for project management, work-package tracking, Gantt planning, and team collaboration | [🌐](https://www.openproject.org/) [🎬](https://www.youtube.com/watch?v=rvCd0xH7rCs) [🛠️](roles/web-app-openproject/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [GitLab](roles/web-app-gitlab/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Nextcloud](roles/web-app-nextcloud/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [OpenResty](roles/svc-prx-openresty/) | beta | NGINX-based web platform and reverse proxy with validated config reloads and Let's Encrypt integration | [🌐](https://openresty.org/) [🎬](https://www.youtube.com/watch?v=NR8U1qYHGqk) [🛠️](roles/svc-prx-openresty/README.md#quick-setup) | [Tor Onion Service](roles/svc-net-tor/) |
| [OpenTalk](roles/web-app-opentalk/) | beta | Sovereign open-source video conferencing platform for audio/video calls, screen sharing, breakout rooms, and SSO | [🌐](https://opentalk.eu/) [🛠️](roles/web-app-opentalk/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Coturn](roles/web-svc-coturn/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Universal Logout](roles/web-svc-logout/) |
| [Package cache](roles/svc-cache-package/) | beta | Cluster-local proxy cache for package upstreams, serving apt, pip, npm and raw artefacts every role declares | [🛠️](roles/svc-cache-package/README.md#quick-setup) | [Docker Swarm](roles/svc-swarm-node/) |
| [Package update](roles/update/) | beta | System-maintenance role for refreshing the package index and upgrading installed packages via the OS package manager | [🛠️](roles/update/README.md#quick-setup) | |
| [PeerTube](roles/web-app-peertube/) | beta | Decentralized, federated platform for peer-to-peer video hosting, streaming, and live broadcasting | [🌐](https://joinpeertube.org/) [🎬](https://framatube.org/w/cX4KAPLTwha6hzLZ5xePGZ) [🛠️](roles/web-app-peertube/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Universal Logout](roles/web-svc-logout/) |
| [Penpot](roles/web-app-penpot/) | beta | Self-hosted design and prototyping platform for UI/UX work, real-time collaboration, and developer handoff | [🌐](https://penpot.app/) [🎬](https://www.youtube.com/watch?v=vAkb4QQmbfk) [🛠️](roles/web-app-penpot/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [pgAdmin](roles/web-app-pgadmin/) | beta | Web-based administration and development platform for managing multiple PostgreSQL servers, with optional OAuth2 login | [🌐](https://www.pgadmin.org/) [🎬](https://www.youtube.com/watch?v=WFT5MaZN6g4) [🛠️](roles/web-app-pgadmin/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [PhpMyAdmin](roles/web-app-phpmyadmin/) | beta | Web-based administration tool for MySQL and MariaDB with schema management, querying, and import/export | [🌐](https://www.phpmyadmin.net/) [🛠️](roles/web-app-phpmyadmin/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Pi Coding Agent](roles/dsk-gnt-pi/) | alpha | Minimal terminal coding agent with a lazy-loading skill system, wired to the platform's own model gateway | [🌐](https://github.com/earendil-works/pi) [🛠️](roles/dsk-gnt-pi/README.md#quick-setup) | [Base](roles/dsk-base/), [LiteLLM Gateway](roles/svc-ai-litellm/) |
| [Pixelfed](roles/web-app-pixelfed/) | beta | Decentralized, federated platform for photo sharing and image feeds across the fediverse | [🌐](https://pixelfed.org/) [🛠️](roles/web-app-pixelfed/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [PostgreSQL](roles/svc-db-postgres/) | beta | Containerized relational database with automated database, user, and privilege provisioning | [🌐](https://www.postgresql.org/) [🛠️](roles/svc-db-postgres/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Tor Onion Service](roles/svc-net-tor/) |
| [Postmarks](roles/web-app-postmarks/) | beta | Single-user ActivityPub bookmarking site federating public bookmarks to Mastodon and the Fediverse | [🌐](https://github.com/ckolderup/postmarks) [🛠️](roles/web-app-postmarks/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Pretix](roles/web-app-pretix/) | beta | Self-hosted ticketing platform for events with online sales, registration management, and secure payments | [🌐](https://pretix.eu/) [🎬](https://www.youtube.com/watch?v=5F6QkZP1Zf0) [🛠️](roles/web-app-pretix/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Prometheus](roles/web-app-prometheus/) | beta | Open-source monitoring and alerting toolkit for storing metrics as time-series data and querying them with PromQL | [🌐](https://prometheus.io/) [🎬](https://www.youtube.com/watch?v=PzFUwBflXYc) [🛠️](roles/web-app-prometheus/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Flowise](roles/web-app-flowise/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Proprietary Drivers](roles/drv-non-free/) | alpha | Proprietary GPU driver installer for Arch-based systems via mhwd nonfree hardware detection | [🛠️](roles/drv-non-free/README.md#quick-setup) | |
| [Qdrant](roles/svc-db-qdrant/) | beta | Central vector database engine for storing and searching per-consumer embeddings shared across the stack | [🌐](https://qdrant.tech/) [🎬](https://www.youtube.com/watch?v=_opNdOa48Lc) [🛠️](roles/svc-db-qdrant/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Flowise](roles/web-app-flowise/), [Hermes Agent](roles/web-app-hermes/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [Tor Onion Service](roles/svc-net-tor/) |
| [RabbitMQ](roles/svc-db-rabbitmq/) | beta | Shared message broker for async messaging with per-consumer virtual host and user isolation | [🌐](https://www.rabbitmq.com/) [🛠️](roles/svc-db-rabbitmq/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Tor Onion Service](roles/svc-net-tor/) |
| [Redirector](roles/web-opt-rdr-domains/) | beta | NGINX glue role for 301 redirects from source to target domains with automatic SSL for the source hosts | [🛠️](roles/web-opt-rdr-domains/README.md#quick-setup) | |
| [Redis](roles/svc-db-redis/) | beta | In-memory key-value cache and store, shared centrally with per-consumer ACL isolation or embedded as a sidecar | [🌐](https://redis.io/) [🛠️](roles/svc-db-redis/README.md#quick-setup) | [Tor Onion Service](roles/svc-net-tor/) |
| [Roulette Wheel](roles/web-app-roulette-wheel/) | alpha | Browser-based spinning wheel app for decision making, random selection, and gamification | [🌐](https://github.com/p-wojt/roulette-wheel) [🛠️](roles/web-app-roulette-wheel/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Searxng](roles/svc-ai-searxng/) | alpha | Metasearch engine the platform queries for web results without handing a user's query to a tracking search provider | [🌐](https://docs.searxng.org/) [🛠️](roles/svc-ai-searxng/README.md#quick-setup) | |
| [SeaweedFS](roles/web-svc-seaweedfs/) | beta | Distributed S3-compatible object store for shared, per-consumer bucket provisioning across web-app roles | [🌐](https://seaweedfs.com/) [🎬](https://www.youtube.com/watch?v=n0hRleSLAcc) [🛠️](roles/web-svc-seaweedfs/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Prometheus](roles/web-app-prometheus/) |
| [SeaweedFS Console](roles/web-app-seaweedfs/) | beta | Browser administration interface for the SeaweedFS object store, serving the filer and master consoles behind SSO | [🌐](https://seaweedfs.com/) [🎬](https://www.youtube.com/watch?v=n0hRleSLAcc) [🛠️](roles/web-app-seaweedfs/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Self-Hosted Runner](roles/svc-runner/) | beta | Self-hosted CI runner infrastructure for executing GitHub Actions workflow jobs in ephemeral Docker containers | [🌐](https://github.com/actions/runner) [🛠️](roles/svc-runner/README.md#quick-setup) | |
| [Semaphore UI](roles/web-app-semaphore/) | beta | Web UI and API for running Ansible, Terraform/OpenTofu, and shell automation on a schedule or on demand | [🌐](https://semaphoreui.com/) [🎬](https://www.youtube.com/watch?v=nzR4yDuZQMU) [🛠️](roles/web-app-semaphore/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Shopware](roles/web-app-shopware/) | beta | Open-source ecommerce platform built on Symfony and Vue.js for building and scaling online storefronts | [🌐](https://www.shopware.com/en/) [🎬](https://www.youtube.com/watch?v=bG57TZPYsyw) [🛠️](roles/web-app-shopware/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Simple Icons](roles/web-svc-simpleicons/) | beta | Containerized icon server for hosting the Simple Icons brand SVG and PNG collection for web and documentation use | [🌐](https://simpleicons.org/) [🛠️](roles/web-svc-simpleicons/README.md#quick-setup) | [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Snipe‑IT](roles/web-app-snipe-it/) | beta | Open-source IT asset management system for tracking hardware and software inventory | [🌐](https://snipeitapp.com/) [🎬](https://www.youtube.com/watch?v=q0V6FAPc1ls) [🛠️](roles/web-app-snipe-it/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Social Home](roles/web-app-socialhome/) | alpha | Privacy-first social platform for households, federating peer-to-peer over WebRTC on an embedded SQLite store | [🌐](https://github.com/social-home-io/socialhome) [🛠️](roles/web-app-socialhome/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Coturn](roles/web-svc-coturn/), [Dashboard](roles/web-app-dashboard/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Stalwart Mail Server](roles/web-app-stalwart/) | beta | All-in-one Stalwart mail server with SMTP, IMAP, JMAP, POP3, ManageSieve, CalDAV, CardDAV and built-in spam filtering | [🌐](https://stalw.art/) [🛠️](roles/web-app-stalwart/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Tor SMTP Gateway (svc-net-tor-smtp)](roles/svc-net-tor-smtp/), [Universal Logout](roles/web-svc-logout/) |
| [Storage Optimizer](roles/svc-opt-ssd-hdd/) | beta | Tiering role placing Docker volumes on SSD or HDD by workload type, with symlinks keeping paths consistent | [🛠️](roles/svc-opt-ssd-hdd/README.md#quick-setup) | |
| [SuiteCRM](roles/web-app-suitecrm/) | beta | Open-source CRM platform for sales, service, cases, and campaign management with workflow automation | [🌐](https://suitecrm.com/) [🎬](https://www.youtube.com/watch?v=pOAs_C3Fp_E) [🛠️](roles/web-app-suitecrm/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Swapfile](roles/svc-opt-swapfile/) | beta | On-target automation for creating and activating swap space via a cloned swapfile script | [🛠️](roles/svc-opt-swapfile/README.md#quick-setup) | |
| [System One](roles/svc-ai-s1/) | beta | Self-hosted System One classifier that answers typed questions so the gateway can route without generating | [🌐](https://huggingface.co/convaiinnovations/laya) [🎬](https://www.youtube.com/watch?v=UoRNo5LoDRE) [🛠️](roles/svc-ai-s1/README.md#quick-setup) | |
| [System One API](roles/web-svc-s1/) | alpha | Public vhost that exposes the System One decision API of svc-ai-s1 | [🛠️](roles/web-svc-s1/README.md#quick-setup) | [Prometheus](roles/web-app-prometheus/), [System One](roles/svc-ai-s1/), [Tor Onion Service](roles/svc-net-tor/) |
| [Taiga](roles/web-app-taiga/) | beta | Open-source agile project management platform for Scrum, Kanban, and hybrid team workflows | [🌐](https://taiga.io/) [🎬](https://www.youtube.com/watch?v=TYPX8nQEU5I) [🛠️](roles/web-app-taiga/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Tika](roles/svc-ai-tika/) | alpha | Central document extraction engine that turns uploaded files into text for retrieval-augmented chat | [🌐](https://tika.apache.org/) [🛠️](roles/svc-ai-tika/README.md#quick-setup) | |
| [Tor Onion Service](roles/svc-net-tor/) | beta | Tor daemon publishing the node as a v3 onion service | [🛠️](roles/svc-net-tor/README.md#quick-setup) | [Asset Mirror (Privacy Proxy)](roles/web-svc-mirror/) |
| [Tor SMTP Gateway (svc-net-tor-smtp)](roles/svc-net-tor-smtp/) | alpha | SMTP gateway that relays .onion recipients through Tor's SOCKS listener | [🛠️](roles/svc-net-tor-smtp/README.md#quick-setup) | |
| [Translation Gateway](roles/web-svc-translate/) | beta | One translation endpoint that picks the engine itself and prefers a reviewed human string | [🌐](https://s.infinito.nexus/code) [🛠️](roles/web-svc-translate/README.md#quick-setup) | [Keycloak](roles/web-app-keycloak/), [LibreTranslate Engine](roles/svc-ai-libretranslate-engine/), [LiteLLM Gateway](roles/svc-ai-litellm/), [LTEngine](roles/svc-ai-ltengine/), [Ollama](roles/svc-ai-ollama/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [System One](roles/svc-ai-s1/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/), [Weblate](roles/web-app-weblate/) |
| [Typesense](roles/svc-db-typesense/) | beta | Central Dockerized search engine shared by multiple apps with per-consumer scoped API keys | [🌐](https://typesense.org/) [🛠️](roles/svc-db-typesense/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Tor Onion Service](roles/svc-net-tor/) |
| [Unbound](roles/svc-dns-unbound/) | beta | Central recursive/forwarding DNSSEC resolver on a static IP for consumer stacks to target as their DNS | [🌐](https://nlnetlabs.nl/projects/unbound/about/) [🛠️](roles/svc-dns-unbound/README.md#quick-setup) | |
| [Universal Logout](roles/web-svc-logout/) | beta | Central logout proxy for single-action sign-out across all OIDC-connected apps, with Nginx snippets and a live status UI | [🛠️](roles/web-svc-logout/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Wazuh](roles/web-app-wazuh/) | beta | Open-source SIEM and XDR platform for monitoring, log analysis, intrusion/vulnerability detection, and compliance | [🌐](https://wazuh.com/) [🎬](https://www.youtube.com/watch?v=peTSzcAueEc) [🛠️](roles/web-app-wazuh/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [web-app-pihole](roles/web-app-pihole/) | beta | Network-wide DNS sinkhole for blocking ads and trackers across all devices, with DHCP and a web admin dashboard | [🌐](https://pi-hole.net/) [🎬](https://youtu.be/KBXTnrD_Zs4) [🛠️](roles/web-app-pihole/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Content Delivery Network](roles/web-svc-cdn/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Weblate](roles/web-app-weblate/) | beta | Translation memory, glossaries and the human review workflow behind the translation gateway | [🌐](https://weblate.org/) [🛠️](roles/web-app-weblate/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Translation Gateway](roles/web-svc-translate/), [Universal Logout](roles/web-svc-logout/) |
| [WireGuard](roles/svc-net-wireguard/) | beta | Kernel WireGuard tunnels, hub-and-spoke meshes under a swarm manager and full meshes between Compose hosts | [🌐](https://www.wireguard.com/) [🛠️](roles/svc-net-wireguard/README.md#quick-setup) | |
| [WordPress](roles/web-app-wordpress/) | beta | Content management system for building and managing websites, blogs, and multisite networks with themes and plugins | [🌐](https://wordpress.org/) [🎬](https://www.youtube.com/watch?v=QU8GFqvXRxE) [🛠️](roles/web-app-wordpress/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Discourse](roles/web-app-discourse/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [OpenClaw](roles/web-app-openclaw/), [Prometheus](roles/web-app-prometheus/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [World Wide Web](roles/web-opt-rdr-www/) | beta | NGINX server blocks that permanently redirect www subdomains to their non-www apex domains | [🛠️](roles/web-opt-rdr-www/README.md#quick-setup) | [Tor Onion Service](roles/svc-net-tor/) |
| [XMPP](roles/web-svc-xmpp/) | beta | Placeholder stub role for a future XMPP server/container deployment, implementation pending | [🌐](https://ejabberd.im/) [🛠️](roles/web-svc-xmpp/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Keycloak](roles/web-app-keycloak/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [XWiki](roles/web-app-xwiki/) | beta | Self-hosted enterprise wiki and knowledge-management platform with collaboration and app-based extensibility | [🌐](https://www.xwiki.org/) [🎬](https://www.youtube.com/watch?v=8DePx30dh2g) [🛠️](roles/web-app-xwiki/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [YOURLS](roles/web-app-yourls/) | beta | Self-hosted URL shortener for creating, tracking, and managing short links with built-in click analytics | [🌐](https://yourls.org/) [🛠️](roles/web-app-yourls/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Zammad](roles/web-app-zammad/) | beta | Open-source helpdesk and ticketing system for handling customer requests via email, chat, phone, and web | [🌐](https://zammad.org/) [🎬](https://www.youtube.com/watch?v=K30V0Uimr-s) [🛠️](roles/web-app-zammad/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [Memcached](roles/svc-db-memcached/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Stalwart Mail Server](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Elasticsearch](roles/svc-db-elasticsearch/) | beta | Central search and analytics engine with per-consumer index namespaces isolating tenants in a shared Docker deployment | [🌐](https://www.elastic.co/elasticsearch) [🛠️](roles/svc-db-elasticsearch/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Documentation](roles/web-app-docs/), [Tor Onion Service](roles/svc-net-tor/) |
| [ERPNext](roles/web-app-erpnext/) | beta | Self-hosted open-source ERP suite for finance, CRM, inventory, manufacturing, HR, sales, and projects | [🌐](https://erpnext.com/) [🎬](https://www.youtube.com/watch?v=JlqE-BfDEUY) [🛠️](roles/web-app-erpnext/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [EspoCRM](roles/web-app-espocrm/) | beta | Open-source CRM platform for managing sales, customer interactions, and business processes across teams | [🌐](https://www.espocrm.com/) [🎬](https://www.youtube.com/watch?v=TH6yJPTPLO0) [🛠️](roles/web-app-espocrm/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Fediwall](roles/web-app-fediwall/) | beta | Self-hosted Fediverse wall for showing recent public posts by hashtag or account in a live masonry grid | [🌐](https://github.com/defnull/fediwall) [🛠️](roles/web-app-fediwall/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Friendica](roles/web-app-friendica/), [Mastodon](roles/web-app-mastodon/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Fider](roles/web-app-fider/) | beta | Open-source community feedback platform for collecting, voting on, and prioritizing feature requests and ideas | [🌐](https://www.fider.io/) [🛠️](roles/web-app-fider/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [File Server](roles/web-svc-file/) | beta | Static file server over HTTPS with directory listing, .well-known handling, and automatic TLS certificates | [🛠️](roles/web-svc-file/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Firewall ruleset](roles/svc-net-firewall/) | beta | nftables packet filter whose rules each role owns as its own table, replaced atomically and reloaded at boot | [🌐](https://www.netfilter.org/projects/nftables/) [🎬](https://www.youtube.com/watch?v=EGKhIljDPCw) [🛠️](roles/svc-net-firewall/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Flowise](roles/web-app-flowise/) | beta | Low-code visual builder for creating, testing, and publishing LLM and RAG workflows as HTTP endpoints | [🌐](https://flowiseai.com/) [🎬](https://www.youtube.com/watch?v=h_0TJTY6Ulg) [🛠️](roles/web-app-flowise/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [Ollama](roles/svc-ai-ollama/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Qdrant](roles/svc-db-qdrant/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Friendica](roles/web-app-friendica/) | beta | Decentralized, federated social-networking platform for peer-to-peer communication and community building | [🌐](https://friendi.ca/) [🛠️](roles/web-app-friendica/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Funkwhale](roles/web-app-funkwhale/) | beta | Self-hosted, federated platform for sharing, hosting, and streaming your own music and audio library | [🌐](https://www.funkwhale.audio/) [🛠️](roles/web-app-funkwhale/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Typesense](roles/svc-db-typesense/), [Universal Logout](roles/web-svc-logout/) |
| [FusionDirectory](roles/web-app-fusiondirectory/) | beta | Web-based LDAP administration interface for managing users, groups, and directory objects | [🌐](https://www.fusiondirectory.org/) [🎬](https://www.youtube.com/watch?v=dThpssnXGyk) [🛠️](roles/web-app-fusiondirectory/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Gitea](roles/web-app-gitea/) | beta | Lightweight self-hosted Git service for code collaboration, version control, and repository management | [🌐](https://about.gitea.com/) [🛠️](roles/web-app-gitea/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [GitLab](roles/web-app-gitlab/) | beta | Self-hosted DevOps platform for Git source-code management, CI/CD pipelines, and issue tracking | [🌐](https://about.gitlab.com/) [🎬](https://www.youtube.com/watch?v=7q9Y1Cv-ib0) [🛠️](roles/web-app-gitlab/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Jenkins](roles/web-app-jenkins/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Matrix](roles/web-app-matrix/), [Mattermost](roles/web-app-mattermost/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Hermes Agent](roles/web-app-hermes/) | beta | Kernel-isolated agent runtime serving an OpenAI-compatible API, routed to models through the shared LLM gateway | [🌐](https://hermes-agent.nousresearch.com/) [🛠️](roles/web-app-hermes/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Kata & gVisor](roles/svc-virt-kata/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Home Assistant](roles/web-app-homeassistant/) | beta | Smart-home automation hub with device integrations, dashboards and a built-in MCP server for AI agent access | [🌐](https://www.home-assistant.io/) [🛠️](roles/web-app-homeassistant/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Flowise](roles/web-app-flowise/), [Hermes Agent](roles/web-app-hermes/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [HTML Server](roles/web-svc-html/) | beta | NGINX vhost for serving static HTML websites over HTTPS with automatic Let's Encrypt certificates | [🛠️](roles/web-svc-html/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Documentation](roles/web-app-docs/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Hugo](roles/web-app-hugo/) | beta | Static site generator building HTML from an upstream Git repository at build time and serving it via nginx | [🌐](https://gohugo.io/) [🛠️](roles/web-app-hugo/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Imprint](roles/web-svc-legal/) | beta | NGINX-served static page rendering a legal imprint (Impressum) from a Jinja2 template | [🛠️](roles/web-svc-legal/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [HTML Server](roles/web-svc-html/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Intel Driver](roles/drv-intel/) | alpha | Intel VA-API media driver for hardware-accelerated video decode and encode across Linux distributions | [🌐](https://github.com/intel/media-driver) [🛠️](roles/drv-intel/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Jellyfin](roles/web-app-jellyfin/) | beta | Self-hosted media server for streaming and organizing movies, TV, music, and photos, with OIDC and LDAP login | [🌐](https://jellyfin.org/) [🎬](https://www.youtube.com/watch?v=0t3lSJL3B_Q) [🛠️](roles/web-app-jellyfin/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Jenkins](roles/web-app-jenkins/) | beta | Open-source automation server for CI/CD pipelines, builds, and plugin-driven deployment workflows | [🌐](https://www.jenkins.io/) [🎬](https://www.youtube.com/watch?v=rNy00_gOo8o) [🛠️](roles/web-app-jenkins/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Gitea](roles/web-app-gitea/), [GitLab](roles/web-app-gitlab/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Mattermost](roles/web-app-mattermost/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Jitsi Meet](roles/web-app-jitsi/) | beta | Self-hosted WebRTC platform for end-to-end-encryptable video conferencing with federated authentication | [🌐](https://jitsi.org/) [🎬](https://www.youtube.com/watch?v=TB7LlM4erx8) [🛠️](roles/web-app-jitsi/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Universal Logout](roles/web-svc-logout/) |
| [Joomla](roles/web-app-joomla/) | beta | Open-source content management system for building websites, intranets, and online applications without writing code | [🌐](https://www.joomla.org/) [🎬](https://www.youtube.com/watch?v=mXFSIC_zM2o) [🛠️](roles/web-app-joomla/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Jupyter](roles/svc-ai-jupyter/) | alpha | Kernel backend that runs the code a chat writes, in a container instead of in the browser sandbox | [🌐](https://jupyter.org/) [🛠️](roles/svc-ai-jupyter/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Kata & gVisor](roles/svc-virt-kata/) | beta | Kernel-isolating container runtimes that sandbox untrusted workloads in a microVM or a userspace kernel | [🌐](https://katacontainers.io/) [🛠️](roles/svc-virt-kata/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Keycloak](roles/web-app-keycloak/) | beta | Self-hosted identity and access management platform for single sign-on, multi-factor authentication, and user federation | [🌐](https://www.keycloak.org/) [🛠️](roles/web-app-keycloak/README.md#quick-setup) | [Content Delivery Network](roles/web-svc-cdn/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/) |
| [KIX](roles/web-app-kix/) | beta | Open-source ITSM and helpdesk platform (OTRS fork) for ticketing, CMDB, knowledge base, and reporting | [🌐](https://www.kixdesk.com/en/) [🎬](https://www.youtube.com/watch?v=D62emos1FQ8) [🛠️](roles/web-app-kix/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [LAM](roles/web-app-lam/) | beta | Web interface for administering LDAP directories: managing users, groups, and other directory objects | [🌐](https://www.ldap-account-manager.org/) [🛠️](roles/web-app-lam/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [LibreTranslate](roles/web-svc-libretranslate/) | beta | Self-hosted open-source machine translation API for translating and detecting text across languages | [🌐](https://libretranslate.com/) [🛠️](roles/web-svc-libretranslate/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [LibreTranslate Engine](roles/svc-ai-libretranslate-engine/) | beta | Machine translation engine without a web surface, for pipelines that call it directly | [🌐](https://libretranslate.com/) [🛠️](roles/svc-ai-libretranslate-engine/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [LID Switch Driver](roles/drv-lid-switch/) | alpha | Power-aware systemd logind configuration for predictable laptop lid-close behavior across battery, AC, and docked states | [🛠️](roles/drv-lid-switch/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Listmonk](roles/web-app-listmonk/) | beta | Self-hosted platform for newsletters and mailing lists with subscriber segmentation and campaign analytics | [🌐](https://listmonk.app/) [🛠️](roles/web-app-listmonk/README.md#quick-setup) | [Assets Server](roles/web-svc-asset/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [LiteLLM Admin UI](roles/web-app-litellm/) | beta | Browser-facing admin interface for the shared LLM gateway, published on its own domain behind the front proxy | [🌐](https://docs.litellm.ai/) [🛠️](roles/web-app-litellm/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [LiteLLM Gateway](roles/svc-ai-litellm/) | beta | OpenAI-compatible LLM gateway routing a single /v1 endpoint to local and hosted model backends with per-consumer keys | [🌐](https://docs.litellm.ai/) [🛠️](roles/svc-ai-litellm/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [LM Studio](roles/svc-ai-lmstudio/), [Ollama](roles/svc-ai-ollama/), [PostgreSQL](roles/svc-db-postgres/), [System One](roles/svc-ai-s1/) |
| [LM Studio](roles/svc-ai-lmstudio/) | beta | Headless local model server for open LLMs with an OpenAI-compatible API on the container network | [🌐](https://lmstudio.ai/) [🛠️](roles/svc-ai-lmstudio/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Documentation](roles/web-app-docs/) |
| [LTEngine](roles/svc-ai-ltengine/) | alpha | LLM-backed translation engine speaking the LibreTranslate API, for pipelines that call it directly | [🌐](https://github.com/LibreTranslate/LTEngine) [🛠️](roles/svc-ai-ltengine/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Magento](roles/web-app-magento/) | alpha | Self-hosted e-commerce platform for catalog management, checkout, promotions, and multi-store online retail | [🌐](https://business.adobe.com/products/commerce/magento/open-source.html) [🎬](https://www.youtube.com/watch?v=nFdz9DZrdFc) [🛠️](roles/web-app-magento/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [MariaDB](roles/svc-db-mariadb/) | beta | Shared relational database server for applications needing central SQL storage, run in Docker | [🌐](https://mariadb.org/) [🎬](https://www.youtube.com/watch?v=YsIJB15fq_c) [🛠️](roles/svc-db-mariadb/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Documentation](roles/web-app-docs/), [Tor Onion Service](roles/svc-net-tor/) |
| [Mastodon](roles/web-app-mastodon/) | beta | Self-hosted federated social network for microblogging, real-time timelines, and community moderation | [🌐](https://joinmastodon.org/) [🛠️](roles/web-app-mastodon/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Matomo](roles/web-app-matomo/) | beta | Self-hosted, privacy-first web analytics platform for real-time visitor tracking and site metrics | [🌐](https://matomo.org/) [🎬](https://www.youtube.com/watch?v=Qc2kooLNDiU) [🛠️](roles/web-app-matomo/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [MariaDB](roles/svc-db-mariadb/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Matrix](roles/web-app-matrix/) | beta | Federated, end-to-end-encrypted messaging platform with a web client and protocol bridges to external chat networks | [🌐](https://matrix.org/) [🎬](https://www.youtube.com/watch?v=3AVsNqH_-9M) [🛠️](roles/web-app-matrix/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Coturn](roles/web-svc-coturn/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [GitLab](roles/web-app-gitlab/), [Jitsi Meet](roles/web-app-jitsi/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [n8n](roles/web-app-n8n/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Mattermost](roles/web-app-mattermost/) | beta | Open-source, self-hosted team messaging platform for real-time collaboration via channels, threads, and integrations | [🌐](https://mattermost.com/) [🎬](https://www.youtube.com/watch?v=szfZfQFUSnU) [🛠️](roles/web-app-mattermost/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Content Delivery Network](roles/web-svc-cdn/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [GitLab](roles/web-app-gitlab/), [Hermes Agent](roles/web-app-hermes/), [Jenkins](roles/web-app-jenkins/), [Jitsi Meet](roles/web-app-jitsi/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [MCP Adapter](roles/svc-ai-mcp-adapter/) | alpha | Reusable per-provider MCP adapter exposing a narrow allowlisted read surface | [🌐](https://modelcontextprotocol.io/) [🛠️](roles/svc-ai-mcp-adapter/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [MediaWiki](roles/web-app-mediawiki/) | beta | Collaborative wiki platform for user-driven documentation with an extensible extension ecosystem and content management | [🌐](https://www.mediawiki.org/) [🎬](https://www.youtube.com/watch?v=-JnIjpRvgNY) [🛠️](roles/web-app-mediawiki/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Discourse](roles/web-app-discourse/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [PeerTube](roles/web-app-peertube/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Translation Gateway](roles/web-svc-translate/), [Universal Logout](roles/web-svc-logout/) |
| [Memcached](roles/svc-db-memcached/) | beta | Central in-memory caching engine with per-consumer key-prefix isolation, usable centrally or as an embedded sidecar | [🌐](https://memcached.org/) [🛠️](roles/svc-db-memcached/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Tor Onion Service](roles/svc-net-tor/) |
| [Meta](roles/web-app-meta/) | alpha | Interactive graph visualization of all Infinito.Nexus roles and their dependencies for architecture transparency | [🛠️](roles/web-app-meta/README.md#quick-setup) | [API](roles/web-svc-api/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Mini-QR](roles/web-app-mini-qr/) | beta | Self-hosted browser tool for generating QR codes from text or URLs with privacy-friendly local rendering | [🌐](https://github.com/lyqht/mini-qr) [🛠️](roles/web-app-mini-qr/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Mobilizon](roles/web-app-mobilizon/) | beta | Federated, self-hosted platform for organizing events and building communities and groups | [🌐](https://joinmobilizon.org/) [🎬](https://framatube.org/w/2mtugeJXaihsQnTHVWHf2E) [🛠️](roles/web-app-mobilizon/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Moodle](roles/web-app-moodle/) | beta | Open-source learning management system for creating, managing, and delivering online courses and e-learning | [🌐](https://moodle.org/) [🎬](https://www.youtube.com/watch?v=3ORsUGVNxGs) [🛠️](roles/web-app-moodle/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [BigBlueButton](roles/web-app-bigbluebutton/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Jitsi Meet](roles/web-app-jitsi/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Matrix](roles/web-app-matrix/), [Nextcloud](roles/web-app-nextcloud/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [n8n](roles/web-app-n8n/) | beta | Self-hosted low-code automation platform for connecting services and building workflow integrations visually | [🌐](https://n8n.io/) [🎬](https://youtu.be/4cQWJViybAQ) [🛠️](roles/web-app-n8n/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Nextcloud](roles/web-app-nextcloud/) | beta | Self-hosted cloud platform for file sync, sharing, real-time collaboration, and team workspaces under your own domain | [🌐](https://nextcloud.com/) [🎬](https://youtu.be/3jcYJGQgenI?si=FDmoMSrAb9_WvviC) [🛠️](roles/web-app-nextcloud/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [BigBlueButton](roles/web-app-bigbluebutton/), [Collabora](roles/web-svc-collabora/), [Corporate Design](roles/web-svc-design/), [Coturn](roles/web-svc-coturn/), [Dashboard](roles/web-app-dashboard/), [Discourse](roles/web-app-discourse/), [Documentation](roles/web-app-docs/), [GitLab](roles/web-app-gitlab/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [MariaDB](roles/svc-db-mariadb/), [Mastodon](roles/web-app-mastodon/), [Matomo](roles/web-app-matomo/), [Matrix](roles/web-app-matrix/), [Mattermost](roles/web-app-mattermost/), [OnlyOffice](roles/web-svc-onlyoffice/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [OpenProject](roles/web-app-openproject/), [PeerTube](roles/web-app-peertube/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/), [XWiki](roles/web-app-xwiki/), [Zammad](roles/web-app-zammad/) |
| [NFS Client](roles/svc-storage-nfs-client/) | beta | Client-side NFS setup for mounting a remote server export on every swarm node, with a deploy-time reachability probe | [🛠️](roles/svc-storage-nfs-client/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [NFS Server](roles/svc-storage-nfs-server/) |
| [NFS Server](roles/svc-storage-nfs-server/) | beta | Kernel-level NFS server for exporting a shared directory tree with IP-restricted access for swarm-node hosts | [🛠️](roles/svc-storage-nfs-server/README.md#quick-setup) | [Backup NFS](roles/svc-bkp-nfs-2-local/), [Documentation](roles/web-app-docs/) |
| [NLLB-200](roles/svc-ai-nllb-engine/) | alpha | NLLB-200 translation model served over HTTP, for pipelines that call it directly | [🌐](https://huggingface.co/facebook/nllb-200-distilled-600M) [🛠️](roles/svc-ai-nllb-engine/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Odoo ERP](roles/web-app-odoo/) | beta | Open-source ERP suite for CRM, sales, accounting, inventory, HR, and website management | [🌐](https://www.odoo.com/) [🎬](https://www.youtube.com/watch?v=FCmFgHVzd3E) [🛠️](roles/web-app-odoo/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Nextcloud](roles/web-app-nextcloud/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Ollama](roles/svc-ai-ollama/) | beta | Self-hosted model server for running open LLMs locally behind a simple HTTP API | [🌐](https://ollama.com/) [🛠️](roles/svc-ai-ollama/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Documentation](roles/web-app-docs/) |
| [OnlyOffice](roles/web-svc-onlyoffice/) | beta | Document server backend for real-time in-browser editing of documents, spreadsheets, and presentations | [🌐](https://www.onlyoffice.com/) [🎬](https://www.youtube.com/watch?v=uiFxnRK_aWM) [🛠️](roles/web-svc-onlyoffice/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Documentation](roles/web-app-docs/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Tor Onion Service](roles/svc-net-tor/) |
| [Open WebUI](roles/web-app-openwebui/) | beta | Self-hosted chat interface for interacting with local and private AI models via backends such as Ollama | [🌐](https://openwebui.com/) [🛠️](roles/web-app-openwebui/README.md#quick-setup) | [Agent Broker](roles/svc-ai-agent-broker/), [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Qdrant](roles/svc-db-qdrant/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [OpenBao](roles/web-app-openbao/) | beta | Identity-based secrets, PKI and encryption manager with OIDC login, group-mapped policies and static-seal auto-unseal | [🌐](https://openbao.org/) [🎬](https://www.youtube.com/watch?v=hPBT-kSS-68) [🛠️](roles/web-app-openbao/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [OpenClaw](roles/web-app-openclaw/) | beta | Self-hosted personal AI agent gateway with a browser control UI, sandboxed in a Kata microVM or gVisor runtime | [🌐](https://openclaw.ai/) [🛠️](roles/web-app-openclaw/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Kata & gVisor](roles/svc-virt-kata/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [OpenCloud](roles/web-app-opencloud/) | beta | Self-hosted platform for file sync, sharing, and collaboration with Keycloak SSO and central LDAP directory | [🌐](https://opencloud.eu/) [🎬](https://www.youtube.com/watch?v=Cg48rFNY0R4) [🛠️](roles/web-app-opencloud/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [OpenLDAP](roles/svc-db-openldap/) | beta | Self-hosted LDAP directory service for centralized user, group, and schema management with TLS-secured access | [🌐](https://www.openldap.org/) [🛠️](roles/svc-db-openldap/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Documentation](roles/web-app-docs/), [Tor Onion Service](roles/svc-net-tor/) |
| [OpenProject](roles/web-app-openproject/) | beta | Self-hosted platform for project management, work-package tracking, Gantt planning, and team collaboration | [🌐](https://www.openproject.org/) [🎬](https://www.youtube.com/watch?v=rvCd0xH7rCs) [🛠️](roles/web-app-openproject/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [GitLab](roles/web-app-gitlab/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Nextcloud](roles/web-app-nextcloud/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [OpenResty](roles/svc-prx-openresty/) | beta | NGINX-based web platform and reverse proxy with validated config reloads and Let's Encrypt integration | [🌐](https://openresty.org/) [🎬](https://www.youtube.com/watch?v=NR8U1qYHGqk) [🛠️](roles/svc-prx-openresty/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Tor Onion Service](roles/svc-net-tor/) |
| [OpenTalk](roles/web-app-opentalk/) | beta | Sovereign open-source video conferencing platform for audio/video calls, screen sharing, breakout rooms, and SSO | [🌐](https://opentalk.eu/) [🛠️](roles/web-app-opentalk/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Coturn](roles/web-svc-coturn/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Universal Logout](roles/web-svc-logout/) |
| [Package cache](roles/svc-cache-package/) | beta | Cluster-local proxy cache for package upstreams, serving apt, pip, npm and raw artefacts every role declares | [🛠️](roles/svc-cache-package/README.md#quick-setup) | [Docker Swarm](roles/svc-swarm-node/), [Documentation](roles/web-app-docs/) |
| [Package update](roles/update/) | beta | System-maintenance role for refreshing the package index and upgrading installed packages via the OS package manager | [🛠️](roles/update/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [PeerTube](roles/web-app-peertube/) | beta | Decentralized, federated platform for peer-to-peer video hosting, streaming, and live broadcasting | [🌐](https://joinpeertube.org/) [🎬](https://framatube.org/w/cX4KAPLTwha6hzLZ5xePGZ) [🛠️](roles/web-app-peertube/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Universal Logout](roles/web-svc-logout/) |
| [Penpot](roles/web-app-penpot/) | beta | Self-hosted design and prototyping platform for UI/UX work, real-time collaboration, and developer handoff | [🌐](https://penpot.app/) [🎬](https://www.youtube.com/watch?v=vAkb4QQmbfk) [🛠️](roles/web-app-penpot/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [pgAdmin](roles/web-app-pgadmin/) | beta | Web-based administration and development platform for managing multiple PostgreSQL servers, with optional OAuth2 login | [🌐](https://www.pgadmin.org/) [🎬](https://www.youtube.com/watch?v=WFT5MaZN6g4) [🛠️](roles/web-app-pgadmin/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [PhpMyAdmin](roles/web-app-phpmyadmin/) | beta | Web-based administration tool for MySQL and MariaDB with schema management, querying, and import/export | [🌐](https://www.phpmyadmin.net/) [🛠️](roles/web-app-phpmyadmin/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Pi Coding Agent](roles/dsk-gnt-pi/) | alpha | Minimal terminal coding agent with a lazy-loading skill system, wired to the platform's own model gateway | [🌐](https://github.com/earendil-works/pi) [🛠️](roles/dsk-gnt-pi/README.md#quick-setup) | [Base](roles/dsk-base/), [Documentation](roles/web-app-docs/), [LiteLLM Gateway](roles/svc-ai-litellm/) |
| [Pixelfed](roles/web-app-pixelfed/) | beta | Decentralized, federated platform for photo sharing and image feeds across the fediverse | [🌐](https://pixelfed.org/) [🛠️](roles/web-app-pixelfed/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [PostgreSQL](roles/svc-db-postgres/) | beta | Containerized relational database with automated database, user, and privilege provisioning | [🌐](https://www.postgresql.org/) [🛠️](roles/svc-db-postgres/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Documentation](roles/web-app-docs/), [Tor Onion Service](roles/svc-net-tor/) |
| [Postmarks](roles/web-app-postmarks/) | beta | Single-user ActivityPub bookmarking site federating public bookmarks to Mastodon and the Fediverse | [🌐](https://github.com/ckolderup/postmarks) [🛠️](roles/web-app-postmarks/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Pretix](roles/web-app-pretix/) | beta | Self-hosted ticketing platform for events with online sales, registration management, and secure payments | [🌐](https://pretix.eu/) [🎬](https://www.youtube.com/watch?v=5F6QkZP1Zf0) [🛠️](roles/web-app-pretix/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Prometheus](roles/web-app-prometheus/) | beta | Open-source monitoring and alerting toolkit for storing metrics as time-series data and querying them with PromQL | [🌐](https://prometheus.io/) [🎬](https://www.youtube.com/watch?v=PzFUwBflXYc) [🛠️](roles/web-app-prometheus/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Flowise](roles/web-app-flowise/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Proprietary Drivers](roles/drv-non-free/) | alpha | Proprietary GPU driver installer for Arch-based systems via mhwd nonfree hardware detection | [🛠️](roles/drv-non-free/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Qdrant](roles/svc-db-qdrant/) | beta | Central vector database engine for storing and searching per-consumer embeddings shared across the stack | [🌐](https://qdrant.tech/) [🎬](https://www.youtube.com/watch?v=_opNdOa48Lc) [🛠️](roles/svc-db-qdrant/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Documentation](roles/web-app-docs/), [Flowise](roles/web-app-flowise/), [Hermes Agent](roles/web-app-hermes/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [Tor Onion Service](roles/svc-net-tor/) |
| [RabbitMQ](roles/svc-db-rabbitmq/) | beta | Shared message broker for async messaging with per-consumer virtual host and user isolation | [🌐](https://www.rabbitmq.com/) [🛠️](roles/svc-db-rabbitmq/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Documentation](roles/web-app-docs/), [Tor Onion Service](roles/svc-net-tor/) |
| [Redirector](roles/web-opt-rdr-domains/) | beta | NGINX glue role for 301 redirects from source to target domains with automatic SSL for the source hosts | [🛠️](roles/web-opt-rdr-domains/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Redis](roles/svc-db-redis/) | beta | In-memory key-value cache and store, shared centrally with per-consumer ACL isolation or embedded as a sidecar | [🌐](https://redis.io/) [🛠️](roles/svc-db-redis/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Tor Onion Service](roles/svc-net-tor/) |
| [Searxng](roles/svc-ai-searxng/) | alpha | Metasearch engine the platform queries for web results without handing a user's query to a tracking search provider | [🌐](https://docs.searxng.org/) [🛠️](roles/svc-ai-searxng/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [SeaweedFS](roles/web-svc-seaweedfs/) | beta | Distributed S3-compatible object store for shared, per-consumer bucket provisioning across web-app roles | [🌐](https://seaweedfs.com/) [🎬](https://www.youtube.com/watch?v=n0hRleSLAcc) [🛠️](roles/web-svc-seaweedfs/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Documentation](roles/web-app-docs/), [Prometheus](roles/web-app-prometheus/) |
| [SeaweedFS Console](roles/web-app-seaweedfs/) | beta | Browser administration interface for the SeaweedFS object store, serving the filer and master consoles behind SSO | [🌐](https://seaweedfs.com/) [🎬](https://www.youtube.com/watch?v=n0hRleSLAcc) [🛠️](roles/web-app-seaweedfs/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Self-Hosted Runner](roles/svc-runner/) | beta | Self-hosted CI runner infrastructure for executing GitHub Actions workflow jobs in ephemeral Docker containers | [🌐](https://github.com/actions/runner) [🛠️](roles/svc-runner/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Semaphore UI](roles/web-app-semaphore/) | beta | Web UI and API for running Ansible, Terraform/OpenTofu, and shell automation on a schedule or on demand | [🌐](https://semaphoreui.com/) [🎬](https://www.youtube.com/watch?v=nzR4yDuZQMU) [🛠️](roles/web-app-semaphore/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Shopware](roles/web-app-shopware/) | beta | Open-source ecommerce platform built on Symfony and Vue.js for building and scaling online storefronts | [🌐](https://www.shopware.com/en/) [🎬](https://www.youtube.com/watch?v=bG57TZPYsyw) [🛠️](roles/web-app-shopware/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Simple Icons](roles/web-svc-simpleicons/) | beta | Containerized icon server for hosting the Simple Icons brand SVG and PNG collection for web and documentation use | [🌐](https://simpleicons.org/) [🛠️](roles/web-svc-simpleicons/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Snipe‑IT](roles/web-app-snipe-it/) | beta | Open-source IT asset management system for tracking hardware and software inventory | [🌐](https://snipeitapp.com/) [🎬](https://www.youtube.com/watch?v=q0V6FAPc1ls) [🛠️](roles/web-app-snipe-it/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Social Home](roles/web-app-socialhome/) | alpha | Privacy-first social platform for households, federating peer-to-peer over WebRTC on an embedded SQLite store | [🌐](https://github.com/social-home-io/socialhome) [🛠️](roles/web-app-socialhome/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Coturn](roles/web-svc-coturn/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Stalwart](roles/web-app-stalwart/) | beta | All-in-one Stalwart mail server with SMTP, IMAP, JMAP, POP3, ManageSieve, CalDAV, CardDAV and built-in spam filtering | [🌐](https://stalw.art/) [🛠️](roles/web-app-stalwart/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Tor SMTP Gateway (svc-net-tor-smtp)](roles/svc-net-tor-smtp/), [Universal Logout](roles/web-svc-logout/) |
| [Storage Optimizer](roles/svc-opt-ssd-hdd/) | beta | Tiering role placing Docker volumes on SSD or HDD by workload type, with symlinks keeping paths consistent | [🛠️](roles/svc-opt-ssd-hdd/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [SuiteCRM](roles/web-app-suitecrm/) | beta | Open-source CRM platform for sales, service, cases, and campaign management with workflow automation | [🌐](https://suitecrm.com/) [🎬](https://www.youtube.com/watch?v=pOAs_C3Fp_E) [🛠️](roles/web-app-suitecrm/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Swapfile](roles/svc-opt-swapfile/) | beta | On-target automation for creating and activating swap space via a cloned swapfile script | [🛠️](roles/svc-opt-swapfile/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [System One](roles/svc-ai-s1/) | beta | Self-hosted System One classifier that answers typed questions so the gateway can route without generating | [🌐](https://huggingface.co/convaiinnovations/laya) [🎬](https://www.youtube.com/watch?v=UoRNo5LoDRE) [🛠️](roles/svc-ai-s1/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [System One API](roles/web-svc-s1/) | alpha | Public vhost that exposes the System One decision API of svc-ai-s1 | [🛠️](roles/web-svc-s1/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Prometheus](roles/web-app-prometheus/), [System One](roles/svc-ai-s1/), [Tor Onion Service](roles/svc-net-tor/) |
| [Taiga](roles/web-app-taiga/) | beta | Open-source agile project management platform for Scrum, Kanban, and hybrid team workflows | [🌐](https://taiga.io/) [🎬](https://www.youtube.com/watch?v=TYPX8nQEU5I) [🛠️](roles/web-app-taiga/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Tika](roles/svc-ai-tika/) | alpha | Central document extraction engine that turns uploaded files into text for retrieval-augmented chat | [🌐](https://tika.apache.org/) [🛠️](roles/svc-ai-tika/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Tor Onion Service](roles/svc-net-tor/) | beta | Tor daemon publishing the node as a v3 onion service | [🛠️](roles/svc-net-tor/README.md#quick-setup) | [Asset Mirror (Privacy Proxy)](roles/web-svc-mirror/), [Documentation](roles/web-app-docs/) |
| [Tor SMTP Gateway (svc-net-tor-smtp)](roles/svc-net-tor-smtp/) | alpha | SMTP gateway that relays .onion recipients through Tor's SOCKS listener | [🛠️](roles/svc-net-tor-smtp/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Translation Gateway](roles/web-svc-translate/) | beta | One translation endpoint that picks the engine itself and prefers a reviewed human string | [🌐](https://s.infinito.nexus/code) [🛠️](roles/web-svc-translate/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [LibreTranslate Engine](roles/svc-ai-libretranslate-engine/), [LiteLLM Gateway](roles/svc-ai-litellm/), [LTEngine](roles/svc-ai-ltengine/), [NLLB-200](roles/svc-ai-nllb-engine/), [Ollama](roles/svc-ai-ollama/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [System One](roles/svc-ai-s1/), [Tor Onion Service](roles/svc-net-tor/), [Weblate](roles/web-app-weblate/) |
| [Typesense](roles/svc-db-typesense/) | beta | Central Dockerized search engine shared by multiple apps with per-consumer scoped API keys | [🌐](https://typesense.org/) [🛠️](roles/svc-db-typesense/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Documentation](roles/web-app-docs/), [Tor Onion Service](roles/svc-net-tor/) |
| [Unbound](roles/svc-dns-unbound/) | beta | Central recursive/forwarding DNSSEC resolver on a static IP for consumer stacks to target as their DNS | [🌐](https://nlnetlabs.nl/projects/unbound/about/) [🛠️](roles/svc-dns-unbound/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [Universal Logout](roles/web-svc-logout/) | beta | Central logout proxy for single-action sign-out across all OIDC-connected apps, with Nginx snippets and a live status UI | [🛠️](roles/web-svc-logout/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Documentation](roles/web-app-docs/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Wazuh](roles/web-app-wazuh/) | beta | Open-source SIEM and XDR platform for monitoring, log analysis, intrusion/vulnerability detection, and compliance | [🌐](https://wazuh.com/) [🎬](https://www.youtube.com/watch?v=peTSzcAueEc) [🛠️](roles/web-app-wazuh/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [web-app-pihole](roles/web-app-pihole/) | beta | Network-wide DNS sinkhole for blocking ads and trackers across all devices, with DHCP and a web admin dashboard | [🌐](https://pi-hole.net/) [🎬](https://youtu.be/KBXTnrD_Zs4) [🛠️](roles/web-app-pihole/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Weblate](roles/web-app-weblate/) | beta | Translation memory, glossaries and the human review workflow behind the translation gateway | [🌐](https://weblate.org/) [🛠️](roles/web-app-weblate/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Translation Gateway](roles/web-svc-translate/), [Universal Logout](roles/web-svc-logout/) |
| [WireGuard](roles/svc-net-wireguard/) | beta | Kernel WireGuard tunnels, hub-and-spoke meshes under a swarm manager and full meshes between Compose hosts | [🌐](https://www.wireguard.com/) [🛠️](roles/svc-net-wireguard/README.md#quick-setup) | [Documentation](roles/web-app-docs/) |
| [WordPress](roles/web-app-wordpress/) | beta | Content management system for building and managing websites, blogs, and multisite networks with themes and plugins | [🌐](https://wordpress.org/) [🎬](https://www.youtube.com/watch?v=QU8GFqvXRxE) [🛠️](roles/web-app-wordpress/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [BigBlueButton](roles/web-app-bigbluebutton/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Discourse](roles/web-app-discourse/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [Listmonk](roles/web-app-listmonk/), [LiteLLM Gateway](roles/svc-ai-litellm/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [OpenClaw](roles/web-app-openclaw/), [PeerTube](roles/web-app-peertube/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Translation Gateway](roles/web-svc-translate/), [Universal Logout](roles/web-svc-logout/) |
| [World Wide Web](roles/web-opt-rdr-www/) | beta | NGINX server blocks that permanently redirect www subdomains to their non-www apex domains | [🛠️](roles/web-opt-rdr-www/README.md#quick-setup) | [Documentation](roles/web-app-docs/), [Tor Onion Service](roles/svc-net-tor/) |
| [XMPP](roles/web-svc-xmpp/) | beta | Placeholder stub role for a future XMPP server/container deployment, implementation pending | [🌐](https://ejabberd.im/) [🛠️](roles/web-svc-xmpp/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [XWiki](roles/web-app-xwiki/) | beta | Self-hosted enterprise wiki and knowledge-management platform with collaboration and app-based extensibility | [🌐](https://www.xwiki.org/) [🎬](https://www.youtube.com/watch?v=8DePx30dh2g) [🛠️](roles/web-app-xwiki/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [YOURLS](roles/web-app-yourls/) | beta | Self-hosted URL shortener for creating, tracking, and managing short links with built-in click analytics | [🌐](https://yourls.org/) [🛠️](roles/web-app-yourls/README.md#quick-setup) | [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Keycloak](roles/web-app-keycloak/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Zammad](roles/web-app-zammad/) | beta | Open-source helpdesk and ticketing system for handling customer requests via email, chat, phone, and web | [🌐](https://zammad.org/) [🎬](https://www.youtube.com/watch?v=K30V0Uimr-s) [🛠️](roles/web-app-zammad/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-design/), [Dashboard](roles/web-app-dashboard/), [Documentation](roles/web-app-docs/), [Hermes Agent](roles/web-app-hermes/), [Keycloak](roles/web-app-keycloak/), [LiteLLM Gateway](roles/svc-ai-litellm/), [Matomo](roles/web-app-matomo/), [Memcached](roles/svc-db-memcached/), [Open WebUI](roles/web-app-openwebui/), [OpenClaw](roles/web-app-openclaw/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Redis](roles/svc-db-redis/), [SeaweedFS](roles/web-svc-seaweedfs/), [Stalwart](roles/web-app-stalwart/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
## Guides 📚
@@ -34,14 +34,16 @@
- matomo_effective_token != ""
- matomo_site_cache is not defined or matomo_site_cache.scope != matomo_site_cache_scope
- name: "🧊 Cache the Matomo site list for the remaining vhosts"
- name: "🧊 Cache the Matomo site list, or its absence, for the remaining vhosts"
ansible.builtin.set_fact:
matomo_site_cache:
scope: "{{ matomo_site_cache_scope }}"
sites: "{{ matomo_site_list.json }}"
when:
- matomo_site_list.status is defined and matomo_site_list.status == 200
- matomo_site_list.json is defined and matomo_site_list.json is not mapping
sites: >-
{{ matomo_site_list.json
if matomo_site_list.status is defined and matomo_site_list.status == 200
and matomo_site_list.json is defined and matomo_site_list.json is not mapping
else none }}
when: matomo_site_list is not skipped
- name: "🔧 Take the site ID for '{{ domain }}' from the cached site list"
ansible.builtin.set_fact:
@@ -53,6 +55,7 @@
when:
- matomo_site_cache is defined
- matomo_site_cache.scope == matomo_site_cache_scope
- matomo_site_cache.sites is not none
- matomo_cached_site_ids | length > 0
- name: "🔎 Check if site {{ domain }} is already registered at Matomo"
@@ -75,7 +78,7 @@
when:
- matomo_effective_token != ""
- matomo_site_id == ""
- matomo_site_list is skipped or (matomo_site_list.status is defined and matomo_site_list.status == 200)
- matomo_site_cache.sites is not none
- block:
- name: "🔧 Set fact for site ID if site already exists"
+1 -1
View File
@@ -23,7 +23,7 @@ For administration commands see [Administration.md](./Administration.md). For DN
OIDC integration follows the variant A+ pattern documented in requirement 013: `web-app-keycloak`'s SSO-proxy sidecar is the gate, the in-role login-broker is the session-handoff agent, and the official `social-app` web client is the user-facing UI.
The broker MUST receive `X-Forwarded-User`, `X-Forwarded-Preferred-Username`, and `X-Forwarded-Email` from `oauth2-proxy`. On a user's first authenticated visit the broker calls the PDS `com.atproto.server.createAccount` endpoint with a synthesised app-password, encrypts that password with AES-256-GCM under a key from the project's credentials vault, and caches the ciphertext in the broker's in-process `sessionCache` keyed by Keycloak username. Subsequent visits decrypt the cached password in-broker, exchange it for a PDS session via `com.atproto.server.createSession`, and seed `localStorage["BSKY_STORAGE"]` so the social-app finds an authenticated session at boot. A broker restart drops the cache; the next SSO visit triggers a fresh `createAccount` and the previous app-password remains valid in PDS until rotated.
The broker MUST receive `X-Forwarded-User`, `X-Forwarded-Preferred-Username`, and `X-Forwarded-Email` from `oauth2-proxy`. On a user's first authenticated visit the broker calls the PDS `com.atproto.server.createAccount` endpoint with a synthesised app-password, encrypts that password with AES-256-GCM under a key from the project's credentials vault, and records handle, DID and ciphertext in the broker volume keyed by Keycloak username. Subsequent visits, also after a broker restart, decrypt the stored password in-broker, exchange it for a PDS session via `com.atproto.server.createSession`, and seed `localStorage["BSKY_STORAGE"]` so the social-app finds an authenticated session at boot. The handle is the username without prefix, `i8-<username>` for a name the PDS reserves, and a handle the user picks in a form when the username exceeds the PDS limit of 18 characters.
LDAP rides the same broker path: Keycloak federates LDAP via `svc-db-openldap` and the broker reads the resulting Keycloak headers via `oauth2-proxy`. Direct LDAP-to-PDS sync is NOT supported, the Keycloak federation layer is the single authority for user identity.
@@ -10,7 +10,9 @@ RUN apk add --no-cache ca-certificates && update-ca-certificates
WORKDIR /app
COPY package.json server.js ./
COPY package.json server.js handle.js store.js ./
RUN mkdir -p /data && chown node:node /data
USER node
EXPOSE 8080
@@ -7,13 +7,17 @@ The broker sits behind `web-app-keycloak`'s SSO-proxy sidecar and in front of th
official `@bluesky-social/social-app` web client. On a user's first
OIDC-authenticated visit, the broker:
1. Looks up the Keycloak user via the Admin REST API. The
service-account credentials are mounted as env, see `KC_ADMIN_*`.
1. Derives the handle `<username>.<PDS_HANDLE_DOMAIN>` from the
Keycloak username, or `i8-<username>.<PDS_HANDLE_DOMAIN>` when the
PDS answers `Reserved handle`. A first label longer than 18
characters cannot be a handle; the broker then shows a form at
`/sso/handle` where the user picks one of 3 to 18 characters from
`[a-z0-9-]` that contains a hyphen and never contains `i8-`.
2. Provisions a Bluesky PDS account via
`com.atproto.server.createAccount` if no encrypted app-password is
recorded on the user yet, encrypts the synthesised app-password
with **AES-256-GCM**, and stores the ciphertext as the
`bluesky_app_password_enc` user attribute.
`com.atproto.server.createAccount` if `BROKER_STORE_PATH` holds no
entry for the username yet, encrypts the synthesised app-password
with **AES-256-GCM**, and records the handle, the DID and the
ciphertext there, keyed by the Keycloak username.
3. Decrypts the stored app-password in-process and exchanges it for
a PDS session via `com.atproto.server.createSession`.
4. Renders an HTML handoff page that drops the resulting session
@@ -35,6 +39,7 @@ synthesised app-password.
| `PDS_URL` | Public Bluesky PDS base URL (`https://api.bluesky.<domain>`), written into the browser `service` field. |
| `PDS_INTERNAL_URL` | In-stack PDS URL for server-side XRPC calls (`http://pds:3000`); defaults to `PDS_URL` when unset. |
| `PDS_HANDLE_DOMAIN` | Suffix for synthesised handles (`<DOMAIN_PRIMARY>`). |
| `BROKER_STORE_PATH` | JSON file in the broker volume that maps usernames to their PDS account. |
| `PDS_INVITE_CODE` | Optional invite code for gated PDS deployments. |
| `KC_ADMIN_BASE_URL` | Keycloak base URL (`https://auth.<domain>`). |
| `KC_ADMIN_REALM` | Realm of the broker's service account (typically the same as user realm).|
@@ -0,0 +1,64 @@
"use strict";
const PDS_HANDLE_LABEL_MIN = 3;
const PDS_HANDLE_LABEL_MAX = 18;
const RESERVED_PREFIX = "i8-";
/**
* First handle label derived from a Keycloak username.
*
* @param {string} username Keycloak username
* @returns {string} lowercase label of [a-z0-9-], without prefix
*/
function deriveLabel(username) {
const mapped = String(username || "")
.toLowerCase()
.slice(0, 256)
.replace(/[^a-z0-9-]+/g, "-")
.replace(/^-+/, "")
.replace(/-+$/, "");
return mapped || "user";
}
/**
* Label for a name the PDS reserves ("admin", "administrator", ...).
*
* @param {string} label derived label
* @returns {string} label carrying the reserved-name prefix
*/
function prefixedLabel(label) {
return `${RESERVED_PREFIX}${label}`;
}
/**
* @param {string} label first handle label
* @returns {boolean} whether the PDS accepts its length
*/
function fitsPds(label) {
return label.length >= PDS_HANDLE_LABEL_MIN && label.length <= PDS_HANDLE_LABEL_MAX;
}
/**
* @param {string} label label the user typed
* @returns {string|null} reason shown in the form, null when acceptable
*/
function chosenLabelError(label) {
if (!/^[a-z0-9-]+$/.test(label)) return "Use lowercase letters, digits and hyphens only.";
if (!fitsPds(label)) {
return `Use ${PDS_HANDLE_LABEL_MIN} to ${PDS_HANDLE_LABEL_MAX} characters.`;
}
if (!label.includes("-")) return "Include at least one hyphen (-).";
if (label.includes(RESERVED_PREFIX)) return `Do not use "${RESERVED_PREFIX}" anywhere in the handle.`;
if (label.startsWith("-") || label.endsWith("-")) return "Do not start or end the handle with a hyphen.";
return null;
}
module.exports = {
PDS_HANDLE_LABEL_MAX,
PDS_HANDLE_LABEL_MIN,
RESERVED_PREFIX,
chosenLabelError,
deriveLabel,
fitsPds,
prefixedLabel,
};
@@ -1,4 +1,3 @@
// nocheck: mirrored-unit-test - a standalone Express server whose module body binds a port and reads the container environment at import
/*
* Bluesky login-broker.
*
@@ -49,6 +48,16 @@ const http = require("node:http");
const https = require("node:https");
const crypto = require("node:crypto");
const { URL } = require("node:url");
const {
PDS_HANDLE_LABEL_MAX,
PDS_HANDLE_LABEL_MIN,
RESERVED_PREFIX,
chosenLabelError,
deriveLabel,
fitsPds,
prefixedLabel
} = require("./handle");
const { openStore } = require("./store");
// --- Configuration --------------------------------------------------
@@ -73,7 +82,9 @@ const CONFIG = {
handoffCookieMaxAgeSec: parseInt(process.env.HANDOFF_COOKIE_MAX_AGE || "3300", 10),
insecureTls: (process.env.INSECURE_TLS || "").toLowerCase() === "true",
siteTitle: requireEnv("SITE_TITLE"),
logoutPath: "/sso/logout"
storePath: requireEnv("BROKER_STORE_PATH"),
logoutPath: "/sso/logout",
chooseHandlePath: "/sso/handle"
};
function requireEnv(name) {
@@ -164,18 +175,6 @@ function fetchJson(method, urlString, opts = {}) {
// --- PDS client -----------------------------------------------------
function sanitiseHandle(username) {
if (!username) return "kc-user";
const lower = username.toLowerCase().slice(0, 256);
const mapped = lower.replace(/[^a-z0-9-]+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
// PDS reserves common service handles ("administrator", "admin", "api",
// "support", "www", "bsky", "atproto", etc.) and rejects createAccount
// with `HandleNotAvailable: Reserved handle`. Always prefix with `kc-`
// so Keycloak-derived handles cannot collide with that reserved list,
// independent of which usernames the realm carries.
return `kc-${mapped || "user"}`;
}
async function pdsCreateAccount({ handle, email, password }) {
const url = `${CONFIG.pdsInternalUrl}/xrpc/com.atproto.server.createAccount`;
const body = { handle, email, password };
@@ -196,7 +195,10 @@ async function pdsCreateSession({ handle, password }) {
const url = `${CONFIG.pdsInternalUrl}/xrpc/com.atproto.server.createSession`;
const res = await fetchJson("POST", url, { body: { identifier: handle, password } });
if (res.status < 200 || res.status >= 300) {
throw new Error(`PDS createSession failed: status=${res.status} body=${res.raw}`);
const err = new Error(`PDS createSession failed: status=${res.status} body=${res.raw}`);
err.pdsStatus = res.status;
err.pdsBody = res.body;
throw err;
}
return res.body;
}
@@ -233,61 +235,109 @@ async function pdsAdminUpdatePassword(did, newPassword) {
// --- High-level orchestration --------------------------------------
// Per-user PDS app-password / DID / handle cache, keyed by Keycloak
// username. In-memory, AES-256-GCM-encrypted at rest.
//
// We deliberately do NOT write the encrypted blob into Keycloak user
// attributes (the previous design): on a realm with LDAP federation
// in WRITABLE mode the bluesky_* attribute write triggers an LDAP
// schema-violating sync push and leaves the federated user in a
// partially-synced state, which then breaks subsequent direct OIDC
// logins for that user (every other realm-OIDC test in the matrix
// would regress as a side-effect of running the broker once). The
// broker is a single-instance sidecar so an in-memory map is enough;
// on broker restart the user re-creates a PDS app-password on first
// SSO visit. The previous app-password remains valid in PDS until
// rotated explicitly — acceptable for this auto-provision flow.
const sessionCache = new Map();
// Exception: the account map lives in the broker's own volume, never in a
// Keycloak user attribute; a bluesky_* attribute write under LDAP federation
// in WRITABLE mode triggers a schema-violating sync push that breaks later
// OIDC logins of that user.
const store = openStore(CONFIG.storePath);
async function ensurePdsSession({ kcUsername, kcEmail }) {
const fullHandle = `${sanitiseHandle(kcUsername)}.${CONFIG.pdsHandleDomain}`;
const cached = sessionCache.get(kcUsername);
let appPasswordEnc = cached ? cached.appPasswordEnc : null;
let did = cached ? cached.did : null;
if (!appPasswordEnc) {
const synthesised = crypto.randomBytes(18).toString("base64url");
class HandleChoiceRequired extends Error {}
function pdsMessageIncludes(err, text) {
return Boolean(
err.pdsBody && typeof err.pdsBody.message === "string" && err.pdsBody.message.includes(text)
);
}
function accountEmail(kcUsername, kcEmail) {
return kcEmail || `${kcUsername}@bridge.local`;
}
async function createAccountWithLabel({ label, kcUsername, kcEmail, password, recoverTaken }) {
const handle = `${label}.${CONFIG.pdsHandleDomain}`;
try {
const created = await pdsCreateAccount({ handle, email: accountEmail(kcUsername, kcEmail), password });
return { handle, did: created.did };
} catch (err) {
if (!recoverTaken || !pdsMessageIncludes(err, "Handle already taken")) throw err;
const owner = store.ownerOf(handle);
if (owner && owner !== kcUsername) throw err;
const did = await pdsResolveHandle(handle);
await pdsAdminUpdatePassword(did, password);
return { handle, did };
}
}
async function provisionAccount({ kcUsername, kcEmail, chosenLabel }) {
const password = crypto.randomBytes(18).toString("base64url");
const request = { kcUsername, kcEmail, password };
let account;
if (chosenLabel) {
account = await createAccountWithLabel(Object.assign({ label: chosenLabel, recoverTaken: false }, request));
} else {
const label = deriveLabel(kcUsername);
if (!fitsPds(label)) throw new HandleChoiceRequired();
try {
const created = await pdsCreateAccount({
handle: fullHandle,
email: kcEmail || `${kcUsername}@bridge.local`,
password: synthesised
});
did = created.did || did;
account = await createAccountWithLabel(Object.assign({ label, recoverTaken: true }, request));
} catch (err) {
// Recover from `Handle already taken` — happens when the broker's
// in-memory cache has been lost (container restart, cross-variant
// deploy that shares the PDS data volume) but the PDS still has
// the account from a previous broker session. Use the PDS admin
// API to reset the password to a fresh value we control, so the
// subsequent createSession works again.
const isHandleTaken =
err.pdsBody && err.pdsBody.error === "InvalidRequest" &&
typeof err.pdsBody.message === "string" &&
err.pdsBody.message.includes("Handle already taken");
if (!isHandleTaken) throw err;
did = await pdsResolveHandle(fullHandle);
await pdsAdminUpdatePassword(did, synthesised);
if (!pdsMessageIncludes(err, "Reserved handle")) throw err;
const reservedLabel = prefixedLabel(label);
if (!fitsPds(reservedLabel)) throw new HandleChoiceRequired();
account = await createAccountWithLabel(Object.assign({ label: reservedLabel, recoverTaken: true }, request));
}
appPasswordEnc = encrypt(synthesised);
sessionCache.set(kcUsername, { appPasswordEnc, did, handle: fullHandle });
}
const entry = { handle: account.handle, did: account.did, appPasswordEnc: encrypt(password) };
store.set(kcUsername, entry);
return entry;
}
const provisioning = new Map();
function provisionOnce(request) {
const pending = provisioning.get(request.kcUsername);
if (pending) return pending;
const run = provisionAccount(request).finally(() => provisioning.delete(request.kcUsername));
provisioning.set(request.kcUsername, run);
return run;
}
function sessionFor(entry) {
return pdsCreateSession({ handle: entry.handle, password: decrypt(entry.appPasswordEnc) });
}
async function storedSession(kcUsername, entry) {
try {
return await sessionFor(entry);
} catch (err) {
if (!pdsMessageIncludes(err, "Invalid identifier or password")) throw err;
}
const password = crypto.randomBytes(18).toString("base64url");
await pdsAdminUpdatePassword(entry.did, password);
const repaired = Object.assign({}, entry, { appPasswordEnc: encrypt(password) });
try {
const session = await sessionFor(repaired);
store.set(kcUsername, repaired);
return session;
} catch (err) {
if (!pdsMessageIncludes(err, "Invalid identifier or password")) throw err;
store.delete(kcUsername);
return null;
}
}
async function ensurePdsSession({ kcUsername, kcEmail, chosenLabel }) {
const stored = store.get(kcUsername);
let session = stored ? await storedSession(kcUsername, stored) : null;
let entry = stored;
if (!session) {
entry = await provisionOnce({ kcUsername, kcEmail, chosenLabel });
session = await sessionFor(entry);
}
const password = decrypt(appPasswordEnc);
const session = await pdsCreateSession({ handle: fullHandle, password });
return {
service: CONFIG.pdsUrl,
did: session.did || did,
handle: session.handle || fullHandle,
email: kcEmail || `${kcUsername}@bridge.local`,
did: session.did || entry.did,
handle: session.handle || entry.handle,
email: accountEmail(kcUsername, kcEmail),
emailConfirmed: true,
accessJwt: session.accessJwt,
refreshJwt: session.refreshJwt
@@ -395,6 +445,59 @@ function renderHandoff(session, redirectTo) {
</html>`;
}
function renderHandleForm({ error, value }) {
const errorHtml = error ? `<p class="error">${escapeHtml(error)}</p>` : "";
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Choose your Bluesky handle</title>
<meta name="referrer" content="no-referrer" />
<style>body{font-family:sans-serif;background:#001a33;color:#eef;margin:0;padding:2em;text-align:center}input,button{font-size:1em;padding:.4em}.error{color:#f99}</style>
</head>
<body>
<h1>Choose your Bluesky handle</h1>
<p>Your username is longer than the ${PDS_HANDLE_LABEL_MAX} characters a Bluesky handle allows.</p>
<p>Pick ${PDS_HANDLE_LABEL_MIN} to ${PDS_HANDLE_LABEL_MAX} lowercase letters, digits and hyphens. The handle must contain a hyphen (-) and must not contain "${RESERVED_PREFIX}".</p>
${errorHtml}
<form method="post" action="${CONFIG.chooseHandlePath}">
<input name="handle" value="${escapeHtml(value)}" required minlength="${PDS_HANDLE_LABEL_MIN}" maxlength="${PDS_HANDLE_LABEL_MAX}" pattern="[a-z0-9-]+" autocomplete="off" autofocus />
<span>.${escapeHtml(CONFIG.pdsHandleDomain)}</span>
<button type="submit">Create account</button>
</form>
</body>
</html>`;
}
function readBody(req, limitBytes) {
return new Promise((resolve, reject) => {
const chunks = [];
let size = 0;
req.on("data", (chunk) => {
size += chunk.length;
if (size > limitBytes) {
reject(new Error("request body too large"));
req.destroy();
return;
}
chunks.push(chunk);
});
req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
req.on("error", reject);
});
}
function isSameOrigin(req) {
const origin = req.headers["origin"];
const host = (req.headers["x-forwarded-host"] || req.headers["host"] || "").toString().split(",")[0].trim();
if (!origin || !host) return false;
try {
return new URL(origin).hostname === new URL(`http://${host}`).hostname;
} catch {
return false;
}
}
function endHtml(res, status, html) {
res.writeHead(status, {
"Content-Type": "text/html; charset=utf-8",
@@ -472,13 +575,49 @@ const server = http.createServer(async (req, res) => {
return;
}
const session = await ensurePdsSession({ kcUsername, kcEmail });
if (path === CONFIG.chooseHandlePath && req.method === "POST") {
if (!isSameOrigin(req)) {
endText(res, 403, "Cross-origin handle submission refused.");
return;
}
const chosenLabel = (new URLSearchParams(await readBody(req, 1024)).get("handle") || "").trim();
const error = chosenLabelError(chosenLabel);
if (error) {
endHtml(res, 400, renderHandleForm({ error, value: chosenLabel }));
return;
}
let chosenSession;
try {
chosenSession = await ensurePdsSession({ kcUsername, kcEmail, chosenLabel });
} catch (err) {
if (!pdsMessageIncludes(err, "Handle already taken")) throw err;
endHtml(res, 409, renderHandleForm({ error: "This handle is already taken.", value: chosenLabel }));
return;
}
console.log(`[broker:${reqId}] chosen handle ${logSafe(chosenSession.handle)} ready (${Date.now() - reqStart}ms)`);
endHtml(res, 200, renderHandoff(chosenSession, "/"));
return;
}
let session;
try {
session = await ensurePdsSession({ kcUsername, kcEmail });
} catch (err) {
if (!(err instanceof HandleChoiceRequired)) throw err;
console.log(`[broker:${reqId}] username too long for a handle → handle form (${Date.now() - reqStart}ms)`);
endHtml(res, 200, renderHandleForm({ error: null, value: "" }));
return;
}
console.log(`[broker:${reqId}] PDS session ready did=${logSafe(session.did)} handle=${logSafe(session.handle)} hasAccessJwt=${!!session.accessJwt} (${Date.now() - reqStart}ms)`);
const html = renderHandoff(session, requestUrl.pathname + (requestUrl.search || ""));
endHtml(res, 200, html);
console.log(`[broker:${reqId}] handoff HTML sent (${Date.now() - reqStart}ms)`);
} catch (err) {
console.error(`[broker:${reqId}] error:`, err.stack || err.message);
if (pdsMessageIncludes(err, "Email already taken")) {
endText(res, 409, "Another Bluesky account on this server already uses your e-mail address, most likely a legacy kc- account. Ask an administrator to delete it.");
return;
}
endText(res, 500, `Broker error: ${escapeHtml(err.message)}`);
}
});
@@ -0,0 +1,43 @@
"use strict";
const fs = require("node:fs");
/**
* Persistent map from Keycloak username to the broker's PDS account.
*
* @param {string} file JSON file inside the broker's volume
* @returns {{get: function(string): (object|null), set: function(string, object): void, delete: function(string): void, ownerOf: function(string): (string|null)}}
* get returns {handle, did, appPasswordEnc} or null; set and delete write
* the file through a rename; ownerOf names the username that holds a handle
*/
function openStore(file) {
const entries = new Map(
fs.existsSync(file) ? Object.entries(JSON.parse(fs.readFileSync(file, "utf8"))) : [],
);
function save() {
const tmp = `${file}.tmp`;
fs.writeFileSync(tmp, JSON.stringify(Object.fromEntries(entries)), { mode: 0o600 });
fs.renameSync(tmp, file);
}
return {
get: (username) => entries.get(username) || null,
set: (username, entry) => {
entries.set(username, entry);
save();
},
delete: (username) => {
entries.delete(username);
save();
},
ownerOf: (handle) => {
for (const [username, entry] of entries) {
if (entry.handle === handle) return username;
}
return null;
},
};
}
module.exports = { openStore };
@@ -18,7 +18,9 @@ const oidcIssuerUrl = normalizeBaseUrl(requireDotenvValue(process.env.OIDC_ISSUE
const canonicalDomain = decodeDotenvQuotedValue(process.env.CANONICAL_DOMAIN || "");
const adminUsername = decodeDotenvQuotedValue(process.env.ADMIN_USERNAME);
const adminPassword = decodeDotenvQuotedValue(process.env.ADMIN_PASSWORD);
const adminEmail = requireDotenvValue(process.env.ADMIN_EMAIL, "ADMIN_EMAIL");
const adminHandle = requireDotenvValue(process.env.ADMIN_HANDLE, "ADMIN_HANDLE");
const adminHandleReserved = requireDotenvValue(process.env.ADMIN_HANDLE_RESERVED, "ADMIN_HANDLE_RESERVED");
const pdsBaseUrl = requireDotenvValue(process.env.PDS_BASE_URL, "PDS_BASE_URL");
async function beforeEach({ page }) {
@@ -68,7 +70,9 @@ module.exports = {
canonicalDomain,
adminUsername,
adminPassword,
adminEmail,
adminHandle,
adminHandleReserved,
pdsBaseUrl,
},
skipUnlessServiceEnabled,
@@ -7,14 +7,14 @@ const { expectPdsProxiesAppView } = require("./_appview");
exports.register = function (shared) {
test("native: PDS proxies Following and Notifications to its configured AppView with an lxm-bound service JWT (no oauth2)", async ({ page }) => {
skipUnlessServiceDisabled("sso");
const { adminHandle, adminPassword, pdsBaseUrl } = shared.env;
expect(adminHandle, "ADMIN_HANDLE must be set when oauth2 is disabled").toBeTruthy();
const { adminEmail, adminPassword, pdsBaseUrl } = shared.env;
expect(adminEmail, "ADMIN_EMAIL must be set when oauth2 is disabled").toBeTruthy();
expect(adminPassword, "ADMIN_PASSWORD must be set when oauth2 is disabled").toBeTruthy();
expect(pdsBaseUrl, "PDS_BASE_URL must be set when oauth2 is disabled").toBeTruthy();
const session = await apiFetchOnion(page.request, `${pdsBaseUrl}/xrpc/com.atproto.server.createSession`, {
method: "POST",
data: { identifier: adminHandle, password: adminPassword },
data: { identifier: adminEmail, password: adminPassword },
timeout: resolveTimeout(30_000),
});
expect(session.status(), `PDS createSession must return 200 (got body: ${await session.text()})`).toBe(200);
@@ -7,8 +7,10 @@ exports.register = function (shared) {
process.env.SSO_SERVICE_ENABLED === "true",
"Native login path only exists when oauth2 is disabled — when oauth2 is on, the broker owns provisioning and the OIDC test covers the journey.",
);
const { baseUrl, adminHandle, adminPassword, pdsBaseUrl } = shared.env;
const { baseUrl, adminEmail, adminHandle, adminHandleReserved, adminPassword, pdsBaseUrl } = shared.env;
expect(adminEmail, "ADMIN_EMAIL must be set when oauth2 is disabled").toBeTruthy();
expect(adminHandle, "ADMIN_HANDLE must be set when oauth2 is disabled").toBeTruthy();
expect(adminHandleReserved, "ADMIN_HANDLE_RESERVED must be set when oauth2 is disabled").toBeTruthy();
expect(adminPassword, "ADMIN_PASSWORD must be set when oauth2 is disabled").toBeTruthy();
expect(pdsBaseUrl, "PDS_BASE_URL must be set when oauth2 is disabled").toBeTruthy();
@@ -30,13 +32,16 @@ exports.register = function (shared) {
`${pdsBaseUrl}/xrpc/com.atproto.server.createSession`,
{
headers: { "Content-Type": "application/json" },
data: { identifier: adminHandle, password: adminPassword },
data: { identifier: adminEmail, password: adminPassword },
},
);
const sessionText = await sessionResp.text();
expect(sessionResp.status(), `PDS createSession must return 200 for the deployed administrator (got body: ${sessionText})`).toBe(200);
const sessionJson = JSON.parse(sessionText);
expect(sessionJson.handle, "createSession response must echo the administrator handle").toBe(adminHandle);
expect(
[adminHandle, adminHandleReserved],
"createSession must echo the administrator handle, without prefix or with i8- for a reserved name",
).toContain(sessionJson.handle);
expect(typeof sessionJson.accessJwt, "createSession response must include an accessJwt").toBe("string");
await apiContext.dispose();
});
+2 -2
View File
@@ -12,8 +12,8 @@ credentials:
description: |-
AES-256-GCM symmetric key used by the login-broker to encrypt
the per-user Bluesky app-password held in the broker's
in-memory cache (see files/login-broker/server.js,
`sessionCache`). Format: `base64:<44-char-base64-of-32-random-bytes>`.
account store (see files/login-broker/store.js,
BROKER_STORE_PATH). Format: `base64:<44-char-base64-of-32-random-bytes>`.
The broker strips the `base64:` prefix at startup.
algorithm: base64_prefixed_32
validation: ^base64:[A-Za-z0-9+/]{43}=$
+10
View File
@@ -5,6 +5,16 @@ pds_data:
- service: pds
target: /opt/pds
broker_data:
type: volume
nfs:
uid: "1000"
gid: "1000"
mode: "0700"
mounts:
- service: broker
target: /data
pdsadmin:
type: bind
source: "{{ [lookup('container', 'web-app-bluesky', 'directories.volumes'), 'pdsadmin', 'pdsadmin'] | path_join }}"
@@ -30,6 +30,30 @@
failed_when:
- bluesky_admin_create.status != 200
- "'Handle already taken' not in (bluesky_admin_create.content | default(''))"
- "'Reserved handle' not in (bluesky_admin_create.content | default(''))"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: "📁 Create the native PDS admin account with the i8- prefix (idempotent)"
uri_retry:
url: "{{ BLUESKY_PDS_INTERNAL_URL }}/xrpc/com.atproto.server.createAccount"
method: POST
headers:
Content-Type: application/json
body_format: json
body:
handle: "{{ BLUESKY_ADMIN_HANDLE_RESERVED }}"
email: "{{ BLUESKY_ADMIN_EMAIL }}"
password: "{{ BLUESKY_ADMIN_PASSWORD }}"
status_code: [200, 400]
validate_certs: false
return_content: true
register: bluesky_admin_create_reserved
changed_when:
- bluesky_admin_create_reserved.status == 200
failed_when:
- bluesky_admin_create_reserved.status != 200
- "'Handle already taken' not in (bluesky_admin_create_reserved.content | default(''))"
when: "'Reserved handle' in (bluesky_admin_create.content | default(''))"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: "🔑 Realign the password an existing native PDS administrator kept"
@@ -41,9 +41,11 @@
hostname: {{ service_name }}
{{ lookup('compose_only', 'pull_policy', 'never') }}
{{ lookup('compose_restart') }}
{{ lookup('container_volumes', service_name) | indent(4) }}
{{ lookup('container_ports', [BLUESKY_BROKER_SERVICE, 'http', DOCKER_BIND_HOST]) | indent(4) }}
environment: # nocheck: compose-environment-from-env-file broker has no env_file (only pds includes the container base), and PDS_ADMIN_PASSWORD carries compose $$ escaping that an env_file would not unescape
BROKER_PORT: "{{ BLUESKY_BROKER_INTERNAL_PORT }}"
BROKER_STORE_PATH: "{{ BLUESKY_BROKER_STORE_PATH }}"
SOCIAL_APP_URL: "http://web:{{ BLUESKY_WEB_INTERNAL_PORT }}"
PDS_URL: "{{ lookup('tls', application_id, 'protocols.web') }}://{{ BLUESKY_API_DOMAIN }}"
PDS_INTERNAL_URL: "http://pds:{{ BLUESKY_PDS_INTERNAL_PORT }}"
@@ -11,8 +11,12 @@
# therefore blocked at the generic dashboard → app → logout persona-flow level — the role's OIDC +
# LDAP tests carry the equivalent contract.
ADMIN_EMAIL={{ BLUESKY_ADMIN_EMAIL | dotenv_quote }}
ADMIN_HANDLE={{ BLUESKY_ADMIN_HANDLE | dotenv_quote }}
ADMIN_HANDLE_RESERVED={{ BLUESKY_ADMIN_HANDLE_RESERVED | dotenv_quote }}
ADMIN_PASSWORD={{ lookup('users', 'platform_administrator').password | dotenv_quote }}
ADMIN_USERNAME={{ lookup('users', 'platform_administrator').username | dotenv_quote }}
@@ -52,7 +56,7 @@ OIDC_ISSUER_URL={{ OIDC.CLIENT.ISSUER_URL | dotenv_quote }}
PDS_BASE_URL={{ lookup('network_url', lookup('canonical_url', application_id, 'api')) | dotenv_quote }}
# nocheck: persona-block-rationale — the PDS knows no role beyond "account exists / does not exist" (README "Single Sign-On" records this as the documented RBAC exception), so there is no admin surface for the helper's adminInteraction; the administrator's PDS identity is the derived handle `kc-<username>.<domain>` (vars/main.yml BLUESKY_ADMIN_HANDLE) and is administered through the `pdsadmin` CLI (Administration.md), not a browser panel.
# nocheck: persona-block-rationale — the PDS knows no role beyond "account exists / does not exist" (README "Single Sign-On" records this as the documented RBAC exception), so there is no admin surface for the helper's adminInteraction; the administrator's PDS identity is the derived handle `<username>.<domain>`, or `i8-<username>.<domain>` for a name the PDS reserves (vars/main.yml BLUESKY_ADMIN_HANDLE, BLUESKY_ADMIN_HANDLE_RESERVED), and is administered through the `pdsadmin` CLI (Administration.md), not a browser panel.
PERSONA_ADMINISTRATOR_BLOCKED=true
# nocheck: persona-block-rationale — social-app is a mobile-first SPA whose logout control sits behind a profile menu the shared auth-surface check cannot reach; the role's own login-broker OIDC test and its LDAP counterpart already prove the Keycloak → broker → BSKY_STORAGE.accessJwt handoff (see TODO.md and the file header).
+3 -1
View File
@@ -136,7 +136,8 @@ BLUESKY_ROTATION_KEY: "{{ lookup('config', application_id, 'secrets.credentials.
BLUESKY_ADMIN_EMAIL: "{{ lookup('users', 'platform_administrator').email }}"
BLUESKY_ADMIN_PASSWORD: "{{ lookup('users', 'platform_administrator').password }}"
BLUESKY_ADMIN_HANDLE: "kc-{{ lookup('users', 'platform_administrator').username }}.{{ BLUESKY_PDS_HANDLE_DOMAIN }}"
BLUESKY_ADMIN_HANDLE: "{{ lookup('users', 'platform_administrator').username }}.{{ BLUESKY_PDS_HANDLE_DOMAIN }}"
BLUESKY_ADMIN_HANDLE_RESERVED: "i8-{{ BLUESKY_ADMIN_HANDLE }}"
BLUESKY_PDS_INTERNAL_URL: "http://127.0.0.1:{{ BLUESKY_API_PORT }}"
BLUESKY_FRONT_PROXY_CONTENT: "{{ lookup('template', 'extra_locations.conf.j2') }}"
@@ -153,6 +154,7 @@ BLUESKY_BROKER_IMAGE: "bluesky_broker_custom"
BLUESKY_BROKER_BASE_IMAGE: "{{ lookup('config', application_id, 'services.broker.image') }}"
BLUESKY_BROKER_BASE_VERSION: "{{ lookup('config', application_id, 'services.broker.version') }}"
BLUESKY_BROKER_SERVICE: "broker"
BLUESKY_BROKER_STORE_PATH: "/data/accounts.json"
BLUESKY_BROKER_CONTAINER: "{{ lookup('config', application_id, 'services.' ~ BLUESKY_BROKER_SERVICE ~ '.name') }}"
BLUESKY_BROKER_PORT: "{{ lookup('config', application_id, 'services.broker.ports.local.http') }}"
BLUESKY_BROKER_INTERNAL_PORT: "{{ lookup('config', application_id, 'services.broker.ports.internal.http') }}"
@@ -99,6 +99,17 @@
delegate_to: "{{ STACK_HOST }}"
run_once: true
- name: "🧹 Matomo | Drop the site list cache of every host before re-injecting"
ansible.builtin.set_fact:
matomo_site_cache:
scope: ""
sites:
delegate_to: "{{ matomo_cache_host }}"
delegate_facts: true
loop: "{{ ansible_play_hosts }}"
loop_control:
loop_var: matomo_cache_host
- name: "📄 Matomo | Re-render consumer injections after the final compose flush"
include_tasks: 08_reinject_consumers.yml
when:
+1 -1
View File
@@ -1,4 +1,4 @@
# Stalwart Mail Server
# Stalwart
## Description
@@ -0,0 +1,41 @@
const test = require("node:test");
const assert = require("node:assert/strict");
const path = require("node:path");
const PROJECT_ROOT = path.resolve(__dirname, "../../../../../../..");
const {
PDS_HANDLE_LABEL_MAX,
chosenLabelError,
deriveLabel,
fitsPds,
prefixedLabel,
} = require(path.join(PROJECT_ROOT, "roles/web-app-bluesky/files/login-broker/handle.js"));
test("a username becomes its label without any prefix", () => {
assert.equal(deriveLabel("biber"), "biber");
assert.equal(deriveLabel("Biber.Test"), "biber-test");
assert.equal(deriveLabel(""), "user");
});
test("only a reserved name carries the i8- prefix", () => {
assert.equal(prefixedLabel("administrator"), "i8-administrator");
assert.ok(fitsPds(prefixedLabel("administrator")));
});
test("a label longer than the PDS limit needs a chosen handle", () => {
assert.equal(deriveLabel("kevinveenbirkenbach").length, PDS_HANDLE_LABEL_MAX + 1);
assert.equal(fitsPds(deriveLabel("kevinveenbirkenbach")), false);
assert.equal(fitsPds("a".repeat(PDS_HANDLE_LABEL_MAX)), true);
assert.equal(fitsPds("ab"), false);
});
test("a chosen handle must carry a hyphen and never i8-", () => {
assert.equal(chosenLabelError("kevin-veen"), null);
assert.match(chosenLabelError("kevinveen"), /hyphen/);
assert.match(chosenLabelError("i8-kevin"), /i8-/);
assert.match(chosenLabelError("kevin-i8-veen"), /i8-/);
assert.match(chosenLabelError("-kevin"), /start or end/);
assert.match(chosenLabelError("kevin-"), /start or end/);
assert.match(chosenLabelError("Kevin-Veen"), /lowercase/);
assert.match(chosenLabelError("kevin-veen-birkenbach"), /characters/);
});
@@ -0,0 +1,266 @@
const test = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const http = require("node:http");
const os = require("node:os");
const path = require("node:path");
const { spawn } = require("node:child_process");
const PROJECT_ROOT = path.resolve(__dirname, "../../../../../../..");
const SERVER = path.join(PROJECT_ROOT, "roles/web-app-bluesky/files/login-broker/server.js");
const DOMAIN = "example.test";
const PUBLIC_HOST = "web.bluesky.example.test";
const ADMIN_PASSWORD = "stub-admin-password";
function startPds() {
const accounts = new Map();
const calls = { createAccount: 0, createAccountDelayMs: 0, adminUpdatePassword: [] };
const reserved = new Set(["administrator", "admin"]);
const server = http.createServer((req, res) => {
const chunks = [];
req.on("data", (c) => chunks.push(c));
req.on("end", () => {
const url = new URL(req.url, "http://pds");
const body = chunks.length ? JSON.parse(Buffer.concat(chunks).toString("utf8")) : {};
const send = (status, payload) => {
res.writeHead(status, { "Content-Type": "application/json" });
res.end(JSON.stringify(payload));
};
const fail = (error, message) => send(400, { error, message });
if (url.pathname === "/xrpc/com.atproto.server.createAccount") {
calls.createAccount += 1;
const front = body.handle.slice(0, -(DOMAIN.length + 1));
if (front.length > 18) return fail("InvalidHandle", "Handle too long");
if (reserved.has(front)) return fail("HandleNotAvailable", "Reserved handle");
for (const account of accounts.values()) {
if (account.handle === body.handle) return fail("HandleNotAvailable", "Handle already taken");
if (account.email === body.email) return fail("InvalidRequest", "Email already taken");
}
const did = `did:plc:${front}`;
accounts.set(did, { handle: body.handle, email: body.email, password: body.password });
return setTimeout(() => send(200, { did, handle: body.handle }), calls.createAccountDelayMs);
}
if (url.pathname === "/xrpc/com.atproto.server.createSession") {
for (const [did, account] of accounts) {
const matches = account.handle === body.identifier || account.email === body.identifier;
if (matches && account.password === body.password) {
return send(200, { did, handle: account.handle, accessJwt: "a", refreshJwt: "r" });
}
}
return send(401, { error: "AuthenticationRequired", message: "Invalid identifier or password" });
}
if (url.pathname === "/xrpc/com.atproto.identity.resolveHandle") {
for (const [did, account] of accounts) {
if (account.handle === url.searchParams.get("handle")) return send(200, { did });
}
return fail("InvalidRequest", "Unable to resolve handle");
}
if (url.pathname === "/xrpc/com.atproto.admin.updateAccountPassword") {
const expected = `Basic ${Buffer.from(`admin:${ADMIN_PASSWORD}`).toString("base64")}`;
if (req.headers.authorization !== expected) return send(401, { error: "AuthMissing" });
calls.adminUpdatePassword.push(body.did);
if (accounts.has(body.did)) accounts.get(body.did).password = body.password;
return send(200, {});
}
return send(404, { error: "NotFound" });
});
});
return new Promise((resolve) => {
server.listen(0, "127.0.0.1", () => resolve({ server, accounts, calls, port: server.address().port }));
});
}
function freePort() {
return new Promise((resolve) => {
const probe = http.createServer().listen(0, "127.0.0.1", () => {
const { port } = probe.address();
probe.close(() => resolve(port));
});
});
}
async function startBroker(pdsPort, storePath) {
const port = await freePort();
const child = spawn(process.execPath, [SERVER], {
env: {
PATH: process.env.PATH,
BROKER_PORT: String(port),
SOCIAL_APP_URL: "http://127.0.0.1:9",
PDS_URL: "https://api.bluesky.example.test",
PDS_INTERNAL_URL: `http://127.0.0.1:${pdsPort}`,
PDS_HANDLE_DOMAIN: DOMAIN,
PDS_ADMIN_PASSWORD: ADMIN_PASSWORD,
BLUESKY_BRIDGE_ENCRYPTION_KEY: `base64:${Buffer.alloc(32, 7).toString("base64")}`,
BROKER_STORE_PATH: storePath,
},
stdio: ["ignore", "pipe", "pipe"],
});
await new Promise((resolve, reject) => {
child.stdout.on("data", (chunk) => {
if (chunk.toString().includes("listening")) resolve();
});
child.on("exit", (code) => reject(new Error(`broker exited with ${code}`)));
});
return { child, port };
}
function stopBroker(broker) {
return new Promise((resolve) => {
broker.child.once("exit", resolve);
broker.child.kill();
});
}
function request(broker, { method = "GET", requestPath = "/", user, email, origin, form }) {
const headers = { Host: PUBLIC_HOST };
if (user) headers["X-Forwarded-Preferred-Username"] = user;
if (email) headers["X-Forwarded-Email"] = email;
if (origin) headers.Origin = origin;
const body = form ? new URLSearchParams(form).toString() : null;
if (body) {
headers["Content-Type"] = "application/x-www-form-urlencoded";
headers["Content-Length"] = Buffer.byteLength(body);
}
return new Promise((resolve, reject) => {
const req = http.request({ host: "127.0.0.1", port: broker.port, method, path: requestPath, headers }, (res) => {
const chunks = [];
res.on("data", (c) => chunks.push(c));
res.on("end", () => resolve({ status: res.statusCode, body: Buffer.concat(chunks).toString("utf8") }));
});
req.on("error", reject);
if (body) req.write(body);
req.end();
});
}
const ORIGIN = `https://${PUBLIC_HOST}`;
let pds;
let storePath;
let broker;
test.before(async () => {
pds = await startPds();
storePath = path.join(fs.mkdtempSync(path.join(os.tmpdir(), "broker-server-")), "accounts.json");
broker = await startBroker(pds.port, storePath);
});
test.after(async () => {
await stopBroker(broker);
pds.server.close();
});
test("a short username gets a handle without prefix", async () => {
const res = await request(broker, { user: "biber", email: "biber@example.test" });
assert.equal(res.status, 200);
assert.match(res.body, /BSKY_STORAGE/);
assert.equal(pds.accounts.get("did:plc:biber").handle, `biber.${DOMAIN}`);
});
test("a reserved username falls back to the i8- prefix", async () => {
const res = await request(broker, { user: "administrator", email: "admin@example.test" });
assert.equal(res.status, 200);
assert.equal(pds.accounts.get("did:plc:i8-administrator").handle, `i8-administrator.${DOMAIN}`);
});
test("a username over 18 characters gets the handle form and no account", async () => {
const before = pds.calls.createAccount;
const res = await request(broker, { user: "kevinveenbirkenbach", email: "kevin@example.test" });
assert.equal(res.status, 200);
assert.match(res.body, /Choose your Bluesky handle/);
assert.equal(pds.calls.createAccount, before);
});
test("the handle form refuses a cross-origin or malformed submission", async () => {
const user = { user: "kevinveenbirkenbach", email: "kevin@example.test", method: "POST", requestPath: "/sso/handle" };
const noOrigin = await request(broker, Object.assign({ form: { handle: "kevin-veen" } }, user));
assert.equal(noOrigin.status, 403);
const foreign = await request(broker, Object.assign({ origin: "https://evil.example", form: { handle: "kevin-veen" } }, user));
assert.equal(foreign.status, 403);
const noHyphen = await request(broker, Object.assign({ origin: ORIGIN, form: { handle: "kevinveen" } }, user));
assert.equal(noHyphen.status, 400);
assert.match(noHyphen.body, /hyphen/);
const prefixed = await request(broker, Object.assign({ origin: ORIGIN, form: { handle: "i8-kevin" } }, user));
assert.equal(prefixed.status, 400);
});
test("an origin with a port still matches the proxied host", async () => {
const res = await request(broker, {
user: "kevinveenbirkenbach",
email: "kevin@example.test",
method: "POST",
requestPath: "/sso/handle",
origin: `${ORIGIN}:8443`,
form: { handle: "kevin-veen" },
});
assert.equal(res.status, 200);
assert.match(res.body, /BSKY_STORAGE/);
assert.equal(pds.accounts.get("did:plc:kevin-veen").handle, `kevin-veen.${DOMAIN}`);
});
test("a chosen handle another user holds is offered again, not taken over", async () => {
const res = await request(broker, {
user: "anotherverylongusername",
email: "other@example.test",
method: "POST",
requestPath: "/sso/handle",
origin: ORIGIN,
form: { handle: "kevin-veen" },
});
assert.equal(res.status, 409);
assert.match(res.body, /already taken/);
assert.equal(pds.calls.adminUpdatePassword.includes("did:plc:kevin-veen"), false);
});
test("a derived handle whose name another user chose is never taken over", async () => {
const res = await request(broker, { user: "kevin.veen", email: "kv@example.test" });
assert.equal(res.status, 500);
assert.equal(pds.calls.adminUpdatePassword.includes("did:plc:kevin-veen"), false);
});
test("an e-mail address a legacy kc- account holds is reported, not retried", async () => {
pds.accounts.set("did:plc:legacy", { handle: `kc-legacy.${DOMAIN}`, email: "legacy@example.test", password: "x" });
const res = await request(broker, { user: "legacy", email: "legacy@example.test" });
assert.equal(res.status, 409);
assert.match(res.body, /legacy kc- account/);
});
test("concurrent first visits create one account", async () => {
const before = pds.calls.createAccount;
pds.calls.createAccountDelayMs = 200;
const visits = await Promise.all([
request(broker, { user: "mapache", email: "mapache@example.test" }),
request(broker, { user: "mapache", email: "mapache@example.test" }),
]);
pds.calls.createAccountDelayMs = 0;
assert.deepEqual(visits.map((v) => v.status), [200, 200]);
assert.equal(pds.calls.createAccount, before + 1);
});
test("a broker restart keeps every account", async () => {
await stopBroker(broker);
broker = await startBroker(pds.port, storePath);
const before = pds.calls.createAccount;
for (const [user, email] of [["biber", "biber@example.test"], ["kevinveenbirkenbach", "kevin@example.test"]]) {
const res = await request(broker, { user, email });
assert.equal(res.status, 200);
assert.match(res.body, /BSKY_STORAGE/);
}
assert.equal(pds.calls.createAccount, before);
});
test("an account the PDS lost is provisioned again", async () => {
pds.accounts.delete("did:plc:biber");
const res = await request(broker, { user: "biber", email: "biber@example.test" });
assert.equal(res.status, 200);
assert.match(res.body, /BSKY_STORAGE/);
assert.ok(pds.accounts.has("did:plc:biber"));
});
test("a password the PDS no longer accepts is reset in place", async () => {
pds.accounts.get("did:plc:i8-administrator").password = "changed-elsewhere";
const before = pds.calls.createAccount;
const res = await request(broker, { user: "administrator", email: "admin@example.test" });
assert.equal(res.status, 200);
assert.equal(pds.calls.createAccount, before);
assert.ok(pds.calls.adminUpdatePassword.includes("did:plc:i8-administrator"));
});
@@ -0,0 +1,55 @@
const test = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const os = require("node:os");
const path = require("node:path");
const PROJECT_ROOT = path.resolve(__dirname, "../../../../../../..");
const { openStore } = require(
path.join(PROJECT_ROOT, "roles/web-app-bluesky/files/login-broker/store.js"),
);
function tempFile() {
return path.join(fs.mkdtempSync(path.join(os.tmpdir(), "broker-store-")), "accounts.json");
}
test("an entry survives a reopen, as after a broker restart", () => {
const file = tempFile();
openStore(file).set("biber", { handle: "biber.example", did: "did:plc:b", appPasswordEnc: "x" });
const reopened = openStore(file);
assert.deepEqual(reopened.get("biber"), {
handle: "biber.example",
did: "did:plc:b",
appPasswordEnc: "x",
});
assert.equal(reopened.get("mapache"), null);
});
test("ownerOf names the username that holds a handle", () => {
const store = openStore(tempFile());
store.set("kevinveenbirkenbach", { handle: "kevin-veen.example", did: "did:plc:k", appPasswordEnc: "y" });
assert.equal(store.ownerOf("kevin-veen.example"), "kevinveenbirkenbach");
assert.equal(store.ownerOf("other.example"), null);
});
test("a deleted entry stays gone after a reopen", () => {
const file = tempFile();
const store = openStore(file);
store.set("biber", { handle: "biber.example", did: "did:plc:b", appPasswordEnc: "x" });
store.delete("biber");
assert.equal(openStore(file).get("biber"), null);
assert.equal(openStore(file).ownerOf("biber.example"), null);
});
test("the file is written owner-only", () => {
const file = tempFile();
openStore(file).set("biber", { handle: "biber.example", did: "did:plc:b", appPasswordEnc: "x" });
assert.equal(fs.statSync(file).mode & 0o777, 0o600);
});
test("a username named like an object key stays a plain entry", () => {
const file = tempFile();
openStore(file).set("__proto__", { handle: "p.example", did: "did:plc:p", appPasswordEnc: "z" });
assert.equal(openStore(file).get("__proto__").handle, "p.example");
assert.equal({}.handle, undefined);
});
@@ -0,0 +1,3 @@
from pathlib import Path
PROJECT_ROOT: Path = Path(__file__).resolve().parents[5]
@@ -0,0 +1,84 @@
import unittest
from jinja2 import Environment
from utils.cache.yaml import load_yaml_any
from . import PROJECT_ROOT
RESOLVE_SITE = (
PROJECT_ROOT / "roles" / "sys-front-inj-matomo" / "tasks" / "resolve_site.yml"
)
INSTALL_PATH = (
PROJECT_ROOT / "roles" / "web-app-matomo" / "tasks" / "03_install_path.yml"
)
SCOPE = "abc"
SITES = [{"idsite": "3", "main_url": "https://a.example"}]
def _tasks(path):
return load_yaml_any(str(path)) or []
def _guard(task):
when = task["when"]
return when if isinstance(when, list) else [when]
def _eval(expressions, context) -> bool:
env = Environment(autoescape=True)
return all(bool(env.compile_expression(expr)(**context)) for expr in expressions)
def _task(tasks, predicate):
return next(task for task in tasks if predicate(task))
class TestNegativeSiteCache(unittest.TestCase):
def setUp(self):
tasks = _tasks(RESOLVE_SITE)
self.load = _task(tasks, lambda t: t.get("register") == "matomo_site_list")
self.site_check = _task(tasks, lambda t: t.get("register") == "site_check")
self.cached_id = _task(
tasks,
lambda t: "matomo_cached_site_ids" in str(t.get("vars", {})),
)
def _state(self, sites, scope=SCOPE):
return {
"matomo_site_cache": {"scope": scope, "sites": sites},
"matomo_site_cache_scope": SCOPE,
"matomo_site_id": "",
"matomo_effective_token": "token",
}
def test_a_cached_absence_skips_both_api_calls(self):
state = self._state(None)
self.assertFalse(_eval(_guard(self.load), state))
self.assertFalse(_eval(_guard(self.site_check), state))
self.assertFalse(_eval(_guard(self.cached_id), state))
def test_a_cached_list_still_asks_for_an_unknown_site(self):
self.assertTrue(_eval(_guard(self.site_check), self._state(SITES)))
def test_a_cache_of_another_scope_reloads_the_list(self):
self.assertTrue(_eval(_guard(self.load), self._state(None, scope="")))
class TestMatomoDropsTheCacheBeforeReinjecting(unittest.TestCase):
def test_the_reset_precedes_the_consumer_reinjection(self):
tasks = _tasks(INSTALL_PATH)
names = [str(t.get("include_tasks", "")) for t in tasks]
reinject = names.index("08_reinject_consumers.yml")
reset = _task(
tasks[:reinject],
lambda t: "matomo_site_cache" in t.get("ansible.builtin.set_fact", {}),
)
self.assertEqual(
reset["ansible.builtin.set_fact"]["matomo_site_cache"]["scope"], ""
)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,42 @@
import unittest
from jinja2 import Environment
from utils.cache.yaml import load_yaml_any
from utils.roles.mapping import ROLE_FILE_VARS_MAIN
from . import PROJECT_ROOT
ROLE = PROJECT_ROOT / "roles" / "web-app-keycloak"
VARS = ROLE / ROLE_FILE_VARS_MAIN
ROUTINES = ROLE / "tasks" / "03_manager_ops" / "update_routines.yml"
REALM = {
"clients": [
{"clientId": "account", "protocol": "openid-connect"},
{"clientId": "cymais.cloud", "protocol": "openid-connect"},
{"clientId": "https://crm.example/saml/metadata", "protocol": "saml"},
]
}
class TestSamlClientsReachExistingRealms(unittest.TestCase):
def test_only_saml_clients_of_the_realm_dictionary_are_selected(self):
template = load_yaml_any(str(VARS))["KEYCLOAK_SAML_CLIENT_IDS"]
expression = template.strip().removeprefix("{{").removesuffix("}}")
selected = Environment(autoescape=True).compile_expression(expression)(
KEYCLOAK_DICTIONARY_REALM=REALM
)
self.assertEqual(selected, ["https://crm.example/saml/metadata"])
def test_the_existing_realm_reconcile_loops_over_saml_clients(self):
task = next(
t
for t in load_yaml_any(str(ROUTINES))
if "10_declared_client.yml" in str(t.get("include_tasks", ""))
)
self.assertIn("KEYCLOAK_SAML_CLIENT_IDS", task["loop"])
if __name__ == "__main__":
unittest.main()