From 5b76b662cb9d06d86c108665def22caeac9f89dd Mon Sep 17 00:00:00 2001
From: Alexis Yushin <alexis@apexive.com>
Date: Thu, 24 Oct 2024 09:21:39 -0400
Subject: [PATCH 1/6] optional role for matrix-fluffygate

---
 docs/configuring-playbook-fluffygate.md       | 147 ++++++++++++++++++
 .../.claudesync/config.local.json             |   7 +
 .../matrix-fluffygate/defaults/main.yml       | 137 ++++++++++++++++
 .../matrix-fluffygate/tasks/install.yml       |  62 ++++++++
 roles/custom/matrix-fluffygate/tasks/main.yml |  20 +++
 .../matrix-fluffygate/tasks/uninstall.yml     |  25 +++
 .../tasks/validate_config.yml                 |  40 +++++
 .../templates/config.yaml.j2                  |  26 ++++
 .../matrix-fluffygate/templates/labels.j2     |  46 ++++++
 .../systemd/matrix-fluffygate.service.j2      |  51 ++++++
 setup.yml                                     |   1 +
 11 files changed, 562 insertions(+)
 create mode 100644 docs/configuring-playbook-fluffygate.md
 create mode 100644 roles/custom/matrix-fluffygate/.claudesync/config.local.json
 create mode 100644 roles/custom/matrix-fluffygate/defaults/main.yml
 create mode 100644 roles/custom/matrix-fluffygate/tasks/install.yml
 create mode 100644 roles/custom/matrix-fluffygate/tasks/main.yml
 create mode 100644 roles/custom/matrix-fluffygate/tasks/uninstall.yml
 create mode 100644 roles/custom/matrix-fluffygate/tasks/validate_config.yml
 create mode 100644 roles/custom/matrix-fluffygate/templates/config.yaml.j2
 create mode 100644 roles/custom/matrix-fluffygate/templates/labels.j2
 create mode 100644 roles/custom/matrix-fluffygate/templates/systemd/matrix-fluffygate.service.j2

diff --git a/docs/configuring-playbook-fluffygate.md b/docs/configuring-playbook-fluffygate.md
new file mode 100644
index 000000000..d63cb8ea2
--- /dev/null
+++ b/docs/configuring-playbook-fluffygate.md
@@ -0,0 +1,147 @@
+# Setting up Fluffygate (optional)
+
+The playbook can install and configure [Fluffygate](https://github.com/krille-chan/fluffygate), a simple Push Gateway for Fluffychat.
+
+See the project's documentation to learn what it does and why it might be useful to you.
+
+**Note**: most people don't need to install their own gateway. This optional playbook component is only useful to people who develop/build their own Matrix client applications themselves, as you'll need access to your own Firebase/FCM and APNS credentials.
+
+## Adjusting the playbook configuration
+
+To enable Fluffygate, add the following configuration to your `inventory/host_vars/matrix.example.com/vars.yml` file:
+
+```yaml
+matrix_fluffygate_enabled: true
+
+# Basic app information
+matrix_fluffygate_app_name: "Your App Name"
+matrix_fluffygate_app_website: "https://example.com"
+
+# Firebase/FCM configuration (for Android / IOS)
+matrix_fluffygate_firebase_project: "your-firebase-project-id"
+matrix_fluffygate_firebase_key: |
+  {
+    # Your Firebase service account key JSON content
+  }
+
+# Notification settings
+matrix_fluffygate_notification_title: "{count} new messages"
+matrix_fluffygate_notification_body: "{body}"
+
+# Android specific notification options
+matrix_fluffygate_android_notification_options:
+  priority: high
+  notification:
+    sound: "default"
+    icon: "notifications_icon"
+    tag: "default_notification"
+
+# APNS specific notification options (for iOS)
+matrix_fluffygate_apns_notification_options:
+  headers:
+    apns-priority: "10"
+  payload:
+    aps:
+      sound: "default"
+      badge: "{count}"
+      mutable-content: 1
+```
+
+For a complete list of available configuration options, see the `defaults/main.yml` file in the role.
+
+### Required Configuration
+
+The following settings are required and must be defined:
+- `matrix_fluffygate_hostname`
+- `matrix_fluffygate_path_prefix`
+- `matrix_fluffygate_container_network`
+- `matrix_fluffygate_app_name`
+- `matrix_fluffygate_app_website`
+
+### Adjusting the Fluffygate URL
+
+By default, this playbook installs Fluffygate at the root path (`/`) of the configured hostname. You can customize both the hostname and path prefix using these variables:
+
+```yaml
+# Configure the hostname where Fluffygate will be served
+matrix_fluffygate_hostname: "push.example.com"
+
+# Configure a custom path prefix (must either be '/' or not end with a slash)
+matrix_fluffygate_path_prefix: /push
+```
+
+### Traefik Integration
+
+Fluffygate includes built-in support for Traefik as a reverse proxy. The following settings control this integration:
+
+```yaml
+# Enable/disable Traefik labels
+matrix_fluffygate_container_labels_traefik_enabled: true
+
+# Configure the Traefik network
+matrix_fluffygate_container_labels_traefik_docker_network: "{{ matrix_fluffygate_container_network }}"
+
+# Additional Traefik configuration
+matrix_fluffygate_container_labels_traefik_rule: "Host(`{{ matrix_fluffygate_container_labels_traefik_hostname }}`)"
+matrix_fluffygate_container_labels_traefik_priority: 0
+matrix_fluffygate_container_labels_traefik_entrypoints: web-secure
+```
+
+## Adjusting DNS records
+
+You will need to configure your DNS records to point the Fluffygate hostname to your server. This typically involves creating either:
+- an A record pointing to your server's IPv4 address
+- a CNAME record pointing to your server's hostname
+
+## Installing
+
+After configuring the playbook and adjusting your DNS records, run the installation command:
+
+```bash
+ansible-playbook -i inventory/hosts setup.yml --tags=setup-all,start
+```
+
+To install only Fluffygate, you can use:
+
+```bash
+ansible-playbook -i inventory/hosts setup.yml --tags=setup-fluffygate,start
+```
+
+## Usage
+
+To make use of your Fluffygate installation:
+
+1. Configure your Matrix client application to use your Fluffygate URL as the push gateway
+2. Ensure your app uses the same Firebase/FCM credentials for Android notifications
+3. Ensure your app uses the same APNS certificates/credentials for iOS notifications
+4. Configure the notification templates and options as needed through the playbook variables
+
+### Debugging
+
+If you need to troubleshoot issues:
+
+1. Enable debug logs by setting:
+```yaml
+matrix_fluffygate_debug_logs: true
+```
+
+2. Check the container logs:
+```bash
+docker logs matrix-fluffygate
+```
+
+## Uninstalling
+
+To remove Fluffygate, first disable it in your `inventory/host_vars/matrix.example.com/vars.yml`:
+
+```yaml
+matrix_fluffygate_enabled: false
+```
+
+Then run the playbook:
+
+```bash
+ansible-playbook -i inventory/hosts setup.yml --tags=setup-fluffygate,start
+```
+
+This will stop the service and remove all associated files.
diff --git a/roles/custom/matrix-fluffygate/.claudesync/config.local.json b/roles/custom/matrix-fluffygate/.claudesync/config.local.json
new file mode 100644
index 000000000..c7f2dc914
--- /dev/null
+++ b/roles/custom/matrix-fluffygate/.claudesync/config.local.json
@@ -0,0 +1,7 @@
+{
+  "active_provider": "claude.ai",
+  "active_organization_id": "4c1644e0-e630-48f7-bb87-4d8387ef9cd8",
+  "active_project_id": "1d6c1d5c-5270-439c-9885-aff7168cb24d",
+  "active_project_name": "matrix-fluffygate",
+  "local_path": "/Users/alexis/Work/witi/witi-matrix-ansible/roles/custom/matrix-fluffygate"
+}
\ No newline at end of file
diff --git a/roles/custom/matrix-fluffygate/defaults/main.yml b/roles/custom/matrix-fluffygate/defaults/main.yml
new file mode 100644
index 000000000..72198309c
--- /dev/null
+++ b/roles/custom/matrix-fluffygate/defaults/main.yml
@@ -0,0 +1,137 @@
+---
+
+# Fluffygate is a reference Push Gateway for Matrix.
+# To make use of it for delivering push notificatins, you'll need to develop/build your own Matrix app.
+# Project source code URL: https://github.com/matrix-org/fluffygate
+matrix_fluffygate_enabled: true
+matrix_fluffygate_identifier: 'matrix-fluffygate'
+
+# App information
+matrix_fluffygate_app_name: "Fluffygate"
+matrix_fluffygate_app_website: "https://example.com"
+matrix_fluffygate_debug_logs: false
+
+# Notification settings
+matrix_fluffygate_notification_title: "{count} new messages"
+matrix_fluffygate_notification_body: "{body}"
+
+# Android notification options
+matrix_fluffygate_android_notification_options:
+  priority: high
+  notification:
+    sound: "default"
+    icon: "notifications_icon"
+    tag: "default_notification"
+
+# APNS notification options
+matrix_fluffygate_apns_notification_options:
+  headers:
+    apns-priority: "10"
+  payload:
+    aps:
+      sound: "default"
+      badge: "{count}"
+      mutable-content: 1
+
+matrix_fluffygate_firebase_key: ''  # JSON key file contents
+matrix_fluffygate_firebase_project: ''  # Firebase project ID
+
+# The hostname at which Fluffygate is served.
+matrix_fluffygate_hostname: ''
+
+# The path at which Fluffygate is exposed.
+# This value must either be `/` or not end with a slash (e.g. `/fluffygate`).
+matrix_fluffygate_path_prefix: /
+
+# renovate: datasource=docker depName=matrixdotorg/fluffygate
+matrix_fluffygate_version: 1.0.3
+
+matrix_fluffygate_base_path: "{{ matrix_base_data_path }}/fluffygate"
+matrix_fluffygate_config_path: "{{ matrix_fluffygate_base_path }}/config"
+matrix_fluffygate_data_path: "{{ matrix_fluffygate_base_path }}/data"
+
+# List of systemd services that matrix-fluffygate.service depends on.
+matrix_fluffygate_systemd_required_services_list: "{{ [devture_systemd_docker_base_docker_service_name] if devture_systemd_docker_base_docker_service_name else [] }}"
+
+# List of systemd services that matrix-fluffygate.service wants
+matrix_fluffygate_systemd_wanted_services_list: []
+
+matrix_fluffygate_docker_image: "{{ matrix_fluffygate_docker_image_registry_prefix }}djangoflow/fluffygate:{{ matrix_fluffygate_docker_image_tag }}"
+matrix_fluffygate_docker_image_tag: "{{ matrix_fluffygate_version }}"
+matrix_fluffygate_docker_image_registry_prefix: "{{ matrix_container_global_registry_prefix }}"
+matrix_fluffygate_docker_image_force_pull: "{{ matrix_fluffygate_docker_image.endswith(':latest') }}"
+
+# The base container network. It will be auto-created by this role if it doesn't exist already.
+matrix_fluffygate_container_network: "{{ matrix_fluffygate_identifier }}"
+
+# A list of additional container networks that the container would be connected to.
+# The role does not create these networks, so make sure they already exist.
+# Use this to expose this container to another reverse proxy, which runs in a different container network.
+matrix_fluffygate_container_additional_networks: []
+
+# Controls whether the matrix-fluffygate container exposes its HTTP port (tcp/6000 in the container).
+#
+# Takes an "<ip>:<port>" or "<port>" value (e.g. "127.0.0.1:6000"), or empty string to not expose.
+matrix_fluffygate_container_http_host_bind_port: ''
+
+# matrix_fluffygate_container_labels_traefik_enabled controls whether labels to assist a Traefik reverse-proxy will be attached to the container.
+# See `../templates/labels.j2` for details.
+#
+# To inject your own other container labels, see `matrix_fluffygate_container_labels_additional_labels`.
+matrix_fluffygate_container_labels_traefik_enabled: true
+matrix_fluffygate_container_labels_traefik_docker_network: "{{ matrix_fluffygate_container_network }}"
+matrix_fluffygate_container_labels_traefik_hostname: "{{ matrix_fluffygate_hostname }}"
+# The path prefix must either be `/` or not end with a slash (e.g. `/fluffygate`).
+matrix_fluffygate_container_labels_traefik_path_prefix: "{{ matrix_fluffygate_path_prefix }}"
+matrix_fluffygate_container_labels_traefik_rule: "Host(`{{ matrix_fluffygate_container_labels_traefik_hostname }}`){% if matrix_fluffygate_container_labels_traefik_path_prefix != '/' %} && PathPrefix(`{{ matrix_fluffygate_container_labels_traefik_path_prefix }}`){% endif %}"
+matrix_fluffygate_container_labels_traefik_priority: 0
+matrix_fluffygate_container_labels_traefik_entrypoints: web-secure
+matrix_fluffygate_container_labels_traefik_tls: "{{ matrix_fluffygate_container_labels_traefik_entrypoints != 'web' }}"
+matrix_fluffygate_container_labels_traefik_tls_certResolver: default  # noqa var-naming
+
+# Controls which additional headers to attach to all HTTP responses.
+# To add your own headers, use `matrix_fluffygate_container_labels_traefik_additional_response_headers_custom`
+matrix_fluffygate_container_labels_traefik_additional_response_headers: "{{ matrix_fluffygate_container_labels_traefik_additional_response_headers_auto | combine(matrix_fluffygate_container_labels_traefik_additional_response_headers_custom) }}"
+matrix_fluffygate_container_labels_traefik_additional_response_headers_auto: {}
+matrix_fluffygate_container_labels_traefik_additional_response_headers_custom: {}
+
+# matrix_fluffygate_container_labels_additional_labels contains a multiline string with additional labels to add to the container label file.
+# See `../templates/labels.j2` for details.
+#
+# Example:
+# matrix_fluffygate_container_labels_additional_labels: |
+#   my.label=1
+#   another.label="here"
+matrix_fluffygate_container_labels_additional_labels: ''
+
+# A list of extra arguments to pass to the container
+matrix_fluffygate_container_extra_arguments: []
+
+matrix_fluffygate_metrics_prometheus_enabled: false
+
+# Default Fluffygate configuration template which covers the generic use case.
+# You can customize it by controlling the various variables inside it.
+#
+# For a more advanced customization, you can extend the default (see `matrix_fluffygate_configuration_extension_yaml`)
+# or completely replace this variable with your own template.
+matrix_fluffygate_configuration_yaml: "{{ lookup('template', 'templates/config.yaml.j2') }}"
+
+matrix_fluffygate_configuration_extension_yaml: |
+  # Your custom YAML configuration for Fluffygate goes here.
+  # This configuration extends the default starting configuration (`matrix_fluffygate_configuration_yaml`).
+  #
+  # You can override individual variables from the default configuration, or introduce new ones.
+  #
+  # If you need something more special, you can take full control by
+  # completely redefining `matrix_fluffygate_configuration_yaml`.
+  #
+  # Example configuration extension follows:
+  # metrics:
+  #   opentracing:
+  #     enabled: true
+
+matrix_fluffygate_configuration_extension: "{{ matrix_fluffygate_configuration_extension_yaml | from_yaml if matrix_fluffygate_configuration_extension_yaml | from_yaml is mapping else {} }}"
+
+# Holds the final fluffygate configuration (a combination of the default and its extension).
+# You most likely don't need to touch this variable. Instead, see `matrix_fluffygate_configuration_yaml`.
+matrix_fluffygate_configuration: "{{ matrix_fluffygate_configuration_yaml | from_yaml | combine(matrix_fluffygate_configuration_extension, recursive=True) }}"
diff --git a/roles/custom/matrix-fluffygate/tasks/install.yml b/roles/custom/matrix-fluffygate/tasks/install.yml
new file mode 100644
index 000000000..2f07af006
--- /dev/null
+++ b/roles/custom/matrix-fluffygate/tasks/install.yml
@@ -0,0 +1,62 @@
+---
+
+- name: Ensure Fluffygate paths exists
+  ansible.builtin.file:
+    path: "{{ item }}"
+    state: directory
+    mode: 0750
+    owner: "{{ matrix_user_username }}"
+    group: "{{ matrix_user_groupname }}"
+  with_items:
+    - "{{ matrix_fluffygate_base_path }}"
+    - "{{ matrix_fluffygate_config_path }}"
+    - "{{ matrix_fluffygate_data_path }}"
+
+- name: Ensure Fluffygate config installed
+  ansible.builtin.copy:
+    content: "{{ matrix_fluffygate_configuration | to_nice_yaml(indent=2, width=999999) }}"
+    dest: "{{ matrix_fluffygate_config_path }}/config.yaml"
+    mode: 0640
+    owner: "{{ matrix_user_username }}"
+    group: "{{ matrix_user_groupname }}"
+
+- name: Ensure Firebase key file is created when enabled
+  ansible.builtin.copy:
+    content: "{{ matrix_fluffygate_firebase_key }}"
+    dest: "{{ matrix_fluffygate_data_path }}/firebase-key.json"
+    mode: 0600
+    owner: "{{ matrix_user_username }}"
+    group: "{{ matrix_user_groupname }}"
+  when: matrix_fluffygate_firebase_key != ''
+
+- name: Ensure Fluffygate labels installed
+  ansible.builtin.template:
+    src: "{{ role_path }}/templates/labels.j2"
+    dest: "{{ matrix_fluffygate_base_path }}/labels"
+    mode: 0640
+    owner: "{{ matrix_user_username }}"
+    group: "{{ matrix_user_groupname }}"
+
+- name: Ensure Fluffygate image is pulled
+  community.docker.docker_image:
+    name: "{{ matrix_fluffygate_docker_image }}"
+    source: "{{ 'pull' if ansible_version.major > 2 or ansible_version.minor > 7 else omit }}"
+    force_source: "{{ matrix_fluffygate_docker_image_force_pull if ansible_version.major > 2 or ansible_version.minor >= 8 else omit }}"
+    force: "{{ omit if ansible_version.major > 2 or ansible_version.minor >= 8 else matrix_fluffygate_docker_image_force_pull }}"
+  register: result
+  retries: "{{ devture_playbook_help_container_retries_count }}"
+  delay: "{{ devture_playbook_help_container_retries_delay }}"
+  until: result is not failed
+
+- name: Ensure Fluffygate container network is created
+  community.general.docker_network:
+    enable_ipv6: "{{ devture_systemd_docker_base_ipv6_enabled }}"
+    name: "{{ matrix_fluffygate_container_network }}"
+    driver: bridge
+    driver_options: "{{ devture_systemd_docker_base_container_networks_driver_options }}"
+
+- name: Ensure matrix-fluffygate.service installed
+  ansible.builtin.template:
+    src: "{{ role_path }}/templates/systemd/matrix-fluffygate.service.j2"
+    dest: "{{ devture_systemd_docker_base_systemd_path }}/matrix-fluffygate.service"
+    mode: 0644
diff --git a/roles/custom/matrix-fluffygate/tasks/main.yml b/roles/custom/matrix-fluffygate/tasks/main.yml
new file mode 100644
index 000000000..b35be01b0
--- /dev/null
+++ b/roles/custom/matrix-fluffygate/tasks/main.yml
@@ -0,0 +1,20 @@
+---
+
+- tags:
+    - setup-all
+    - setup-fluffygate
+    - install-all
+    - install-fluffygate
+  block:
+    - when: matrix_fluffygate_enabled | bool
+      ansible.builtin.include_tasks: "{{ role_path }}/tasks/validate_config.yml"
+
+    - when: matrix_fluffygate_enabled | bool
+      ansible.builtin.include_tasks: "{{ role_path }}/tasks/install.yml"
+
+- tags:
+    - setup-all
+    - setup-fluffygate
+  block:
+    - when: not matrix_fluffygate_enabled | bool
+      ansible.builtin.include_tasks: "{{ role_path }}/tasks/uninstall.yml"
diff --git a/roles/custom/matrix-fluffygate/tasks/uninstall.yml b/roles/custom/matrix-fluffygate/tasks/uninstall.yml
new file mode 100644
index 000000000..6f23c4553
--- /dev/null
+++ b/roles/custom/matrix-fluffygate/tasks/uninstall.yml
@@ -0,0 +1,25 @@
+---
+
+- name: Check existence of matrix-fluffygate service
+  ansible.builtin.stat:
+    path: "{{ devture_systemd_docker_base_systemd_path }}/matrix-fluffygate.service"
+  register: matrix_fluffygate_service_stat
+
+- when: matrix_fluffygate_service_stat.stat.exists | bool
+  block:
+    - name: Ensure matrix-fluffygate is stopped
+      ansible.builtin.service:
+        name: matrix-fluffygate
+        state: stopped
+        enabled: false
+        daemon_reload: true
+
+    - name: Ensure matrix-fluffygate.service doesn't exist
+      ansible.builtin.file:
+        path: "{{ devture_systemd_docker_base_systemd_path }}/matrix-fluffygate.service"
+        state: absent
+
+    - name: Ensure Fluffygate base directory doesn't exist
+      ansible.builtin.file:
+        path: "{{ matrix_fluffygate_base_path }}"
+        state: absent
diff --git a/roles/custom/matrix-fluffygate/tasks/validate_config.yml b/roles/custom/matrix-fluffygate/tasks/validate_config.yml
new file mode 100644
index 000000000..af74ac79e
--- /dev/null
+++ b/roles/custom/matrix-fluffygate/tasks/validate_config.yml
@@ -0,0 +1,40 @@
+---
+
+- name: Fail if required Fluffygate settings not defined
+  ansible.builtin.fail:
+    msg: >
+      You need to define a required configuration setting (`{{ item }}`).
+  when: "vars[item] == ''"
+  with_items:
+    - matrix_fluffygate_hostname
+    - matrix_fluffygate_path_prefix
+    - matrix_fluffygate_container_network
+
+- when: matrix_fluffygate_container_labels_traefik_enabled | bool
+  block:
+    - name: Fail if required Fluffygate Traefik settings not defined
+      ansible.builtin.fail:
+        msg: >-
+          You need to define a required configuration setting (`{{ item }}`).
+      when: "vars[item] == ''"
+      with_items:
+        - matrix_fluffygate_container_labels_traefik_hostname
+        - matrix_fluffygate_container_labels_traefik_path_prefix
+
+    # We ensure it doesn't end with a slash, because we handle both (slash and no-slash).
+    # Knowing that `matrix_fluffygate_container_labels_traefik_path_prefix` does not end with a slash
+    # ensures we know how to set these routes up without having to do "does it end with a slash" checks elsewhere.
+    - name: Fail if matrix_fluffygate_container_labels_traefik_path_prefix ends with a slash
+      ansible.builtin.fail:
+        msg: >-
+          matrix_fluffygate_container_labels_traefik_path_prefix (`{{ matrix_fluffygate_container_labels_traefik_path_prefix }}`) must either be `/` or not end with a slash (e.g. `/fluffygate`).
+      when: "matrix_fluffygate_container_labels_traefik_path_prefix != '/' and matrix_fluffygate_container_labels_traefik_path_prefix[-1] == '/'"
+
+- name: Fail if required Fluffygate settings not defined
+  ansible.builtin.fail:
+    msg: >
+      You need to define a required configuration setting (`{{ item }}`).
+  when: "vars[item] == ''"
+  with_items:
+    - matrix_fluffygate_app_name
+    - matrix_fluffygate_app_website
diff --git a/roles/custom/matrix-fluffygate/templates/config.yaml.j2 b/roles/custom/matrix-fluffygate/templates/config.yaml.j2
new file mode 100644
index 000000000..58173ad00
--- /dev/null
+++ b/roles/custom/matrix-fluffygate/templates/config.yaml.j2
@@ -0,0 +1,26 @@
+port: 8080
+bindAddress: "0.0.0.0"
+
+# Information about the corresponding app
+appName: "{{ matrix_fluffygate_app_name }}"
+appWebsite: "{{ matrix_fluffygate_app_website }}"
+
+# (Optional) Display logs for debugging
+debugLogs: {{ matrix_fluffygate_debug_logs | to_json }}
+
+# The default notification title and body. {count} will be replaced by the unread
+# count of the push notification. Won't be set by default for clearing notifications.
+notificationTitle: "{{ matrix_fluffygate_notification_title }}"
+notificationBody: "{{ matrix_fluffygate_notification_body }}"
+
+# Add json keys to send to fcm for android and apns configurations
+androidNotificationOptions: {{ matrix_fluffygate_android_notification_options | to_json }}
+apnsNotificationOptions: {{ matrix_fluffygate_apns_notification_options | to_json }}
+
+# You firebase project ID and the path to the key file for your service account.
+{% if matrix_fluffygate_firebase_project %}
+projectId: "{{ matrix_fluffygate_firebase_project }}"
+{% endif %}
+{% if matrix_fluffygate_firebase_key %}
+fcmKeyFilePath: "/data/firebase-key.json"
+{% endif %}
diff --git a/roles/custom/matrix-fluffygate/templates/labels.j2 b/roles/custom/matrix-fluffygate/templates/labels.j2
new file mode 100644
index 000000000..9c0aeb8fd
--- /dev/null
+++ b/roles/custom/matrix-fluffygate/templates/labels.j2
@@ -0,0 +1,46 @@
+{% if matrix_fluffygate_container_labels_traefik_enabled %}
+traefik.enable=true
+
+{% if matrix_fluffygate_container_labels_traefik_docker_network %}
+traefik.docker.network={{ matrix_fluffygate_container_labels_traefik_docker_network }}
+{% endif %}
+
+traefik.http.services.matrix-fluffygate.loadbalancer.server.port=6000
+
+{% set middlewares = [] %}
+
+{% if matrix_fluffygate_container_labels_traefik_path_prefix != '/' %}
+traefik.http.middlewares.matrix-fluffygate-slashless-redirect.redirectregex.regex=({{ matrix_fluffygate_container_labels_traefik_path_prefix | quote }})$
+traefik.http.middlewares.matrix-fluffygate-slashless-redirect.redirectregex.replacement=${1}/
+{% set middlewares = middlewares + ['matrix-fluffygate-slashless-redirect'] %}
+{% endif %}
+
+{% if matrix_fluffygate_container_labels_traefik_path_prefix != '/' %}
+traefik.http.middlewares.matrix-fluffygate-strip-prefix.stripprefix.prefixes={{ matrix_fluffygate_container_labels_traefik_path_prefix }}
+{% set middlewares = middlewares + ['matrix-fluffygate-strip-prefix'] %}
+{% endif %}
+
+{% if matrix_fluffygate_container_labels_traefik_additional_response_headers.keys() | length > 0 %}
+{% for name, value in matrix_fluffygate_container_labels_traefik_additional_response_headers.items() %}
+traefik.http.middlewares.matrix-fluffygate-add-headers.headers.customresponseheaders.{{ name }}={{ value }}
+{% endfor %}
+{% set middlewares = middlewares + ['matrix-fluffygate-add-headers'] %}
+{% endif %}
+
+traefik.http.routers.matrix-fluffygate.rule={{ matrix_fluffygate_container_labels_traefik_rule }}
+{% if matrix_fluffygate_container_labels_traefik_priority | int > 0 %}
+traefik.http.routers.matrix-fluffygate.priority={{ matrix_fluffygate_container_labels_traefik_priority }}
+{% endif %}
+traefik.http.routers.matrix-fluffygate.service=matrix-fluffygate
+{% if middlewares | length > 0 %}
+traefik.http.routers.matrix-fluffygate.middlewares={{ middlewares | join(',') }}
+{% endif %}
+traefik.http.routers.matrix-fluffygate.entrypoints={{ matrix_fluffygate_container_labels_traefik_entrypoints }}
+traefik.http.routers.matrix-fluffygate.tls={{ matrix_fluffygate_container_labels_traefik_tls | to_json }}
+{% if matrix_fluffygate_container_labels_traefik_tls %}
+traefik.http.routers.matrix-fluffygate.tls.certResolver={{ matrix_fluffygate_container_labels_traefik_tls_certResolver }}
+{% endif %}
+
+{% endif %}
+
+{{ matrix_fluffygate_container_labels_additional_labels }}
diff --git a/roles/custom/matrix-fluffygate/templates/systemd/matrix-fluffygate.service.j2 b/roles/custom/matrix-fluffygate/templates/systemd/matrix-fluffygate.service.j2
new file mode 100644
index 000000000..611105ae5
--- /dev/null
+++ b/roles/custom/matrix-fluffygate/templates/systemd/matrix-fluffygate.service.j2
@@ -0,0 +1,51 @@
+#jinja2: lstrip_blocks: "True"
+[Unit]
+Description=Matrix Fluffygate
+{% for service in matrix_fluffygate_systemd_required_services_list %}
+Requires={{ service }}
+After={{ service }}
+{% endfor %}
+{% for service in matrix_fluffygate_systemd_wanted_services_list %}
+Wants={{ service }}
+{% endfor %}
+DefaultDependencies=no
+
+[Service]
+Type=simple
+Environment="HOME={{ devture_systemd_docker_base_systemd_unit_home_path }}"
+ExecStartPre=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} stop --time={{ devture_systemd_docker_base_container_stop_grace_time_seconds }} matrix-fluffygate 2>/dev/null || true'
+ExecStartPre=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} rm matrix-fluffygate 2>/dev/null || true'
+
+ExecStartPre={{ devture_systemd_docker_base_host_command_docker }} create \
+			--rm \
+			--name=matrix-fluffygate \
+			--log-driver=none \
+			--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \
+			--cap-drop=ALL \
+			--network={{ matrix_fluffygate_container_network }} \
+			{% if matrix_fluffygate_container_http_host_bind_port %}
+			-p {{ matrix_fluffygate_container_http_host_bind_port }}:6000 \
+			{% endif %}
+			--label-file={{ matrix_fluffygate_base_path }}/labels \
+			--mount type=bind,src={{ matrix_fluffygate_config_path }},dst=/etc/fluffygate \
+			--mount type=bind,src={{ matrix_fluffygate_data_path }},dst=/data \
+			{% for arg in matrix_fluffygate_container_extra_arguments %}
+			{{ arg }} \
+			{% endfor %}
+			{{ matrix_fluffygate_docker_image }}
+
+{% for network in matrix_fluffygate_container_additional_networks %}
+ExecStartPre={{ devture_systemd_docker_base_host_command_docker }} network connect {{ network }} matrix-fluffygate
+{% endfor %}
+
+ExecStart={{ devture_systemd_docker_base_host_command_docker }} start --attach matrix-fluffygate
+
+ExecStop=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} stop --time={{ devture_systemd_docker_base_container_stop_grace_time_seconds }} matrix-fluffygate 2>/dev/null || true'
+ExecStop=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} rm matrix-fluffygate 2>/dev/null || true'
+
+Restart=always
+RestartSec=30
+SyslogIdentifier=matrix-fluffygate
+
+[Install]
+WantedBy=multi-user.target
diff --git a/setup.yml b/setup.yml
index b9eb5b8d6..552665046 100644
--- a/setup.yml
+++ b/setup.yml
@@ -126,6 +126,7 @@
     - custom/matrix-sliding-sync
     - custom/matrix-email2matrix
     - custom/matrix-sygnal
+    - custom/matrix-fluffygate
     - galaxy/ntfy
     - custom/matrix-static-files
     - custom/matrix-coturn

From d628b7f9d3947135d70e056f3fb58fea9cfbba9e Mon Sep 17 00:00:00 2001
From: Alexis Yushin <alexis@apexive.com>
Date: Thu, 24 Oct 2024 09:40:32 -0400
Subject: [PATCH 2/6] fixed default fluffygate port

---
 roles/custom/matrix-fluffygate/templates/labels.j2 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/roles/custom/matrix-fluffygate/templates/labels.j2 b/roles/custom/matrix-fluffygate/templates/labels.j2
index 9c0aeb8fd..27b992fd2 100644
--- a/roles/custom/matrix-fluffygate/templates/labels.j2
+++ b/roles/custom/matrix-fluffygate/templates/labels.j2
@@ -5,7 +5,7 @@ traefik.enable=true
 traefik.docker.network={{ matrix_fluffygate_container_labels_traefik_docker_network }}
 {% endif %}
 
-traefik.http.services.matrix-fluffygate.loadbalancer.server.port=6000
+traefik.http.services.matrix-fluffygate.loadbalancer.server.port=8080
 
 {% set middlewares = [] %}
 

From fc9dac763dd2ea474a13eb81fef3bf35d4c69832 Mon Sep 17 00:00:00 2001
From: Alexis Yushin <alexis@apexive.com>
Date: Thu, 24 Oct 2024 10:10:43 -0400
Subject: [PATCH 3/6] connect to traefik network by default

---
 roles/custom/matrix-fluffygate/defaults/main.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/roles/custom/matrix-fluffygate/defaults/main.yml b/roles/custom/matrix-fluffygate/defaults/main.yml
index 72198309c..bda649097 100644
--- a/roles/custom/matrix-fluffygate/defaults/main.yml
+++ b/roles/custom/matrix-fluffygate/defaults/main.yml
@@ -62,7 +62,7 @@ matrix_fluffygate_docker_image_registry_prefix: "{{ matrix_container_global_regi
 matrix_fluffygate_docker_image_force_pull: "{{ matrix_fluffygate_docker_image.endswith(':latest') }}"
 
 # The base container network. It will be auto-created by this role if it doesn't exist already.
-matrix_fluffygate_container_network: "{{ matrix_fluffygate_identifier }}"
+matrix_fluffygate_container_network: "{{ traefik_container_network }}"
 
 # A list of additional container networks that the container would be connected to.
 # The role does not create these networks, so make sure they already exist.

From 934deda88aa5d7eb23fe508b51e0359e4060c071 Mon Sep 17 00:00:00 2001
From: Alexis Yushin <alexis@apexive.com>
Date: Sat, 9 Nov 2024 16:20:07 -0800
Subject: [PATCH 4/6] Update docs/configuring-playbook-fluffygate.md

Co-authored-by: Suguru Hirahara <luixxiul@users.noreply.github.com>
---
 docs/configuring-playbook-fluffygate.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/docs/configuring-playbook-fluffygate.md b/docs/configuring-playbook-fluffygate.md
index d63cb8ea2..2630a96d7 100644
--- a/docs/configuring-playbook-fluffygate.md
+++ b/docs/configuring-playbook-fluffygate.md
@@ -121,9 +121,9 @@ To make use of your Fluffygate installation:
 If you need to troubleshoot issues:
 
 1. Enable debug logs by setting:
-```yaml
-matrix_fluffygate_debug_logs: true
-```
+    ```yaml
+    matrix_fluffygate_debug_logs: true
+    ```
 
 2. Check the container logs:
 ```bash

From 614dc4a51bd49ca30b8349adf44d6aeeff05f33c Mon Sep 17 00:00:00 2001
From: Alexis Yushin <alexis@apexive.com>
Date: Sat, 9 Nov 2024 16:20:12 -0800
Subject: [PATCH 5/6] Update docs/configuring-playbook-fluffygate.md

Co-authored-by: Suguru Hirahara <luixxiul@users.noreply.github.com>
---
 docs/configuring-playbook-fluffygate.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/docs/configuring-playbook-fluffygate.md b/docs/configuring-playbook-fluffygate.md
index 2630a96d7..99f59970e 100644
--- a/docs/configuring-playbook-fluffygate.md
+++ b/docs/configuring-playbook-fluffygate.md
@@ -126,9 +126,9 @@ If you need to troubleshoot issues:
     ```
 
 2. Check the container logs:
-```bash
-docker logs matrix-fluffygate
-```
+    ```bash
+    docker logs matrix-fluffygate
+    ```
 
 ## Uninstalling
 

From 74e7f41aea27f61b4dedb61fb066136e54c3b92e Mon Sep 17 00:00:00 2001
From: Alexis Yushin <alexis@apexive.com>
Date: Sat, 9 Nov 2024 19:21:20 -0500
Subject: [PATCH 6/6] cleanup

---
 .../custom/matrix-fluffygate/.claudesync/config.local.json | 7 -------
 1 file changed, 7 deletions(-)
 delete mode 100644 roles/custom/matrix-fluffygate/.claudesync/config.local.json

diff --git a/roles/custom/matrix-fluffygate/.claudesync/config.local.json b/roles/custom/matrix-fluffygate/.claudesync/config.local.json
deleted file mode 100644
index c7f2dc914..000000000
--- a/roles/custom/matrix-fluffygate/.claudesync/config.local.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "active_provider": "claude.ai",
-  "active_organization_id": "4c1644e0-e630-48f7-bb87-4d8387ef9cd8",
-  "active_project_id": "1d6c1d5c-5270-439c-9885-aff7168cb24d",
-  "active_project_name": "matrix-fluffygate",
-  "local_path": "/Users/alexis/Work/witi/witi-matrix-ansible/roles/custom/matrix-fluffygate"
-}
\ No newline at end of file