From 04795554b7849157863113ceab3eb35928608e54 Mon Sep 17 00:00:00 2001 From: drew Date: Wed, 6 May 2026 00:56:22 -0400 Subject: [PATCH] Add matrix to stack --- playbook.yml | 11 ++- roles/coturn/meta/main.yml | 4 + roles/coturn/tasks/firewall.yml | 11 +++ roles/coturn/tasks/main.yml | 68 +++++++++++++++++ roles/coturn/templates/coturn.container.j2 | 17 +++++ roles/coturn/templates/turnserver.conf.j2 | 15 ++++ roles/matrix_synapse/meta/main.yml | 6 ++ roles/matrix_synapse/tasks/main.yml | 73 +++++++++++++++++++ .../templates/homeserver.yaml.j2 | 48 ++++++++++++ .../templates/synapse.container.j2 | 16 ++++ roles/postgres/meta/main.yml | 4 + roles/postgres/tasks/main.yml | 70 ++++++++++++++++++ .../postgres/templates/postgres.container.j2 | 18 +++++ roles/tailscale/defaults/main.yml | 3 + roles/tailscale/tasks/main.yml | 36 +++++++++ roles/vpn/templates/gluetun.container.j2 | 2 +- 16 files changed, 400 insertions(+), 2 deletions(-) create mode 100644 roles/coturn/meta/main.yml create mode 100644 roles/coturn/tasks/firewall.yml create mode 100644 roles/coturn/tasks/main.yml create mode 100644 roles/coturn/templates/coturn.container.j2 create mode 100644 roles/coturn/templates/turnserver.conf.j2 create mode 100644 roles/matrix_synapse/meta/main.yml create mode 100644 roles/matrix_synapse/tasks/main.yml create mode 100644 roles/matrix_synapse/templates/homeserver.yaml.j2 create mode 100644 roles/matrix_synapse/templates/synapse.container.j2 create mode 100644 roles/postgres/meta/main.yml create mode 100644 roles/postgres/tasks/main.yml create mode 100644 roles/postgres/templates/postgres.container.j2 create mode 100644 roles/tailscale/defaults/main.yml create mode 100644 roles/tailscale/tasks/main.yml diff --git a/playbook.yml b/playbook.yml index bc2150b..7a9cc70 100644 --- a/playbook.yml +++ b/playbook.yml @@ -43,4 +43,13 @@ - base_os - firewall_base - container_runtime - - selinux_containers \ No newline at end of file + - selinux_containers + +- name: Matrix + hosts: matrix + become: true + roles: + - base_os + - firewall_base + - container_runtime + - matrix_synapse \ No newline at end of file diff --git a/roles/coturn/meta/main.yml b/roles/coturn/meta/main.yml new file mode 100644 index 0000000..daa07a7 --- /dev/null +++ b/roles/coturn/meta/main.yml @@ -0,0 +1,4 @@ +--- +# coturn/meta/main.yml +dependencies: + - role: selinux_containers \ No newline at end of file diff --git a/roles/coturn/tasks/firewall.yml b/roles/coturn/tasks/firewall.yml new file mode 100644 index 0000000..bacea94 --- /dev/null +++ b/roles/coturn/tasks/firewall.yml @@ -0,0 +1,11 @@ +--- +# coturn/tasks/firewall.yml +- name: Open required firewall rules + become: true + ansible.posix.firewalld: + port: "{{ item.port | default(omit) }}" + service: "{{ item.service | default(omit) }}" + permanent: true + state: enabled + immediate: true + loop: "{{ coturn_firewall_rules }}" \ No newline at end of file diff --git a/roles/coturn/tasks/main.yml b/roles/coturn/tasks/main.yml new file mode 100644 index 0000000..02ce3e0 --- /dev/null +++ b/roles/coturn/tasks/main.yml @@ -0,0 +1,68 @@ +--- +# coturn/tasks/main.yml +- import_tasks: firewall.yml + +- name: Create stack and config directories + file: + path: "{{ item }}" + state: directory + owner: "{{ container_user }}" + group: "{{ container_group }}" + mode: "0755" + recurse: yes + loop: "{{ coturn_base_directories }}" + +- name: Directory SELinux requirement + ansible.builtin.set_fact: + selinux_container_paths: "{{ coturn_base_directories }}" + +- import_role: + name: selinux_containers + tasks_from: labels + +- name: Ensure container app config directories are owned by container UID + become: true + file: + path: "{{ coturn_dir }}/conf" + state: directory + owner: "{{ container_user }}" + group: "{{ container_group }}" + recurse: true + +- name: Deploy Turnserver configuration template + template: + src: turnserver.conf.j2 + dest: "{{ coturn_config_dir }}/turnserver.conf" + owner: "{{ container_user }}" + group: "{{ container_group }}" + mode: '0600' + +- name: Deploy Coturn Quadlet + template: + src: coturn.container.j2 + dest: "{{ container_config_dir }}/coturn.container" + owner: "{{ container_user }}" + group: "{{ container_group }}" + mode: '0644' + +- name: Force systemd reload (blocking) + become: true + become_user: "{{ container_user }}" + environment: + XDG_RUNTIME_DIR: "{{ container_runtime_dir }}" + command: systemctl --user daemon-reload + +- name: Wait for quadlet generation + pause: + seconds: 1 + +- name: Start and enable Coturn service + become: true + become_user: "{{ container_user }}" + environment: + XDG_RUNTIME_DIR: "{{ container_runtime_dir }}" + systemd: + name: coturn.service + scope: user + state: started + enabled: true \ No newline at end of file diff --git a/roles/coturn/templates/coturn.container.j2 b/roles/coturn/templates/coturn.container.j2 new file mode 100644 index 0000000..dfd09ce --- /dev/null +++ b/roles/coturn/templates/coturn.container.j2 @@ -0,0 +1,17 @@ +[Unit] +Description=Coturn TURN server for Matrix +After=network-online.target homelab-network.service +Requires=homelab-network.service + +[Container] +ContainerName=coturn +Image=docker.io/coturn/coturn:latest +Volume={{ coturn_config_dir }}/turnserver.conf:/etc/coturn/turnserver.conf:Z +Network=homelab.network +PublishPort=3478:3478/tcp +PublishPort=3478:3478/udp +PublishPort=49152-49172:49152-49172/udp +Exec=-c /etc/coturn/turnserver.conf + +[Install] +WantedBy=multi-user.target default.target \ No newline at end of file diff --git a/roles/coturn/templates/turnserver.conf.j2 b/roles/coturn/templates/turnserver.conf.j2 new file mode 100644 index 0000000..7870837 --- /dev/null +++ b/roles/coturn/templates/turnserver.conf.j2 @@ -0,0 +1,15 @@ +# /etc/coturn/turnserver.conf +listening-port=3478 +fingerprint +lt-cred-mech +use-auth-secret +static-auth-secret={{ vault_matrix_turn_shared_secret }} +realm=matrix.{{ domain_name }} +total-quota=0 +bps-capacity=0 +stale-nonce=600 +no-stdout-log +min-port=49152 +max-port=49172 + +external-ip={{ nanode_public_ip }} \ No newline at end of file diff --git a/roles/matrix_synapse/meta/main.yml b/roles/matrix_synapse/meta/main.yml new file mode 100644 index 0000000..eb2c7bd --- /dev/null +++ b/roles/matrix_synapse/meta/main.yml @@ -0,0 +1,6 @@ +--- +# matrix_synapse/meta/main.yml +dependencies: + - role: tailscale + - role: postgres + - role: coturn \ No newline at end of file diff --git a/roles/matrix_synapse/tasks/main.yml b/roles/matrix_synapse/tasks/main.yml new file mode 100644 index 0000000..9639889 --- /dev/null +++ b/roles/matrix_synapse/tasks/main.yml @@ -0,0 +1,73 @@ +--- +# matrix_synapse/tasks/main.yml +- name: Create stack and config directories + file: + path: "{{ item }}" + state: directory + owner: "{{ container_user }}" + group: "{{ container_group }}" + mode: "0755" + loop: "{{ synapse_base_directories }}" + +- name: Directory SELinux requirement + ansible.builtin.set_fact: + selinux_container_paths: "{{ synapse_base_directories }}" + +- import_role: + name: selinux_containers + tasks_from: labels + +#- name: Ensure container app config directories are owned by container UID +# become: true +# file: +# path: "{{ synapse_config_dir }}" +# state: directory +# owner: "{{ container_user }}" +# group: "{{ container_group }}" +# recurse: true + +- name: Deploy homesever configuration template + template: + src: homeserver.yaml.j2 + dest: "{{ synapse_config_dir }}/homeserver.yaml" + owner: "{{ container_user }}" + group: "{{ container_group }}" + mode: '0600' + +- name: Ensure Synapse signing key is deployed + copy: + content: "{{ vault_matrix_signing_key }}" + dest: "{{ deploy_signing_key_path }}" + owner: "{{ container_user }}" + group: "{{ container_group }}" + mode: '0600' + +- name: Deploy Synapse Quadlet + template: + src: synapse.container.j2 + dest: "{{ container_config_dir }}/synapse.container" + owner: "{{ container_user }}" + group: "{{ container_group }}" + mode: '0644' + +- name: Force systemd reload (blocking) + become: true + become_user: "{{ container_user }}" + environment: + XDG_RUNTIME_DIR: "{{ container_runtime_dir }}" + command: systemctl --user daemon-reload + +- name: Wait for quadlet generation + pause: + seconds: 1 + +- name: Start and enable Synapse service + become: true + become_user: "{{ container_user }}" + environment: + XDG_RUNTIME_DIR: "{{ container_runtime_dir }}" + systemd: + name: synapse.service + scope: user + state: started + enabled: true \ No newline at end of file diff --git a/roles/matrix_synapse/templates/homeserver.yaml.j2 b/roles/matrix_synapse/templates/homeserver.yaml.j2 new file mode 100644 index 0000000..da0e786 --- /dev/null +++ b/roles/matrix_synapse/templates/homeserver.yaml.j2 @@ -0,0 +1,48 @@ +server_name: "{{ domain_name }}" +public_baseurl: "https://matrix.{{ domain_name }}/" +pid_file: /data/homeserver.pid + +signing_key_path: "/data/{{ domain_name }}.signing.key" +registration_shared_secret: "{{ vault_matrix_registration_shared_secret }}" +macaroon_secret_key: "{{ vault_matrix_macaroon_secret }}" +form_secret: "{{ vault_matrix_form_secret }}" + +presence: + enabled: true + +report_stats: false + +trusted_key_servers: + - server_name: "matrix.org" +suppress_key_server_warning: true + +media_store_path: "/data/media_store" +uploads_path: "/data/uploads" + +# Database configuration +database: + name: psycopg2 + args: + user: synapse + password: "{{ vault_matrix_postgres_password }}" + database: synapse + host: 10.89.0.54 + cp_min: 5 + cp_max: 10 + +# Voice/Video (Coturn) integration +turn_uris: + - "turn:matrix.{{ domain_name }}:3478?transport=udp" + - "turn:matrix.{{ domain_name }}:3478?transport=tcp" +turn_shared_secret: "{{ vault_matrix_turn_shared_secret }}" +turn_user_lifetime: 86400000 + +# Listeners +listeners: + - port: 8008 + tls: false + type: http + x_forwarded: true + resources: + - names: [client, federation] + compress: false \ No newline at end of file diff --git a/roles/matrix_synapse/templates/synapse.container.j2 b/roles/matrix_synapse/templates/synapse.container.j2 new file mode 100644 index 0000000..8a96f2f --- /dev/null +++ b/roles/matrix_synapse/templates/synapse.container.j2 @@ -0,0 +1,16 @@ +[Unit] +Description=Matrix Synapse Homeserver +After=network-online.target postgres.service coturn.service +Requires=postgres.service + +[Container] +ContainerName=synapse +Image=docker.io/matrixdotorg/synapse:latest +Volume={{ synapse_config_dir }}:/data:Z +Network=homelab.network +# Expose the client-server API port +PublishPort={{ tailscale_ip }}:8008:8008 +UserNS=keep-id + +[Install] +WantedBy=multi-user.target default.target \ No newline at end of file diff --git a/roles/postgres/meta/main.yml b/roles/postgres/meta/main.yml new file mode 100644 index 0000000..3572468 --- /dev/null +++ b/roles/postgres/meta/main.yml @@ -0,0 +1,4 @@ +--- +# postgres/meta/main.yml +dependencies: + - role: selinux_containers \ No newline at end of file diff --git a/roles/postgres/tasks/main.yml b/roles/postgres/tasks/main.yml new file mode 100644 index 0000000..6566968 --- /dev/null +++ b/roles/postgres/tasks/main.yml @@ -0,0 +1,70 @@ +--- +# postgres/tasks/main.yml +- name: Create stack and config directories + file: + path: "{{ item }}" + state: directory + owner: "{{ container_user }}" + group: "{{ container_group }}" + mode: "0755" + loop: "{{ postgres_base_directories }}" + +- name: Directory SELinux requirement + ansible.builtin.set_fact: + selinux_container_paths: "{{ postgres_base_directories }}" + +- import_role: + name: selinux_containers + tasks_from: labels + +- name: Ensure container app config directories are owned by container UID + become: true + file: + path: "{{ postgres_config_dir }}" + state: directory + owner: "{{ container_user }}" + group: "{{ container_group }}" + recurse: true + +- name: Deploy Postgres Quadlet + template: + src: postgres.container.j2 + dest: "{{ container_config_dir }}/postgres.container" + owner: "{{ container_user }}" + group: "{{ container_group }}" + mode: "0600" + +- name: Force systemd reload (blocking) + become: true + become_user: "{{ container_user }}" + environment: + XDG_RUNTIME_DIR: "{{ container_runtime_dir }}" + command: systemctl --user daemon-reload + +- name: Wait for quadlet generation + pause: + seconds: 1 + +- name: Start and enable Postgres service + become: true + become_user: "{{ container_user }}" + environment: + XDG_RUNTIME_DIR: "{{ container_runtime_dir }}" + systemd: + name: postgres.service + scope: user + state: started + enabled: true + +- name: Wait for Postgres to be ready (Handling the double-start) + become: true + become_user: "{{ container_user }}" + environment: + XDG_RUNTIME_DIR: "{{ container_runtime_dir }}" + ansible.builtin.command: + cmd: "podman exec postgres pg_isready -U synapse -d synapse" + register: pg_check + until: pg_check.rc == 0 + retries: 20 + delay: 5 + changed_when: false \ No newline at end of file diff --git a/roles/postgres/templates/postgres.container.j2 b/roles/postgres/templates/postgres.container.j2 new file mode 100644 index 0000000..3bee2dc --- /dev/null +++ b/roles/postgres/templates/postgres.container.j2 @@ -0,0 +1,18 @@ +[Unit] +Description=PostgreSQL for Matrix +After=network-online.target homelab-network.service +Requires=homelab-network.service + +[Container] +ContainerName=postgres +Image=docker.io/library/postgres:16-alpine +Environment=POSTGRES_USER=synapse +Environment=POSTGRES_PASSWORD={{ vault_matrix_postgres_password }} +Environment=POSTGRES_DB=synapse +Environment=POSTGRES_INITDB_ARGS="--lc-collate=C --lc-ctype=C --encoding=UTF8" +Volume={{ postgres_data_dir }}:/var/lib/postgresql/data +Network=homelab.network +IP=10.89.0.54 + +[Install] +WantedBy=multi-user.target default.target \ No newline at end of file diff --git a/roles/tailscale/defaults/main.yml b/roles/tailscale/defaults/main.yml new file mode 100644 index 0000000..a7f9497 --- /dev/null +++ b/roles/tailscale/defaults/main.yml @@ -0,0 +1,3 @@ +#base_os/defaults/main.yml +tailscale_install_packages: + - tailscale \ No newline at end of file diff --git a/roles/tailscale/tasks/main.yml b/roles/tailscale/tasks/main.yml new file mode 100644 index 0000000..b322e0f --- /dev/null +++ b/roles/tailscale/tasks/main.yml @@ -0,0 +1,36 @@ +--- +# tailscale/tasks/main.yml +- name: Add Tailscale repository + become: true + ansible.builtin.get_url: + url: https://pkgs.tailscale.com/stable/rhel/9/tailscale.repo + dest: /etc/yum.repos.d/tailscale.repo + mode: '0644' + +- name: Install required base packages + become: true + dnf: + name: "{{ item }}" + state: present + loop: "{{ tailscale_install_packages }}" + +- name: Start tailscaled + become: true + ansible.builtin.systemd: + name: tailscaled + state: started + enabled: true + +- name: Bring Tailscale up (without hijacking DNS) + become: true + ansible.builtin.command: + cmd: > + tailscale up + --authkey={{ vault_tailscale_auth_key }} + --accept-dns=false + --reset + register: ts_up + changed_when: "'already authenticated' not in ts_up.stderr" + failed_when: + - ts_up.rc != 0 + - "'already authenticated' not in ts_up.stderr" \ No newline at end of file diff --git a/roles/vpn/templates/gluetun.container.j2 b/roles/vpn/templates/gluetun.container.j2 index 3cf61dd..0531c13 100644 --- a/roles/vpn/templates/gluetun.container.j2 +++ b/roles/vpn/templates/gluetun.container.j2 @@ -30,7 +30,7 @@ PublishPort=9696:9696 Environment=VPN_SERVICE_PROVIDER=mullvad Environment=VPN_TYPE=wireguard -Environment=WIREGUARD_PRIVATE_KEY={{ vpn_private_key }} +Environment=WIREGUARD_PRIVATE_KEY={{ vault_vpn_private_key }} Environment=WIREGUARD_ADDRESSES={{ vpn_addresses }} Environment=FIREWALL_ENABLED=on