diff --git a/README.md b/README.md index 358d025..7d9c160 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ Roles for deploying matrix infrastructure using ansible. - [`cinny`](roles/cinny/README.md): [Cinny](https://cinny.in/) Web Client - [`element`](roles/element/README.md): [Element](https://element.io/) Web Client +- [`synapse`](roles/synapse/README.md): [Synapse](https://github.com/element-hq/synapse/), + a matrix homeserver implemention by Element ## License diff --git a/playbooks/synapse.yml b/playbooks/synapse.yml new file mode 100644 index 0000000..737e837 --- /dev/null +++ b/playbooks/synapse.yml @@ -0,0 +1,6 @@ +--- +- name: Deploy and configure synapse + hosts: "{{ synapse_hosts | default('synapse') }}" + become: "{{ synapse_become | default(true) }}" + roles: + - role: finallycoffee.matrix.synapse diff --git a/roles/synapse/README.md b/roles/synapse/README.md new file mode 100644 index 0000000..ced5eb0 --- /dev/null +++ b/roles/synapse/README.md @@ -0,0 +1,29 @@ +# `finallycoffee.matrix.synapse` ansible role + +## Configuration + +### Required + +The following variables need to be populated: + +- `synapse_domain` - the domain this homeserver should be authoritative for. +- `synapse_signing_key` - the signing key synapse should use. + Set either this or `synapse_role_generate_signing_key: true`. + +## Other + +- [Configure your database](docs/database.md) +- [Configure your listeners](docs/listeners.md) +- [Configure logging](docs/logging.md) + +## Deployment methods + +### Docker + +Set `synapse_deployment_method: docker` to deploy synapse in docker container(s). +This is currently the default. + +### Planned methods + +- virtual env + systemd +- podman diff --git a/roles/synapse/defaults/main/container.yml b/roles/synapse/defaults/main/container.yml new file mode 100644 index 0000000..c5b4e6d --- /dev/null +++ b/roles/synapse/defaults/main/container.yml @@ -0,0 +1,55 @@ +--- +synapse_container_name: synapse +synapse_container_image: >-2 + {{ + [ + synapse_container_image_repository, + synapse_container_image_tag | default('v' ~ synapse_version, true) + ] | join(':') + }} +synapse_container_image_registry: ghcr.io +synapse_container_image_namespace: element-hq +synapse_container_image_name: synapse +synapse_container_image_repository: >-2 + {{ synapse_container_image_registry + ~ (('/' ~ synapse_container_image_namespace) + if synapse_container_image_namespace else '') + ~ '/' ~ synapse_container_image_name }} +synapse_container_image_source: pull +synapse_container_image_tag: ~ +synapse_container_env: {} +synapse_container_user: >- + {{ ((synapse_user_info is defined) and ('uid' in synapse_user_info)) + | ternary(synapse_user_info.uid, synapse_user) }} +synapse_container_group: ~ +synapse_container_ports: ~ +synapse_container_labels: ~ +synapse_container_ulimits: ~ +synapse_container_networks: ~ +synapse_container_purge_networks: ~ +synapse_container_dns_servers: ~ +synapse_container_etc_hosts: ~ +synapse_container_memory: ~ +synapse_container_memory_reservation: ~ +synapse_container_memory_swap: ~ +synapse_container_state: "started" +synapse_container_restart_policy: "unless-stopped" + +synapse_container_volumes: ~ +synapse_container_default_volumes: + - "{{ synapse_homeserver_config_file }}:/data/homeserver.yaml:ro" + - "{{ synapse_logging_config_file }}:{{ synapse_logging_config_file }}:ro" + - "{{ synapse_signing_key_file }}:{{ synapse_signing_key_file }}:ro" + - "{{ synapse_data_path }}:{{ synapse_data_path }}:z" + - "{{ synapse_media_store_path }}:{{ synapse_media_store_path }}:z" + - "{{ synapse_log_path }}:{{ synapse_log_path }}:z" +synapse_container_tls_volumes: + - "{{ synapse_config_tls_certificate_path }}:{{ synapse_config_tls_certificate_path }}:ro" + - "{{ synapse_config_tls_private_key_path }}:{{ synapse_config_tls_private_key_path_path }}:ro" +synapse_container_all_volumes: >- + {{ synapse_container_default_volumes | default([], true) + + (synapse_container_tls_volumes + if (synapse_config_tls_private_key_path | default(false, true) | bool + and synapse_config_tls_certificate_path | default(false, true) | bool) + else []) + + synapse_container_volumes | default([], true) }} diff --git a/roles/synapse/defaults/main/homeserver.api.yml b/roles/synapse/defaults/main/homeserver.api.yml new file mode 100644 index 0000000..e5ed8f4 --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.api.yml @@ -0,0 +1,31 @@ +--- +synapse_config_macaroon_secret_key: ~ +synapse_config_form_secret: ~ +synapse_config_use_appservice_legacy_authorization: false +synapse_config_track_appservice_user_ips: false +synapse_config_track_puppeted_user_ips: false +synapse_config_app_service_config_files: [] +synapse_config_room_prejoin_state_disable_default_event_types: false +synapse_config_room_prejoin_state_additional_event_types: [] + +synapse_base_api_config: + app_service_config_files: "{{ synapse_config_app_service_config_files }}" + use_appservice_legacy_authorization: >- + {{ synapse_config_use_appservice_legacy_authorization }} + track_appservice_user_ips: >- + {{ synapse_config_track_appservice_user_ips }} + track_puppeted_user_ips: >- + {{ synapse_config_track_puppeted_user_ips }} + room_prejoin_state: + disable_default_event_types: >-2 + {{ synapse_config_room_prejoin_state_disable_default_event_types }} + additional_event_types: >-2 + {{ synapse_config_room_prejoin_state_additional_event_types }} +synapse_api_config: >-2 + {{ + synapse_base_api_config + | combine(({"macaroon_secret_key": synapse_config_macaroon_secret_key}) + if synapse_config_macaroon_secret_key | default(false, true) else {}) + | combine(({"form_secret": synapse_config_form_secret}) + if synapse_config_form_secret | default(false, true) else {}) + }} diff --git a/roles/synapse/defaults/main/homeserver.cache.yml b/roles/synapse/defaults/main/homeserver.cache.yml new file mode 100644 index 0000000..d4796f9 --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.cache.yml @@ -0,0 +1,15 @@ +--- +synapse_config_event_cache_size: "10K" +synapse_config_caches_global_factor: 0.5 +synapse_config_caches_per_cache_factors: {} +synapse_config_caches_expire_caches: true +synapse_config_caches_sync_response_cache_duration: "2m" + +synapse_cache_config: + event_cache_size: "{{ synapse_config_event_cache_size }}" + caches: + global_factor: "{{ synapse_config_caches_global_factor }}" + per_cache_factors: "{{ synapse_config_caches_per_cache_factors }}" + expire_caches: "{{ synapse_config_caches_expire_caches }}" + sync_response_cache_duration: >- + {{ synapse_config_caches_sync_response_cache_duration }} diff --git a/roles/synapse/defaults/main/homeserver.config.yml b/roles/synapse/defaults/main/homeserver.config.yml new file mode 100644 index 0000000..5e4e3a6 --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.config.yml @@ -0,0 +1,30 @@ +--- +synapse_config_server_name: "{{ synapse_domain }}" +synapse_config_log_config_path: >- + {{ synapse_logging_config_file }} +synapse_config_media_store_path: >- + {{ synapse_media_store_path }} +synapse_config_signing_key_path: >- + {{ synapse_signing_key_file }} +synapse_config_trusted_key_servers: + - server_name: "matrix.org" +synapse_listeners_config: "{{ synapse_config_listeners }}" + +synapse_default_config: >- + {{ + synapse_default_server_config + | combine(synapse_tls_config) + | combine(synapse_email_config) + | combine(synapse_federation_config) + | combine(synapse_media_config) + | combine(synapse_turn_config) + | combine(synapse_cache_config) + | combine(synapse_ratelimit_config) + | combine(synapse_metrics_config) + | combine(synapse_api_config) + | combine(synapse_push_config) + }} + +synapse_homeserver_config: >- + {{ synapse_default_config + | combine(synapse_config | default({})) }} diff --git a/roles/synapse/defaults/main/homeserver.database.yml b/roles/synapse/defaults/main/homeserver.database.yml new file mode 100644 index 0000000..2dd0ccb --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.database.yml @@ -0,0 +1,10 @@ +--- +synapse_config_database_name: sqlite3 +synapse_config_database_args: + database: "{{ synapse_sqlite_database_file }}" +synapse_config_database_txn_limit: "{{ 10000 | int}}" + +synapse_database_config: + name: "{{ synapse_config_database_name }}" + args: "{{ synapse_config_database_args }}" + txn_limit: "{{ synapse_config_database_txn_limit }}" diff --git a/roles/synapse/defaults/main/homeserver.email.yml b/roles/synapse/defaults/main/homeserver.email.yml new file mode 100644 index 0000000..2f2f047 --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.email.yml @@ -0,0 +1,51 @@ +--- +synapse_config_email_smtp_host: ~ +synapse_config_email_smtp_port: 465 +synapse_config_email_smtp_user: ~ +synapse_config_email_smtp_pass: ~ +synapse_config_email_force_tls: false +synapse_config_email_require_transport_security: false +synapse_config_email_enable_tls: true +synapse_config_email_app_name: "[matrix]" +synapse_config_email_notif_from: >- + "%(app)s" +synapse_config_email_enable_notifs: false +synapse_config_email_notif_for_new_users: true +synapse_config_email_notif_delay_before_mail: "10m" +synapse_config_email_client_base_url: "https://matrix.to" +synapse_config_email_validation_token_lifetime: "1h" +synapse_config_email_invite_client_location: ~ +synapse_config_email_subjects: {} + +synapse_email_config: >- + {{ + (synapse_base_email_config + if synapse_config_email_smtp_host | default(false, true) else {}) + | combine(synapse_base_email_auth_config + if (synapse_config_email_smtp_user | default(false, true) + and synapse_config_email_smtp_pass | default(false, true)) + else {}) + | combine(({"email": {"invite_client_location": synapse_config_email_invite_client_location}}) + if synapse_config_email_invite_client_location | default(false, true) else {}) + }} +synapse_base_email_auth_config: + smtp_user: "{{ synapse_config_email_smtp_user }}" + smtp_pass: "{{ synapse_config_email_smtp_pass }}" +synapse_base_email_config: + email: + smtp_host: "{{ synapse_config_email_smtp_host }}" + smtp_port: "{{ synapse_config_email_smtp_port }}" + force_tls: "{{ synapse_config_email_force_tls }}" + require_transport_security: >- + {{ synapse_config_email_require_transport_security}} + enable_tls: "{{ synapse_config_email_enable_tls }}" + app_name: "{{ synapse_config_email_app_name }}" + notif_from: "{[ synapse_config_email_notif_from }}" + enable_notifs: "{{ synapse_config_email_enable_notifs }}" + notif_for_new_users: "{{ synapse_config_email_notif_for_new_users }}" + notif_delay_before_mail: >- + {{ synapse_config_email_notif_delay_before_mail }} + client_base_url: "{{ synapse_config_email_client_base_url }}" + validation_token_lifetime: >- + {{ synapse_config_email_validation_token_lifetime }} + subjects: "{{ synapse_config_email_subjects }}" diff --git a/roles/synapse/defaults/main/homeserver.federation.yml b/roles/synapse/defaults/main/homeserver.federation.yml new file mode 100644 index 0000000..6eb0be8 --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.federation.yml @@ -0,0 +1,39 @@ +--- +# see https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#federation +synapse_config_federation_domain_whitelist: ~ +synapse_config_federation_whitelist_endpoint_enabled: true +synapse_config_federation_metrics_domains: [] +# see https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#federation-1 +# for federation retry / network tuning +synapse_config_federation: {} +synapse_config_allow_profile_lookup_over_federation: false +synapse_config_allow_device_name_lookup_over_federation: false + +synapse_config_federation_verify_certificates: true +synapse_config_federation_client_minimum_tls_version: "1.2" +synapse_config_federation_verification_whitelist: [] +synapse_config_federation_custom_ca_list: [] + +synapse_federation_tls_config: + federation_verify_certificates: "{{ synapse_config_federation_verify_certificates }}" + federation_client_minimum_tls_version: >- + {{ synapse_config_federation_client_minimum_tls_version }} + federation_certificate_verification_whitelist: >- + {{ synapse_config_federation_verification_whitelist }} + +synapse_federation_config: >- + {{ + { + "federation_whitelist_endpoint_enabled" : synapse_config_federation_whitelist_endpoint_enabled, + "federation_metrics_domains": synapse_config_federation_metrics_domains, + "allow_profile_lookup_over_federation": synapse_config_allow_profile_lookup_over_federation, + "allow_device_name_lookup_over_federation": synapse_config_allow_device_name_lookup_over_federation, + "federation": synapse_config_federation + } + | combine(synapse_federation_tls_config) + | combine(({"federation_custom_ca_list": synapse_config_federation_custom_ca_list}) + if (synapse_config_federation_custom_ca_list | default(false, true) + and synapse_config_federation_custom_ca_list | length > 0) else {}) + | combine(({"federation_domain_whitelist": synapse_config_federation_domain_whitelist}) + if synapse_config_federation_domain_whitelist | default(false, true) else {}) + }} diff --git a/roles/synapse/defaults/main/homeserver.listeners.yml b/roles/synapse/defaults/main/homeserver.listeners.yml new file mode 100644 index 0000000..9a44d5f --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.listeners.yml @@ -0,0 +1,41 @@ +--- +synapse_config_listeners: >- + {{ synapse_listeners_default_config }} +synapse_config_listeners_port: 8080 +synapse_config_listeners_tls: false +synapse_config_listeners_type: http +synapse_config_listeners_x_forwarded: true +synapse_config_listeners_bind_addresses: + - "::1" + - "127.0.0.1" +synapse_config_listeners_resources: + - names: "{{ synapse_config_listeners_resources_names }}" + compress: "{{ synapse_config_listeners_resources_compress }}" +synapse_config_listeners_resources_names: + - client + - federation +synapse_config_listeners_resources_compress: false +synapse_listeners_default_config: + - port: "{{ synapse_config_listeners_port }}" + tls: "{{ synapse_config_listeners_tls }}" + type: "{{ synapse_config_listeners_type }}" + x_forwarded: "{{ synapse_config_listeners_x_forwarded }}" + bind_addresses: "{{ synapse_config_listeners_bind_addresses }}" + resources: "{{ synapse_config_listeners_resources }}" +synapse_config_metrics_listener_port: 9000 +synapse_config_metrics_listener_tls: false +synapse_config_metrics_listener_type: http +synapse_config_metrics_listener_x_forwarded: false +synapse_config_metrics_listener_bind_addresses: + - "127.0.0.1" + - "::1" +synapse_config_metrics_listener_resources: + - names: metrics + compress: false +synapse_metrics_listener: + - port: "{{ synapse_config_metrics_listener_port }}" + tls: "{{ synapse_config_metrics_listener_tls }}" + type: "{{ synapse_config_metrics_listener_type }}" + x_forwarded: "{{ synapse_config_metrics_listener_x_forwarded }}" + bind_addresses: "{{ synapse_config_metrics_listener_bind_addresses }}" + resources: "{{ synapse_config_metrics_listener_resources }}" diff --git a/roles/synapse/defaults/main/homeserver.media_repo.yml b/roles/synapse/defaults/main/homeserver.media_repo.yml new file mode 100644 index 0000000..dee2969 --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.media_repo.yml @@ -0,0 +1,99 @@ +--- +# Media repo configuration +synapse_config_enable_media_repo: true #TODO: set to false if workers enabled +synapse_config_enable_authenticated_media: true +synapse_config_media_store_path: "{{ synapse_media_store_path }}" +synapse_config_max_pending_media_uploads: 10 +synapse_config_unused_expiration_time: "1h" +# see https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#media_storage_providers +synapse_config_media_store_providers: [] +synapse_config_max_upload_size: "50M" +synapse_config_max_image_pixels: "32M" +synapse_config_dynamic_thumbnails: true + +# The following values are KiB/Mib per burst/second +synapse_config_remote_media_download_burst_count: "500M" +synapse_config_remote_media_download_per_second: "87K" + +# Blacklist known spam servers here +synapse_config_prevent_media_downloads_from: [] + +synapse_config_media_retention_local_media_lifetime: ~ +synapse_config_media_retention_remote_media_lifetime: ~ +synapse_config_media_retention: >- + {{ {} + | combine(({"local_media_lifetime": synapse_config_media_retention_local_media_lifetime}) + if synapse_config_media_retention_local_media_lifetime | default(false, true) else {}) + | combine(({"remote_media_lifetime": synapse_config_media_retention_remote_media_lifetime }) + if synapse_config_media_retention_remote_media_lifetime | default(false, true) else {}) + }} + +# URL preview handling +synapse_config_url_preview_enabled: true +# Following recommendations from +# https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#url_preview_ip_range_blacklist +synapse_config_url_preview_ip_range_blacklist: + - '127.0.0.0/8' + - '10.0.0.0/8' + - '172.16.0.0/12' + - '192.168.0.0/16' + - '100.64.0.0/10' + - '192.0.0.0/24' + - '169.254.0.0/16' + - '192.88.99.0/24' + - '198.18.0.0/15' + - '192.0.2.0/24' + - '198.51.100.0/24' + - '203.0.113.0/24' + - '224.0.0.0/4' + - '::1/128' + - 'fe80::/10' + - 'fc00::/7' + - '2001:db8::/32' + - 'ff00::/8' + - 'fec0::/10' +synapse_config_url_preview_ip_range_whitelist: ~ +# see https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#url_preview_url_blacklist +synapse_config_url_preview_url_blacklist: + - username: "*" + - netloc: '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + # see https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#url_preview_accept_language +synapse_config_url_preview_accept_language: + - "en" +synapse_config_max_spider_size: 8M +synapse_config_oembed_disable_default_providers: false +synapse_config_oembed_additional_providers: [] + +synapse_base_media_config: + enable_media_repo: "{{ synapse_config_enable_media_repo }}" + enable_authenticated_media: "{{ synapse_config_enable_authenticated_media }}" + media_store_path: "{{ synapse_config_media_store_path }}" + max_pending_media_uploads: "{{ synapse_config_max_pending_media_uploads }}" + unused_expiration_time: "{{ synapse_config_unused_expiration_time }}" + media_store_providers: "{{ synapse_config_media_store_providers }}" + max_upload_size: "{{ synapse_config_max_upload_size }}" + max_image_pixels: "{{ synapse_config_max_image_pixels }}" + # Media - remote media handling + remote_media_download_burst_count: >- + {{ synapse_config_remote_media_download_burst_count }} + remote_media_download_per_second: >- + {{ synapse_config_remote_media_download_per_second }} + prevent_media_downloads_from: "{{ synapse_config_prevent_media_downloads_from }}" + media_retention: "{{ synapse_config_media_retention }}" + # Media - URL preview options + dynamic_thumbnails: "{{ synapse_config_dynamic_thumbnails }}" + url_preview_enabled: "{{ synapse_config_url_preview_enabled }}" + url_preview_ip_range_blacklist: >- + {{ synapse_config_url_preview_ip_range_blacklist }} + url_preview_url_blacklist: "{{ synapse_config_url_preview_url_blacklist }}" + url_preview_accept_language: "{{ synapse_config_url_preview_accept_language }}" + max_spider_size: "{{ synapse_config_max_spider_size }}" + oembed: + disable_default_providers: "{{ synapse_config_oembed_disable_default_providers }}" + additional_providers: "{{ synapse_config_oembed_additional_providers }}" +synapse_media_config: >-2 + {{ + synapse_base_media_config + | combine(({'url_preview_ip_range_whitelist': synapse_config_url_preview_ip_range_whitelist}) + if synapse_config_url_preview_ip_range_whitelist | default(false, true) else {}) + }} diff --git a/roles/synapse/defaults/main/homeserver.metrics.yml b/roles/synapse/defaults/main/homeserver.metrics.yml new file mode 100644 index 0000000..64c6ff2 --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.metrics.yml @@ -0,0 +1,28 @@ +--- +synapse_config_enable_metrics: false +synapse_config_sentry_environment: ~ +synapse_config_sentry_dsn: ~ +synapse_config_metrics_flags_known_servers: true +synapse_config_report_stats: true +synapse_config_report_stats_endpoint: >- + https://matrix.org/report-usage-stats/push + +synapse_metrics_sentry_config: >- + {{ {} + | combine(({"environment": synapse_config_sentry_environment }) + if synapse_config_sentry_environment | default(false, true) else {}) + | combine(({"dsn": synapse_config_sentry_dsn }) + if synapse_config_sentry_dsn | default(false, true) else {}) + }} + +synapse_base_metrics_config: + enable_metrics: "{{ synapse_config_enable_metrics }}" + metrics_flags: + known_servers: "{{ synapse_config_metrics_flags_known_servers }}" + report_stats: "{{ synapse_config_report_stats }}" + report_stats_endpoint: "{{ synapse_config_report_stats_endpoint }}" +synapse_metrics_config: >- + {{ synapse_base_metrics_config + | combine(({"sentry": synapse_metrics_sentry_config}) + if (synapse_config_sentry_dsn or synapse_config_sentry_environment) else {}) + }} diff --git a/roles/synapse/defaults/main/homeserver.push.yml b/roles/synapse/defaults/main/homeserver.push.yml new file mode 100644 index 0000000..2f546e2 --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.push.yml @@ -0,0 +1,13 @@ +--- +synapse_config_push_enabled: true +synapse_config_push_include_content: true +synapse_config_push_group_unread_count_by_room: true +synapse_config_push_jitter_delay: "1s" + +synapse_push_config: + push: + enabled: "{{ synapse_config_push_enabled }}" + include_content: "{{ synapse_config_push_include_content }}" + group_unread_count_by_room: >- + {{ synapse_config_push_group_unread_count_by_room }} + jitter_delay: "{{ synapse_config_push_jitter_delay }}" diff --git a/roles/synapse/defaults/main/homeserver.ratelimits.yml b/roles/synapse/defaults/main/homeserver.ratelimits.yml new file mode 100644 index 0000000..a59b8ce --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.ratelimits.yml @@ -0,0 +1,112 @@ +--- +# Ratelimit config, see +# https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#ratelimiting +synapse_config_rc_message_per_second: 0.2 +synapse_config_rc_message_burst_count: 10 + +synapse_config_rc_registration_per_second: 0.1 +synapse_config_rc_registration_burst_count: 5 + +synapse_config_rc_registration_token_validity_per_second: 0.1 +synapse_config_rc_registration_token_validity_burst_count: 5 + +synapse_config_rc_login_address_per_second: 0.003 +synapse_config_rc_login_address_burst_count: 5 +synapse_config_rc_login_account_per_second: 0.003 +synapse_config_rc_login_account_burst_count: 5 +synapse_config_rc_login_failed_attempts_per_second: 0.17 +synapse_config_rc_login_failed_attempts_burst_count: 3 + +synapse_config_rc_admin_redaction_per_second: 2 +synapse_config_rc_admin_redaction_burst_count: 75 + +synapse_config_rc_joins_local_per_second: 0.1 +synapse_config_rc_joins_local_burst_count: 10 +synapse_config_rc_joins_remote_per_second: 0.01 +synapse_config_rc_joins_remote_burst_count: 10 +synapse_config_rc_joins_per_room_per_second: 1 +synapse_config_rc_joins_per_room_burst_count: 10 + +synapse_config_rc_3pid_validation_per_second: 0.003 +synapse_config_rc_3pid_validation_burst_count: 5 + +synapse_config_rc_invites_per_room_per_second: 0.3 +synapse_config_rc_invites_per_room_burst_count: 10 +synapse_config_rc_invites_per_user_per_second: 0.003 +synapse_config_rc_invites_per_user_burst_count: 5 +synapse_config_rc_invites_per_issuer_per_second: 0.3 +synapse_config_rc_invites_per_issuer_burst_count: 10 + +synapse_config_rc_third_party_invite_per_second: 0.2 +synapse_config_rc_third_party_invite_burst_count: 10 + +synapse_config_rc_media_create_per_second: 10 +synapse_config_rc_media_create_burst_count: 50 + +synapse_config_rc_federation_window_size: 1000 # in ms +synapse_config_rc_federation_sleep_limit: 10 +synapse_config_rc_federation_sleep_delay: 500 # in ms +synapse_config_rc_federation_reject_limit: 50 +synapse_config_rc_federation_concurrent: 5 +synapse_config_federation_rr_transactions_per_room_per_second: 50 + +synapse_ratelimit_config: + rc_message: + per_second: "{{ synapse_config_rc_message_per_second }}" + burst_count: "{{ synapse_config_rc_message_burst_count }}" + rc_registration: + per_second: "{{ synapse_config_rc_registration_per_second }}" + burst_count: "{{ synapse_config_rc_registration_burst_count }}" + rc_registration_token_validity: + per_second: "{{ synapse_config_rc_registration_token_validity_per_second }}" + burst_count: "{{ synapse_config_rc_registration_token_validity_burst_count }}" + rc_login: + address: + per_second: "{{ synapse_config_rc_login_address_per_second }}" + burst_count: "{{ synapse_config_rc_login_address_burst_count }}" + account: + per_second: "{{ synapse_config_rc_login_account_per_second }}" + burst_count: "{{ synapse_config_rc_login_account_burst_count}}" + failed_attemps: + per_second: "{{ synapse_config_rc_login_failed_attempts_per_second }}" + burst_count: "{{ synapse_config_rc_login_failed_attempts_burst_count }}" + rc_admin_redaction: + per_second: "{{ synapse_config_rc_admin_redaction_per_second }}" + burst_count: "{{ synapse_config_rc_admin_redaction_burst_count }}" + rc_joins: + local: + per_second: "{{ synapse_config_rc_joins_local_per_second }}" + burst_count: "{{ synapse_config_rc_joins_local_burst_count }}" + remote: + per_second: "{{ synapse_config_rc_joins_remote_per_second }}" + burst_count: "{{ synapse_config_rc_joins_remote_burst_count}}" + rc_joins_per_room: + per_second: "{{ synapse_config_rc_joins_per_room_per_second }}" + burst_count: "{{ synapse_config_rc_joins_per_room_burst_count }}" + rc_3pid_validation: + per_second: "{{ synapse_config_rc_3pid_validation_per_second }}" + burst_count: "{{ synapse_config_rc_3pid_validation_burst_count }}" + rc_invites: + per_room: + per_second: "{{ synapse_config_rc_invites_per_room_per_second }}" + burst_count: "{{ synapse_config_rc_invites_per_room_burst_count }}" + per_user: + per_second: "{{ synapse_config_rc_invites_per_user_per_second }}" + burst_count: "{{ synapse_config_rc_invites_per_user_burst_count }}" + per_issuer: + per_second: "{{ synapse_config_rc_invites_per_issuer_per_second }}" + burst_count: "{{ synapse_config_rc_invites_per_issuer_burst_count }}" + rc_third_party_invite: + per_second: "{{ synapse_config_rc_third_party_invite_per_second }}" + burst_count: "{{ synapse_config_rc_third_party_invite_burst_count }}" + rc_media_create: + per_second: "{{ synapse_config_rc_media_create_per_second }}" + burst_count: "{{ synapse_config_rc_media_create_burst_count }}" + rc_federation: + window_size: "{{ synapse_config_rc_federation_window_size }}" + sleep_limit: "{{ synapse_config_rc_federation_sleep_limit }}" + sleep_delay: "{{ synapse_config_rc_federation_sleep_delay }}" + reject_limit: "{{ synapse_config_rc_federation_reject_limit }}" + concurrent: "{{ synapse_config_rc_federation_concurrent }}" + federation_rr_transactions_per_room_per_second: >- + {{ synapse_config_federation_rr_transactions_per_room_per_second }} diff --git a/roles/synapse/defaults/main/homeserver.server.yml b/roles/synapse/defaults/main/homeserver.server.yml new file mode 100644 index 0000000..e6f2c0d --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.server.yml @@ -0,0 +1,78 @@ +--- +# Config options from the `server` section of +# https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#server +synapse_config_pid_file: "{{ synapse_pid_file }}" +synapse_config_public_baseurl: "https://{{ synapse_config_server_name }}" +synapse_config_serve_server_wellknown: false +synapse_config_extra_well_known_client_content: {} +synapse_config_soft_file_limit: 0 +synapse_config_require_auth_for_profile_requests: false +synapse_config_limit_profile_requests_to_users_who_share_rooms: false +synapse_config_include_profile_data_on_invite: true +synapse_config_allow_public_rooms_without_auth: false +synapse_config_allow_public_rooms_over_federation: false +synapse_config_default_room_version: "10" +synapse_config_filter_timeline_limit: 200 +synapse_config_block_non_admin_invites: false +synapse_config_enable_search: true +synapse_config_dummy_events_threshold: 10 +synapse_config_delete_stale_devices_after: "90d" +synapse_config_key_refresh_interval: "1d" +synapse_config_suppress_key_server_warning: false + +synapse_config_ip_range_blacklist: + - '127.0.0.0/8' + - '10.0.0.0/8' + - '172.16.0.0/12' + - '192.168.0.0/16' + - '100.64.0.0/10' + - '192.0.0.0/24' + - '169.254.0.0/16' + - '192.88.99.0/24' + - '198.18.0.0/15' + - '192.0.2.0/24' + - '198.51.100.0/24' + - '203.0.113.0/24' + - '224.0.0.0/4' + - '::1/128' + - 'fe80::/10' + - 'fc00::/7' + - '2001:db8::/32' + - 'ff00::/8' + - 'fec0::/10' +synapse_config_ip_range_whitelist: [] + +synapse_default_server_config: + server_name: "{{ synapse_config_server_name }}" + pid_file: "{{ synapse_config_pid_file }}" + listeners: "{{ synapse_listeners_config }}" + database: "{{ synapse_database_config }}" + log_config: "{{ synapse_config_log_config_path }}" + signing_key_path: "{{ synapse_config_signing_key_path }}" + key_refresh_interval: "{{ synapse_config_key_refresh_interval }}" + trusted_key_servers: "{{ synapse_config_trusted_key_servers }}" + suppress_key_server_warning: "{{ synapse_config_suppress_key_server_warning }}" + public_baseurl: "{{ synapse_config_public_baseurl }}" + serve_server_wellknown: "{{ synapse_config_serve_server_wellknown }}" + extra_well_known_client_content: >- + {{ synapse_config_extra_well_known_client_content }} + soft_file_limit: "{{ synapse_config_soft_file_limit }}" + # presence: TODO + require_auth_for_profile_requests: >- + {{ synapse_config_require_auth_for_profile_requests }} + limit_profile_requests_to_users_who_share_rooms: >- + {{ synapse_config_limit_profile_requests_to_users_who_share_rooms }} + include_profile_data_on_invite: >- + {{ synapse_config_include_profile_data_on_invite }} + allow_public_rooms_without_auth: >- + {{ synapse_config_allow_public_rooms_without_auth }} + allow_public_rooms_over_federation: >- + {{ synapse_config_allow_public_rooms_over_federation }} + default_room_version: "{{ synapse_config_default_room_version }}" + filter_timeline_limit: "{{ synapse_config_filter_timeline_limit }}" + block_non_admin_invites: "{{ synapse_config_block_non_admin_invites }}" + enable_search: "{{ synapse_config_enable_search }}" + ip_range_blacklist: "{{ synapse_config_ip_range_blacklist }}" + ip_range_whitelist: "{{ synapse_config_ip_range_whitelist }}" + dummy_events_threshold: "{{ synapse_config_dummy_events_threshold }}" + delete_stale_devices_after: "{{ synapse_config_delete_stale_devices_after }}" diff --git a/roles/synapse/defaults/main/homeserver.tls.yml b/roles/synapse/defaults/main/homeserver.tls.yml new file mode 100644 index 0000000..3a014f3 --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.tls.yml @@ -0,0 +1,10 @@ +--- +synapse_config_tls_certificate_path: ~ +synapse_config_tls_private_key_path: ~ +synapse_tls_config: >- + {{ {} + | combine(({"tls_certificate_path": synapse_config_tls_certificate_path }) + if synapse_config_tls_certificate_path | default(false, true) else {}) + | combine(({"tls_private_key_path": synapse_config_tls_private_key_path }) + if synapse_config_tls_private_key_path | default(false, true) else {}) + }} diff --git a/roles/synapse/defaults/main/homeserver.turn.yml b/roles/synapse/defaults/main/homeserver.turn.yml new file mode 100644 index 0000000..9b680d7 --- /dev/null +++ b/roles/synapse/defaults/main/homeserver.turn.yml @@ -0,0 +1,23 @@ +--- +# TURN / RTC configuration +synapse_config_turn_uris: [] +synapse_config_turn_shared_secret: ~ +synapse_config_turn_username: ~ +synapse_config_turn_password: ~ +synapse_config_turn_user_lifetime: "2h" +synapse_config_turn_allow_guests: false + +synapse_turn_config_base: + turn_uris: "{{ synapse_config_turn_uris }}" + turn_user_lifetime: "{{ synapse_config_turn_user_lifetime }}" + turn_allow_guests: "{{ synapse_config_turn_allow_guests }}" +synapse_turn_config: >-2 + {{ + synapse_turn_config_base + | combine(({ turn_shared_secret: synapse_config_turn_shared_secret }) + if synapse_config_turn_shared_secret | default(false, true) else {}) + | combine(({ turn_username: synapse_config_turn_username }) + if synapse_config_username | default(false, true) else {}) + | combine(({ turn_password: synapse_config_turn_password }) + if synapse_config_turn_password | default(false, true) else {}) + }} diff --git a/roles/synapse/defaults/main/log.config.yml b/roles/synapse/defaults/main/log.config.yml new file mode 100644 index 0000000..2cdc7e0 --- /dev/null +++ b/roles/synapse/defaults/main/log.config.yml @@ -0,0 +1,88 @@ +--- + +synapse_log_config_root_level: "INFO" +synapse_log_config_disable_existing_loggers: false + +# Formatter config +synapse_log_config_formatters_precise_name: precise +synapse_log_config_formatters_precise: + format: >- + %(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s +synapse_log_config_formatters: >- + {{ + { synapse_log_config_formatters_precise_name: synapse_log_config_formatters_precise } + }} + +# Loggers config +synapse_log_config_loggers_synapse_storage_sql_level: >- + {{ synapse_log_config_root_level }} +synapse_log_config_loggers_synapse_storage_sql: + level: "{{ synapse_log_config_loggers_synapse_storage_sql_level }}" +synapse_log_config_loggers: + "synapse.storage.SQL": "{{ synapse_log_config_loggers_synapse_storage_sql }}" + +# File handler +synapse_log_config_handlers_file_name: file +synapse_log_config_handlers_file_class: >- + logging.handlers.TimedRotatingFileHandler +synapse_log_config_handlers_file_formatter: >- + {{ synapse_log_config_formatters_precise_name }} +synapse_log_config_handlers_file_filename: >- + {{ synapse_homeserver_log_path }} +synapse_log_config_handlers_file_when: midnight +synapse_log_config_handlers_file_backup_count: 3 +synapse_log_config_handlers_file_encoding: utf8 +synapse_log_config_handlers_file: + class: "{{ synapse_log_config_handlers_file_class }}" + formatter: "{{ synapse_log_config_handlers_file_formatter }}" + filename: "{{ synapse_log_config_handlers_file_filename }}" + when: "{{ synapse_log_config_handlers_file_when }}" + backupCount: "{{ synapse_log_config_handlers_file_backup_count }}" + encoding: "{{ synapse_log_config_handlers_file_encoding }}" + +# Buffer handler +synapse_log_config_handlers_buffer_name: buffer +synapse_log_config_handlers_buffer_class: >- + synapse.logging.handlers.PeriodicallyFlushingMemoryHandler +synapse_log_config_handlers_buffer_target: file +synapse_log_config_handlers_buffer_capacity: 10 +synapse_log_config_handlers_buffer_flush_level: 30 +synapse_log_config_handlers_buffer_period: 5 +synapse_log_config_handlers_buffer: + class: "{{ synapse_log_config_handlers_buffer_class }}" + target: "{{ synapse_log_config_handlers_buffer_target }}" + capacity: "{{ synapse_log_config_handlers_buffer_capacity }}" + flushLevel: "{{ synapse_log_config_handlers_buffer_flush_level }}" + period: "{{ synapse_log_config_handlers_buffer_period }}" + +# Console handler +synapse_log_config_handlers_console_name: console +synapse_log_config_handlers_console_class: logging.StreamHandler +synapse_log_config_handlers_console_formatter: >- + {{ synapse_log_config_formatters_precise_name }} +synapse_log_config_handlers_console: + class: "{{ synapse_log_config_handlers_console_class }}" + formatter: "{{ synapse_log_config_handlers_console_formatter }}" + +# Handler config +synapse_log_config_handlers: >-2 + {{ + { + synapse_log_config_handlers_file_name: synapse_log_config_handlers_file, + synapse_log_config_handlers_buffer_name: synapse_log_config_handlers_buffer, + synapse_log_config_handlers_console_name: synapse_log_config_handlers_console, + } + }} + +synapse_log_config_root_handlers: + - "{{ synapse_log_config_handlers_buffer_name }}" + +synapse_log_config: + version: 1 + formatters: "{{ synapse_log_config_formatters }}" + root: + level: "{{ synapse_log_config_root_level }}" + handlers: "{{ synapse_log_config_root_handlers }}" + handlers: "{{ synapse_log_config_handlers }}" + loggers: "{{ synapse_log_config_loggers }}" + disable_existing_loggers: "{{ synapse_log_config_disable_existing_loggers }}" diff --git a/roles/synapse/defaults/main/main.yml b/roles/synapse/defaults/main/main.yml new file mode 100644 index 0000000..ccfaf6a --- /dev/null +++ b/roles/synapse/defaults/main/main.yml @@ -0,0 +1,24 @@ +--- + +synapse_user: synapse +synapse_version: "1.115.0" +synapse_state: "present" +synapse_deployment_method: "docker" + +synapse_base_path: /opt/synapse +synapse_config_path: "{{ synapse_base_path }}/config" +synapse_data_path: "{{ synapse_base_path }}/data" +synapse_media_store_path: "{{ synapse_data_path }}/media_store" +synapse_log_path: "/var/log/synapse" +synapse_homeserver_log_path: "{{ synapse_log_path }}/homeserver.log" + +synapse_signing_key: ~ +synapse_signing_key_file: >- + {{ synapse_config_path }}/{{ synapse_domain }}.signing.key +synapse_homeserver_config_file: "{{ synapse_config_path }}/homeserver.yaml" +synapse_logging_config_file: >- + {{ synapse_config_path }}/{{ synapse_domain }}.log.config +synapse_pid_file: "{{ synapse_data_path }}/homeserver.pid" +synapse_sqlite_database_file: "{{ synapse_data_path }}/homeserver.db" + +synapse_role_generate_signing_key: false diff --git a/roles/synapse/docs/database.md b/roles/synapse/docs/database.md new file mode 100644 index 0000000..8319e53 --- /dev/null +++ b/roles/synapse/docs/database.md @@ -0,0 +1,27 @@ +# `synapse` database configuration + +Per default, the ansible role supplies a `sqlite`-database (file-based), +which is located in `/opt/synapse/data/homeserver.db` (`synapse_sqlite_database_file`). + +## PostgresQL + +To configure synapse for use with postgresql, set `synapse_config_database_name` to `psycopg2`. + +Set your connection information in `synapse_config_database_args` like this: +```yaml +synapse_config_database_args: + user: my_synapse_db_user + password: my_synapse_db_password + host: my_database_host + port: my_database_port_to_connect_to + # connection pooling (cp) settings, min and max connections + cp_min: 5 | int + cp_max: 20 | int +``` + +Also see [the upstream documentation on the `database` config key](https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#database-1). + +## Transaction limits + +The ansible role sets a default transaction limit of 10.000 concurrent transactions. +This configuration can be overridden in `synapse_config_database_txn_limit`. diff --git a/roles/synapse/docs/listeners.md b/roles/synapse/docs/listeners.md new file mode 100644 index 0000000..0c707ee --- /dev/null +++ b/roles/synapse/docs/listeners.md @@ -0,0 +1,85 @@ +# `synapse` listener config + +Synapse serves endpoints under so-called listeners, which are +defined in `synapse_listeners_config`. The role gives some pre- +configured options to set for use in various scenarios. + +## Behind reverse proxy which does SSL offloading + +The `synapse_listeners_default_config` is analog to the upstream +defaults and will serve both federation and client API on a +single HTTP port, without TLS or compression, while trusting the +`X-Forwarded-For` headers. + +Use it like this: +```yaml +synapse_listeners_config: "{{ synapse_listeners_default_config }}" +# Change the port like this +synapse_config_listeners_port: 8090 +# If you use docker or your reverse-proxy is not local, +# set the listen_addresses like this +synapse_config_listeners_bind_addresses: + - "::" + - "0.0.0.0" +``` + +### Additional local metrics listener + +The role provides a ready-to-use configuration for a locally-reachable +metrics listener in `synapse_metrics_listener`. + +To enable it, set `synapse_config_listeners: "{{ synapse_listeners_default_config + synapse_metrics_listener}}`. + +To customize the listener, see [the `synapse_config_metrics_listener_*` variables +in `defaults/main/homeserver.listeners.yml`](../defaults/main/homeserver.listeners.yml). + +The defaults will create a http-only metrics listener on port 9000 which +will listen on `127.0.0.1` and `::1`. + +## Synapse handling TLS without reverse proxy + +Supply your certificates using `synapse_config_tls_{certificate,private_key}_path`. + +Then you can either customize the default listener like this: +```yaml +# synapse_config_tls_certificate_path: "/etc/ssl/{{ synapse_domain }}.pem" +# synapse_config_tls_private_key_path: "/etc/ssl/{{ synapse_domain }}.key" +synapse_config_listeners_port: 443 +synapse_config_listeners_tls: true +synapse_config_listeners_type: https +synapse_config_listeners_x_forwarded: false +synapse_config_listeners_resources_compress: true +synapse_config_serve_server_wellknown: true +``` + +or you can serve federation over a different port, by completely rewriting +the role's defaults: +```yaml +synapse_config_listeners: + - port: 8448 + tls: true + type: https + x_forwarded: true + bind_addresses: + - 10.0.0.1 + - fd00::1 + resources: + - names: federation + compress: true + - port: 443 + tls: true + type: https + x_forwarded: true + bind_addresses: + - 10.0.0.2 + - fd00::2 + resources: + - names: client + compress: true +``` + +It is possible to mix and match those listeners to almost all requirements, +like listening locally without HTTPs for federation and using a WAF / firewall / +reverse proxy infront of synapse for federation (see: "Secure Border Gateways") +and trusting the `X-Forwarded-For` Header, while having clients +directly connect to synapse. diff --git a/roles/synapse/docs/logging.md b/roles/synapse/docs/logging.md new file mode 100644 index 0000000..3138ab4 --- /dev/null +++ b/roles/synapse/docs/logging.md @@ -0,0 +1,48 @@ +# `synapse` logging configuration + +Synapse uses a `buffer` handler per default, which flushes +periodically, but flushes logs immediately for log events +with a level greater or equal to WARNING. + +To set your desired log level, specify it in `synapse_log_config_root_level`. + +## Formatters + +By default, the upstream `precise` formatter is availabe. To define and use +more formatters, extend `synapse_log_config_formatters` like this: + +```yaml +synapse_log_config_formatters_custom_json: + custom_json: + format: >- + {"lineno": %(lineno)d, "level": "%(levelname)s", "req_id": "%(request)s", "msg": "%(message)s"} +synapse_log_config_formatters: >-2 + {{ + ({ synapse_log_config_formatters_precise_name: synapse_log_config_formatters_precise }) + | combine(synapse_log_config_formatters_custom_json) + }} + +# Set handlers to use your formatter like this +synapse_log_config_handlers_file_formatter: custom_json +synapse_log_config_handlers_console_formatter: custom_json +``` + +## Handlers + +For modifying the built-in `file`/`buffer`/`console` handlers, see +[the defaults in `../defaults/main/log.config.yml`](../defaults/main/log.config.yml). + +### Containers + +For typical container setups, it is often recommended to log all +logs to `stdout`/`stderr`. This can be easily archieved by setting +`synapse_log_config_root_handlers: [ synapse_log_config_handlers_console_name ]`. + +## Child loggers + +To set a different configuration / log level for child loggers of +the root logger (currently, this is only `synapse.storage.SQL`), +override `synapse_log_config_loggers` directly or for the SQL loggers, +set the level in `synapse_log_config_loggers_synapse_storage_sql_level` +(which defaults to `synapse_log_config_root_level`). + diff --git a/roles/synapse/handlers/main.yml b/roles/synapse/handlers/main.yml new file mode 100644 index 0000000..fb47255 --- /dev/null +++ b/roles/synapse/handlers/main.yml @@ -0,0 +1,8 @@ +--- +- name: Ensure synapse is restarted + listen: synapse-restart + community.docker.docker_container: + name: "{{ synapse_container_name }}" + state: started + restart: true + when: synapse_deployment_method == 'docker' diff --git a/roles/synapse/tasks/check.yml b/roles/synapse/tasks/check.yml new file mode 100644 index 0000000..b5ab290 --- /dev/null +++ b/roles/synapse/tasks/check.yml @@ -0,0 +1,32 @@ +--- +- name: Ensure synapse_state is valid + ansible.builtin.fail: + msg: "State '{{ synapse_state }}' is not known, supported states are {{ synapse_states | join(', ') }}" + when: synapse_state not in synapse_states + +- name: Ensure synapse deployment method is supported + ansible.builtin.fail: + msg: >- + Deployment method '{{ synapse_deployment_method }}' + is unknown! Supported methods are: + {{ synapse_deployment_methods | join(', ') }} + when: synapse_deployment_method not in synapse_deployment_methods + +- name: Ensure required variables are given + fail: + msg: "Required variable '{{ item }}' is undefined!" + loop: "{{ synapse_required_variables }}" + when: >-2 + item not in hostvars[ansible_host] + or hostvars[ansible_host][item] | length == 0 + +- name: Ensure conditionally required variables are given + fail: + msg: "Required variable '{{ item.name }}' is undefined!" + loop: "{{ synapse_conditionally_required_variables }}" + loop_control: + label: "{{ item.name }}" + when: >-2 + item.when + and (item.name not in hostvars[ansible_host] + or hostvars[ansible_host][item.name] | length == 0) diff --git a/roles/synapse/tasks/configure.yml b/roles/synapse/tasks/configure.yml new file mode 100644 index 0000000..b157266 --- /dev/null +++ b/roles/synapse/tasks/configure.yml @@ -0,0 +1,66 @@ +--- +- name: Ensure synapse user '{{ synapse_user }}' is {{ synapse_state }} + ansible.builtin.user: + name: "{{ synapse_user }}" + state: "{{ synapse_state }}" + system: "{{ synapse_user_system | default(true, true) }}" + create_home: "{{ synapse_user_create_home | default(false, true) }}" + groups: "{{ synapse_user_groups | default(omit, true) }}" + append: "{{ (synapse_user_groups is defined) | ternary(true, omit) }}" + register: synapse_user_info + +- name: Ensure directories for synapse are {{ synapse_state }} + ansible.builtin.file: + path: "{{ item.path }}" + state: "{{ (synapse_state == 'present') | ternary('directory', 'absent') }}" + mode: "{{ item.mode | default('0750') }}" + owner: "{{ item.owner | default(synapse_user_info.uid | default(synapse_user)) }}" + group: "{{ item.group | default(synapse_user_info.group | default(synapse_user)) }}" + loop: + - path: "{{ synapse_base_path }}" + mode: "0755" + - path: "{{ synapse_config_path }}" + mode: "0755" + - path: "{{ synapse_data_path }}" + mode: "0755" + - path: "{{ synapse_media_store_path }}" + mode: "0755" + - path: "{{ synapse_log_path }}" + mode: "0755" + loop_control: + label: "{{ item.path }}" + +- name: Ensure synapse signing key is generated + finallycoffee.matrix.synapse_signing_key: + path: "{{ synapse_signing_key_file }}" + state: "{{ synapse_state }}" + when: synapse_role_generate_signing_key + notify: + - synapse-restart + +- name: Ensure configuration files are templated + ansible.builtin.copy: + dest: "{{ config_file.path }}" + content: "{{ config_file.content }}" + mode: "{{ config_file.mode | default('0640') }}" + owner: "{{ config_file.owner | default(synapse_user_info.uid | default(synapse_user)) }}" + group: "{{ config_file.group | default(synapse_user_info.group | default(synapse_user)) }}" + loop: >- + {{ synapse_configs_to_write + + (synapse_keys_to_write if not synapse_role_generate_signing_key else []) + + synapse_configs | default([]) }} + loop_control: + loop_var: config_file + label: "{{ config_file.path }}" + vars: + synapse_configs_to_write: + - content: "{{ synapse_homeserver_config | to_nice_yaml(width=1000) }}" + path: "{{ synapse_homeserver_config_file }}" + - content: "{{ synapse_log_config | to_nice_yaml(width=1000) }}" + path: "{{ synapse_logging_config_file }}" + synapse_keys_to_write: + - content: "{{ synapse_signing_key }}" + path: "{{ synapse_signing_key_file }}" + mode: "0640" + notify: + - synapse-restart diff --git a/roles/synapse/tasks/deploy-docker.yml b/roles/synapse/tasks/deploy-docker.yml new file mode 100644 index 0000000..fbcb62d --- /dev/null +++ b/roles/synapse/tasks/deploy-docker.yml @@ -0,0 +1,32 @@ +--- +- name: Ensure container image '{{ synapse_container_image }}' is {{ synapse_state }} on host + community.docker.docker_image: + name: "{{ synapse_container_image }}" + state: "{{ synapse_state }}" + source: "{{ synapse_container_image_source }}" + force_source: "{{ synapse_container_image_tag | default(false, true) | bool }}" + register: synapse_container_image_info + until: synapse_container_image_info is success + retries: 4 + delay: 2 + +- name: Ensure synapse container '{{ synapse_container_name }}' is {{ (synapse_state == 'present') | ternary('started', 'absent') }} + community.docker.docker_container: + name: "{{ synapse_container_name }}" + image: "{{ synapse_container_image }}" + env: "{{ synapse_container_env | default(omit, true) }}" + user: "{{ synapse_container_user | default(omit, true) }}" + groups: "{{ synapse_container_groups | default(omit, true) }}" + ports: "{{ synapse_container_ports | default(omit, true) }}" + labels: "{{ synapse_container_labels | default(omit, true) }}" + ulimits: "{{ synapse_container_ulimits | default(omit, true) }}" + volumes: "{{ synapse_container_all_volumes }}" + networks: "{{ synapse_container_networks | default(omit, true) }}" + purge_networks: "{{ synapse_container_purge_networks | default(omit, true) }}" + dns_servers: "{{ synapse_container_dns_servers | default(omit, true) }}" + etc_hosts: "{{ synapse_container_etc_hosts | default(omit, true) }}" + memory: "{{ synapse_container_memory | default(omit, true) }}" + memory_reservation: "{{ synapse_container_memory_reservation | default(omit, true) }}" + memory_swap: "{{ synapse_container_memory_swap | default(omit, true) }}" + restart_policy: "{{ synapse_container_restart_policy }}" + state: "{{ synapse_container_state }}" diff --git a/roles/synapse/tasks/main.yml b/roles/synapse/tasks/main.yml new file mode 100644 index 0000000..2b563a1 --- /dev/null +++ b/roles/synapse/tasks/main.yml @@ -0,0 +1,13 @@ +--- + +- name: Ensure checks are passing + ansible.builtin.include_tasks: + file: "check.yml" + +- name: Ensure base configuration is created + ansible.builtin.include_tasks: + file: "configure.yml" + +- name: Deploy using {{ synapse_deployment_method }} + ansible.builtin.include_tasks: + file: "deploy-{{ synapse_deployment_method }}.yml" diff --git a/roles/synapse/vars/main.yml b/roles/synapse/vars/main.yml new file mode 100644 index 0000000..00fe1c8 --- /dev/null +++ b/roles/synapse/vars/main.yml @@ -0,0 +1,14 @@ +--- +synapse_states: + - present + - absent + +synapse_deployment_methods: + - docker + +synapse_required_variables: + - synapse_domain + +synapse_conditionally_required_variables: + - name: synapse_signing_key + when: "{{ not synapse_role_generate_signing_key | bool }}"