Parcourir la source

release-test-1

xcad il y a 3 mois
Parent
commit
7bf03312f1
70 fichiers modifiés avec 864 ajouts et 2516 suppressions
  1. 1 0
      CHANGELOG.md
  2. 9 2
      cli/core/display/display_icons.py
  3. 93 6
      cli/core/display/display_status.py
  4. 5 3
      cli/core/schema/compose/v1.2.json
  5. 2 1
      cli/core/template/variable_collection.py
  6. 25 13
      library/compose/adguardhome/compose.yaml.j2
  7. 3 0
      library/compose/alloy/template.yaml
  8. 1 2
      library/compose/bind9/template.yaml
  9. 5 1
      library/compose/checkmk/compose.yaml.j2
  10. 8 1
      library/compose/checkmk/template.yaml
  11. 1 1
      library/compose/dockge/template.yaml
  12. 42 35
      library/compose/gitea/compose.yaml.j2
  13. 11 9
      library/compose/gitea/template.yaml
  14. 1 1
      library/compose/gitlab-runner/template.yaml
  15. 2 2
      library/compose/gitlab/.env.j2
  16. 0 0
      library/compose/gitlab/.env.password.j2
  17. 0 0
      library/compose/gitlab/.env.registry.j2
  18. 65 131
      library/compose/gitlab/compose.yaml.j2
  19. 3 16
      library/compose/gitlab/template.yaml
  20. 41 5
      library/compose/grafana/compose.yaml.j2
  21. 16 22
      library/compose/grafana/template.yaml
  22. 10 26
      library/compose/homepage/template.yaml
  23. 1 0
      library/compose/influxdb/template.yaml
  24. 2 1
      library/compose/mariadb/template.yaml
  25. 2 2
      library/compose/n8n/template.yaml
  26. 7 5
      library/compose/netbox/template.yaml
  27. 1 0
      library/compose/nginx/template.yaml
  28. 2 1
      library/compose/openwebui/template.yaml
  29. 0 137
      library/compose/pangolin/compose.yaml.j2.final
  30. 0 113
      library/compose/pangolin/template.yaml.backup
  31. 25 20
      library/compose/passbolt/compose.yaml.j2
  32. 12 116
      library/compose/passbolt/template.yaml
  33. 0 38
      library/compose/pihole/common/networks.yaml.j2
  34. 0 3
      library/compose/pihole/common/secrets.yaml.j2
  35. 0 21
      library/compose/pihole/common/volumes.yaml.j2
  36. 262 8
      library/compose/pihole/compose.yaml.j2
  37. 0 266
      library/compose/pihole/compose.yaml.j2.backup
  38. 0 133
      library/compose/pihole/services/pihole.yaml.j2
  39. 15 30
      library/compose/pihole/template.yaml
  40. 42 98
      library/compose/portainer/compose.yaml.j2
  41. 0 124
      library/compose/portainer/compose.yaml.j2.final
  42. 0 118
      library/compose/portainer/compose.yaml.j2.portfix
  43. 11 17
      library/compose/portainer/template.yaml
  44. 2 2
      library/compose/postgres/template.yaml
  45. 2 23
      library/compose/renovate/template.yaml
  46. 2 15
      library/compose/semaphoreui/.env.j2
  47. 48 147
      library/compose/semaphoreui/compose.yaml.j2
  48. 0 264
      library/compose/semaphoreui/compose.yaml.j2.bak3
  49. 0 222
      library/compose/semaphoreui/compose.yaml.j2.final
  50. 0 204
      library/compose/semaphoreui/compose.yaml.j2.portfix
  51. 60 88
      library/compose/semaphoreui/template.yaml
  52. 1 1
      library/compose/traefik/compose.yaml.j2
  53. 2 3
      library/compose/traefik/template.yaml
  54. 2 1
      library/compose/twingate-connector/template.yaml
  55. 2 1
      library/compose/uptimekuma/template.yaml
  56. 1 1
      library/compose/whoami/template.yaml
  57. 2 2
      library/helm/certmanager/template.yaml
  58. 1 1
      library/kubernetes/certmanager-certificate/template.yaml
  59. 1 1
      library/kubernetes/certmanager-clusterissuer/template.yaml
  60. 1 1
      library/kubernetes/certmanager-issuer/template.yaml
  61. 1 1
      library/kubernetes/traefik-ingressroute/template.yaml
  62. 1 1
      library/kubernetes/traefik-ingressroutetcp/template.yaml
  63. 2 2
      library/kubernetes/traefik-middleware/template.yaml
  64. 1 1
      library/terraform/netbox-cluster-type/template.yaml
  65. 1 1
      library/terraform/netbox-cluster/template.yaml
  66. 1 1
      library/terraform/netbox-device-role/template.yaml
  67. 1 1
      library/terraform/netbox-device-type/template.yaml
  68. 1 1
      library/terraform/netbox-device/template.yaml
  69. 1 1
      library/terraform/netbox-manufacturer/template.yaml
  70. 1 1
      library/terraform/netbox-vm/template.yaml

+ 1 - 0
CHANGELOG.md

@@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Markdown formatting support for template descriptions and next steps (#1471)
 - Markdown formatting support for template descriptions and next steps (#1471)
 - Output directory flag `--output`/`-o` for `generate` command (#1534) - Replaces positional directory argument
 - Output directory flag `--output`/`-o` for `generate` command (#1534) - Replaces positional directory argument
 - Variable property `autogenerated_length` to specify custom length for auto-generated values (default: 32 characters)
 - Variable property `autogenerated_length` to specify custom length for auto-generated values (default: 32 characters)
+- Nerd Font icon support with shortcode replacement in template descriptions - Rich visual feedback using standardized icon system
 
 
 ### Changed
 ### Changed
 - Schema is now managed in JSON for better standardization and clarity (#1555)
 - Schema is now managed in JSON for better standardization and clarity (#1555)

+ 9 - 2
cli/core/display/display_icons.py

@@ -49,10 +49,17 @@ class IconManager:
 
 
     # Shortcode Mappings (emoji-style codes to Nerd Font icons)
     # Shortcode Mappings (emoji-style codes to Nerd Font icons)
     # Format: ":code:" -> "\uf000"
     # Format: ":code:" -> "\uf000"
+    #
+    # Usage:
+    # 1. In regular text: ":mycode: Some text" - icon replaces shortcode inline
+    # 2. In markdown lists: "- :mycode: List item" - icon replaces bullet with color
+    #
     # To add new shortcodes:
     # To add new shortcodes:
     # 1. Add entry to this dict: ":mycode:": "\uf000"
     # 1. Add entry to this dict: ":mycode:": "\uf000"
-    # 2. Use in template descriptions: ":mycode: Some text"
-    # 3. Shortcode will be automatically replaced when markdown is rendered
+    # 2. Use in template descriptions or markdown content
+    # 3. Shortcodes are automatically replaced when markdown is rendered
+    # 4. List items starting with shortcodes get colored icons instead of bullets
+    #
     # Find Nerd Font codes at: https://www.nerdfonts.com/cheat-sheet
     # Find Nerd Font codes at: https://www.nerdfonts.com/cheat-sheet
     SHORTCODES: ClassVar[dict[str, str]] = {
     SHORTCODES: ClassVar[dict[str, str]] = {
         ":warning:": "\uf071",  #  (exclamation-triangle)
         ":warning:": "\uf071",  #  (exclamation-triangle)

+ 93 - 6
cli/core/display/display_status.py

@@ -1,12 +1,16 @@
 from __future__ import annotations
 from __future__ import annotations
 
 
 import logging
 import logging
+import re
 from typing import TYPE_CHECKING
 from typing import TYPE_CHECKING
 
 
 from rich import box
 from rich import box
+from rich._loop import loop_first
 from rich.console import Console, ConsoleOptions, RenderResult
 from rich.console import Console, ConsoleOptions, RenderResult
-from rich.markdown import Heading, Markdown
+from rich.markdown import Heading, ListItem, Markdown
 from rich.panel import Panel
 from rich.panel import Panel
+from rich.segment import Segment
+from rich.text import Text
 
 
 from .display_icons import IconManager
 from .display_icons import IconManager
 from .display_settings import DisplaySettings
 from .display_settings import DisplaySettings
@@ -36,16 +40,85 @@ class LeftAlignedHeading(Heading):
             yield text
             yield text
 
 
 
 
+class IconListItem(ListItem):
+    """Custom list item that replaces bullets with colored icons from shortcodes."""
+
+    def render_bullet(self, console: Console, options: ConsoleOptions) -> RenderResult:
+        """Render list item with icon replacement if text starts with :shortcode:."""
+        # Get the text content from elements
+        text_content = ""
+        for element in self.elements:
+            if hasattr(element, "text"):
+                text_content = element.text.plain
+                break
+
+        icon_used = None
+        icon_color = "cyan"  # Default color for icons
+        shortcode_found = None
+
+        # Scan for shortcode at the beginning
+        for shortcode, icon in IconManager.SHORTCODES.items():
+            if text_content.strip().startswith(shortcode):
+                icon_used = icon
+                shortcode_found = shortcode
+
+                # Map shortcodes to colors
+                shortcode_colors = {
+                    ":warning:": "yellow",
+                    ":error:": "red",
+                    ":check:": "green",
+                    ":success:": "green",
+                    ":info:": "blue",
+                    ":docker:": "blue",
+                    ":kubernetes:": "blue",
+                    ":rocket:": "magenta",
+                    ":star:": "yellow",
+                    ":lightning:": "yellow",
+                }
+                icon_color = shortcode_colors.get(shortcode, "cyan")
+                break
+
+        if icon_used and shortcode_found:
+            # Remove the shortcode from the text in all elements
+            for element in self.elements:
+                if hasattr(element, "text"):
+                    # Replace the shortcode in the Text object
+                    plain_text = element.text.plain
+                    new_text = plain_text.replace(shortcode_found, "", 1).lstrip()
+                    # Reconstruct the Text object with the same style
+                    element.text = Text(new_text, style=element.text.style)
+
+            # Render with custom colored icon instead of bullet
+            render_options = options.update(width=options.max_width - 3)
+            lines = console.render_lines(self.elements, render_options, style=self.style)
+            bullet_style = console.get_style(icon_color, default="none")
+
+            bullet = Segment(f" {icon_used} ", bullet_style)
+            padding = Segment(" " * 3)
+            new_line = Segment("\n")
+
+            for first, line in loop_first(lines):
+                yield bullet if first else padding
+                yield from line
+                yield new_line
+        else:
+            # No icon found, use default list item rendering
+            yield from super().render_bullet(console, options)
+
+
 class LeftAlignedMarkdown(Markdown):
 class LeftAlignedMarkdown(Markdown):
-    """Custom Markdown renderer with left-aligned headings."""
+    """Custom Markdown renderer with left-aligned headings and icon list items."""
 
 
     def __init__(self, markup: str, **kwargs):
     def __init__(self, markup: str, **kwargs):
-        """Initialize with custom heading element."""
+        """Initialize with custom heading and list item elements."""
         super().__init__(markup, **kwargs)
         super().__init__(markup, **kwargs)
 
 
         # Replace heading element to use left alignment
         # Replace heading element to use left alignment
         self.elements["heading_open"] = LeftAlignedHeading
         self.elements["heading_open"] = LeftAlignedHeading
 
 
+        # Replace list item element to use icon replacement
+        self.elements["list_item_open"] = IconListItem
+
 
 
 class StatusDisplay:
 class StatusDisplay:
     """Status messages and error display.
     """Status messages and error display.
@@ -205,12 +278,26 @@ class StatusDisplay:
         """Render markdown content with left-aligned headings.
         """Render markdown content with left-aligned headings.
 
 
         Replaces emoji-style shortcodes (e.g., :warning:, :info:) with Nerd Font icons
         Replaces emoji-style shortcodes (e.g., :warning:, :info:) with Nerd Font icons
-        before rendering.
+        before rendering, EXCEPT for shortcodes at the start of list items which are
+        handled by IconListItem to replace the bullet.
 
 
         Args:
         Args:
             content: Markdown-formatted text to render (may contain shortcodes)
             content: Markdown-formatted text to render (may contain shortcodes)
         """
         """
         if not self.quiet:
         if not self.quiet:
-            # Replace shortcodes with Nerd Font icons before rendering
-            processed_content = IconManager.replace_shortcodes(content)
+            # Replace shortcodes with Nerd Font icons, but preserve list item shortcodes
+            # Pattern: "- :shortcode:" at start of line should NOT be replaced
+            lines = content.split("\n")
+            processed_lines = []
+
+            for line in lines:
+                # Check if line is a list item starting with a shortcode
+                if re.match(r"^\s*-\s+:[a-z]+:", line):
+                    # Keep the line as-is, IconListItem will handle it
+                    processed_lines.append(line)
+                else:
+                    # Replace shortcodes normally
+                    processed_lines.append(IconManager.replace_shortcodes(line))
+
+            processed_content = "\n".join(processed_lines)
             self.base._print_markdown(LeftAlignedMarkdown(processed_content))
             self.base._print_markdown(LeftAlignedMarkdown(processed_content))

+ 5 - 3
cli/core/schema/compose/v1.2.json

@@ -390,33 +390,35 @@
         "name": "database_host",
         "name": "database_host",
         "description": "Database host",
         "description": "Database host",
         "type": "str",
         "type": "str",
-        "needs": ["database_external=true"],
-        "default": "database",
+        "needs": ["database_external=true;database_type=postgres,mysql"],
         "required": true
         "required": true
       },
       },
       {
       {
         "name": "database_port",
         "name": "database_port",
         "description": "Database port",
         "description": "Database port",
         "type": "int",
         "type": "int",
+        "needs": ["database_external=true;database_type=postgres,mysql"],
         "required": true
         "required": true
       },
       },
       {
       {
         "name": "database_name",
         "name": "database_name",
         "description": "Database name",
         "description": "Database name",
         "type": "str",
         "type": "str",
+        "needs": ["database_type=postgres,mysql"],
         "required": true
         "required": true
       },
       },
       {
       {
         "name": "database_user",
         "name": "database_user",
         "description": "Database user",
         "description": "Database user",
         "type": "str",
         "type": "str",
+        "needs": ["database_type=postgres,mysql"],
         "required": true
         "required": true
       },
       },
       {
       {
         "name": "database_password",
         "name": "database_password",
         "description": "Database password",
         "description": "Database password",
         "type": "str",
         "type": "str",
-        "default": "",
+        "needs": ["database_type=postgres,mysql"],
         "sensitive": true,
         "sensitive": true,
         "autogenerated": true,
         "autogenerated": true,
         "required": true
         "required": true

+ 2 - 1
cli/core/template/variable_collection.py

@@ -813,7 +813,8 @@ class VariableCollection:
                 logger.error(error_msg)
                 logger.error(error_msg)
 
 
         if errors:
         if errors:
-            logger.warning(f"Some defaults failed to apply: {'; '.join(errors)}")
+            # Raise exception to halt execution on validation errors
+            raise ValueError(f"Variable validation failed: {'; '.join(errors)}")
 
 
         return successful
         return successful
 
 

+ 25 - 13
library/compose/adguardhome/compose.yaml.j2

@@ -17,6 +17,13 @@ services:
       {{ network_name }}:
       {{ network_name }}:
       {% endif %}
       {% endif %}
     {% endif %}
     {% endif %}
+    {#
+      Port mappings (only in bridge mode or default network):
+      - HTTP/HTTPS (80/443) ports are only exposed when Traefik is disabled
+      - Initial setup port 3000 is exposed during first-time setup
+      - DNS and related ports (53, 853, 5443) are always exposed
+      - In host or macvlan mode, ports are bound directly to host network
+    #}
     {% if network_mode == '' or network_mode == 'bridge' or traefik_enabled %}
     {% if network_mode == '' or network_mode == 'bridge' or traefik_enabled %}
     ports:
     ports:
       {% if not traefik_enabled %}
       {% if not traefik_enabled %}
@@ -32,7 +39,6 @@ services:
       - "{{ ports_tls }}:853/tcp"
       - "{{ ports_tls }}:853/tcp"
       - "{{ ports_dnscrypt }}:5443/tcp"
       - "{{ ports_dnscrypt }}:5443/tcp"
       - "{{ ports_dnscrypt }}:5443/udp"
       - "{{ ports_dnscrypt }}:5443/udp"
-      {% endif %}
     {% endif %}
     {% endif %}
     volumes:
     volumes:
       {% if volume_mode == 'mount' %}
       {% if volume_mode == 'mount' %}
@@ -61,6 +67,11 @@ services:
       - traefik.http.routers.{{ service_name }}_https.tls=true
       - traefik.http.routers.{{ service_name }}_https.tls=true
       - traefik.http.routers.{{ service_name }}_https.tls.certresolver={{ traefik_tls_certresolver }}
       - traefik.http.routers.{{ service_name }}_https.tls.certresolver={{ traefik_tls_certresolver }}
       {% endif %}
       {% endif %}
+      {#
+        Initial setup routing (port 3000):
+        Routes setup wizard through separate Traefik service.
+        Note: Setup wizard is available at http://<host>.<domain>/setup during initial configuration.
+      #}
       {% if initial_setup %}
       {% if initial_setup %}
       - traefik.http.services.{{ service_name }}_setup.loadBalancer.server.port=3000
       - traefik.http.services.{{ service_name }}_setup.loadBalancer.server.port=3000
       - traefik.http.routers.{{ service_name }}_setup.service={{ service_name }}_setup
       - traefik.http.routers.{{ service_name }}_setup.service={{ service_name }}_setup
@@ -71,16 +82,17 @@ services:
       {% endif %}
       {% endif %}
     {% endif %}
     {% endif %}
 
 
+{% if network_mode == 'bridge' or network_mode == 'macvlan' or traefik_enabled %}
 {#
 {#
-  Network definitions (only when needed):
-  - When network_mode is empty: no definition needed (uses Docker's default bridge)
-  - When network_mode is 'bridge': define custom bridge network
-  - When network_mode is 'macvlan': configure macvlan with static IP (for Compose mode)
-    Note: In Swarm mode, macvlan networks must be created manually with config-only networks on each node
-  - When swarm_enabled: use overlay network for multi-host communication
-  - Traefik network: always external (managed by Traefik)
+  Network definitions:
+  - 'bridge' mode: creates custom bridge network
+  - 'macvlan' mode: creates macvlan network with static IP assignment
+    (requires manual network creation in Swarm mode)
+  - Swarm overlay: used when swarm_enabled=true with bridge mode
+  - Traefik network: always external (managed separately by Traefik stack)
+  - Default mode (network_mode=''): uses Docker's default bridge (no definition needed)
+  - Host mode: no network definition (container uses host network stack directly)
 #}
 #}
-{% if network_mode == 'bridge' or network_mode == 'macvlan' or traefik_enabled %}
 networks:
 networks:
   {% if network_mode == 'bridge' or network_mode == 'macvlan'%}
   {% if network_mode == 'bridge' or network_mode == 'macvlan'%}
   {{ network_name }}:
   {{ network_name }}:
@@ -110,13 +122,13 @@ networks:
   {% endif %}
   {% endif %}
 {% endif %}
 {% endif %}
 
 
+{% if volume_mode == 'local' %}
 {#
 {#
   Volume definitions:
   Volume definitions:
-  - When volume_mode is 'local' (default): use docker-managed local volumes
-  - When volume_mode is 'nfs': configure NFS-backed volumes
-  - When volume_mode is 'mount': no volume definition needed (bind mounts used directly)
+  - 'local' mode: Docker-managed local volumes
+  - 'nfs' mode: NFS-backed volumes for shared storage
+  - 'mount' mode: bind mounts (no volume definition needed)
 #}
 #}
-{% if volume_mode == 'local' %}
 volumes:
 volumes:
   {{ service_name }}_work:
   {{ service_name }}_work:
     driver: local
     driver: local

+ 3 - 0
library/compose/alloy/template.yaml

@@ -4,6 +4,9 @@ metadata:
   name: Grafana Alloy
   name: Grafana Alloy
   description: |-
   description: |-
     Grafana Alloy is an open telemetry collector that collects, processes, and exports metrics to various backends.
     Grafana Alloy is an open telemetry collector that collects, processes, and exports metrics to various backends.
+    ## Prerequisites
+    - :warning: When alloy runs in a container, you should set the `container_hostname` to a unique value to identify
+    the instance in your monitoring backend. Otherwise it defaults to the container ID.
     ## Resources
     ## Resources
     - **Project**: https://grafana.com/oss/alloy/
     - **Project**: https://grafana.com/oss/alloy/
     - **Documentation**: https://grafana.com/docs/alloy/latest/
     - **Documentation**: https://grafana.com/docs/alloy/latest/

+ 1 - 2
library/compose/bind9/template.yaml

@@ -18,8 +18,7 @@ metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
     id: bind-9
     id: bind-9
-  draft: false
-  next_steps: ""
+  draft: true
 schema: "1.2"
 schema: "1.2"
 spec:
 spec:
   dns_security:
   dns_security:

+ 5 - 1
library/compose/checkmk/compose.yaml.j2

@@ -1,16 +1,20 @@
 ---
 ---
 services:
 services:
   {{ service_name }}:
   {{ service_name }}:
-    image: checkmk/check-mk-raw:2.4.0-p1
+    image: checkmk/check-mk-raw:2.4.0p17
     restart: {{ restart_policy }}
     restart: {{ restart_policy }}
     environment:
     environment:
+      {% if container_timezone %}
       - TZ={{ container_timezone }}
       - TZ={{ container_timezone }}
+      {% endif %}
       - CMK_PASSWORD=${CMK_PASSWORD}
       - CMK_PASSWORD=${CMK_PASSWORD}
       - CMK_SITE_ID={{ cmk_site_id }}
       - CMK_SITE_ID={{ cmk_site_id }}
     tmpfs:
     tmpfs:
       - /opt/omd/sites/{{ cmk_site_id }}/tmp:uid={{ user_uid }},gid={{ user_gid }}
       - /opt/omd/sites/{{ cmk_site_id }}/tmp:uid={{ user_uid }},gid={{ user_gid }}
     volumes:
     volumes:
+      {% if not container_timezone %}
       - /etc/localtime:/etc/localtime:ro
       - /etc/localtime:/etc/localtime:ro
+      {% endif %}
       - {{ service_name }}_data:/omd/sites:rw
       - {{ service_name }}_data:/omd/sites:rw
     {% if traefik_enabled %}
     {% if traefik_enabled %}
     networks:
     networks:

+ 8 - 1
library/compose/checkmk/template.yaml

@@ -14,12 +14,18 @@ metadata:
     * **Project:** https://checkmk.com/
     * **Project:** https://checkmk.com/
     * **Documentation:** https://docs.checkmk.com/latest/en/
     * **Documentation:** https://docs.checkmk.com/latest/en/
     * **GitHub:** https://github.com/tribe29/checkmk
     * **GitHub:** https://github.com/tribe29/checkmk
+  next_steps: |-
+    Log in with your initial admin user:
+    ```bash
+    Username: cmkadmin
+    Password: {{ cmk_password }}
+    ```
   version: 2.4.0-latest
   version: 2.4.0-latest
   author: Christian Lempa
   author: Christian Lempa
   date: '2025-09-28'
   date: '2025-09-28'
   tags:
   tags:
     - traefik
     - traefik
-schema: "1.2"
+schema: 1.2
 spec:
 spec:
   general:
   general:
     vars:
     vars:
@@ -48,3 +54,4 @@ spec:
         description: Agent port
         description: Agent port
         type: int
         type: int
         default: 5000
         default: 5000
+        required: true

+ 1 - 1
library/compose/dockge/template.yaml

@@ -17,7 +17,7 @@ metadata:
   date: '2025-09-28'
   date: '2025-09-28'
   tags:
   tags:
     - traefik
     - traefik
-schema: "1.2"
+schema: 1.2
 spec:
 spec:
   general:
   general:
     vars:
     vars:

+ 42 - 35
library/compose/gitea/compose.yaml.j2

@@ -3,30 +3,35 @@ services:
     image: docker.io/gitea/gitea:1.25.1
     image: docker.io/gitea/gitea:1.25.1
     restart: {{ restart_policy }}
     restart: {{ restart_policy }}
     environment:
     environment:
-      - TZ={{ container_timezone }}
       - USER_UID={{ user_uid }}
       - USER_UID={{ user_uid }}
       - USER_GID={{ user_gid }}
       - USER_GID={{ user_gid }}
-      - GITEA__database__DB_TYPE=postgres
-      - GITEA__database__HOST={{ service_name }}-postgres:5432
+      {% if database_type != 'sqlite' %}
+      - GITEA__database__DB_TYPE={{ database_type }}
+      {% if database_external %}
+      - GITEA__database__HOST={{ database_host }}
+      {% else %}
+      - GITEA__database__HOST={{ service_name }}_db
+      {% endif %}
       - GITEA__database__NAME={{ database_name }}
       - GITEA__database__NAME={{ database_name }}
       - GITEA__database__USER={{ database_user }}
       - GITEA__database__USER={{ database_user }}
       - GITEA__database__PASSWD=${DATABASE_PASSWORD}
       - GITEA__database__PASSWD=${DATABASE_PASSWORD}
+      {% endif %}
       - GITEA__server__SSH_PORT={{ ports_ssh }}
       - GITEA__server__SSH_PORT={{ ports_ssh }}
       {% if not traefik_enabled %}
       {% if not traefik_enabled %}
       - GITEA__server__ROOT_URL={{ gitea_url }}
       - GITEA__server__ROOT_URL={{ gitea_url }}
       {% else %}
       {% else %}
       - GITEA__server__ROOT_URL=https://{{ traefik_host }}.{{ traefik_domain }}
       - GITEA__server__ROOT_URL=https://{{ traefik_host }}.{{ traefik_domain }}
       {% endif %}
       {% endif %}
-    {% if not database_external or traefik_enabled %}
+    {% if not database_external and (database_type == "postgres" or database_type == "mysql") or traefik_enabled %}
     networks:
     networks:
-    {% if not database_external %}
+    {% if not database_external and database_type != 'sqlite' %}
       - {{ service_name }}_backend
       - {{ service_name }}_backend
     {% endif %}
     {% endif %}
     {% if traefik_enabled %}
     {% if traefik_enabled %}
       - {{ traefik_network }}
       - {{ traefik_network }}
     {% endif %}
     {% endif %}
     {% endif %}
     {% endif %}
-    ports:
+    ports:  
       {% if not traefik_enabled %}
       {% if not traefik_enabled %}
       - "{{ ports_http }}:3000"
       - "{{ ports_http }}:3000"
       {% endif %}
       {% endif %}
@@ -39,29 +44,25 @@ services:
     labels:
     labels:
       - traefik.enable=true
       - traefik.enable=true
       - traefik.docker.network={{ traefik_network }}
       - traefik.docker.network={{ traefik_network }}
-      - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=3000
-      - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-http.entrypoints=web
+      - traefik.http.services.{{ service_name }}_web.loadBalancer.server.port=3000
+      - traefik.http.routers.{{ service_name }}_http.service={{ service_name }}_web
+      - traefik.http.routers.{{ service_name }}_http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+      - traefik.http.routers.{{ service_name }}_http.entrypoints=web
       {% if traefik_tls_enabled %}
       {% if traefik_tls_enabled %}
-      - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-https.entrypoints=websecure
-      - traefik.http.routers.{{ service_name }}-https.tls=true
-      - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
+      - traefik.http.routers.{{ service_name }}_https.service={{ service_name }}_web
+      - traefik.http.routers.{{ service_name }}_https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+      - traefik.http.routers.{{ service_name }}_https.entrypoints=websecure
+      - traefik.http.routers.{{ service_name }}_https.tls=true
+      - traefik.http.routers.{{ service_name }}_https.tls.certresolver={{ traefik_tls_certresolver }}
       {% endif %}
       {% endif %}
     {% endif %}
     {% endif %}
-    {% if not database_external %}
+    {% if not database_external and database_type != 'sqlite' %}
     depends_on:
     depends_on:
-      - {{ service_name }}-postgres
+      - {{ service_name }}_db
     {% endif %}
     {% endif %}
 
 
-  {#
-    PostgreSQL: Main database for Gitea (only if not using external database)
-    Stores repositories metadata, users, issues, and pull requests
-  #}
-  {% if not database_external %}
-  {{ service_name }}-postgres:
+  {% if not database_external and database_type == "postgres" %}
+  {{ service_name }}_db:
     image: docker.io/library/postgres:17.6
     image: docker.io/library/postgres:17.6
     restart: {{ restart_policy }}
     restart: {{ restart_policy }}
     environment:
     environment:
@@ -78,27 +79,33 @@ services:
       timeout: 10s
       timeout: 10s
       retries: 5
       retries: 5
     volumes:
     volumes:
-      - {{ service_name }}_postgres:/var/lib/postgresql/data
+      - {{ service_name }}_db:/var/lib/postgresql/data
+  {% elif not database_external and database_type == "mysql" %}
+  {{ service_name }}_db:
+    image: docker.io/library/mysql:8.1
+    restart: {{ restart_policy }}
+    environment:
+      - MYSQL_USER={{ database_user }}
+      - MYSQL_PASSWORD=${DATABASE_PASSWORD}
+      - MYSQL_DATABASE={{ database_name }}
+      - MYSQL_ROOT_PASSWORD=${DATABASE_PASSWORD}
+    networks:
+      - {{ service_name }}_backend
+    volumes:
+      - {{ service_name }}_db:/var/lib/mysql
   {% endif %}
   {% endif %}
 
 
-{#
-  Volume definitions:
-  - {{ service_name }}_data: Persistent storage for repositories and configuration
-  - {{ service_name }}_postgres: PostgreSQL database storage (only if not using external database)
-#}
 volumes:
 volumes:
   {{ service_name }}_data:
   {{ service_name }}_data:
     driver: local
     driver: local
   {% if not database_external %}
   {% if not database_external %}
-  {{ service_name }}_postgres:
+  {% if database_type == "postgres" or database_type == "mysql" %}
+  {{ service_name }}_db:
     driver: local
     driver: local
   {% endif %}
   {% endif %}
+  {% endif %}
 
 
-{#
-  Network definitions (only when Traefik is enabled):
-  - Traefik network: always external (managed by Traefik)
-#}
-{% if not database_external or traefik_enabled %}
+{% if not database_external and (database_type == "postgres" or database_type == "mysql") or traefik_enabled %}
 networks:
 networks:
   {% if not database_external %}
   {% if not database_external %}
   {{ service_name }}_backend:
   {{ service_name }}_backend:

+ 11 - 9
library/compose/gitea/template.yaml

@@ -7,9 +7,13 @@ metadata:
     written in Go. It's similar to GitHub, Bitbucket, and GitLab, providing Git repository
     written in Go. It's similar to GitHub, Bitbucket, and GitLab, providing Git repository
     hosting, code review, team collaboration, and more.
     hosting, code review, team collaboration, and more.
     ## Prerequisites
     ## Prerequisites
-    * **Project:** https://gitea.io/
-    * **Documentation:** https://docs.gitea.io/
-    * **GitHub:** https://github.com/go-gitea/gitea
+    - :info: Gitea supports multiple database backends. You can choose between SQLite (default),
+    PostgreSQL, or MySQL. SQLite is suitable for small deployments, while PostgreSQL and MySQL
+    are recommended for larger installations.
+    ## References
+    - **Project:** https://gitea.io/
+    - **Documentation:** https://docs.gitea.io/
+    - **GitHub:** https://github.com/go-gitea/gitea
   icon:
   icon:
     provider: selfh
     provider: selfh
     id: gitea
     id: gitea
@@ -18,12 +22,12 @@ metadata:
   date: '2025-11-05'
   date: '2025-11-05'
   tags:
   tags:
     - traefik
     - traefik
-schema: "1.2"
+schema: 1.2
 spec:
 spec:
   general:
   general:
     vars:
     vars:
       service_name:
       service_name:
-        default: "gitea"
+        default: gitea
       gitea_url:
       gitea_url:
         description: "Public URL"
         description: "Public URL"
         type: str
         type: str
@@ -31,12 +35,10 @@ spec:
         default: "https://git.example.com"
         default: "https://git.example.com"
   database:
   database:
     vars:
     vars:
-      database_type:
-        default: "postgres"
       database_name:
       database_name:
-        default: "gitea"
+        default: gitea
       database_user:
       database_user:
-        default: "gitea"
+        default: gitea
   ports:
   ports:
     vars:
     vars:
       ports_http:
       ports_http:

+ 1 - 1
library/compose/gitlab-runner/template.yaml

@@ -15,7 +15,7 @@ metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
     id: gitlab
     id: gitlab
-  draft: false
+  draft: true
   next_steps: ""
   next_steps: ""
 schema: "1.2"
 schema: "1.2"
 spec: {}
 spec: {}

+ 2 - 2
library/compose/gitlab/.env.j2

@@ -1,3 +1,3 @@
-# GitLab Environment Variables
-# Note: Initial root password only applies on FIRST initialization
+{% if not swarm_enabled %}
 GITLAB_ROOT_PASSWORD={{ root_password }}
 GITLAB_ROOT_PASSWORD={{ root_password }}
+{% endif %}

+ 0 - 0
library/compose/gitlab/.env.password.j2


+ 0 - 0
library/compose/gitlab/.env.registry.j2


+ 65 - 131
library/compose/gitlab/compose.yaml.j2

@@ -1,121 +1,79 @@
 services:
 services:
   {{ service_name }}:
   {{ service_name }}:
     image: docker.io/gitlab/gitlab-ce:18.5.1-ce.0
     image: docker.io/gitlab/gitlab-ce:18.5.1-ce.0
-    {#
-      If not in swarm mode, check whether container_name is set and apply restart policy,
-      else swarm mode handles restarts via deploy.restart_policy
-    #}
     {% if not swarm_enabled %}
     {% if not swarm_enabled %}
     restart: {{ restart_policy }}
     restart: {{ restart_policy }}
-    container_name: {{ container_name }}
     {% endif %}
     {% endif %}
-    {#
-      Set container hostname for GitLab identification
-    #}
-    hostname: {{ container_hostname }}
-    {#
-      Shared memory size for GitLab (required for proper operation)
-    #}
     shm_size: '256m'
     shm_size: '256m'
-    {#
-      When traefik is enabled, add traefik network for reverse proxy access
-    #}
+    environment:
+      - 
     {% if traefik_enabled %}
     {% if traefik_enabled %}
     networks:
     networks:
       {{ traefik_network }}:
       {{ traefik_network }}:
     {% endif %}
     {% endif %}
-    {#
-      Environment file containing GitLab configuration variables
-    #}
-    env_file:
-      - ./.env
-    {#
-      When swarm_enabled is set, use Docker configs for GitLab configuration
-    #}
-    {% if swarm_enabled %}
-    configs:
-      - source: gitlab_config
-        target: /etc/gitlab/gitlab.rb
-    {% endif %}
-    {#
-      Port mappings:
-      - HTTP: Web interface (only if Traefik is disabled)
-      - SSH: Git SSH access (always exposed, cannot be proxied)
-      - Registry: Container registry (if enabled)
-      Note: Swarm mode uses 'host' mode for port publishing to avoid port conflicts
-    #}
     ports:
     ports:
       {% if not traefik_enabled %}
       {% if not traefik_enabled %}
-      {% if swarm_enabled %}
-      - target: 80
-        published: {{ ports_http }}
-        protocol: tcp
-        mode: host
-      {% else %}
       - "{{ ports_http }}:80"
       - "{{ ports_http }}:80"
       {% endif %}
       {% endif %}
-      {% endif %}
       - "{{ ports_ssh }}:22"
       - "{{ ports_ssh }}:22"
       {% if registry_enabled %}
       {% if registry_enabled %}
       - "{{ ports_registry }}:5000"
       - "{{ ports_registry }}:5000"
       {% endif %}
       {% endif %}
-    {#
-      Volume configuration:
-      - config: GitLab configuration files
-      - logs: GitLab log files
-      - data: GitLab data (repositories, uploads, etc.)
-    #}
     volumes:
     volumes:
+      {% if volume_mode == 'mount' %}
       {% if not swarm_enabled %}
       {% if not swarm_enabled %}
-      - ./config/gitlab.rb:/etc/gitlab/gitlab.rb:ro
+      - {{ volume_mount_path }}/config/gitlab.rb:/etc/gitlab/gitlab.rb:ro
       {% endif %}
       {% endif %}
-      {% if volume_mode == 'mount' %}
       - {{ volume_mount_path }}/config:/etc/gitlab
       - {{ volume_mount_path }}/config:/etc/gitlab
       - {{ volume_mount_path }}/logs:/var/log/gitlab
       - {{ volume_mount_path }}/logs:/var/log/gitlab
       - {{ volume_mount_path }}/data:/var/opt/gitlab
       - {{ volume_mount_path }}/data:/var/opt/gitlab
       {% else %}
       {% else %}
-      - gitlab-config:/etc/gitlab
-      - gitlab-logs:/var/log/gitlab
-      - gitlab-data:/var/opt/gitlab
+      {% if not swarm_enabled %}
+      - ./config/gitlab.rb:/etc/gitlab/gitlab.rb:ro
+      {% endif %}
+      - {{ service_name }}_config:/etc/gitlab
+      - {{ service_name }}_logs:/var/log/gitlab
+      - {{ service_name }}_data:/var/opt/gitlab
       {% endif %}
       {% endif %}
-    {#
-      When traefik_enabled is set, and not running in swarm mode, add traefik labels
-      (optionally enable TLS if traefik_tls_enabled is set)
-      Also configure registry routing if registry is enabled
-    #}
     {% if traefik_enabled and not swarm_enabled %}
     {% if traefik_enabled and not swarm_enabled %}
     labels:
     labels:
       - traefik.enable=true
       - traefik.enable=true
       - traefik.docker.network={{ traefik_network }}
       - traefik.docker.network={{ traefik_network }}
-      - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=80
-      - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
+      - traefik.http.services.{{ service_name }}_web.loadBalancer.server.port=80
+      - traefik.http.routers.{{ service_name }}_http.service={{ service_name }}_web
+      - traefik.http.routers.{{ service_name }}_http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+      - traefik.http.routers.{{ service_name }}_http.entrypoints=web
       {% if traefik_tls_enabled %}
       {% if traefik_tls_enabled %}
-      - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-      - traefik.http.routers.{{ service_name }}-https.tls=true
-      - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
+      - traefik.http.routers.{{ service_name }}_https.service={{ service_name }}_web
+      - traefik.http.routers.{{ service_name }}_https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+      - traefik.http.routers.{{ service_name }}_https.entrypoints=websecure
+      - traefik.http.routers.{{ service_name }}_https.tls=true
+      - traefik.http.routers.{{ service_name }}_https.tls.certresolver={{ traefik_tls_certresolver }}
       {% endif %}
       {% endif %}
       {% if registry_enabled %}
       {% if registry_enabled %}
-      - traefik.http.services.{{ service_name }}-registry.loadBalancer.server.port=5000
-      - traefik.http.routers.{{ service_name }}-registry-http.service={{ service_name }}-registry
-      - traefik.http.routers.{{ service_name }}-registry-http.rule=Host(`{{ traefik_registry_host }}`)
-      - traefik.http.routers.{{ service_name }}-registry-http.entrypoints={{ traefik_entrypoint }}
+      - traefik.http.services.{{ service_name }}_registry.loadBalancer.server.port=5000
+      - traefik.http.routers.{{ service_name }}_registry-http.service={{ service_name }}_registry
+      - traefik.http.routers.{{ service_name }}_registry-http.rule=Host(`{{ traefik_registry_host }}`)
+      - traefik.http.routers.{{ service_name }}_registry-http.entrypoints=web
       {% if traefik_tls_enabled %}
       {% if traefik_tls_enabled %}
-      - traefik.http.routers.{{ service_name }}-registry-https.service={{ service_name }}-registry
-      - traefik.http.routers.{{ service_name }}-registry-https.rule=Host(`{{ traefik_registry_host }}`)
-      - traefik.http.routers.{{ service_name }}-registry-https.entrypoints={{ traefik_tls_entrypoint }}
-      - traefik.http.routers.{{ service_name }}-registry-https.tls=true
-      - traefik.http.routers.{{ service_name }}-registry-https.tls.certresolver={{ traefik_tls_certresolver }}
+      - traefik.http.routers.{{ service_name }}_registry-https.service={{ service_name }}_registry
+      - traefik.http.routers.{{ service_name }}_registry-https.rule=Host(`{{ traefik_registry_host }}`)
+      - traefik.http.routers.{{ service_name }}_registry-https.entrypoints=websecure
+      - traefik.http.routers.{{ service_name }}_registry-https.tls=true
+      - traefik.http.routers.{{ service_name }}_registry-https.tls.certresolver={{ traefik_tls_certresolver }}
       {% endif %}
       {% endif %}
       {% endif %}
       {% endif %}
     {% endif %}
     {% endif %}
     {#
     {#
-      When swarm_enabled is set, use Docker secrets for sensitive data
+      Docker Swarm configuration (only when swarm_enabled is set):
+      - Configs: GitLab configuration file
+      - Secrets: Root password and registry secret (if registry enabled)
+      - Deploy: Replication, placement, restart policy, and Traefik labels
     #}
     #}
     {% if swarm_enabled %}
     {% if swarm_enabled %}
+    configs:
+      - source: gitlab_config
+        target: /etc/gitlab/gitlab.rb
     secrets:
     secrets:
       - source: {{ service_name }}_root_password
       - source: {{ service_name }}_root_password
         target: /run/secrets/gitlab_root_password
         target: /run/secrets/gitlab_root_password
@@ -125,17 +83,9 @@ services:
         target: /run/secrets/gitlab_registry_secret
         target: /run/secrets/gitlab_registry_secret
         mode: 0400
         mode: 0400
       {% endif %}
       {% endif %}
-    {#
-      Deploy configuration for Swarm mode:
-      - Configure replicas, placement constraints, and restart policy
-      - Resources: Set CPU/memory limits (and reservations in Swarm mode)
-      - Traefik: Labels for reverse proxy integration (Swarm mode)
-    #}
     deploy:
     deploy:
-      mode: {{ swarm_placement_mode }}
-      {% if swarm_placement_mode == 'replicated' %}
-      replicas: {{ swarm_replicas }}
-      {% endif %}
+      mode: replicated
+      replicas: 1
       {% if swarm_placement_host %}
       {% if swarm_placement_host %}
       placement:
       placement:
         constraints:
         constraints:
@@ -143,48 +93,32 @@ services:
       {% endif %}
       {% endif %}
       restart_policy:
       restart_policy:
         condition: on-failure
         condition: on-failure
-      {% if resources_enabled %}
-      resources:
-        limits:
-          cpus: '{{ resources_cpu_limit }}'
-          memory: {{ resources_memory_limit }}
-        {% if swarm_enabled %}
-        reservations:
-          cpus: '{{ resources_cpu_reservation }}'
-          memory: {{ resources_memory_reservation }}
-        {% endif %}
-      {% endif %}
-      {#
-        When traefik_enabled is set in swarm mode, add traefik labels
-        (optionally enable TLS if traefik_tls_enabled is set)
-        Also configure registry routing if registry is enabled
-      #}
-      {% if swarm_enabled and traefik_enabled %}
+      {% if traefik_enabled %}
       labels:
       labels:
         - traefik.enable=true
         - traefik.enable=true
         - traefik.docker.network={{ traefik_network }}
         - traefik.docker.network={{ traefik_network }}
-        - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=80
-        - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
+        - traefik.http.services.{{ service_name }}_web.loadBalancer.server.port=80
+        - traefik.http.routers.{{ service_name }}_http.service={{ service_name }}_web
+        - traefik.http.routers.{{ service_name }}_http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+        - traefik.http.routers.{{ service_name }}_http.entrypoints=web
         {% if traefik_tls_enabled %}
         {% if traefik_tls_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-        - traefik.http.routers.{{ service_name }}-https.tls=true
-        - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
+        - traefik.http.routers.{{ service_name }}_https.service={{ service_name }}_web
+        - traefik.http.routers.{{ service_name }}_https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+        - traefik.http.routers.{{ service_name }}_https.entrypoints=websecure
+        - traefik.http.routers.{{ service_name }}_https.tls=true
+        - traefik.http.routers.{{ service_name }}_https.tls.certresolver={{ traefik_tls_certresolver }}
         {% endif %}
         {% endif %}
         {% if registry_enabled %}
         {% if registry_enabled %}
-        - traefik.http.services.{{ service_name }}-registry.loadBalancer.server.port=5000
-        - traefik.http.routers.{{ service_name }}-registry-http.service={{ service_name }}-registry
-        - traefik.http.routers.{{ service_name }}-registry-http.rule=Host(`{{ traefik_registry_host }}`)
-        - traefik.http.routers.{{ service_name }}-registry-http.entrypoints={{ traefik_entrypoint }}
+        - traefik.http.services.{{ service_name }}_registry.loadBalancer.server.port=5000
+        - traefik.http.routers.{{ service_name }}_registry-http.service={{ service_name }}_registry
+        - traefik.http.routers.{{ service_name }}_registry-http.rule=Host(`{{ traefik_registry_host }}`)
+        - traefik.http.routers.{{ service_name }}_registry-http.entrypoints=web
         {% if traefik_tls_enabled %}
         {% if traefik_tls_enabled %}
-        - traefik.http.routers.{{ service_name }}-registry-https.service={{ service_name }}-registry
-        - traefik.http.routers.{{ service_name }}-registry-https.rule=Host(`{{ traefik_registry_host }}`)
-        - traefik.http.routers.{{ service_name }}-registry-https.entrypoints={{ traefik_tls_entrypoint }}
-        - traefik.http.routers.{{ service_name }}-registry-https.tls=true
-        - traefik.http.routers.{{ service_name }}-registry-https.tls.certresolver={{ traefik_tls_certresolver }}
+        - traefik.http.routers.{{ service_name }}_registry-https.service={{ service_name }}_registry
+        - traefik.http.routers.{{ service_name }}_registry-https.rule=Host(`{{ traefik_registry_host }}`)
+        - traefik.http.routers.{{ service_name }}_registry-https.entrypoints=websecure
+        - traefik.http.routers.{{ service_name }}_registry-https.tls=true
+        - traefik.http.routers.{{ service_name }}_registry-https.tls.certresolver={{ traefik_tls_certresolver }}
         {% endif %}
         {% endif %}
         {% endif %}
         {% endif %}
       {% endif %}
       {% endif %}
@@ -198,31 +132,31 @@ services:
 #}
 #}
 {% if volume_mode == 'local' %}
 {% if volume_mode == 'local' %}
 volumes:
 volumes:
-  gitlab-config:
+  {{ service_name }}_config:
     driver: local
     driver: local
-  gitlab-logs:
+  {{ service_name }}_logs:
     driver: local
     driver: local
-  gitlab-data:
+  {{ service_name }}_data:
     driver: local
     driver: local
 {% elif volume_mode == 'nfs' %}
 {% elif volume_mode == 'nfs' %}
 volumes:
 volumes:
-  gitlab-config:
+  {{ service_name }}_config:
     driver: local
     driver: local
     driver_opts:
     driver_opts:
       type: nfs
       type: nfs
-      o: addr={{ volume_nfs_server }},{{ volume_nfs_options }}
+      o: addr={{ volume_nfs_server }},nfsvers=4,{{ volume_nfs_options }}
       device: ":{{ volume_nfs_path }}/config"
       device: ":{{ volume_nfs_path }}/config"
-  gitlab-logs:
+  {{ service_name }}_logs:
     driver: local
     driver: local
     driver_opts:
     driver_opts:
       type: nfs
       type: nfs
-      o: addr={{ volume_nfs_server }},{{ volume_nfs_options }}
+      o: addr={{ volume_nfs_server }},nfsvers=4,{{ volume_nfs_options }}
       device: ":{{ volume_nfs_path }}/logs"
       device: ":{{ volume_nfs_path }}/logs"
-  gitlab-data:
+  {{ service_name }}_data:
     driver: local
     driver: local
     driver_opts:
     driver_opts:
       type: nfs
       type: nfs
-      o: addr={{ volume_nfs_server }},{{ volume_nfs_options }}
+      o: addr={{ volume_nfs_server }},nfsvers=4,{{ volume_nfs_options }}
       device: ":{{ volume_nfs_path }}/data"
       device: ":{{ volume_nfs_path }}/data"
 {% endif %}
 {% endif %}
 
 

+ 3 - 16
library/compose/gitlab/template.yaml

@@ -6,7 +6,8 @@ metadata:
   description: |
   description: |
     A **complete DevOps platform** that provides Git repository management, CI/CD pipelines,
     A **complete DevOps platform** that provides Git repository management, CI/CD pipelines,
     issue tracking, and container registry in a single application.
     issue tracking, and container registry in a single application.
-    ## Important Configuration Notes
+    ## Prerequisites
+    - ...
     **Performance Presets**:
     **Performance Presets**:
     - `homelab`: Optimized for low-resource environments (limited workers, reduced PostgreSQL buffers)
     - `homelab`: Optimized for low-resource environments (limited workers, reduced PostgreSQL buffers)
     - `default`: Standard server configuration for production use
     - `default`: Standard server configuration for production use
@@ -29,7 +30,6 @@ metadata:
   tags:
   tags:
     - traefik
     - traefik
     - swarm
     - swarm
-    - volume_modes
   next_steps: |
   next_steps: |
     ## Post-Installation Steps
     ## Post-Installation Steps
     1. **Start GitLab**:
     1. **Start GitLab**:
@@ -60,15 +60,12 @@ metadata:
     ## Additional Resources
     ## Additional Resources
     - Documentation: https://docs.gitlab.com/
     - Documentation: https://docs.gitlab.com/
     - GitLab Runner: https://docs.gitlab.com/runner/
     - GitLab Runner: https://docs.gitlab.com/runner/
+  draft: true
 spec:
 spec:
   general:
   general:
     vars:
     vars:
       service_name:
       service_name:
         default: "gitlab"
         default: "gitlab"
-      container_name:
-        default: "gitlab"
-      container_hostname:
-        default: "gitlab"
       external_url:
       external_url:
         type: str
         type: str
         description: External URL for GitLab
         description: External URL for GitLab
@@ -99,17 +96,7 @@ spec:
         default: true
         default: true
   ports:
   ports:
     vars:
     vars:
-      ports_http:
-        type: int
-        description: HTTP port
-        default: 80
-      ports_https:
-        type: int
-        description: HTTPS port
-        default: 443
       ports_ssh:
       ports_ssh:
-        type: int
-        description: SSH port
         default: 2424
         default: 2424
       ports_registry:
       ports_registry:
         type: int
         type: int

+ 41 - 5
library/compose/grafana/compose.yaml.j2

@@ -2,14 +2,14 @@ services:
   {{ service_name }}:
   {{ service_name }}:
     image: docker.io/grafana/grafana-oss:12.1.1
     image: docker.io/grafana/grafana-oss:12.1.1
     restart: {{ restart_policy }}
     restart: {{ restart_policy }}
-    {% if database_type == 'postgres' or authentik_enabled%}
+    {% if database_type != 'sqlite' or authentik_enabled %}
     environment:
     environment:
       {% if database_type == 'postgres' %}
       {% if database_type == 'postgres' %}
       - GF_DATABASE_TYPE=postgres
       - GF_DATABASE_TYPE=postgres
       {% if database_external %}
       {% if database_external %}
       - GF_DATABASE_HOST={{ database_host }}
       - GF_DATABASE_HOST={{ database_host }}
       {% else %}
       {% else %}
-      - GF_DATABASE_HOST={{ service_name }}_postgres:5432
+      - GF_DATABASE_HOST={{ service_name }}_db
       {% endif %}
       {% endif %}
       - GF_DATABASE_NAME={{ database_name }}
       - GF_DATABASE_NAME={{ database_name }}
       - GF_DATABASE_USER={{ database_user }}
       - GF_DATABASE_USER={{ database_user }}
@@ -34,9 +34,14 @@ services:
       - GF_AUTH_GENERIC_OAUTH_SKIP_ORG_ROLE_SYNC=true
       - GF_AUTH_GENERIC_OAUTH_SKIP_ORG_ROLE_SYNC=true
       {% endif %}
       {% endif %}
     {% endif %}
     {% endif %}
-    {% if traefik_enabled %}
+    {% if not database_external and (database_type == "postgres") or traefik_enabled %}
     networks:
     networks:
-      {{ traefik_network }}:
+    {% if not database_external and database_type != 'sqlite' %}
+      - {{ service_name }}_backend
+    {% endif %}
+    {% if traefik_enabled %}
+      - {{ traefik_network }}
+    {% endif %}
     {% endif %}
     {% endif %}
     {% if not traefik_enabled %}
     {% if not traefik_enabled %}
     ports:
     ports:
@@ -61,12 +66,43 @@ services:
       {% endif %}
       {% endif %}
     {% endif %}
     {% endif %}
 
 
-{% if traefik_enabled %}
+  {% if not database_external and database_type == "postgres" %}
+  {{ service_name }}_db:
+    image: docker.io/library/postgres:17.6
+    restart: {{ restart_policy }}
+    environment:
+      - POSTGRES_USER={{ database_user }}
+      - POSTGRES_PASSWORD=${GRAFANA_DB_PASSWORD}
+      - POSTGRES_DB={{ database_name }}
+    networks:
+      - {{ service_name }}_backend
+    healthcheck:
+      test: ["CMD-SHELL", "pg_isready -U {{ database_user }}"]
+      start_period: 30s
+      interval: 10s
+      timeout: 10s
+      retries: 5
+    volumes:
+      - {{ service_name }}_db:/var/lib/postgresql/data
+  {% endif %}
+
+{% if not database_external and (database_type == "postgres") or traefik_enabled %}
 networks:
 networks:
+  {% if not database_external %}
+  {{ service_name }}_backend:
+    driver: bridge
+  {% endif %}
+  {% if traefik_enabled %}
   {{ traefik_network }}:
   {{ traefik_network }}:
     external: true
     external: true
+  {% endif %}
 {% endif %}
 {% endif %}
 
 
+
 volumes:
 volumes:
   {{ service_name }}_data:
   {{ service_name }}_data:
     driver: local
     driver: local
+  {% if not database_external and database_type == 'postgres' %}
+  {{ service_name }}_db:
+    driver: local
+  {% endif %}

+ 16 - 22
library/compose/grafana/template.yaml

@@ -6,9 +6,9 @@ metadata:
     Grafana is an open-source platform for monitoring and observability that allows you to visualize and analyze metrics, logs, and traces from various data
     Grafana is an open-source platform for monitoring and observability that allows you to visualize and analyze metrics, logs, and traces from various data
     sources. It provides a powerful and flexible dashboarding solution for IT infrastructure and application monitoring.
     sources. It provides a powerful and flexible dashboarding solution for IT infrastructure and application monitoring.
     ## Prerequisites
     ## Prerequisites
-    * **Project:** https://grafana.com/
-    * **Documentation:** https://grafana.com/docs/grafana/latest/
-    * **GitHub:** https://github.com/grafana/grafana
+    - **Project:** https://grafana.com/
+    - **Documentation:** https://grafana.com/docs/grafana/latest/
+    - **GitHub:** https://github.com/grafana/grafana
   icon:
   icon:
     provider: selfh
     provider: selfh
     id: grafana
     id: grafana
@@ -29,34 +29,28 @@ spec:
   general:
   general:
     vars:
     vars:
       service_name:
       service_name:
-        default: "grafana"
+        default: grafana
   ports:
   ports:
     vars:
     vars:
       ports_http:
       ports_http:
         default: 3000
         default: 3000
-  database:
-    vars:
-      database_type:
-        options: ["sqlite", "postgres"]
-        default: "sqlite"
-      database_host:
-        default: "postgres:5432"
-        needs: "database_type=postgres"
-      database_name:
-        default: "grafana"
-        needs: "database_type=postgres"
-      database_user:
-        default: "grafana"
-        needs: "database_type=postgres"
-      database_password:
-        needs: "database_type=postgres"
   authentik:
   authentik:
     vars:
     vars:
       authentik_url:
       authentik_url:
-        default: "https://auth.home.arpa"
+        default: https://auth.home.arpa
       authentik_slug:
       authentik_slug:
-        default: "grafana"
+        default: grafana
   traefik:
   traefik:
     vars:
     vars:
       traefik_host:
       traefik_host:
         default: grafana
         default: grafana
+  database:
+    vars:
+      database_type:
+        options:
+          - sqlite
+          - postgres
+      database_name:
+        default: grafana
+      database_user:
+        default: grafana

+ 10 - 26
library/compose/homepage/template.yaml

@@ -1,52 +1,36 @@
 ---
 ---
 kind: compose
 kind: compose
-schema: "1.2"
 metadata:
 metadata:
-  icon:
-    provider: selfh
-    id: homepage
   name: Homepage
   name: Homepage
-  description: |
+  description: |-
     Homepage is a modern, fully static, fast, secure fully customizable application dashboard with integrations
     Homepage is a modern, fully static, fast, secure fully customizable application dashboard with integrations
     for over 100 services and translations into multiple languages.
     for over 100 services and translations into multiple languages.
-    
+
     Project: https://gethomepage.dev/
     Project: https://gethomepage.dev/
     Documentation: https://gethomepage.dev/latest/
     Documentation: https://gethomepage.dev/latest/
     GitHub: https://github.com/gethomepage/homepage
     GitHub: https://github.com/gethomepage/homepage
   version: v1.6.1
   version: v1.6.1
   author: Christian Lempa
   author: Christian Lempa
-  date: '2025-11-05'
+  date: "2025-11-05"
   tags:
   tags:
     - traefik
     - traefik
     - swarm
     - swarm
     - volume_modes
     - volume_modes
+  icon:
+    provider: simpleicons
+    id: homepage
   draft: true
   draft: true
+  next_steps: ""
+schema: "1.2"
 spec:
 spec:
   general:
   general:
     vars:
     vars:
-      service_name:
+      container_hostname:
         default: homepage
         default: homepage
       container_name:
       container_name:
         default: homepage
         default: homepage
-      container_hostname:
+      service_name:
         default: homepage
         default: homepage
-  homepage:
-    title: Homepage Configuration
-    required: true
-    vars:
-      homepage_allowed_hosts:
-        type: str
-        description: Allowed hosts (comma-separated, required for security)
-        default: "*"
-        extra: "Set to specific domains in production (e.g., homepage.home.arpa)"
-      homepage_puid:
-        type: int
-        description: User ID (optional, leave 0 to use container default)
-        default: 0
-      homepage_pgid:
-        type: int
-        description: Group ID (optional, leave 0 to use container default)
-        default: 0
   ports:
   ports:
     vars:
     vars:
       ports_http:
       ports_http:

+ 1 - 0
library/compose/influxdb/template.yaml

@@ -23,6 +23,7 @@ metadata:
   date: '2025-09-28'
   date: '2025-09-28'
   tags:
   tags:
     - traefik
     - traefik
+  draft: true
 schema: "1.2"
 schema: "1.2"
 spec:
 spec:
   ports:
   ports:

+ 2 - 1
library/compose/mariadb/template.yaml

@@ -1,6 +1,5 @@
 ---
 ---
 kind: compose
 kind: compose
-schema: "1.2"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
@@ -23,6 +22,8 @@ metadata:
   author: Christian Lempa
   author: Christian Lempa
   date: '2025-09-28'
   date: '2025-09-28'
   tags: []
   tags: []
+  draft: true
+schema: 1.2
 spec:
 spec:
   general:
   general:
     vars:
     vars:

+ 2 - 2
library/compose/n8n/template.yaml

@@ -29,8 +29,8 @@ metadata:
   tags:
   tags:
     - traefik
     - traefik
     - database
     - database
-  next_steps:
-schema: "1.2"
+  draft: true
+schema: 1.2
 spec:
 spec:
   general:
   general:
     vars:
     vars:

+ 7 - 5
library/compose/netbox/template.yaml

@@ -3,11 +3,13 @@ kind: compose
 metadata:
 metadata:
   name: NetBox
   name: NetBox
   description: |-
   description: |-
-    Network infrastructure management (IPAM/DCIM) and network automation source of truth. Provides comprehensive API for managing IP addresses, circuits, devices, racks, cables, and other network infrastructure components with powerful automation capabilities.
+    Network infrastructure management (IPAM/DCIM) and network automation source of truth. Provides comprehensive API
+    for managing IP addresses, circuits, devices, racks, cables, and other network infrastructure components with powerful
+    automation capabilities.
     ## References
     ## References
-    * **Project:** https://netbox.dev/
-    * **Documentation:** https://docs.netbox.dev/
-    * **GitHub:** https://github.com/netbox-community/netbox
+    - **Project:** https://netbox.dev/
+    - **Documentation:** https://docs.netbox.dev/
+    - **GitHub:** https://github.com/netbox-community/netbox
   version: 4.2.3
   version: 4.2.3
   author: Christian Lempa
   author: Christian Lempa
   date: "2025-11-13"
   date: "2025-11-13"
@@ -25,7 +27,7 @@ metadata:
     Username: admin
     Username: admin
     Password: admin
     Password: admin
     ```
     ```
-schema: "1.2"
+schema: 1.2
 spec:
 spec:
   database:
   database:
     vars:
     vars:

+ 1 - 0
library/compose/nginx/template.yaml

@@ -21,6 +21,7 @@ metadata:
   tags:
   tags:
     - traefik
     - traefik
     - swarm
     - swarm
+  draft: true
 spec:
 spec:
   general:
   general:
     vars:
     vars:

+ 2 - 1
library/compose/openwebui/template.yaml

@@ -4,7 +4,7 @@ schema: "1.2"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: openwebui
+    id: open-webui
   name: Openwebui
   name: Openwebui
   description: >
   description: >
     OpenWebUI is an open-source web-based user interface for managing and interacting with AI models.
     OpenWebUI is an open-source web-based user interface for managing and interacting with AI models.
@@ -24,6 +24,7 @@ metadata:
   tags:
   tags:
     - traefik
     - traefik
     - authentik
     - authentik
+  draft: true
 spec:
 spec:
   general:
   general:
     vars:
     vars:

+ 0 - 137
library/compose/pangolin/compose.yaml.j2.final

@@ -1,137 +0,0 @@
----
-services:
-  {{ service_name }}:
-    image: docker.io/fosrl/pangolin:latest
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    container_name: {{ container_name }}
-    {% endif %}
-    hostname: {{ container_hostname }}
-    {#
-      When traefik is enabled, add traefik network for reverse proxy access
-    #}
-    {% if traefik_enabled %}
-    networks:
-      {{ traefik_network }}:
-    {% endif %}
-      {% if network_mode == 'macvlan' %}
-      {{ network_name }}:
-        ipv4_address: {{ network_macvlan_ipv4_address }}
-      {% elif network_mode == 'bridge' %}
-      {{ network_name }}:
-      {% endif %}
-    {% endif %}
-    {% if network_mode == 'bridge' and not traefik_enabled %}
-    ports:
-      {% if swarm_enabled %}
-      - target: 8080
-        published: {{ ports_http }}
-        protocol: tcp
-        mode: host
-      {% else %}
-      - "{{ ports_http }}:8080/tcp"
-      {% endif %}
-    {% endif %}
-    {% if environment_enabled or postgres_enabled %}
-    environment:
-      {% if postgres_enabled %}
-      POSTGRES_CONNECTION_STRING: "{{ postgres_connection_string }}"
-      {% endif %}
-      {% if environment_enabled %}
-      {% if environment_log_level %}
-      LOG_LEVEL: "{{ environment_log_level }}"
-      {% endif %}
-      {% if environment_crowdsec_enabled %}
-      CROWDSEC_ENABLED: "true"
-      {% endif %}
-      {% endif %}
-    {% endif %}
-    volumes:
-      {% if volume_mode == 'mount' %}
-      - {{ volume_mount_path }}/data:/app/data:rw
-      - {{ volume_mount_path }}/config:/app/config:rw
-      {% elif volume_mode in ['local', 'nfs'] %}
-      - {{ service_name }}-data:/app/data
-      - {{ service_name }}-config:/app/config
-      {% endif %}
-    {% if swarm_enabled or resources_enabled %}
-    deploy:
-      {% if swarm_enabled %}
-      mode: replicated
-      replicas: 1
-      restart_policy:
-        condition: on-failure
-      {% endif %}
-      {% if resources_enabled %}
-      resources:
-        limits:
-          cpus: '{{ resources_cpu_limit }}'
-          memory: {{ resources_memory_limit }}
-        {% if swarm_enabled %}
-        reservations:
-          cpus: '{{ resources_cpu_reservation }}'
-          memory: {{ resources_memory_reservation }}
-        {% endif %}
-      {% endif %}
-      {% if swarm_enabled and traefik_enabled %}
-      labels:
-        - traefik.enable=true
-        - traefik.docker.network={{ traefik_network }}
-        - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=8080
-        - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-        {% if traefik_tls_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-        - traefik.http.routers.{{ service_name }}-https.tls=true
-        - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-        {% endif %}
-      {% endif %}
-    {% endif %}
-    {% if traefik_enabled and not swarm_enabled %}
-    labels:
-      - traefik.enable=true
-      - traefik.docker.network={{ traefik_network }}
-      - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=8080
-      - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-      {% if traefik_tls_enabled %}
-      - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-      - traefik.http.routers.{{ service_name }}-https.tls=true
-      - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-      {% endif %}
-    {% endif %}
-
-{% if volume_mode == 'local' %}
-volumes:
-  {{ service_name }}-data:
-    driver: local
-  {{ service_name }}-config:
-    driver: local
-{% elif volume_mode == 'nfs' %}
-volumes:
-  {{ service_name }}-data:
-    driver: local
-    driver_opts:
-      type: nfs
-      o: addr={{ volume_nfs_server }},{{ volume_nfs_options }}
-      device: ":{{ volume_nfs_path }}/data"
-  {{ service_name }}-config:
-    driver: local
-    driver_opts:
-      type: nfs
-      o: addr={{ volume_nfs_server }},{{ volume_nfs_options }}
-      device: ":{{ volume_nfs_path }}/config"
-{% endif %}
-
-    {% endif %}
-  {% if traefik_enabled %}
-  {{ traefik_network }}:
-    external: true
-  {% endif %}
-{% endif %}

+ 0 - 113
library/compose/pangolin/template.yaml.backup

@@ -1,113 +0,0 @@
----
-kind: compose
-schema: "1.2"
-metadata:
-  name: Pangolin
-  description: |
-    Self-hosted reverse proxy server that securely exposes private resources on distributed networks through
-    encrypted WireGuard tunnels. Pangolin enables access from anywhere without opening ports, using a custom
-    user-space WireGuard client (Newt) for secure connectivity. Features include automatic tunnel management,
-    integrated CrowdSec security, and support for both PostgreSQL and SQLite databases.
-    ## References
-    * **Project:** https://github.com/fosrl/pangolin
-    * **Documentation:** https://github.com/fosrl/pangolin/blob/main/README.md
-    * **Docker Hub:** https://hub.docker.com/r/fosrl/pangolin
-  version: latest
-  author: Christian Lempa
-  date: '2025-11-13'
-  tags:
-    - traefik
-    - swarm
-    - proxy
-    - wireguard
-  next_steps: |
-    ### 1. Configure Database
-    {% if postgres_enabled -%}
-    Make sure PostgreSQL is running and accessible at:
-    * Connection string: {{ postgres_connection_string }}
-    {% else -%}
-    Pangolin will use SQLite database stored in the data volume.
-    {% endif -%}
-    ### 2. Deploy the Service
-    {% if swarm_enabled -%}
-    Deploy to Docker Swarm:
-    ```bash
-    docker stack deploy -c compose.yaml pangolin
-    ```
-    {% else -%}
-    Start Pangolin using Docker Compose:
-    ```bash
-    docker compose up -d
-    ```
-    {% endif -%}
-    ### 3. Access the Web Interface
-    {% if traefik_enabled -%}
-    * Navigate to: **https://{{ traefik_host }}.{{ traefik_domain }}**
-    {% else -%}
-    * Navigate to: **http://localhost:{{ ports_http }}**
-    {% endif -%}
-    ### 4. Configure WireGuard Clients
-    * Use the Pangolin web interface to create and manage WireGuard tunnels
-    * Deploy Newt client on remote machines to establish secure connections
-spec:
-  general:
-    vars:
-      service_name:
-        default: "pangolin"
-      container_name:
-        default: "pangolin"
-      container_hostname:
-        default: "pangolin"
-  traefik:
-    vars:
-      traefik_host:
-        default: "pangolin"
-  network:
-    vars:
-      network_name:
-        default: "pangolin_network"
-  ports:
-    vars:
-      ports_http:
-        description: "External HTTP port (web interface)"
-        type: int
-        default: 8080
-        needs: ["traefik_enabled=false", "network_mode=bridge"]
-  volume:
-    vars:
-      volume_mount_path:
-        default: "/mnt/storage/pangolin"
-  postgres:
-    title: "PostgreSQL Configuration"
-    toggle: postgres_enabled
-    needs: null
-    vars:
-      postgres_enabled:
-        type: bool
-        default: false
-        description: "Use PostgreSQL database (SQLite is default)"
-      postgres_connection_string:
-        type: str
-        default: "postgresql://postgres:postgres@localhost:5432"
-        description: "PostgreSQL connection string"
-        needs: "postgres_enabled=true"
-  environment:
-    title: "Environment Variables"
-    toggle: environment_enabled
-    needs: null
-    vars:
-      environment_enabled:
-        type: bool
-        default: false
-        description: "Configure additional environment variables"
-      environment_crowdsec_enabled:
-        type: bool
-        default: false
-        description: "Enable CrowdSec integration"
-        needs: "environment_enabled=true"
-      environment_log_level:
-        type: enum
-        default: "info"
-        options: ["debug", "info", "warn", "error"]
-        description: "Log level"
-        needs: "environment_enabled=true"

+ 25 - 20
library/compose/passbolt/compose.yaml.j2

@@ -1,25 +1,12 @@
-volumes:
-  passbolt-db:
-  passbolt-data-gpg:
-  passbolt-data-jwt:
+---
 services:
 services:
-  {{ service_name }}-db:
-    container_name: {{ container_name }}-db
-    image: docker.io/library/mariadb:11.3
-    environment:
-      - MYSQL_RANDOM_ROOT_PASSWORD=true
-      - MYSQL_DATABASE=$PASSBOLT_DB_NAME
-      - MYSQL_USER=$PASSBOLT_DB_USER
-      - MYSQL_PASSWORD=$PASSBOLT_DB_PASS
-    volumes:
-      - passbolt-db:/var/lib/mysql
-    restart: unless-stopped
   {{ service_name }}:
   {{ service_name }}:
-    container_name: {{ container_name }}
     image: docker.io/passbolt/passbolt:5.6.1-1-ce
     image: docker.io/passbolt/passbolt:5.6.1-1-ce
-    depends_on:
-      - {{ service_name }}-db
+    restart: unless-stopped
     environment:
     environment:
+      {% if container_timezone%}
+      - APP_DEFAULT_TIMEZONE={{ container_timezone }}
+      {% endif %}
       - APP_FULL_BASE_URL=https://passbolt.domain.tld
       - APP_FULL_BASE_URL=https://passbolt.domain.tld
       - DATASOURCES_DEFAULT_HOST={{ service_name }}-db
       - DATASOURCES_DEFAULT_HOST={{ service_name }}-db
       - DATASOURCES_DEFAULT_USERNAME=$PASSBOLT_DB_USER
       - DATASOURCES_DEFAULT_USERNAME=$PASSBOLT_DB_USER
@@ -32,7 +19,25 @@ services:
       - EMAIL_TRANSPORT_DEFAULT_TLS=true
       - EMAIL_TRANSPORT_DEFAULT_TLS=true
       - EMAIL_DEFAULT_FROM=no-reply@domain.tld
       - EMAIL_DEFAULT_FROM=no-reply@domain.tld
     volumes:
     volumes:
-      - passbolt-data-gpg:/etc/passbolt/gpg
-      - passbolt-data-jwt:/etc/passbolt/jwt
+      - {{ service_name }}-gpg:/etc/passbolt/gpg
+      - {{ service_name }}-jwt:/etc/passbolt/jwt
     command: ["/usr/bin/wait-for.sh", "-t", "0", "passbolt-db:3306", "--", "/docker-entrypoint.sh"]
     command: ["/usr/bin/wait-for.sh", "-t", "0", "passbolt-db:3306", "--", "/docker-entrypoint.sh"]
+    depends_on:
+      - {{ service_name }}-db
+
+  {{ service_name }}-db:
+    image: docker.io/library/mariadb:11.3.0
     restart: unless-stopped
     restart: unless-stopped
+    environment:
+      - MYSQL_RANDOM_ROOT_PASSWORD=true
+      - MYSQL_DATABASE=$PASSBOLT_DB_NAME
+      - MYSQL_USER=$PASSBOLT_DB_USER
+      - MYSQL_PASSWORD=$PASSBOLT_DB_PASS
+    volumes:
+      - passbolt-db:/var/lib/mysql
+
+
+volumes:
+  passbolt-db:
+  {{ service_name }}-gpg:
+  {{ service_name }}-jwt:

+ 12 - 116
library/compose/passbolt/template.yaml

@@ -1,141 +1,37 @@
 ---
 ---
 kind: compose
 kind: compose
-schema: "1.2"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
     id: passbolt
     id: passbolt
   name: Passbolt
   name: Passbolt
   description: |-
   description: |-
-    Passbolt is an open-source password manager designed for teams and businesses. It provides a secure way to store, share, and manage passwords and sensitive
-    information collaboratively.
-
-    ## Prerequisites
-    * **Project:** https://www.passbolt.com/
-    * **Documentation:** https://help.passbolt.com/
-    * **GitHub:** https://github.com/passbolt/passbolt
-
+    Passbolt is an open-source password manager designed for teams and businesses. It provides a secure way to store,
+    share, and manage passwords and sensitive information collaboratively.
+    ## References
+    - **Project:** https://www.passbolt.com/
+    - **Documentation:** https://help.passbolt.com/
+    - **GitHub:** https://github.com/passbolt/passbolt
   version: 11.3
   version: 11.3
   author: Christian Lempa
   author: Christian Lempa
   date: '2025-09-28'
   date: '2025-09-28'
   tags:
   tags:
     - traefik
     - traefik
     - database
     - database
+  draft: true
+schema: 1.2
 spec:
 spec:
   general:
   general:
     vars:
     vars:
       service_name:
       service_name:
-        default: "passbolt"
-      container_name:
-        default: "passbolt"
-      container_timezone:
-        default: "UTC"
-  ports:
-    vars:
-      ports_http:
-        description: HTTP port for Passbolt
-        type: int
-        default: 80
-      ports_https:
-        description: HTTPS port for Passbolt
-        type: int
-        default: 443
+        default: passbolt
   traefik:
   traefik:
     vars:
     vars:
-      traefik_enabled:
-        type: bool
-        default: false
-      traefik_network:
-        default: "traefik"
       traefik_host:
       traefik_host:
-        default: "passbolt"
-      traefik_domain:
-        default: "home.arpa"
-      traefik_entrypoint:
-        default: "web"
-      traefik_tls_entrypoint:
-        default: "websecure"
-      traefik_tls_enabled:
-        type: bool
-        default: true
-      traefik_tls_certresolver:
-        default: "cloudflare"
+        default: passbolt
   database:
   database:
     vars:
     vars:
-      database_type:
-        options: ["sqlite", "postgres", "mysql"]
-        default: "mysql"
-      database_external:
-        description: Use an external database server?
-        extra: skips creation of internal database container
-        type: bool
-        needs: "database_type=mysql,postgres"
-        default: false
-      database_host:
-        description: Database host
-        type: str
-        needs: "database_external=true"
-        default: "passbolt-db"
-        required: true
-      database_port:
-        description: Database port
-        type: int
-        required: true
       database_name:
       database_name:
-        description: Database name
-        type: str
-        required: true
+        default: passbolt
       database_user:
       database_user:
-        description: Database user
-        type: str
-        required: true
-      database_password:
-        description: Database password
-        type: str
-        sensitive: true
-        required: true
-  volume:
-    vars:
-      volume_mode:
-        type: enum
-        options: ["local", "mount", "nfs"]
-        default: "local"
-      volume_mount_path:
-        description: Host path for bind mounts
-        type: str
-        default: "/mnt/storage"
-        needs: "volume_mode=mount"
-        required: true
-      volume_nfs_server:
-        description: NFS server address
-        type: str
-        default: "192.168.1.1"
-        needs: "volume_mode=nfs"
-        required: true
-      volume_nfs_path:
-        description: NFS export path
-        type: str
-        default: "/export"
-        needs: "volume_mode=nfs"
-        required: true
-      volume_nfs_options:
-        description: NFS mount options (comma-separated)
-        type: str
-        default: "rw,nolock,soft"
-        needs: "volume_mode=nfs"
-        required: true
-  resources:
-    vars:
-      resources_enabled:
-        type: bool
-        default: false
-      resources_cpu_limit:
-        description: Maximum CPU cores (e.g., 0.5, 1.0, 2.0)
-        type: str
-        default: "1.0"
-        required: true
-      resources_memory_limit:
-        description: Maximum memory (e.g., 512M, 1G, 2G)
-        type: str
-        default: "1G"
-        required: true
+        default: passbolt

+ 0 - 38
library/compose/pihole/common/networks.yaml.j2

@@ -1,38 +0,0 @@
-{#
-  Network definitions (only when needed):
-  - When network_mode is empty: no definition needed (uses Docker's default bridge)
-  - When network_mode is 'bridge': define custom bridge network
-  - When network_mode is 'macvlan': configure macvlan with static IP (for Compose mode)
-    Note: In Swarm mode, macvlan networks must be created manually with config-only networks on each node
-  - When swarm_enabled: use overlay network for multi-host communication
-  - Traefik network: always external (managed by Traefik)
-#}
-{% if network_mode == 'bridge' or network_mode == 'macvlan' or traefik_enabled %}
-networks:
-  {% if network_mode == 'bridge' or network_mode == 'macvlan'%}
-  {{ network_name }}:
-    {% if network_external %}
-    external: true
-    {% else %}
-    {% if network_mode == 'macvlan' %}
-    driver: macvlan
-    driver_opts:
-      parent: {{ network_macvlan_parent_interface }}
-    ipam:
-      config:
-        - subnet: {{ network_macvlan_subnet }}
-          gateway: {{ network_macvlan_gateway }}
-    name: {{ network_name }}
-    {% elif swarm_enabled %}
-    driver: overlay
-    attachable: true
-    {% else %}
-    driver: bridge
-    {% endif %}
-    {% endif %}
-  {% endif %}
-  {% if traefik_enabled %}
-  {{ traefik_network }}:
-    external: true
-  {% endif %}
-{% endif %}

+ 0 - 3
library/compose/pihole/common/secrets.yaml.j2

@@ -1,3 +0,0 @@
-secrets:
-  {{ service_name }}_webpassword:
-    file: ./.env.secret.webpassword

+ 0 - 21
library/compose/pihole/common/volumes.yaml.j2

@@ -1,21 +0,0 @@
-{% if volume_mode == 'local' %}
-volumes:
-  {{ service_name }}-dnsmasq:
-    driver: local
-  {{ service_name }}-pihole:
-    driver: local
-{% elif volume_mode == 'nfs' %}
-volumes:
-  {{ service_name }}-dnsmasq:
-    driver: local
-    driver_opts:
-      type: nfs
-      o: addr={{ volume_nfs_server }},{{ volume_nfs_options }}
-      device: ":{{ volume_nfs_path }}/dnsmasq"
-  {{ service_name }}-pihole:
-    driver: local
-    driver_opts:
-      type: nfs
-      o: addr={{ volume_nfs_server }},{{ volume_nfs_options }}
-      device: ":{{ volume_nfs_path }}/pihole"
-{% endif %}

+ 262 - 8
library/compose/pihole/compose.yaml.j2

@@ -1,12 +1,266 @@
+---
+services:
+  {{ service_name }}:
+    image: docker.io/pihole/pihole:2025.11.0
+    {#
+      If not in swarm mode, check whether container_name is set and apply restart policy,
+      else swarm mode handles restarts via deploy.restart_policy
+    #}
+    {% if not swarm_enabled %}
+    restart: {{ restart_policy }}
+    {% if container_name %}
+    container_name: {{ container_name }}
+    {% endif %}
+    {% endif %}
+    {#
+      Set container hostname (Pi-hole requires this for proper operation)
+    #}
+    {% if container_hostname %}
+    hostname: {{ container_hostname }}
+    {% endif %}
+    {#
+      Environment variables for Pi-hole configuration
+      - TZ: Timezone for proper log rotation
+      - PIHOLE_UID/GID: User/group for file permissions
+      - WEBPASSWORD: Admin password (from env file in compose mode, from secret in swarm mode)
+      - FTLCONF_dns_listeningMode: In bridge mode, listen on all interfaces
+    #}
+    environment:
+      - TZ={{ container_timezone }}
+      - PIHOLE_UID={{ user_uid }}
+      - PIHOLE_GID={{ user_gid }}
+      {% if swarm_enabled %}
+      - WEBPASSWORD_FILE={{ service_name }}_webpassword
+      {% else %}
+      - FTLCONF_webserver_api_password=${WEBPASSWORD}
+      {% endif %}
+      {% if network_mode == 'bridge' %}
+      - FTLCONF_dns_listeningMode=all
+      {% endif %}
+    {#
+      Network configuration based on network_mode:
+      - 'host': Use host networking (direct access to host network stack, not supported in Swarm)
+      - 'bridge': Custom bridge network (default Docker networking)
+      - 'macvlan': Container gets its own MAC/IP on physical network (requires external macvlan network setup in Swarm)
+      - '' (empty): Uses Docker's default bridge network
+      When traefik is enabled, always add traefik network
+    #}
+    {% if network_mode == 'host' %}
+    network_mode: host
+    {% elif network_mode == 'bridge' or network_mode == 'macvlan' or traefik_enabled %}
+    networks:
+      {% if traefik_enabled %}
+      {{ traefik_network }}:
+      {% endif %}
+      {% if network_mode == 'macvlan' %}
+      {{ network_name }}:
+        ipv4_address: {{ network_macvlan_ipv4_address }}
+      {% elif network_mode == 'bridge' %}
+      {{ network_name }}:
+      {% endif %}
+    {% endif %}
+    {#
+      Port mappings when in bridge mode (or empty, which defaults to bridge)
+      - HTTP/HTTPS: Web interface (only if Traefik is disabled)
+      - DNS: Port 53 TCP/UDP (always exposed, even with Traefik, since DNS can't be proxied)
+      - NTP: Port 123 UDP (network time protocol, always exposed)
+      Note: Swarm mode uses 'host' mode for port publishing to avoid port conflicts
+      Note: Host and macvlan modes don't need port mappings (direct network access)
+    #}
+    {% if network_mode == '' or network_mode == 'bridge' or traefik_enabled %}
+    ports:
+      {% if not traefik_enabled %}
+      {% if swarm_enabled %}
+      - target: 80
+        published: {{ ports_http }}
+        protocol: tcp
+        mode: host
+      - target: 443
+        published: {{ ports_https }}
+        protocol: tcp
+        mode: host
+      {% else %}
+      - "{{ ports_http }}:80/tcp"
+      - "{{ ports_https }}:443/tcp"
+      {% endif %}
+      {% endif %}
+      {% if swarm_enabled %}
+      - target: 53
+        published: {{ ports_dns }}
+        protocol: tcp
+        mode: host
+      - target: 53
+        published: {{ ports_dns }}
+        protocol: udp
+        mode: host
+      - target: 123
+        published: {{ ports_ntp }}
+        protocol: udp
+        mode: host
+      {% else %}
+      - "{{ ports_dns }}:53/tcp"
+      - "{{ ports_dns }}:53/udp"
+      - "{{ ports_ntp }}:123/udp"
+      {% endif %}
+    {% endif %}
+    {#
+      Volume configuration for persistent data
+      - When volume_mode is 'mount': bind mount from host path
+      - When volume_mode is 'local', 'nfs', or empty: use docker-managed volumes
+    #}
+    volumes:
+      {% if volume_mode == 'mount' %}
+      - {{ volume_mount_path }}/dnsmasq:/etc/dnsmasq.d:rw
+      - {{ volume_mount_path }}/pihole:/etc/pihole:rw
+      {% else %}
+      - {{ service_name }}-dnsmasq:/etc/dnsmasq.d
+      - {{ service_name }}-pihole:/etc/pihole
+      {% endif %}
+    {#
+      Required capabilities:
+      - NET_ADMIN: For DHCP and routing table operations
+      - SYS_TIME: For NTP functionality
+    #}
+    cap_add:
+      - NET_ADMIN
+      - SYS_TIME
+    {#
+      When swarm_enabled is set, use Docker secrets for admin password
+    #}
+    {% if swarm_enabled %}
+    secrets:
+      - {{ service_name }}_webpassword
+    {% endif %}
+    {#
+      Deploy configuration for Swarm mode:
+      - Single replica with node placement constraint (Pi-hole doesn't support multi-replica)
+      - Multiple instances would conflict with DNS/DHCP services
+      - Traefik: Labels for reverse proxy integration (Swarm mode)
+      Note: For macvlan in Swarm, create config-only networks on each node first, then use --scope swarm
+    #}
+    {% if swarm_enabled %}
+    deploy:
+      mode: replicated
+      replicas: 1
+      placement:
+        constraints:
+          - node.hostname == {{ swarm_placement_host }}
+      restart_policy:
+        condition: on-failure
+      {#
+        When traefik_enabled is set in swarm mode, add traefik labels
+        (optionally enable TLS if traefik_tls_enabled is set)
+      #}
+      {% if traefik_enabled %}
+      labels:
+        - traefik.enable=true
+        - traefik.docker.network={{ traefik_network }}
+        - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=80
+        - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
+        - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+        - traefik.http.routers.{{ service_name }}-http.entrypoints=web
+        {% if traefik_tls_enabled %}
+        - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
+        - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+        - traefik.http.routers.{{ service_name }}-https.entrypoints=websecure
+        - traefik.http.routers.{{ service_name }}-https.tls=true
+        - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
+        {% endif %}
+      {% endif %}
+    {% endif %}
+    {#
+      When traefik_enabled is set, and not running in swarm mode, add traefik labels
+      (optionally enable TLS if traefik_tls_enabled is set)
+    #}
+    {% if traefik_enabled and not swarm_enabled %}
+    labels:
+      - traefik.enable=true
+      - traefik.docker.network={{ traefik_network }}
+      - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=80
+      - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
+      - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+      - traefik.http.routers.{{ service_name }}-http.entrypoints=web
+      {% if traefik_tls_enabled %}
+      - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
+      - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+      - traefik.http.routers.{{ service_name }}-https.entrypoints=websecure
+      - traefik.http.routers.{{ service_name }}-https.tls=true
+      - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
+      {% endif %}
+    {% endif %}
+
 {#
 {#
-  Pi-hole Docker Compose Configuration
+  When swarm_enabled is set, define Docker secret for admin password
 #}
 #}
-include:
-  - services/pihole.yaml
-  {% if network_mode == 'bridge' or network_mode == 'macvlan' or traefik_enabled %}
-  - common/networks.yaml
+{% if swarm_enabled %}
+secrets:
+  {{ service_name }}_webpassword:
+    file: ./.env.secret.webpassword
+{% endif %}
+
+{#
+  Volume definitions:
+  - When volume_mode is 'local' (default): use docker-managed local volumes
+  - When volume_mode is 'nfs': configure NFS-backed volumes
+  - When volume_mode is 'mount': no volume definition needed (bind mounts used directly)
+#}
+{% if volume_mode == 'local' %}
+volumes:
+  {{ service_name }}-dnsmasq:
+    driver: local
+  {{ service_name }}-pihole:
+    driver: local
+{% elif volume_mode == 'nfs' %}
+volumes:
+  {{ service_name }}-dnsmasq:
+    driver: local
+    driver_opts:
+      type: nfs
+      o: addr={{ volume_nfs_server }},{{ volume_nfs_options }}
+      device: ":{{ volume_nfs_path }}/dnsmasq"
+  {{ service_name }}-pihole:
+    driver: local
+    driver_opts:
+      type: nfs
+      o: addr={{ volume_nfs_server }},{{ volume_nfs_options }}
+      device: ":{{ volume_nfs_path }}/pihole"
+{% endif %}
+
+{#
+  Network definitions (only when needed):
+  - When network_mode is empty: no definition needed (uses Docker's default bridge)
+  - When network_mode is 'bridge': define custom bridge network
+  - When network_mode is 'macvlan': configure macvlan with static IP (for Compose mode)
+    Note: In Swarm mode, macvlan networks must be created manually with config-only networks on each node
+  - When swarm_enabled: use overlay network for multi-host communication
+  - Traefik network: always external (managed by Traefik)
+#}
+{% if network_mode == 'bridge' or network_mode == 'macvlan' or traefik_enabled %}
+networks:
+  {% if network_mode == 'bridge' or network_mode == 'macvlan' %}
+  {{ network_name }}:
+    {% if network_external %}
+    external: true
+    {% else %}
+    {% if network_mode == 'macvlan' %}
+    driver: macvlan
+    driver_opts:
+      parent: {{ network_macvlan_parent_interface }}
+    ipam:
+      config:
+        - subnet: {{ network_macvlan_subnet }}
+          gateway: {{ network_macvlan_gateway }}
+    name: {{ network_name }}
+    {% elif swarm_enabled %}
+    driver: overlay
+    attachable: true
+    {% else %}
+    driver: bridge
+    {% endif %}
+    {% endif %}
   {% endif %}
   {% endif %}
-  - common/volumes.yaml
-  {% if swarm_enabled %}
-  - common/secrets.yaml
+  {% if traefik_enabled %}
+  {{ traefik_network }}:
+    external: true
   {% endif %}
   {% endif %}
+{% endif %}

+ 0 - 266
library/compose/pihole/compose.yaml.j2.backup

@@ -1,266 +0,0 @@
----
-services:
-  {{ service_name }}:
-    image: docker.io/pihole/pihole:2025.11.0
-    {#
-      If not in swarm mode, check whether container_name is set and apply restart policy,
-      else swarm mode handles restarts via deploy.restart_policy
-    #}
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    {% if container_name %}
-    container_name: {{ container_name }}
-    {% endif %}
-    {% endif %}
-    {#
-      Set container hostname (Pi-hole requires this for proper operation)
-    #}
-    {% if container_hostname %}
-    hostname: {{ container_hostname }}
-    {% endif %}
-    {#
-      Environment variables for Pi-hole configuration
-      - TZ: Timezone for proper log rotation
-      - PIHOLE_UID/GID: User/group for file permissions
-      - WEBPASSWORD: Admin password (from env file in compose mode, from secret in swarm mode)
-      - FTLCONF_dns_listeningMode: In bridge mode, listen on all interfaces
-    #}
-    environment:
-      - TZ={{ container_timezone }}
-      - PIHOLE_UID={{ user_uid }}
-      - PIHOLE_GID={{ user_gid }}
-      {% if swarm_enabled %}
-      - WEBPASSWORD_FILE={{ service_name }}_webpassword
-      {% else %}
-      - FTLCONF_webserver_api_password=${WEBPASSWORD}
-      {% endif %}
-      {% if network_mode == 'bridge' %}
-      - FTLCONF_dns_listeningMode=all
-      {% endif %}
-    {#
-      Network configuration based on network_mode:
-      - 'host': Use host networking (direct access to host network stack, not supported in Swarm)
-      - 'bridge': Custom bridge network (default Docker networking)
-      - 'macvlan': Container gets its own MAC/IP on physical network (requires external macvlan network setup in Swarm)
-      - '' (empty): Uses Docker's default bridge network
-      When traefik is enabled, always add traefik network
-    #}
-    {% if network_mode == 'host' %}
-    network_mode: host
-    {% elif network_mode == 'bridge' or network_mode == 'macvlan' or traefik_enabled %}
-    networks:
-      {% if traefik_enabled %}
-      {{ traefik_network }}:
-      {% endif %}
-      {% if network_mode == 'macvlan' %}
-      {{ network_name }}:
-        ipv4_address: {{ network_macvlan_ipv4_address }}
-      {% elif network_mode == 'bridge' %}
-      {{ network_name }}:
-      {% endif %}
-    {% endif %}
-    {#
-      Port mappings when in bridge mode (or empty, which defaults to bridge)
-      - HTTP/HTTPS: Web interface (only if Traefik is disabled)
-      - DNS: Port 53 TCP/UDP (always exposed, even with Traefik, since DNS can't be proxied)
-      - NTP: Port 123 UDP (network time protocol, always exposed)
-      Note: Swarm mode uses 'host' mode for port publishing to avoid port conflicts
-      Note: Host and macvlan modes don't need port mappings (direct network access)
-    #}
-    {% if network_mode == '' or network_mode == 'bridge' or traefik_enabled %}
-    ports:
-      {% if not traefik_enabled %}
-      {% if swarm_enabled %}
-      - target: 80
-        published: {{ ports_http }}
-        protocol: tcp
-        mode: host
-      - target: 443
-        published: {{ ports_https }}
-        protocol: tcp
-        mode: host
-      {% else %}
-      - "{{ ports_http }}:80/tcp"
-      - "{{ ports_https }}:443/tcp"
-      {% endif %}
-      {% endif %}
-      {% if swarm_enabled %}
-      - target: 53
-        published: {{ ports_dns }}
-        protocol: tcp
-        mode: host
-      - target: 53
-        published: {{ ports_dns }}
-        protocol: udp
-        mode: host
-      - target: 123
-        published: {{ ports_ntp }}
-        protocol: udp
-        mode: host
-      {% else %}
-      - "{{ ports_dns }}:53/tcp"
-      - "{{ ports_dns }}:53/udp"
-      - "{{ ports_ntp }}:123/udp"
-      {% endif %}
-    {% endif %}
-    {#
-      Volume configuration for persistent data
-      - When volume_mode is 'mount': bind mount from host path
-      - When volume_mode is 'local', 'nfs', or empty: use docker-managed volumes
-    #}
-    volumes:
-      {% if volume_mode == 'mount' %}
-      - {{ volume_mount_path }}/dnsmasq:/etc/dnsmasq.d:rw
-      - {{ volume_mount_path }}/pihole:/etc/pihole:rw
-      {% else %}
-      - {{ service_name }}-dnsmasq:/etc/dnsmasq.d
-      - {{ service_name }}-pihole:/etc/pihole
-      {% endif %}
-    {#
-      Required capabilities:
-      - NET_ADMIN: For DHCP and routing table operations
-      - SYS_TIME: For NTP functionality
-    #}
-    cap_add:
-      - NET_ADMIN
-      - SYS_TIME
-    {#
-      When swarm_enabled is set, use Docker secrets for admin password
-    #}
-    {% if swarm_enabled %}
-    secrets:
-      - {{ service_name }}_webpassword
-    {% endif %}
-    {#
-      Deploy configuration for Swarm mode:
-      - Single replica with node placement constraint (Pi-hole doesn't support multi-replica)
-      - Multiple instances would conflict with DNS/DHCP services
-      - Traefik: Labels for reverse proxy integration (Swarm mode)
-      Note: For macvlan in Swarm, create config-only networks on each node first, then use --scope swarm
-    #}
-    {% if swarm_enabled %}
-    deploy:
-      mode: replicated
-      replicas: 1
-      placement:
-        constraints:
-          - node.hostname == {{ swarm_placement_host }}
-      restart_policy:
-        condition: on-failure
-      {#
-        When traefik_enabled is set in swarm mode, add traefik labels
-        (optionally enable TLS if traefik_tls_enabled is set)
-      #}
-      {% if traefik_enabled %}
-      labels:
-        - traefik.enable=true
-        - traefik.docker.network={{ traefik_network }}
-        - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=80
-        - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-        {% if traefik_tls_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-        - traefik.http.routers.{{ service_name }}-https.tls=true
-        - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-        {% endif %}
-      {% endif %}
-    {% endif %}
-    {#
-      When traefik_enabled is set, and not running in swarm mode, add traefik labels
-      (optionally enable TLS if traefik_tls_enabled is set)
-    #}
-    {% if traefik_enabled and not swarm_enabled %}
-    labels:
-      - traefik.enable=true
-      - traefik.docker.network={{ traefik_network }}
-      - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=80
-      - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-      {% if traefik_tls_enabled %}
-      - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-      - traefik.http.routers.{{ service_name }}-https.tls=true
-      - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-      {% endif %}
-    {% endif %}
-
-{#
-  When swarm_enabled is set, define Docker secret for admin password
-#}
-{% if swarm_enabled %}
-secrets:
-  {{ service_name }}_webpassword:
-    file: ./.env.secret.webpassword
-{% endif %}
-
-{#
-  Volume definitions:
-  - When volume_mode is 'local' (default): use docker-managed local volumes
-  - When volume_mode is 'nfs': configure NFS-backed volumes
-  - When volume_mode is 'mount': no volume definition needed (bind mounts used directly)
-#}
-{% if volume_mode == 'local' %}
-volumes:
-  {{ service_name }}-dnsmasq:
-    driver: local
-  {{ service_name }}-pihole:
-    driver: local
-{% elif volume_mode == 'nfs' %}
-volumes:
-  {{ service_name }}-dnsmasq:
-    driver: local
-    driver_opts:
-      type: nfs
-      o: addr={{ volume_nfs_server }},{{ volume_nfs_options }}
-      device: ":{{ volume_nfs_path }}/dnsmasq"
-  {{ service_name }}-pihole:
-    driver: local
-    driver_opts:
-      type: nfs
-      o: addr={{ volume_nfs_server }},{{ volume_nfs_options }}
-      device: ":{{ volume_nfs_path }}/pihole"
-{% endif %}
-
-{#
-  Network definitions (only when needed):
-  - When network_mode is empty: no definition needed (uses Docker's default bridge)
-  - When network_mode is 'bridge': define custom bridge network
-  - When network_mode is 'macvlan': configure macvlan with static IP (for Compose mode)
-    Note: In Swarm mode, macvlan networks must be created manually with config-only networks on each node
-  - When swarm_enabled: use overlay network for multi-host communication
-  - Traefik network: always external (managed by Traefik)
-#}
-{% if network_mode == 'bridge' or network_mode == 'macvlan' or traefik_enabled %}
-networks:
-  {% if network_mode == 'bridge' or network_mode == 'macvlan' %}
-  {{ network_name }}:
-    {% if network_external %}
-    external: true
-    {% else %}
-    {% if network_mode == 'macvlan' %}
-    driver: macvlan
-    driver_opts:
-      parent: {{ network_macvlan_parent_interface }}
-    ipam:
-      config:
-        - subnet: {{ network_macvlan_subnet }}
-          gateway: {{ network_macvlan_gateway }}
-    name: {{ network_name }}
-    {% elif swarm_enabled %}
-    driver: overlay
-    attachable: true
-    {% else %}
-    driver: bridge
-    {% endif %}
-    {% endif %}
-  {% endif %}
-  {% if traefik_enabled %}
-  {{ traefik_network }}:
-    external: true
-  {% endif %}
-{% endif %}

+ 0 - 133
library/compose/pihole/services/pihole.yaml.j2

@@ -1,133 +0,0 @@
-{#
-  Pi-hole: Network-wide ad blocking and DNS privacy
-  Provides DNS, DHCP, and ad blocking services
-#}
-services:
-  {{ service_name }}:
-    image: docker.io/pihole/pihole:2025.11.0
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    {% if container_name %}
-    container_name: {{ container_name }}
-    {% endif %}
-    {% endif %}
-    {% if container_hostname %}
-    hostname: {{ container_hostname }}
-    {% endif %}
-    environment:
-      - TZ={{ container_timezone }}
-      - PIHOLE_UID={{ user_uid }}
-      - PIHOLE_GID={{ user_gid }}
-      {% if swarm_enabled %}
-      - WEBPASSWORD_FILE={{ service_name }}_webpassword
-      {% else %}
-      - FTLCONF_webserver_api_password=${WEBPASSWORD}
-      {% endif %}
-      {% if network_mode == 'bridge' %}
-      - FTLCONF_dns_listeningMode=all
-      {% endif %}
-    {% if network_mode == 'host' %}
-    network_mode: host
-    {% elif network_mode == 'bridge' or network_mode == 'macvlan' or traefik_enabled %}
-    networks:
-      {% if traefik_enabled %}
-      {{ traefik_network }}:
-      {% endif %}
-      {% if network_mode == 'macvlan' %}
-      {{ network_name }}:
-        ipv4_address: {{ network_macvlan_ipv4_address }}
-      {% elif network_mode == 'bridge' %}
-      {{ network_name }}:
-      {% endif %}
-    {% endif %}
-    {% if network_mode == '' or network_mode == 'bridge' or traefik_enabled %}
-    ports:
-      {% if not traefik_enabled %}
-      {% if swarm_enabled %}
-      - target: 80
-        published: {{ ports_http }}
-        protocol: tcp
-        mode: host
-      - target: 443
-        published: {{ ports_https }}
-        protocol: tcp
-        mode: host
-      {% else %}
-      - "{{ ports_http }}:80/tcp"
-      - "{{ ports_https }}:443/tcp"
-      {% endif %}
-      {% endif %}
-      {% if swarm_enabled %}
-      - target: 53
-        published: {{ ports_dns }}
-        protocol: tcp
-        mode: host
-      - target: 53
-        published: {{ ports_dns }}
-        protocol: udp
-        mode: host
-      - target: 123
-        published: {{ ports_ntp }}
-        protocol: udp
-        mode: host
-      {% else %}
-      - "{{ ports_dns }}:53/tcp"
-      - "{{ ports_dns }}:53/udp"
-      - "{{ ports_ntp }}:123/udp"
-      {% endif %}
-    {% endif %}
-    volumes:
-      {% if volume_mode == 'mount' %}
-      - {{ volume_mount_path }}/dnsmasq:/etc/dnsmasq.d:rw
-      - {{ volume_mount_path }}/pihole:/etc/pihole:rw
-      {% else %}
-      - {{ service_name }}-dnsmasq:/etc/dnsmasq.d
-      - {{ service_name }}-pihole:/etc/pihole
-      {% endif %}
-    cap_add:
-      - NET_ADMIN
-      - SYS_TIME
-    {% if swarm_enabled %}
-    secrets:
-      - {{ service_name }}_webpassword
-    deploy:
-      mode: replicated
-      replicas: 1
-      placement:
-        constraints:
-          - node.hostname == {{ swarm_placement_host }}
-      restart_policy:
-        condition: on-failure
-      {% if traefik_enabled %}
-      labels:
-        - traefik.enable=true
-        - traefik.docker.network={{ traefik_network }}
-        - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=80
-        - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-        {% if traefik_tls_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-        - traefik.http.routers.{{ service_name }}-https.tls=true
-        - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-        {% endif %}
-      {% endif %}
-    {% endif %}
-    {% if traefik_enabled and not swarm_enabled %}
-    labels:
-      - traefik.enable=true
-      - traefik.docker.network={{ traefik_network }}
-      - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=80
-      - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-      {% if traefik_tls_enabled %}
-      - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-      - traefik.http.routers.{{ service_name }}-https.tls=true
-      - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-      {% endif %}
-    {% endif %}

+ 15 - 30
library/compose/pihole/template.yaml

@@ -4,54 +4,40 @@ schema: "1.2"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: pihole
+    id: pi-hole
   name: Pihole
   name: Pihole
   description: |
   description: |
     Network-wide advertisement and internet tracker blocking application that functions as a DNS blackhole.
     Network-wide advertisement and internet tracker blocking application that functions as a DNS blackhole.
     Provides DNS-level content filtering for all network devices, improving browsing performance, privacy, and security.
     Provides DNS-level content filtering for all network devices, improving browsing performance, privacy, and security.
     Supports custom blocklists, whitelists, and seamless integration with existing network infrastructure.
     Supports custom blocklists, whitelists, and seamless integration with existing network infrastructure.
-    ##  Swarm Deployment Warning
-    Pi-hole uses local storage and configuration files and does NOT support running multiple replicas.
+    ## Prerequisites
+    - :warning: Pi-hole uses local storage and configuration files and does NOT support running multiple replicas.
     This template enforces a single replica with node placement constraints to ensure stable DNS resolution.
     This template enforces a single replica with node placement constraints to ensure stable DNS resolution.
     ## References
     ## References
-    * **Project:** https://pi-hole.net/
-    * **Documentation:** https://docs.pi-hole.net/
-    * **GitHub:** https://github.com/pi-hole/pi-hole
+    - **Project:** https://pi-hole.net/
+    - **Documentation:** https://docs.pi-hole.net/
+    - **GitHub:** https://github.com/pi-hole/pi-hole
   version: 2025.11.0
   version: 2025.11.0
   author: Christian Lempa
   author: Christian Lempa
   date: '2025-11-05'
   date: '2025-11-05'
   tags:
   tags:
     - traefik
     - traefik
     - swarm
     - swarm
-    - network_modes
-    - volume_modes
-  next_steps: |
-    ### 1. Deploy the Service
-    {% if swarm_enabled -%}
-    Deploy to Docker Swarm:
+    - network
+    - volume
+  next_steps: |-
+    Log in with your initial admin user:
     ```bash
     ```bash
-    docker stack deploy -c compose.yaml pihole
+    Username: admin
+    Password: {{ webpassword }}
     ```
     ```
-    {% else -%}
-    Start Pi-hole using Docker Compose:
-    ```bash
-    docker compose up -d
-    ```
-    {% endif -%}
-    ### 2. Access the Web Interface
-    {% if traefik_enabled -%}
-    * Navigate to: **https://{{ traefik_host }}/admin**
-    {% else -%}
-    * Navigate to: **http://localhost:{{ ports_http }}/admin**
-    {% endif -%}
-    * Login using the admin password (check `.env.secret` file).
 spec:
 spec:
   general:
   general:
     vars:
     vars:
       service_name:
       service_name:
-        default: "pihole"
+        default: pihole
       container_name:
       container_name:
-        default: "pihole"
+        default: pihole
   admin_settings:
   admin_settings:
     description: "Admin Pi-hole Settings"
     description: "Admin Pi-hole Settings"
     required: true
     required: true
@@ -60,7 +46,6 @@ spec:
         description: "Web interface admin password"
         description: "Web interface admin password"
         type: str
         type: str
         sensitive: true
         sensitive: true
-        default: ""
         autogenerated: true
         autogenerated: true
   ports:
   ports:
     vars:
     vars:
@@ -80,7 +65,7 @@ spec:
   traefik:
   traefik:
     vars:
     vars:
       traefik_host:
       traefik_host:
-        default: "pihole.home.arpa"
+        default: pihole
   network:
   network:
     vars:
     vars:
       network_mode:
       network_mode:

+ 42 - 98
library/compose/portainer/compose.yaml.j2

@@ -3,72 +3,46 @@ services:
     image: docker.io/portainer/portainer-ce:2.35.0-alpine
     image: docker.io/portainer/portainer-ce:2.35.0-alpine
     {% if not swarm_enabled %}
     {% if not swarm_enabled %}
     restart: {{ restart_policy }}
     restart: {{ restart_policy }}
-    container_name: {{ container_name }}
     {% endif %}
     {% endif %}
-    hostname: {{ container_hostname }}
     environment:
     environment:
       - TZ={{ container_timezone }}
       - TZ={{ container_timezone }}
-    {% if network_mode == 'host' %}
-    network_mode: host
-    {% else %}
+    {% if traefik_enabled %}
     networks:
     networks:
-      {% if traefik_enabled %}
       {{ traefik_network }}:
       {{ traefik_network }}:
-      {% endif %}
-      {% if network_mode == 'macvlan' %}
-      {{ network_name }}:
-        ipv4_address: {{ network_macvlan_ipv4_address }}
-      {% elif network_mode == 'bridge' %}
-      {{ network_name }}:
-      {% endif %}
     {% endif %}
     {% endif %}
-    {% if not traefik_enabled and network_mode == 'bridge' %}
     ports:
     ports:
-      {% if swarm_enabled %}
-      - target: 9000
-        published: {{ ports_http }}
-        protocol: tcp
-        mode: host
-      - target: 9443
-        published: {{ ports_https }}
-        protocol: tcp
-        mode: host
-      - target: 8000
-        published: {{ ports_edge }}
-        protocol: tcp
-        mode: host
-      {% else %}
+    {% if not traefik_enabled %}
       - "{{ ports_http }}:9000"
       - "{{ ports_http }}:9000"
       - "{{ ports_https }}:9443"
       - "{{ ports_https }}:9443"
-      - "{{ ports_edge }}:8000"
-      {% endif %}
     {% endif %}
     {% endif %}
+      - "{{ ports_edge }}:8000"
     volumes:
     volumes:
       - /run/docker.sock:/var/run/docker.sock
       - /run/docker.sock:/var/run/docker.sock
-      - portainer-data:/data
+      {% if volume_mode == 'mount' %}
+      - {{ volume_mount_path }}/data:/data
+      {% else %}
+      - {{ service_name }}_data:/data
+      {% endif %}
     {% if traefik_enabled and not swarm_enabled %}
     {% if traefik_enabled and not swarm_enabled %}
     labels:
     labels:
       - traefik.enable=true
       - traefik.enable=true
       - traefik.docker.network={{ traefik_network }}
       - traefik.docker.network={{ traefik_network }}
-      - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=9000
-      - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
+      - traefik.http.services.{{ service_name }}_web.loadBalancer.server.port=9000
+      - traefik.http.routers.{{ service_name }}_http.service={{ service_name }}_web
+      - traefik.http.routers.{{ service_name }}_http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+      - traefik.http.routers.{{ service_name }}_http.entrypoints=web
       {% if traefik_tls_enabled %}
       {% if traefik_tls_enabled %}
-      - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-      - traefik.http.routers.{{ service_name }}-https.tls=true
-      - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
+      - traefik.http.routers.{{ service_name }}_https.service={{ service_name }}_web
+      - traefik.http.routers.{{ service_name }}_https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+      - traefik.http.routers.{{ service_name }}_https.entrypoints=websecure
+      - traefik.http.routers.{{ service_name }}_https.tls=true
+      - traefik.http.routers.{{ service_name }}_https.tls.certresolver={{ traefik_tls_certresolver }}
       {% endif %}
       {% endif %}
     {% endif %}
     {% endif %}
-    {% if swarm_enabled or resources_enabled %}
+    {% if swarm_enabled %}
     deploy:
     deploy:
-      {% if swarm_enabled %}
-      mode: {{ swarm_placement_mode }}
-      {% if swarm_placement_mode == 'replicated' %}
-      replicas: {{ swarm_replicas }}
-      {% endif %}
+      mode: replicated
+      replicas: 1
       {% if swarm_placement_host %}
       {% if swarm_placement_host %}
       placement:
       placement:
         constraints:
         constraints:
@@ -76,70 +50,40 @@ services:
       {% endif %}
       {% endif %}
       restart_policy:
       restart_policy:
         condition: on-failure
         condition: on-failure
-      {% endif %}
-      {% if resources_enabled %}
-      resources:
-        limits:
-          cpus: '{{ resources_cpu_limit }}'
-          memory: {{ resources_memory_limit }}
-        {% if swarm_enabled %}
-        reservations:
-          cpus: '{{ resources_cpu_reservation }}'
-          memory: {{ resources_memory_reservation }}
-        {% endif %}
-      {% endif %}
-      {% if swarm_enabled and traefik_enabled %}
+      {% if traefik_enabled %}
       labels:
       labels:
         - traefik.enable=true
         - traefik.enable=true
         - traefik.docker.network={{ traefik_network }}
         - traefik.docker.network={{ traefik_network }}
-        - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=9000
-        - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-http.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
+        - traefik.http.services.{{ service_name }}_web.loadBalancer.server.port=9000
+        - traefik.http.routers.{{ service_name }}_http.service={{ service_name }}_web
+        - traefik.http.routers.{{ service_name }}_http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+        - traefik.http.routers.{{ service_name }}_http.entrypoints=web
         {% if traefik_tls_enabled %}
         {% if traefik_tls_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-        - traefik.http.routers.{{ service_name }}-https.tls=true
-        - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
+        - traefik.http.routers.{{ service_name }}_https.service={{ service_name }}_web
+        - traefik.http.routers.{{ service_name }}_https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
+        - traefik.http.routers.{{ service_name }}_https.entrypoints=websecure
+        - traefik.http.routers.{{ service_name }}_https.tls=true
+        - traefik.http.routers.{{ service_name }}_https.tls.certresolver={{ traefik_tls_certresolver }}
         {% endif %}
         {% endif %}
       {% endif %}
       {% endif %}
     {% endif %}
     {% endif %}
 
 
+{% if volume_mode == 'local' %}
+volumes:
+  {{ service_name }}_data:
+    driver: local
+{% elif volume_mode == 'nfs' %}
 volumes:
 volumes:
-  portainer-data:
+  {{ service_name }}_data:
     driver: local
     driver: local
+    driver_opts:
+      type: nfs
+      o: addr={{ volume_nfs_server }},nfsvers=4,{{ volume_nfs_options }}
+      device: ":{{ volume_nfs_path }}/data"
+{% endif %}
 
 
-{% if network_mode != 'host' %}
+{% if traefik_enabled %}
 networks:
 networks:
-  {{ network_name }}:
-    {% if network_external %}
-    external: true
-    {% else %}
-    {% if network_mode == 'macvlan' %}
-    driver: macvlan
-    driver_opts:
-      parent: {{ network_macvlan_parent_interface }}
-    ipam:
-      config:
-        - subnet: {{ network_macvlan_subnet }}
-          gateway: {{ network_macvlan_gateway }}
-    name: {{ network_name }}
-    {% elif swarm_enabled %}
-    driver: overlay
-    attachable: true
-    {% else %}
-    driver: bridge
-    {% endif %}
-    {% endif %}
-  {% if traefik_enabled %}
   {{ traefik_network }}:
   {{ traefik_network }}:
     external: true
     external: true
-  {% endif %}
 {% endif %}
 {% endif %}

+ 0 - 124
library/compose/portainer/compose.yaml.j2.final

@@ -1,124 +0,0 @@
-services:
-  {{ service_name }}:
-    image: docker.io/portainer/portainer-ce:2.35.0-alpine
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    container_name: {{ container_name }}
-    {% endif %}
-    hostname: {{ container_hostname }}
-    environment:
-      - TZ={{ container_timezone }}
-    {#
-      When traefik is enabled, add traefik network for reverse proxy access
-    #}
-    {% if traefik_enabled %}
-    networks:
-      {{ traefik_network }}:
-    {% endif %}
-      {% if network_mode == 'macvlan' %}
-      {{ network_name }}:
-        ipv4_address: {{ network_macvlan_ipv4_address }}
-      {% elif network_mode == 'bridge' %}
-      {{ network_name }}:
-      {% endif %}
-    {% endif %}
-    {% if not traefik_enabled and network_mode == 'bridge' %}
-    ports:
-      {% if swarm_enabled %}
-      - target: 9000
-        published: {{ ports_http }}
-        protocol: tcp
-        mode: host
-      - target: 9443
-        published: {{ ports_https }}
-        protocol: tcp
-        mode: host
-      - target: 8000
-        published: {{ ports_edge }}
-        protocol: tcp
-        mode: host
-      {% else %}
-      - "{{ ports_http }}:9000"
-      - "{{ ports_https }}:9443"
-      - "{{ ports_edge }}:8000"
-      {% endif %}
-    {% endif %}
-    volumes:
-      - /run/docker.sock:/var/run/docker.sock
-      - portainer-data:/data
-    {% if traefik_enabled and not swarm_enabled %}
-    labels:
-      - traefik.enable=true
-      - traefik.docker.network={{ traefik_network }}
-      - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=9000
-      - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-      {% if traefik_tls_enabled %}
-      - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-      - traefik.http.routers.{{ service_name }}-https.tls=true
-      - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-      {% endif %}
-    {% endif %}
-    {% if swarm_enabled or resources_enabled %}
-    deploy:
-      {% if swarm_enabled %}
-      mode: {{ swarm_placement_mode }}
-      {% if swarm_placement_mode == 'replicated' %}
-      replicas: {{ swarm_replicas }}
-      {% endif %}
-      {% if swarm_placement_host %}
-      placement:
-        constraints:
-          - node.hostname == {{ swarm_placement_host }}
-      {% endif %}
-      restart_policy:
-        condition: on-failure
-      {% endif %}
-      {% if resources_enabled %}
-      resources:
-        limits:
-          cpus: '{{ resources_cpu_limit }}'
-          memory: {{ resources_memory_limit }}
-        {% if swarm_enabled %}
-        reservations:
-          cpus: '{{ resources_cpu_reservation }}'
-          memory: {{ resources_memory_reservation }}
-        {% endif %}
-      {% endif %}
-      {% if swarm_enabled and traefik_enabled %}
-      labels:
-        - traefik.enable=true
-        - traefik.docker.network={{ traefik_network }}
-        - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=9000
-        - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-http.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
-        {% if traefik_tls_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-        - traefik.http.routers.{{ service_name }}-https.tls=true
-        - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
-        {% endif %}
-      {% endif %}
-    {% endif %}
-
-volumes:
-  portainer-data:
-    driver: local
-
-    {% endif %}
-  {% if traefik_enabled %}
-  {{ traefik_network }}:
-    external: true
-  {% endif %}
-{% endif %}

+ 0 - 118
library/compose/portainer/compose.yaml.j2.portfix

@@ -1,118 +0,0 @@
-services:
-  {{ service_name }}:
-    image: docker.io/portainer/portainer-ce:2.35.0-alpine
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    container_name: {{ container_name }}
-    {% endif %}
-    hostname: {{ container_hostname }}
-    environment:
-      - TZ={{ container_timezone }}
-    {#
-      When traefik is enabled, add traefik network for reverse proxy access
-    #}
-    {% if traefik_enabled %}
-    networks:
-      {{ traefik_network }}:
-    {% endif %}
-    {% endif %}
-    {% if not traefik_enabled and network_mode == 'bridge' %}
-    ports:
-      {% if swarm_enabled %}
-      - target: 9000
-        published: {{ ports_http }}
-        protocol: tcp
-        mode: host
-      - target: 9443
-        published: {{ ports_https }}
-        protocol: tcp
-        mode: host
-      - target: 8000
-        published: {{ ports_edge }}
-        protocol: tcp
-        mode: host
-      {% else %}
-      - "{{ ports_http }}:9000"
-      - "{{ ports_https }}:9443"
-      - "{{ ports_edge }}:8000"
-      {% endif %}
-    {% endif %}
-    volumes:
-      - /run/docker.sock:/var/run/docker.sock
-      - portainer-data:/data
-    {% if traefik_enabled and not swarm_enabled %}
-    labels:
-      - traefik.enable=true
-      - traefik.docker.network={{ traefik_network }}
-      - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=9000
-      - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-      {% if traefik_tls_enabled %}
-      - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-      - traefik.http.routers.{{ service_name }}-https.tls=true
-      - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-      {% endif %}
-    {% endif %}
-    {% if swarm_enabled or resources_enabled %}
-    deploy:
-      {% if swarm_enabled %}
-      mode: {{ swarm_placement_mode }}
-      {% if swarm_placement_mode == 'replicated' %}
-      replicas: {{ swarm_replicas }}
-      {% endif %}
-      {% if swarm_placement_host %}
-      placement:
-        constraints:
-          - node.hostname == {{ swarm_placement_host }}
-      {% endif %}
-      restart_policy:
-        condition: on-failure
-      {% endif %}
-      {% if resources_enabled %}
-      resources:
-        limits:
-          cpus: '{{ resources_cpu_limit }}'
-          memory: {{ resources_memory_limit }}
-        {% if swarm_enabled %}
-        reservations:
-          cpus: '{{ resources_cpu_reservation }}'
-          memory: {{ resources_memory_reservation }}
-        {% endif %}
-      {% endif %}
-      {% if swarm_enabled and traefik_enabled %}
-      labels:
-        - traefik.enable=true
-        - traefik.docker.network={{ traefik_network }}
-        - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=9000
-        - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-http.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
-        {% if traefik_tls_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-        - traefik.http.routers.{{ service_name }}-https.tls=true
-        - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
-        {% endif %}
-      {% endif %}
-    {% endif %}
-
-volumes:
-  portainer-data:
-    driver: local
-
-    {% endif %}
-  {% if traefik_enabled %}
-  {{ traefik_network }}:
-    external: true
-  {% endif %}
-{% endif %}

+ 11 - 17
library/compose/portainer/template.yaml

@@ -1,49 +1,43 @@
 ---
 ---
 kind: compose
 kind: compose
-schema: "1.2"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
     id: portainer
     id: portainer
   name: Portainer
   name: Portainer
-  description: >
+  description: |-
     Portainer is a powerful and user-friendly management tool for Docker and Kubernetes environments.
     Portainer is a powerful and user-friendly management tool for Docker and Kubernetes environments.
     It provides a simple web-based interface to manage containers, images, networks, and volumes,
     It provides a simple web-based interface to manage containers, images, networks, and volumes,
     making it easier to deploy and monitor applications.
     making it easier to deploy and monitor applications.
-
-
-    Project: https://www.portainer.io/
-
-    Documentation: https://docs.portainer.io/
-
-    GitHub: https://github.com/portainer/portainer
+    ## References
+    - **Project:** https://www.portainer.io/
+    - **Documentation:** https://docs.portainer.io/
+    - **GitHub:** https://github.com/portainer/portainer
   version: 2.35.0-alpine
   version: 2.35.0-alpine
   author: Christian Lempa
   author: Christian Lempa
   date: '2025-10-31'
   date: '2025-10-31'
   tags:
   tags:
     - traefik
     - traefik
+    - swarm
+    - volumes
+schema: 1.2
 spec:
 spec:
   general:
   general:
     vars:
     vars:
       service_name:
       service_name:
-        default: "portainer"
-      container_name:
-        default: "portainer"
+        default: portainer
   ports:
   ports:
     vars:
     vars:
       ports_http:
       ports_http:
-        description: "Host port for HTTP (9000)"
-        type: int
         default: 9000
         default: 9000
       ports_https:
       ports_https:
-        description: "Host port for HTTPS (9443)"
-        type: int
         default: 9443
         default: 9443
       ports_edge:
       ports_edge:
         description: "Host port for Edge agent (8000)"
         description: "Host port for Edge agent (8000)"
         type: int
         type: int
         default: 8000
         default: 8000
+        required: true
   traefik:
   traefik:
     vars:
     vars:
       traefik_host:
       traefik_host:
-        default: portainer.home.arpa
+        default: portainer

+ 2 - 2
library/compose/postgres/template.yaml

@@ -4,7 +4,7 @@ schema: "1.2"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: postgres
+    id: postgresql
   name: PostgreSQL
   name: PostgreSQL
   description: >
   description: >
     PostgreSQL is a powerful, open source object-relational database system with over 30 years of active development
     PostgreSQL is a powerful, open source object-relational database system with over 30 years of active development
@@ -21,7 +21,7 @@ metadata:
   date: '2025-09-28'
   date: '2025-09-28'
   tags:
   tags:
     - swarm
     - swarm
-    - volume_mode
+  draft: true
 spec:
 spec:
   general:
   general:
     vars:
     vars:

+ 2 - 23
library/compose/renovate/template.yaml

@@ -4,7 +4,7 @@ schema: "1.2"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: renovate
+    id: mend-renovate
   name: Renovate
   name: Renovate
   description: |-
   description: |-
     **Renovate** is an automated dependency update tool that creates pull requests for newer versions of dependencies.
     **Renovate** is an automated dependency update tool that creates pull requests for newer versions of dependencies.
@@ -28,28 +28,7 @@ metadata:
   tags:
   tags:
     - traefik
     - traefik
     - swarm
     - swarm
-  next_steps: |
-    ## Post-Installation Steps
-    {% if swarm_enabled -%}
-    1. **Deploy to Docker Swarm**:
-       ```bash
-       docker stack deploy -c compose.yaml {{ service_name }}
-       ```
-       Secrets are automatically created from the generated `.env.secret.*` files.
-    2. **Access the Web Interface**:
-       - {%- if traefik_enabled %}Visit: https://{{ traefik_host }}
-       {%- else %}Visit: http://<swarm-node-ip>:{{ ports_http }}{% endif %}
-    3. **Configure webhooks** in your Git platform to trigger Renovate on repository events
-    {% else -%}
-    1. **Deploy with Docker Compose**:
-       ```bash
-       docker compose up -d
-       ```
-    2. **Access the Web Interface**:
-       - {%- if traefik_enabled %}Visit: https://{{ traefik_host }}
-       {%- else %}Visit: http://localhost:{{ ports_http }}{% endif %}
-    3. **Configure webhooks** in your Git platform to trigger Renovate on repository events
-    {% endif -%}
+  draft: true
 spec:
 spec:
   general:
   general:
     vars:
     vars:

+ 2 - 15
library/compose/semaphoreui/.env.j2

@@ -1,16 +1,3 @@
-# Semaphore Secrets
-# Contains sensitive credentials
-
-# Database Password
 DATABASE_PASSWORD={{ database_password }}
 DATABASE_PASSWORD={{ database_password }}
-
-# Admin Password
-SEMAPHORE_ADMIN_PASSWORD={{ semaphore_admin_password }}
-
-# Access Key Encryption
-SEMAPHORE_ACCESS_KEY_ENCRYPTION={{ semaphore_access_key_encryption }}
-
-{% if email_enabled -%}
-# Email Password
-EMAIL_PASSWORD={{ email_password }}
-{% endif %}
+SEMAPHORE_ADMIN_PASSWORD={{ admin_pass }}
+SEMAPHORE_ACCESS_KEY_ENCRYPTION={{ secret_key }}

+ 48 - 147
library/compose/semaphoreui/compose.yaml.j2

@@ -1,204 +1,105 @@
 services:
 services:
   {{ service_name }}:
   {{ service_name }}:
     image: docker.io/semaphoreui/semaphore:v2.16.43
     image: docker.io/semaphoreui/semaphore:v2.16.43
-    {% if not swarm_enabled %}
     restart: {{ restart_policy }}
     restart: {{ restart_policy }}
-    container_name: {{ container_name }}
-    {% endif %}
-    hostname: {{ container_hostname }}
-    user: "{{ user_uid }}:{{ user_gid }}"
-    environment:
-      - TZ={{ container_timezone }}
-      {% if database_type == 'mysql' %}
-      - SEMAPHORE_DB_DIALECT=mysql
-      {% elif database_type == 'postgres' %}
-      - SEMAPHORE_DB_DIALECT=postgres
-      {% endif %}
+    environment:  
+      - SEMAPHORE_DB_DIALECT={{ database_type }}
       {% if database_external %}
       {% if database_external %}
       - SEMAPHORE_DB_HOST={{ database_host }}
       - SEMAPHORE_DB_HOST={{ database_host }}
       {% else %}
       {% else %}
-      - SEMAPHORE_DB_HOST={{ service_name }}-{{ database_type }}
+      - SEMAPHORE_DB_HOST={{ service_name }}_db
       {% endif %}
       {% endif %}
-      - SEMAPHORE_DB_PORT={% if database_type == 'postgres' %}5432{% else %}3306{% endif %}
       - SEMAPHORE_DB={{ database_name }}
       - SEMAPHORE_DB={{ database_name }}
       - SEMAPHORE_DB_USER={{ database_user }}
       - SEMAPHORE_DB_USER={{ database_user }}
       - SEMAPHORE_DB_PASS=${DATABASE_PASSWORD}
       - SEMAPHORE_DB_PASS=${DATABASE_PASSWORD}
-      - SEMAPHORE_ADMIN={{ semaphore_admin_name }}
-      - SEMAPHORE_ADMIN_NAME={{ semaphore_admin_name }}
-      - SEMAPHORE_ADMIN_EMAIL={{ semaphore_admin_email }}
+      - SEMAPHORE_ADMIN={{ admin_user }}
+      - SEMAPHORE_ADMIN_NAME={{ admin_name }}
+      - SEMAPHORE_ADMIN_EMAIL={{ admin_email }}
       - SEMAPHORE_ADMIN_PASSWORD=${SEMAPHORE_ADMIN_PASSWORD}
       - SEMAPHORE_ADMIN_PASSWORD=${SEMAPHORE_ADMIN_PASSWORD}
-      - SEMAPHORE_PLAYBOOK_PATH={{ semaphore_playbook_path }}
+      - SEMAPHORE_PLAYBOOK_PATH=/tmp/semaphore/
       - SEMAPHORE_ACCESS_KEY_ENCRYPTION=${SEMAPHORE_ACCESS_KEY_ENCRYPTION}
       - SEMAPHORE_ACCESS_KEY_ENCRYPTION=${SEMAPHORE_ACCESS_KEY_ENCRYPTION}
       - ANSIBLE_HOST_KEY_CHECKING={{ ansible_host_key_checking }}
       - ANSIBLE_HOST_KEY_CHECKING={{ ansible_host_key_checking }}
-      {% if email_enabled %}
-      - SEMAPHORE_EMAIL_SENDER={{ email_from }}
-      - SEMAPHORE_EMAIL_HOST={{ email_host }}
-      - SEMAPHORE_EMAIL_PORT={{ email_port }}
-      - SEMAPHORE_EMAIL_USERNAME={{ email_username }}
-      - SEMAPHORE_EMAIL_PASSWORD=${EMAIL_PASSWORD}
-      - SEMAPHORE_EMAIL_SECURE={{ email_use_tls }}
-      {% endif %}
+    {% if not database_external or traefik_enabled %}
+    networks:
+    {% if not database_external %}
+      - {{ service_name }}_backend
+    {% endif %}
+    {% if traefik_enabled %}
+      - {{ traefik_network }}
+    {% endif %}
     {% endif %}
     {% endif %}
     {% if not traefik_enabled %}
     {% if not traefik_enabled %}
     ports:
     ports:
-      {% if swarm_enabled %}
-      - target: 3000
-        published: {{ ports_http }}
-        protocol: tcp
-        mode: host
-      {% else %}
       - "{{ ports_http }}:3000"
       - "{{ ports_http }}:3000"
-      {% endif %}
     {% endif %}
     {% endif %}
-    volumes:
-      - ./inventory:/inventory:ro
-      - ./authorized-keys:/authorized-keys:ro
-      - ./config:/etc/semaphore:rw
-    {% if traefik_enabled and not swarm_enabled %}
+    {% if traefik_enabled %}
     labels:
     labels:
       - traefik.enable=true
       - traefik.enable=true
       - traefik.docker.network={{ traefik_network }}
       - traefik.docker.network={{ traefik_network }}
       - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=3000
       - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=3000
       - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
       - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
       - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
       - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
+      - traefik.http.routers.{{ service_name }}-http.entrypoints=web
       {% if traefik_tls_enabled %}
       {% if traefik_tls_enabled %}
       - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
       - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
       - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
       - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
+      - traefik.http.routers.{{ service_name }}-https.entrypoints=websecure
       - traefik.http.routers.{{ service_name }}-https.tls=true
       - traefik.http.routers.{{ service_name }}-https.tls=true
       - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
       - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
       {% endif %}
       {% endif %}
     {% endif %}
     {% endif %}
+    {% if not database_external %}
     depends_on:
     depends_on:
-      {% if database_type == 'mysql' %}
-      - {{ service_name }}-mysql
-      {% elif database_type == 'postgres' %}
-      - {{ service_name }}-postgres
-      {% endif %}
-    {% if swarm_enabled or resources_enabled %}
-    deploy:
-      {% if swarm_enabled %}
-      mode: {{ swarm_placement_mode }}
-      {% if swarm_placement_mode == 'replicated' %}
-      replicas: {{ swarm_replicas }}
-      {% endif %}
-      {% if swarm_placement_host %}
-      placement:
-        constraints:
-          - node.hostname == {{ swarm_placement_host }}
-      {% endif %}
-      restart_policy:
-        condition: on-failure
-      {% endif %}
-      {% if resources_enabled %}
-      resources:
-        limits:
-          cpus: '{{ resources_cpu_limit }}'
-          memory: {{ resources_memory_limit }}
-        {% if swarm_enabled %}
-        reservations:
-          cpus: '{{ resources_cpu_reservation }}'
-          memory: {{ resources_memory_reservation }}
-        {% endif %}
-      {% endif %}
-      {% if swarm_enabled and traefik_enabled %}
-      labels:
-        - traefik.enable=true
-        - traefik.docker.network={{ traefik_network }}
-        - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=3000
-        - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-http.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
-        {% if traefik_tls_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-        - traefik.http.routers.{{ service_name }}-https.tls=true
-        - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
-        {% endif %}
-      {% endif %}
+      - {{ service_name }}_db
     {% endif %}
     {% endif %}
 
 
-  {% if not database_external %}
-  {% if database_type == 'mysql' %}
-  {{ service_name }}-mysql:
-    image: docker.io/library/mysql:8.4
-    {% if not swarm_enabled %}
+  {% if not database_external and database_type == "postgres" %}
+  {{ service_name }}_db:
+    image: docker.io/library/postgres:17.6
     restart: {{ restart_policy }}
     restart: {{ restart_policy }}
-    container_name: {{ service_name }}-mysql
-    {% endif %}
     environment:
     environment:
-      {% if database_type == 'mysql' %}
-      - MYSQL_RANDOM_ROOT_PASSWORD=yes
-      - MYSQL_DATABASE={{ database_name }}
-      - MYSQL_USER={{ database_user }}
-      - MYSQL_PASSWORD=${DATABASE_PASSWORD}
-      - MYSQL_CHARSET=utf8mb4
-      - MYSQL_COLLATION=utf8mb4_unicode_ci
-      {% elif database_type == 'postgres' %}
-      - POSTGRES_DB={{ database_name }}
       - POSTGRES_USER={{ database_user }}
       - POSTGRES_USER={{ database_user }}
       - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
       - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
-      - POSTGRES_INITDB_ARGS=--encoding=UTF8 --locale=C
-      {% endif %}
+      - POSTGRES_DB={{ database_name }}
+    networks:
+      - {{ service_name }}_backend
     healthcheck:
     healthcheck:
-      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "{{ database_user }}", "-p{{ database_password }}"]
+      test: ["CMD-SHELL", "pg_isready -U {{ database_user }}"]
       start_period: 30s
       start_period: 30s
       interval: 10s
       interval: 10s
       timeout: 10s
       timeout: 10s
       retries: 5
       retries: 5
-    {% endif %}
     volumes:
     volumes:
-      - database_data:/var/lib/mysql
-  {% elif database_type == 'postgres' %}
-  {{ service_name }}-postgres:
-    image: docker.io/library/postgres:17.6
-    {% if not swarm_enabled %}
+      - {{ service_name }}_db:/var/lib/postgresql/data
+  {% elif not database_external and database_type == "mysql" %}
+  {{ service_name }}_db:
+    image: docker.io/library/mysql:8.1
     restart: {{ restart_policy }}
     restart: {{ restart_policy }}
-    container_name: {{ service_name }}-postgres
-    {% endif %}
     environment:
     environment:
-      {% if database_type == 'mysql' %}
-      - MYSQL_RANDOM_ROOT_PASSWORD=yes
-      - MYSQL_DATABASE={{ database_name }}
       - MYSQL_USER={{ database_user }}
       - MYSQL_USER={{ database_user }}
       - MYSQL_PASSWORD=${DATABASE_PASSWORD}
       - MYSQL_PASSWORD=${DATABASE_PASSWORD}
-      - MYSQL_CHARSET=utf8mb4
-      - MYSQL_COLLATION=utf8mb4_unicode_ci
-      {% elif database_type == 'postgres' %}
-      - POSTGRES_DB={{ database_name }}
-      - POSTGRES_USER={{ database_user }}
-      - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
-      - POSTGRES_INITDB_ARGS=--encoding=UTF8 --locale=C
-      {% endif %}
-    healthcheck:
-      test: ["CMD-SHELL", "pg_isready -U {{ database_user }}"]
-      start_period: 30s
-      interval: 10s
-      timeout: 10s
-      retries: 5
-    {% endif %}
+      - MYSQL_DATABASE={{ database_name }}
+      - MYSQL_ROOT_PASSWORD=${DATABASE_PASSWORD}
+    networks:
+      - {{ service_name }}_backend
     volumes:
     volumes:
-      - database_data:/var/lib/postgresql/data
-  {% endif %}
+      - {{ service_name }}_db:/var/lib/mysql
   {% endif %}
   {% endif %}
 
 
-    {% endif %}
+{% if not database_external %}
+volumes:
+  {{ service_name }}_db:
+    driver: local
+{% endif %}
+
+{% if not database_external or traefik_enabled %}
+networks:
+  {% if not database_external %}
+  {{ service_name }}_backend:
+    driver: bridge
+  {% endif %}
   {% if traefik_enabled %}
   {% if traefik_enabled %}
   {{ traefik_network }}:
   {{ traefik_network }}:
     external: true
     external: true
   {% endif %}
   {% endif %}
 {% endif %}
 {% endif %}
-
-volumes:
-  {% if not database_external %}
-  database_data:
-    driver: local
-  {% endif %}

+ 0 - 264
library/compose/semaphoreui/compose.yaml.j2.bak3

@@ -1,264 +0,0 @@
-services:
-  {{ service_name }}:
-    image: docker.io/semaphoreui/semaphore:v2.16.43
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    container_name: {{ container_name }}
-    {% endif %}
-    hostname: {{ container_hostname }}
-    user: "{{ user_uid }}:{{ user_gid }}"
-    environment:
-      - TZ={{ container_timezone }}
-      {% if database_type == 'mysql' %}
-      - SEMAPHORE_DB_DIALECT=mysql
-      {% elif database_type == 'postgres' %}
-      - SEMAPHORE_DB_DIALECT=postgres
-      {% endif %}
-      {% if database_external %}
-      - SEMAPHORE_DB_HOST={{ database_host }}
-      {% else %}
-      - SEMAPHORE_DB_HOST={{ service_name }}-{{ database_type }}
-      {% endif %}
-      - SEMAPHORE_DB_PORT={% if database_type == 'postgres' %}5432{% else %}3306{% endif %}
-      - SEMAPHORE_DB={{ database_name }}
-      - SEMAPHORE_DB_USER={{ database_user }}
-      - SEMAPHORE_DB_PASS=${DATABASE_PASSWORD}
-      - SEMAPHORE_ADMIN={{ semaphore_admin_name }}
-      - SEMAPHORE_ADMIN_NAME={{ semaphore_admin_name }}
-      - SEMAPHORE_ADMIN_EMAIL={{ semaphore_admin_email }}
-      - SEMAPHORE_ADMIN_PASSWORD=${SEMAPHORE_ADMIN_PASSWORD}
-      - SEMAPHORE_PLAYBOOK_PATH={{ semaphore_playbook_path }}
-      - SEMAPHORE_ACCESS_KEY_ENCRYPTION=${SEMAPHORE_ACCESS_KEY_ENCRYPTION}
-      - ANSIBLE_HOST_KEY_CHECKING={{ ansible_host_key_checking }}
-      {% if email_enabled %}
-      - SEMAPHORE_EMAIL_SENDER={{ email_from }}
-      - SEMAPHORE_EMAIL_HOST={{ email_host }}
-      - SEMAPHORE_EMAIL_PORT={{ email_port }}
-      - SEMAPHORE_EMAIL_USERNAME={{ email_username }}
-      - SEMAPHORE_EMAIL_PASSWORD=${EMAIL_PASSWORD}
-      - SEMAPHORE_EMAIL_SECURE={{ email_use_tls }}
-      {% endif %}
-    {% if network_mode == 'host' %}
-    network_mode: host
-    {% else %}
-    networks:
-      {% if traefik_enabled %}
-      {{ traefik_network }}:
-      {% endif %}
-      {% if network_mode == 'macvlan' %}
-      {{ network_name }}:
-        ipv4_address: {{ network_macvlan_ipv4_address }}
-      {% elif network_mode == 'bridge' %}
-      {{ network_name }}:
-      {% endif %}
-    {% endif %}
-    {% if not traefik_enabled and network_mode == 'bridge' %}
-    ports:
-      {% if swarm_enabled %}
-      - target: 3000
-        published: {{ ports_http }}
-        protocol: tcp
-        mode: host
-      {% else %}
-      - "{{ ports_http }}:3000"
-      {% endif %}
-    {% endif %}
-    volumes:
-      - ./inventory:/inventory:ro
-      - ./authorized-keys:/authorized-keys:ro
-      - ./config:/etc/semaphore:rw
-    {% if traefik_enabled and not swarm_enabled %}
-    labels:
-      - traefik.enable=true
-      - traefik.docker.network={{ traefik_network }}
-      - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=3000
-      - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-      {% if traefik_tls_enabled %}
-      - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-      - traefik.http.routers.{{ service_name }}-https.tls=true
-      - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-      {% endif %}
-    {% endif %}
-    depends_on:
-      {% if database_type == 'mysql' %}
-      - {{ service_name }}-mysql
-      {% elif database_type == 'postgres' %}
-      - {{ service_name }}-postgres
-      {% endif %}
-    {% if swarm_enabled or resources_enabled %}
-    deploy:
-      {% if swarm_enabled %}
-      mode: {{ swarm_placement_mode }}
-      {% if swarm_placement_mode == 'replicated' %}
-      replicas: {{ swarm_replicas }}
-      {% endif %}
-      {% if swarm_placement_host %}
-      placement:
-        constraints:
-          - node.hostname == {{ swarm_placement_host }}
-      {% endif %}
-      restart_policy:
-        condition: on-failure
-      {% endif %}
-      {% if resources_enabled %}
-      resources:
-        limits:
-          cpus: '{{ resources_cpu_limit }}'
-          memory: {{ resources_memory_limit }}
-        {% if swarm_enabled %}
-        reservations:
-          cpus: '{{ resources_cpu_reservation }}'
-          memory: {{ resources_memory_reservation }}
-        {% endif %}
-      {% endif %}
-      {% if swarm_enabled and traefik_enabled %}
-      labels:
-        - traefik.enable=true
-        - traefik.docker.network={{ traefik_network }}
-        - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=3000
-        - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-http.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
-        {% if traefik_tls_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-        - traefik.http.routers.{{ service_name }}-https.tls=true
-        - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
-        {% endif %}
-      {% endif %}
-    {% endif %}
-
-  {% if not database_external %}
-  {% if database_type == 'mysql' %}
-  {{ service_name }}-mysql:
-    image: docker.io/library/mysql:8.4
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    container_name: {{ service_name }}-mysql
-    {% endif %}
-    environment:
-      {% if database_type == 'mysql' %}
-      - MYSQL_RANDOM_ROOT_PASSWORD=yes
-      - MYSQL_DATABASE={{ database_name }}
-      - MYSQL_USER={{ database_user }}
-      - MYSQL_PASSWORD=${DATABASE_PASSWORD}
-      - MYSQL_CHARSET=utf8mb4
-      - MYSQL_COLLATION=utf8mb4_unicode_ci
-      {% elif database_type == 'postgres' %}
-      - POSTGRES_DB={{ database_name }}
-      - POSTGRES_USER={{ database_user }}
-      - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
-      - POSTGRES_INITDB_ARGS=--encoding=UTF8 --locale=C
-      {% endif %}
-    healthcheck:
-      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "{{ database_user }}", "-p{{ database_password }}"]
-      start_period: 30s
-      interval: 10s
-      timeout: 10s
-      retries: 5
-    {% if network_mode == 'host' %}
-    network_mode: host
-    {% else %}
-    networks:
-      {% if traefik_enabled %}
-      {{ traefik_network }}:
-      {% endif %}
-      {% if network_mode == 'macvlan' %}
-      {{ network_name }}:
-        ipv4_address: {{ network_macvlan_ipv4_address }}
-      {% elif network_mode == 'bridge' %}
-      {{ network_name }}:
-      {% endif %}
-    {% endif %}
-    volumes:
-      - database_data:/var/lib/mysql
-  {% elif database_type == 'postgres' %}
-  {{ service_name }}-postgres:
-    image: docker.io/library/postgres:17.6
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    container_name: {{ service_name }}-postgres
-    {% endif %}
-    environment:
-      {% if database_type == 'mysql' %}
-      - MYSQL_RANDOM_ROOT_PASSWORD=yes
-      - MYSQL_DATABASE={{ database_name }}
-      - MYSQL_USER={{ database_user }}
-      - MYSQL_PASSWORD=${DATABASE_PASSWORD}
-      - MYSQL_CHARSET=utf8mb4
-      - MYSQL_COLLATION=utf8mb4_unicode_ci
-      {% elif database_type == 'postgres' %}
-      - POSTGRES_DB={{ database_name }}
-      - POSTGRES_USER={{ database_user }}
-      - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
-      - POSTGRES_INITDB_ARGS=--encoding=UTF8 --locale=C
-      {% endif %}
-    healthcheck:
-      test: ["CMD-SHELL", "pg_isready -U {{ database_user }}"]
-      start_period: 30s
-      interval: 10s
-      timeout: 10s
-      retries: 5
-    {% if network_mode == 'host' %}
-    network_mode: host
-    {% else %}
-    networks:
-      {% if traefik_enabled %}
-      {{ traefik_network }}:
-      {% endif %}
-      {% if network_mode == 'macvlan' %}
-      {{ network_name }}:
-        ipv4_address: {{ network_macvlan_ipv4_address }}
-      {% elif network_mode == 'bridge' %}
-      {{ network_name }}:
-      {% endif %}
-    {% endif %}
-    volumes:
-      - database_data:/var/lib/postgresql/data
-  {% endif %}
-  {% endif %}
-
-{% if network_mode != 'host' %}
-networks:
-  {{ network_name }}:
-    {% if network_external %}
-    external: true
-    {% else %}
-    {% if network_mode == 'macvlan' %}
-    driver: macvlan
-    driver_opts:
-      parent: {{ network_macvlan_parent_interface }}
-    ipam:
-      config:
-        - subnet: {{ network_macvlan_subnet }}
-          gateway: {{ network_macvlan_gateway }}
-    name: {{ network_name }}
-    {% elif swarm_enabled %}
-    driver: overlay
-    attachable: true
-    {% else %}
-    driver: bridge
-    {% endif %}
-    {% endif %}
-  {% if traefik_enabled %}
-  {{ traefik_network }}:
-    external: true
-  {% endif %}
-{% endif %}
-
-volumes:
-  {% if not database_external %}
-  database_data:
-    driver: local
-  {% endif %}

+ 0 - 222
library/compose/semaphoreui/compose.yaml.j2.final

@@ -1,222 +0,0 @@
-services:
-  {{ service_name }}:
-    image: docker.io/semaphoreui/semaphore:v2.16.43
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    container_name: {{ container_name }}
-    {% endif %}
-    hostname: {{ container_hostname }}
-    user: "{{ user_uid }}:{{ user_gid }}"
-    environment:
-      - TZ={{ container_timezone }}
-      {% if database_type == 'mysql' %}
-      - SEMAPHORE_DB_DIALECT=mysql
-      {% elif database_type == 'postgres' %}
-      - SEMAPHORE_DB_DIALECT=postgres
-      {% endif %}
-      {% if database_external %}
-      - SEMAPHORE_DB_HOST={{ database_host }}
-      {% else %}
-      - SEMAPHORE_DB_HOST={{ service_name }}-{{ database_type }}
-      {% endif %}
-      - SEMAPHORE_DB_PORT={% if database_type == 'postgres' %}5432{% else %}3306{% endif %}
-      - SEMAPHORE_DB={{ database_name }}
-      - SEMAPHORE_DB_USER={{ database_user }}
-      - SEMAPHORE_DB_PASS=${DATABASE_PASSWORD}
-      - SEMAPHORE_ADMIN={{ semaphore_admin_name }}
-      - SEMAPHORE_ADMIN_NAME={{ semaphore_admin_name }}
-      - SEMAPHORE_ADMIN_EMAIL={{ semaphore_admin_email }}
-      - SEMAPHORE_ADMIN_PASSWORD=${SEMAPHORE_ADMIN_PASSWORD}
-      - SEMAPHORE_PLAYBOOK_PATH={{ semaphore_playbook_path }}
-      - SEMAPHORE_ACCESS_KEY_ENCRYPTION=${SEMAPHORE_ACCESS_KEY_ENCRYPTION}
-      - ANSIBLE_HOST_KEY_CHECKING={{ ansible_host_key_checking }}
-      {% if email_enabled %}
-      - SEMAPHORE_EMAIL_SENDER={{ email_from }}
-      - SEMAPHORE_EMAIL_HOST={{ email_host }}
-      - SEMAPHORE_EMAIL_PORT={{ email_port }}
-      - SEMAPHORE_EMAIL_USERNAME={{ email_username }}
-      - SEMAPHORE_EMAIL_PASSWORD=${EMAIL_PASSWORD}
-      - SEMAPHORE_EMAIL_SECURE={{ email_use_tls }}
-      {% endif %}
-      {% if network_mode == 'macvlan' %}
-      {{ network_name }}:
-        ipv4_address: {{ network_macvlan_ipv4_address }}
-      {% elif network_mode == 'bridge' %}
-      {{ network_name }}:
-      {% endif %}
-    {% endif %}
-    {% if not traefik_enabled and network_mode == 'bridge' %}
-    ports:
-      {% if swarm_enabled %}
-      - target: 3000
-        published: {{ ports_http }}
-        protocol: tcp
-        mode: host
-      {% else %}
-      - "{{ ports_http }}:3000"
-      {% endif %}
-    {% endif %}
-    volumes:
-      - ./inventory:/inventory:ro
-      - ./authorized-keys:/authorized-keys:ro
-      - ./config:/etc/semaphore:rw
-    {% if traefik_enabled and not swarm_enabled %}
-    labels:
-      - traefik.enable=true
-      - traefik.docker.network={{ traefik_network }}
-      - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=3000
-      - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-      {% if traefik_tls_enabled %}
-      - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-      - traefik.http.routers.{{ service_name }}-https.tls=true
-      - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-      {% endif %}
-    {% endif %}
-    depends_on:
-      {% if database_type == 'mysql' %}
-      - {{ service_name }}-mysql
-      {% elif database_type == 'postgres' %}
-      - {{ service_name }}-postgres
-      {% endif %}
-    {% if swarm_enabled or resources_enabled %}
-    deploy:
-      {% if swarm_enabled %}
-      mode: {{ swarm_placement_mode }}
-      {% if swarm_placement_mode == 'replicated' %}
-      replicas: {{ swarm_replicas }}
-      {% endif %}
-      {% if swarm_placement_host %}
-      placement:
-        constraints:
-          - node.hostname == {{ swarm_placement_host }}
-      {% endif %}
-      restart_policy:
-        condition: on-failure
-      {% endif %}
-      {% if resources_enabled %}
-      resources:
-        limits:
-          cpus: '{{ resources_cpu_limit }}'
-          memory: {{ resources_memory_limit }}
-        {% if swarm_enabled %}
-        reservations:
-          cpus: '{{ resources_cpu_reservation }}'
-          memory: {{ resources_memory_reservation }}
-        {% endif %}
-      {% endif %}
-      {% if swarm_enabled and traefik_enabled %}
-      labels:
-        - traefik.enable=true
-        - traefik.docker.network={{ traefik_network }}
-        - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=3000
-        - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-http.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
-        {% if traefik_tls_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-        - traefik.http.routers.{{ service_name }}-https.tls=true
-        - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
-        {% endif %}
-      {% endif %}
-    {% endif %}
-
-  {% if not database_external %}
-  {% if database_type == 'mysql' %}
-  {{ service_name }}-mysql:
-    image: docker.io/library/mysql:8.4
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    container_name: {{ service_name }}-mysql
-    {% endif %}
-    environment:
-      {% if database_type == 'mysql' %}
-      - MYSQL_RANDOM_ROOT_PASSWORD=yes
-      - MYSQL_DATABASE={{ database_name }}
-      - MYSQL_USER={{ database_user }}
-      - MYSQL_PASSWORD=${DATABASE_PASSWORD}
-      - MYSQL_CHARSET=utf8mb4
-      - MYSQL_COLLATION=utf8mb4_unicode_ci
-      {% elif database_type == 'postgres' %}
-      - POSTGRES_DB={{ database_name }}
-      - POSTGRES_USER={{ database_user }}
-      - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
-      - POSTGRES_INITDB_ARGS=--encoding=UTF8 --locale=C
-      {% endif %}
-    healthcheck:
-      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "{{ database_user }}", "-p{{ database_password }}"]
-      start_period: 30s
-      interval: 10s
-      timeout: 10s
-      retries: 5
-      {% if network_mode == 'macvlan' %}
-      {{ network_name }}:
-        ipv4_address: {{ network_macvlan_ipv4_address }}
-      {% elif network_mode == 'bridge' %}
-      {{ network_name }}:
-      {% endif %}
-    {% endif %}
-    volumes:
-      - database_data:/var/lib/mysql
-  {% elif database_type == 'postgres' %}
-  {{ service_name }}-postgres:
-    image: docker.io/library/postgres:17.6
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    container_name: {{ service_name }}-postgres
-    {% endif %}
-    environment:
-      {% if database_type == 'mysql' %}
-      - MYSQL_RANDOM_ROOT_PASSWORD=yes
-      - MYSQL_DATABASE={{ database_name }}
-      - MYSQL_USER={{ database_user }}
-      - MYSQL_PASSWORD=${DATABASE_PASSWORD}
-      - MYSQL_CHARSET=utf8mb4
-      - MYSQL_COLLATION=utf8mb4_unicode_ci
-      {% elif database_type == 'postgres' %}
-      - POSTGRES_DB={{ database_name }}
-      - POSTGRES_USER={{ database_user }}
-      - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
-      - POSTGRES_INITDB_ARGS=--encoding=UTF8 --locale=C
-      {% endif %}
-    healthcheck:
-      test: ["CMD-SHELL", "pg_isready -U {{ database_user }}"]
-      start_period: 30s
-      interval: 10s
-      timeout: 10s
-      retries: 5
-      {% if network_mode == 'macvlan' %}
-      {{ network_name }}:
-        ipv4_address: {{ network_macvlan_ipv4_address }}
-      {% elif network_mode == 'bridge' %}
-      {{ network_name }}:
-      {% endif %}
-    {% endif %}
-    volumes:
-      - database_data:/var/lib/postgresql/data
-  {% endif %}
-  {% endif %}
-
-    {% endif %}
-  {% if traefik_enabled %}
-  {{ traefik_network }}:
-    external: true
-  {% endif %}
-{% endif %}
-
-volumes:
-  {% if not database_external %}
-  database_data:
-    driver: local
-  {% endif %}

+ 0 - 204
library/compose/semaphoreui/compose.yaml.j2.portfix

@@ -1,204 +0,0 @@
-services:
-  {{ service_name }}:
-    image: docker.io/semaphoreui/semaphore:v2.16.43
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    container_name: {{ container_name }}
-    {% endif %}
-    hostname: {{ container_hostname }}
-    user: "{{ user_uid }}:{{ user_gid }}"
-    environment:
-      - TZ={{ container_timezone }}
-      {% if database_type == 'mysql' %}
-      - SEMAPHORE_DB_DIALECT=mysql
-      {% elif database_type == 'postgres' %}
-      - SEMAPHORE_DB_DIALECT=postgres
-      {% endif %}
-      {% if database_external %}
-      - SEMAPHORE_DB_HOST={{ database_host }}
-      {% else %}
-      - SEMAPHORE_DB_HOST={{ service_name }}-{{ database_type }}
-      {% endif %}
-      - SEMAPHORE_DB_PORT={% if database_type == 'postgres' %}5432{% else %}3306{% endif %}
-      - SEMAPHORE_DB={{ database_name }}
-      - SEMAPHORE_DB_USER={{ database_user }}
-      - SEMAPHORE_DB_PASS=${DATABASE_PASSWORD}
-      - SEMAPHORE_ADMIN={{ semaphore_admin_name }}
-      - SEMAPHORE_ADMIN_NAME={{ semaphore_admin_name }}
-      - SEMAPHORE_ADMIN_EMAIL={{ semaphore_admin_email }}
-      - SEMAPHORE_ADMIN_PASSWORD=${SEMAPHORE_ADMIN_PASSWORD}
-      - SEMAPHORE_PLAYBOOK_PATH={{ semaphore_playbook_path }}
-      - SEMAPHORE_ACCESS_KEY_ENCRYPTION=${SEMAPHORE_ACCESS_KEY_ENCRYPTION}
-      - ANSIBLE_HOST_KEY_CHECKING={{ ansible_host_key_checking }}
-      {% if email_enabled %}
-      - SEMAPHORE_EMAIL_SENDER={{ email_from }}
-      - SEMAPHORE_EMAIL_HOST={{ email_host }}
-      - SEMAPHORE_EMAIL_PORT={{ email_port }}
-      - SEMAPHORE_EMAIL_USERNAME={{ email_username }}
-      - SEMAPHORE_EMAIL_PASSWORD=${EMAIL_PASSWORD}
-      - SEMAPHORE_EMAIL_SECURE={{ email_use_tls }}
-      {% endif %}
-    {% endif %}
-    {% if not traefik_enabled and network_mode == 'bridge' %}
-    ports:
-      {% if swarm_enabled %}
-      - target: 3000
-        published: {{ ports_http }}
-        protocol: tcp
-        mode: host
-      {% else %}
-      - "{{ ports_http }}:3000"
-      {% endif %}
-    {% endif %}
-    volumes:
-      - ./inventory:/inventory:ro
-      - ./authorized-keys:/authorized-keys:ro
-      - ./config:/etc/semaphore:rw
-    {% if traefik_enabled and not swarm_enabled %}
-    labels:
-      - traefik.enable=true
-      - traefik.docker.network={{ traefik_network }}
-      - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=3000
-      - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-      {% if traefik_tls_enabled %}
-      - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-      - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-      - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-      - traefik.http.routers.{{ service_name }}-https.tls=true
-      - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-      {% endif %}
-    {% endif %}
-    depends_on:
-      {% if database_type == 'mysql' %}
-      - {{ service_name }}-mysql
-      {% elif database_type == 'postgres' %}
-      - {{ service_name }}-postgres
-      {% endif %}
-    {% if swarm_enabled or resources_enabled %}
-    deploy:
-      {% if swarm_enabled %}
-      mode: {{ swarm_placement_mode }}
-      {% if swarm_placement_mode == 'replicated' %}
-      replicas: {{ swarm_replicas }}
-      {% endif %}
-      {% if swarm_placement_host %}
-      placement:
-        constraints:
-          - node.hostname == {{ swarm_placement_host }}
-      {% endif %}
-      restart_policy:
-        condition: on-failure
-      {% endif %}
-      {% if resources_enabled %}
-      resources:
-        limits:
-          cpus: '{{ resources_cpu_limit }}'
-          memory: {{ resources_memory_limit }}
-        {% if swarm_enabled %}
-        reservations:
-          cpus: '{{ resources_cpu_reservation }}'
-          memory: {{ resources_memory_reservation }}
-        {% endif %}
-      {% endif %}
-      {% if swarm_enabled and traefik_enabled %}
-      labels:
-        - traefik.enable=true
-        - traefik.docker.network={{ traefik_network }}
-        - traefik.http.services.{{ service_name }}-web.loadBalancer.server.port=3000
-        - traefik.http.routers.{{ service_name }}-http.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-http.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-http.entrypoints={{ traefik_entrypoint }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-http.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
-        {% if traefik_tls_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.service={{ service_name }}-web
-        - traefik.http.routers.{{ service_name }}-https.rule=Host(`{{ traefik_host }}.{{ traefik_domain }}`)
-        - traefik.http.routers.{{ service_name }}-https.entrypoints={{ traefik_tls_entrypoint }}
-        - traefik.http.routers.{{ service_name }}-https.tls=true
-        - traefik.http.routers.{{ service_name }}-https.tls.certresolver={{ traefik_tls_certresolver }}
-        {% if authentik_enabled %}
-        - traefik.http.routers.{{ service_name }}-https.middlewares={{ authentik_traefik_middleware }}
-        {% endif %}
-        {% endif %}
-      {% endif %}
-    {% endif %}
-
-  {% if not database_external %}
-  {% if database_type == 'mysql' %}
-  {{ service_name }}-mysql:
-    image: docker.io/library/mysql:8.4
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    container_name: {{ service_name }}-mysql
-    {% endif %}
-    environment:
-      {% if database_type == 'mysql' %}
-      - MYSQL_RANDOM_ROOT_PASSWORD=yes
-      - MYSQL_DATABASE={{ database_name }}
-      - MYSQL_USER={{ database_user }}
-      - MYSQL_PASSWORD=${DATABASE_PASSWORD}
-      - MYSQL_CHARSET=utf8mb4
-      - MYSQL_COLLATION=utf8mb4_unicode_ci
-      {% elif database_type == 'postgres' %}
-      - POSTGRES_DB={{ database_name }}
-      - POSTGRES_USER={{ database_user }}
-      - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
-      - POSTGRES_INITDB_ARGS=--encoding=UTF8 --locale=C
-      {% endif %}
-    healthcheck:
-      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "{{ database_user }}", "-p{{ database_password }}"]
-      start_period: 30s
-      interval: 10s
-      timeout: 10s
-      retries: 5
-    {% endif %}
-    volumes:
-      - database_data:/var/lib/mysql
-  {% elif database_type == 'postgres' %}
-  {{ service_name }}-postgres:
-    image: docker.io/library/postgres:17.6
-    {% if not swarm_enabled %}
-    restart: {{ restart_policy }}
-    container_name: {{ service_name }}-postgres
-    {% endif %}
-    environment:
-      {% if database_type == 'mysql' %}
-      - MYSQL_RANDOM_ROOT_PASSWORD=yes
-      - MYSQL_DATABASE={{ database_name }}
-      - MYSQL_USER={{ database_user }}
-      - MYSQL_PASSWORD=${DATABASE_PASSWORD}
-      - MYSQL_CHARSET=utf8mb4
-      - MYSQL_COLLATION=utf8mb4_unicode_ci
-      {% elif database_type == 'postgres' %}
-      - POSTGRES_DB={{ database_name }}
-      - POSTGRES_USER={{ database_user }}
-      - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
-      - POSTGRES_INITDB_ARGS=--encoding=UTF8 --locale=C
-      {% endif %}
-    healthcheck:
-      test: ["CMD-SHELL", "pg_isready -U {{ database_user }}"]
-      start_period: 30s
-      interval: 10s
-      timeout: 10s
-      retries: 5
-    {% endif %}
-    volumes:
-      - database_data:/var/lib/postgresql/data
-  {% endif %}
-  {% endif %}
-
-    {% endif %}
-  {% if traefik_enabled %}
-  {{ traefik_network }}:
-    external: true
-  {% endif %}
-{% endif %}
-
-volumes:
-  {% if not database_external %}
-  database_data:
-    driver: local
-  {% endif %}

+ 60 - 88
library/compose/semaphoreui/template.yaml

@@ -1,117 +1,89 @@
 ---
 ---
 kind: compose
 kind: compose
-schema: "1.2"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: semaphoreui
+    id: semaphore-ui
   name: Semaphore UI
   name: Semaphore UI
-  description: >
+  description: |-
     Modern UI for Ansible automation with task scheduling and web-based management.
     Modern UI for Ansible automation with task scheduling and web-based management.
     Semaphore provides a beautiful web interface to run Ansible playbooks, manage
     Semaphore provides a beautiful web interface to run Ansible playbooks, manage
     inventories, and schedule automated tasks. Perfect for teams who want a
     inventories, and schedule automated tasks. Perfect for teams who want a
     user-friendly way to execute and monitor Ansible automation.
     user-friendly way to execute and monitor Ansible automation.
-
-
-    Project: https://www.semaphoreui.com/
-
-    Documentation: https://docs.semaphoreui.com/
-
-    GitHub: https://github.com/semaphoreui/semaphore
+    ## Prerequisites
+    - :info: SemaphoreUI supports multiple database backends. You can choose between SQLite (default),
+    PostgreSQL, or MySQL. SQLite is suitable for small deployments, while PostgreSQL and MySQL
+    are recommended for larger installations.
+    ## References
+    - **Project:** https://www.semaphoreui.com/
+    - **Documentation:** https://docs.semaphoreui.com/
+    - **GitHub:** https://github.com/semaphoreui/semaphore
   version: v2.16.43
   version: v2.16.43
   author: Christian Lempa
   author: Christian Lempa
   date: '2025-11-07'
   date: '2025-11-07'
   tags:
   tags:
     - traefik
     - traefik
-  next_steps: |
-    1. Start Semaphore UI:
-       docker compose up -d
-
-    2. Access the web interface:
-       {% if traefik_enabled -%}
-       - Via Traefik: https://{{ traefik_host }}
-       {% if not traefik_enabled and network_mode == 'bridge' %}- Direct access: http://localhost:{{ ports_http }}{% endif %}
-       {%- else -%}
-       - Open http://localhost:{{ ports_http }} in your browser
-       {%- endif %}
-
-    3. Login with your admin credentials:
-       - Username: {{ semaphore_admin_name }}
-       - Email: {{ semaphore_admin_email }}
-       - Password: {{ semaphore_admin_password }}
-
-    4. Getting started:
-       - Add SSH keys for accessing your managed hosts
-       - Create your first project and link it to a Git repository
-       - Add inventories (static or dynamic)
-       - Create task templates from your Ansible playbooks
-       - Schedule or run tasks on-demand
-
-    5. Security recommendations:
-       - Change the admin password after first login
-       - Enable two-factor authentication in user settings
-       - Review user permissions and create additional users
-       - Use SSH key authentication for Ansible connections
-
-    For more information, visit: https://docs.semaphoreui.com/
-
+    - database
+  next_steps: |-
+    Log in with your initial admin user:
+    ```bash
+    Username: {{ admin_user }}
+    Password: {{ admin_pass }}
+    ```
+schema: 1.2
 spec:
 spec:
   general:
   general:
     vars:
     vars:
       service_name:
       service_name:
-        default: "semaphore"
+        default: semaphoreui
       container_name:
       container_name:
-        default: "semaphore"
-  database:
-    required: true
-    vars:
-      database_type:
-        default: "mysql"
-      database_name:
-        default: "semaphore"
-      database_user:
-        default: "semaphore"
-  ports:
-    vars:
-      ports_http:
-        description: "Host port for web interface"
-        type: int
-        default: 3000
-  traefik:
-    vars:
-      traefik_host:
-        default: semaphoreui.home.arpa
-  semaphore:
-    description: "Configure Ansible Semaphore application settings"
-    required: true
-    vars:
-      semaphore_admin_name:
-        description: "Initial admin username"
-        type: str
-        default: "admin"
-      semaphore_admin_email:
-        description: "Admin email address"
+        default: semaphoreui
+      secret_key:
+        description: "Secret key for encrypting access keys"
         type: str
         type: str
-        default: "admin@home.arpa"
-      semaphore_admin_password:
-        description: "Initial admin password"
-        extra: "Leave empty for auto-generated 20-character secure password"
-        type: str
-        default: ""
         sensitive: true
         sensitive: true
         autogenerated: true
         autogenerated: true
-      semaphore_access_key_encryption:
-        description: "Encryption key for access keys storage"
-        extra: "Leave empty for auto-generated 32-character secure key"
+        required: true
+      admin_user:
+        description: "Administrator username"
+        type: str
+        required: true
+        default: admin
+      admin_name:
+        description: "Administrator full name"
+        type: str
+        required: true
+        default: Administrator
+      admin_email:
+        description: "Administrator email address"
+        type: str
+        required: true
+        default: admin@home.arpa
+      admin_pass:
+        description: "Administrator password"
         type: str
         type: str
-        default: ""
         sensitive: true
         sensitive: true
         autogenerated: true
         autogenerated: true
-      semaphore_playbook_path:
-        description: "Path for temporary playbook execution"
-        type: str
-        default: "/tmp/semaphore/"
+        required: true
       ansible_host_key_checking:
       ansible_host_key_checking:
         description: "Enable Ansible SSH host key checking"
         description: "Enable Ansible SSH host key checking"
         type: bool
         type: bool
-        default: false
+  ports:
+    vars:
+      ports_http:
+        default: 3000
+  traefik:
+    vars:
+      traefik_host:
+        default: semaphoreui
+  database:
+    vars:
+      database_type:
+        options:
+          - postgres
+          - mysql
+        default: mysql
+      database_name:
+        default: semaphore
+      database_user:
+        default: semaphore

+ 1 - 1
library/compose/traefik/compose.yaml.j2

@@ -1,7 +1,7 @@
 ---
 ---
 services:
 services:
   {{ service_name }}:
   {{ service_name }}:
-    image: docker.io/library/traefik:v3.5.4
+    image: docker.io/library/traefik:v3.6.4
     {% if not swarm_enabled %}
     {% if not swarm_enabled %}
     {% if container_name %}
     {% if container_name %}
     container_name: {{ container_name }}
     container_name: {{ container_name }}

+ 2 - 3
library/compose/traefik/template.yaml

@@ -9,13 +9,12 @@ metadata:
     - **Project:** https://traefik.io/
     - **Project:** https://traefik.io/
     - **Documentation:** https://doc.traefik.io/traefik/
     - **Documentation:** https://doc.traefik.io/traefik/
     - **GitHub:** https://github.com/traefik/traefik
     - **GitHub:** https://github.com/traefik/traefik
-  version: v3.5.4
+  version: v3.6.4
   author: Christian Lempa
   author: Christian Lempa
   date: "2025-11-05"
   date: "2025-11-05"
   tags:
   tags:
-    - authentik
     - swarm
     - swarm
-    - volume_mode
+    - volume
   icon:
   icon:
     provider: simpleicons
     provider: simpleicons
     id: traefikproxy
     id: traefikproxy

+ 2 - 1
library/compose/twingate-connector/template.yaml

@@ -4,7 +4,7 @@ schema: "1.2"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: twingate-connector
+    id: twingate
   name: Twingate_Connector
   name: Twingate_Connector
   description: >
   description: >
     The Twingate Connector is a lightweight software component that establishes secure connections between your private network and the
     The Twingate Connector is a lightweight software component that establishes secure connections between your private network and the
@@ -23,6 +23,7 @@ metadata:
   date: '2025-10-31'
   date: '2025-10-31'
   tags:
   tags:
     - swarm
     - swarm
+  draft: true
 spec:
 spec:
   general:
   general:
     vars:
     vars:

+ 2 - 1
library/compose/uptimekuma/template.yaml

@@ -4,7 +4,7 @@ schema: "1.2"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: uptimekuma
+    id: uptime-kuma
   name: Uptimekuma
   name: Uptimekuma
   description: >
   description: >
     Uptimekuma is a self-hosted monitoring tool that allows you to keep track of the uptime and performance of your websites and services.
     Uptimekuma is a self-hosted monitoring tool that allows you to keep track of the uptime and performance of your websites and services.
@@ -20,6 +20,7 @@ metadata:
   author: Christian Lempa
   author: Christian Lempa
   date: '2025-10-31'
   date: '2025-10-31'
   tags: []
   tags: []
+  draft: true
 spec:
 spec:
   general:
   general:
     vars:
     vars:

+ 1 - 1
library/compose/whoami/template.yaml

@@ -3,7 +3,7 @@ kind: compose
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: whoami
+    id: traefik
   name: Whoami
   name: Whoami
   description: |
   description: |
     A **simple web application** that displays information about the HTTP request it receives.
     A **simple web application** that displays information about the HTTP request it receives.

+ 2 - 2
library/helm/certmanager/template.yaml

@@ -16,8 +16,8 @@ metadata:
   date: "2025-01-11"
   date: "2025-01-11"
   tags: []
   tags: []
   icon:
   icon:
-    provider: simpleicons
-    id: letsencrypt
+    provider: selfh
+    id: lets-encrypt
   draft: true
   draft: true
   next_steps: ""
   next_steps: ""
 schema: "1.0"
 schema: "1.0"

+ 1 - 1
library/kubernetes/certmanager-certificate/template.yaml

@@ -4,7 +4,7 @@ schema: "1.0"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: certmanager-certificate
+    id: lets-encrypt
   name: Cert-Manager Certificate
   name: Cert-Manager Certificate
   description: >
   description: >
     Cert-manager Certificate resource for requesting TLS certificates from an Issuer or ClusterIssuer.
     Cert-manager Certificate resource for requesting TLS certificates from an Issuer or ClusterIssuer.

+ 1 - 1
library/kubernetes/certmanager-clusterissuer/template.yaml

@@ -4,7 +4,7 @@ schema: "1.0"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: certmanager-clusterissuer
+    id: lets-encrypt
   name: Cert-Manager ClusterIssuer (Cloudflare)
   name: Cert-Manager ClusterIssuer (Cloudflare)
   description: >
   description: >
     Cert-manager ClusterIssuer for automatic TLS certificate management with Let's Encrypt and Cloudflare DNS-01 challenge.
     Cert-manager ClusterIssuer for automatic TLS certificate management with Let's Encrypt and Cloudflare DNS-01 challenge.

+ 1 - 1
library/kubernetes/certmanager-issuer/template.yaml

@@ -4,7 +4,7 @@ schema: "1.0"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: certmanager-issuer
+    id: lets-encrypt
   name: Cert-Manager Issuer (Cloudflare)
   name: Cert-Manager Issuer (Cloudflare)
   description: >
   description: >
     Cert-manager Issuer for automatic TLS certificate management with Let's Encrypt and Cloudflare DNS-01 challenge.
     Cert-manager Issuer for automatic TLS certificate management with Let's Encrypt and Cloudflare DNS-01 challenge.

+ 1 - 1
library/kubernetes/traefik-ingressroute/template.yaml

@@ -4,7 +4,7 @@ schema: "1.0"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: traefik-ingressroute
+    id: traefik
   name: Traefik IngressRoute
   name: Traefik IngressRoute
   description: >
   description: >
     Traefik IngressRoute CRD for HTTP/HTTPS routing with advanced features.
     Traefik IngressRoute CRD for HTTP/HTTPS routing with advanced features.

+ 1 - 1
library/kubernetes/traefik-ingressroutetcp/template.yaml

@@ -4,7 +4,7 @@ schema: "1.0"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: traefik-ingressroutetcp
+    id: traefik
   name: Traefik IngressRouteTCP
   name: Traefik IngressRouteTCP
   description: >
   description: >
     Traefik IngressRouteTCP CRD for TCP routing (non-HTTP protocols).
     Traefik IngressRouteTCP CRD for TCP routing (non-HTTP protocols).

+ 2 - 2
library/kubernetes/traefik-middleware/template.yaml

@@ -16,8 +16,8 @@ metadata:
   date: "2025-01-11"
   date: "2025-01-11"
   tags: []
   tags: []
   icon:
   icon:
-    provider: simpleicons
-    id: traefikproxy
+    provider: selfh
+    id: traefik
   draft: false
   draft: false
   next_steps: ""
   next_steps: ""
 schema: "1.0"
 schema: "1.0"

+ 1 - 1
library/terraform/netbox-cluster-type/template.yaml

@@ -4,7 +4,7 @@ schema: "1.0"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: terraform
+    id: netbox
   name: NetBox Cluster Type
   name: NetBox Cluster Type
   description: >
   description: >
     Create NetBox cluster type for categorizing virtualization clusters.
     Create NetBox cluster type for categorizing virtualization clusters.

+ 1 - 1
library/terraform/netbox-cluster/template.yaml

@@ -4,7 +4,7 @@ schema: "1.0"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: terraform
+    id: netbox
   name: NetBox Cluster
   name: NetBox Cluster
   description: >
   description: >
     Create NetBox virtualization cluster for organizing virtual machines.
     Create NetBox virtualization cluster for organizing virtual machines.

+ 1 - 1
library/terraform/netbox-device-role/template.yaml

@@ -4,7 +4,7 @@ schema: "1.0"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: terraform
+    id: netbox
   name: NetBox Device Role
   name: NetBox Device Role
   description: >
   description: >
     Create NetBox device role for categorizing physical devices.
     Create NetBox device role for categorizing physical devices.

+ 1 - 1
library/terraform/netbox-device-type/template.yaml

@@ -4,7 +4,7 @@ schema: "1.0"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: terraform
+    id: netbox
   name: NetBox Device Type
   name: NetBox Device Type
   description: >
   description: >
     Create NetBox device type for hardware models.
     Create NetBox device type for hardware models.

+ 1 - 1
library/terraform/netbox-device/template.yaml

@@ -4,7 +4,7 @@ schema: "1.0"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: terraform
+    id: netbox
   name: NetBox Device
   name: NetBox Device
   description: >
   description: >
     Register a physical device in NetBox with automatic role, type, and manufacturer creation.
     Register a physical device in NetBox with automatic role, type, and manufacturer creation.

+ 1 - 1
library/terraform/netbox-manufacturer/template.yaml

@@ -4,7 +4,7 @@ schema: "1.0"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: terraform
+    id: netbox
   name: NetBox Manufacturer
   name: NetBox Manufacturer
   description: >
   description: >
     Create NetBox manufacturer for device hardware vendors.
     Create NetBox manufacturer for device hardware vendors.

+ 1 - 1
library/terraform/netbox-vm/template.yaml

@@ -4,7 +4,7 @@ schema: "1.0"
 metadata:
 metadata:
   icon:
   icon:
     provider: selfh
     provider: selfh
-    id: terraform
+    id: netbox
   name: NetBox Virtual Machine
   name: NetBox Virtual Machine
   description: >
   description: >
     Register a virtual machine in NetBox with cluster and site association.
     Register a virtual machine in NetBox with cluster and site association.