Split playbook into multiple roles
As suggested in #63 (Github issue), splitting the playbook's logic into multiple roles will be beneficial for maintainability. This patch realizes this split. Still, some components affect others, so the roles are not really independent of one another. For example: - disabling mxisd (`matrix_mxisd_enabled: false`), causes Synapse and riot-web to reconfigure themselves with other (public) Identity servers. - enabling matrix-corporal (`matrix_corporal_enabled: true`) affects how reverse-proxying (by `matrix-nginx-proxy`) is done, in order to put matrix-corporal's gateway server in front of Synapse We may be able to move away from such dependencies in the future, at the expense of a more complicated manual configuration, but it's probably not worth sacrificing the convenience we have now. As part of this work, the way we do "start components" has been redone now to use a loop, as suggested in #65 (Github issue). This should make restarting faster and more reliable.
This commit is contained in:
50
roles/matrix-nginx-proxy/defaults/main.yml
Normal file
50
roles/matrix-nginx-proxy/defaults/main.yml
Normal file
@ -0,0 +1,50 @@
|
||||
# By default, this playbook sets up its own nginx proxy server on port 80/443.
|
||||
# This is fine if you're dedicating the whole server to Matrix.
|
||||
# But in case that's not the case, you may wish to prevent that
|
||||
# and take care of proxying by yourself.
|
||||
matrix_nginx_proxy_enabled: true
|
||||
|
||||
matrix_nginx_proxy_docker_image: "nginx:1.15.8-alpine"
|
||||
|
||||
matrix_nginx_proxy_data_path: "{{ matrix_base_data_path }}/nginx-proxy"
|
||||
matrix_nginx_proxy_confd_path: "{{ matrix_nginx_proxy_data_path }}/conf.d"
|
||||
|
||||
# The addresses where the Matrix Client API is.
|
||||
# Certain extensions (like matrix-corporal) may override this in order to capture all traffic.
|
||||
matrix_nginx_proxy_matrix_client_api_addr_with_proxy_container: "matrix-synapse:8008"
|
||||
matrix_nginx_proxy_matrix_client_api_addr_sans_proxy_container: "localhost:8008"
|
||||
|
||||
# Specifies when to reload the matrix-nginx-proxy service so that
|
||||
# a new SSL certificate could go into effect.
|
||||
matrix_nginx_proxy_reload_cron_time_definition: "20 4 */5 * *"
|
||||
|
||||
# Specifies which SSL protocols to use when serving Riot and Synapse
|
||||
# Note TLSv1.3 is not yet available in dockerized nginx
|
||||
# See: https://github.com/nginxinc/docker-nginx/issues/190
|
||||
matrix_nginx_proxy_ssl_protocols: "TLSv1.1 TLSv1.2"
|
||||
|
||||
# By default, this playbook automatically retrieves and auto-renews
|
||||
# free SSL certificates from Let's Encrypt.
|
||||
#
|
||||
# The following retrieval methods are supported:
|
||||
# - "lets-encrypt" - the playbook obtains free SSL certificates from Let's Encrypt
|
||||
# - "self-signed" - the playbook generates and self-signs certificates
|
||||
# - "manually-managed" - lets you manage certificates by yourself (manually; see below)
|
||||
#
|
||||
# If you decide to manage certificates by yourself (`matrix_ssl_retrieval_method: manually-managed`),
|
||||
# you'd need to drop them into the directory specified by `matrix_ssl_config_dir_path`
|
||||
# obeying the following hierarchy:
|
||||
# - <matrix_ssl_config_dir_path>/live/<domain>/fullchain.pem
|
||||
# - <matrix_ssl_config_dir_path>/live/<domain>/privkey.pem
|
||||
# where <domain> refers to the domains that you need (usually `hostname_matrix` and `hostname_riot`).
|
||||
matrix_ssl_retrieval_method: "lets-encrypt"
|
||||
|
||||
# Controls whether to obtain production or staging certificates from Let's Encrypt.
|
||||
matrix_ssl_lets_encrypt_staging: false
|
||||
matrix_ssl_lets_encrypt_certbot_docker_image: "certbot/certbot:v0.30.0"
|
||||
matrix_ssl_lets_encrypt_certbot_standalone_http_port: 2402
|
||||
matrix_ssl_lets_encrypt_support_email: "{{ host_specific_matrix_ssl_lets_encrypt_support_email }}"
|
||||
|
||||
matrix_ssl_base_path: "{{ matrix_base_data_path }}/ssl"
|
||||
matrix_ssl_config_dir_path: "{{ matrix_ssl_base_path }}/config"
|
||||
matrix_ssl_log_dir_path: "{{ matrix_ssl_base_path }}/log"
|
3
roles/matrix-nginx-proxy/tasks/init.yml
Normal file
3
roles/matrix-nginx-proxy/tasks/init.yml
Normal file
@ -0,0 +1,3 @@
|
||||
- set_fact:
|
||||
matrix_systemd_services_list: "{{ matrix_systemd_services_list + ['matrix-nginx-proxy'] }}"
|
||||
when: "matrix_nginx_proxy_enabled"
|
23
roles/matrix-nginx-proxy/tasks/main.yml
Normal file
23
roles/matrix-nginx-proxy/tasks/main.yml
Normal file
@ -0,0 +1,23 @@
|
||||
- import_tasks: "{{ role_path }}/tasks/init.yml"
|
||||
tags:
|
||||
- always
|
||||
|
||||
- import_tasks: "{{ role_path }}/tasks/ssl/main.yml"
|
||||
when: run_setup
|
||||
tags:
|
||||
- setup-all
|
||||
- setup-nginx-proxy
|
||||
- setup-ssl
|
||||
|
||||
- import_tasks: "{{ role_path }}/tasks/setup_nginx_proxy.yml"
|
||||
when: run_setup
|
||||
tags:
|
||||
- setup-all
|
||||
- setup-nginx-proxy
|
||||
|
||||
- import_tasks: "{{ role_path }}/tasks/self_check_well_known.yml"
|
||||
delegate_to: 127.0.0.1
|
||||
become: false
|
||||
when: run_self_check
|
||||
tags:
|
||||
- self-check
|
65
roles/matrix-nginx-proxy/tasks/self_check_well_known.yml
Normal file
65
roles/matrix-nginx-proxy/tasks/self_check_well_known.yml
Normal file
@ -0,0 +1,65 @@
|
||||
---
|
||||
|
||||
- set_fact:
|
||||
well_known_url_matrix: "https://{{ hostname_matrix }}/.well-known/matrix/client"
|
||||
well_known_url_identity: "https://{{ hostname_identity }}/.well-known/matrix/client"
|
||||
|
||||
# These well-known files may be served without a `Content-Type: application/json` header,
|
||||
# so we can't rely on the uri module's automatic parsing of JSON.
|
||||
- name: Check .well-known on the matrix hostname
|
||||
uri:
|
||||
url: "{{ well_known_url_matrix }}"
|
||||
follow_redirects: false
|
||||
return_content: true
|
||||
register: result_well_known_matrix
|
||||
ignore_errors: true
|
||||
|
||||
- name: Fail if .well-known not working on the matrix hostname
|
||||
fail:
|
||||
msg: "Failed checking that well-known is configured at `{{ hostname_matrix }}` (checked endpoint: `{{ well_known_url_matrix }}`). Is port 443 open in your firewall? Full error: {{ result_well_known_matrix }}"
|
||||
when: "result_well_known_matrix.failed"
|
||||
|
||||
- name: Parse JSON for well-known payload at the matrix hostname
|
||||
set_fact:
|
||||
well_known_matrix_payload: "{{ result_well_known_matrix.content|from_json }}"
|
||||
|
||||
- name: Fail if .well-known not CORS-aware on the matrix hostname
|
||||
fail:
|
||||
msg: "Well-known serving for `{{ hostname_matrix }}` (checked endpoint: `{{ well_known_url_matrix }}`) is not CORS-aware. The file needs to be served with an Access-Control-Allow-Origin header set."
|
||||
when: "'access_control_allow_origin' not in result_well_known_matrix"
|
||||
|
||||
- name: Report working .well-known on the matrix hostname
|
||||
debug:
|
||||
msg: "well-known is configured correctly for `{{ hostname_matrix }}` (checked endpoint: `{{ well_known_url_matrix }}`)"
|
||||
|
||||
- name: Check .well-known on the identity hostname
|
||||
uri:
|
||||
url: "{{ well_known_url_identity }}"
|
||||
follow_redirects: false
|
||||
return_content: true
|
||||
register: result_well_known_identity
|
||||
ignore_errors: true
|
||||
|
||||
- name: Fail if .well-known not working on the identity hostname
|
||||
fail:
|
||||
msg: "Failed checking that well-known is configured at `{{ hostname_identity }}` (checked endpoint: `{{ well_known_url_identity }}`). Is port 443 open in your firewall? Full error: {{ result_well_known_identity }}"
|
||||
when: "result_well_known_identity.failed"
|
||||
|
||||
- name: Parse JSON for well-known payload at the identity hostname
|
||||
set_fact:
|
||||
well_known_identity_payload: "{{ result_well_known_identity.content|from_json }}"
|
||||
|
||||
- name: Fail if .well-known not CORS-aware on the identity hostname
|
||||
fail:
|
||||
msg: "Well-known serving for `{{ hostname_identity }}` (checked endpoint: `{{ well_known_url_identity }}`) is not CORS-aware. The file needs to be served with an Access-Control-Allow-Origin header set. See docs/configuring-well-known.md"
|
||||
when: "'access_control_allow_origin' not in result_well_known_identity"
|
||||
|
||||
# For people who manually copy the well-known file, try to detect if it's outdated
|
||||
- name: Fail if well-known is different on matrix hostname and identity hostname
|
||||
fail:
|
||||
msg: "The well-known files at `{{ hostname_matrix }}` and `{{ hostname_identity }}` are different. Perhaps you copied the file manually before and now it's outdated?"
|
||||
when: "well_known_matrix_payload != well_known_identity_payload"
|
||||
|
||||
- name: Report working .well-known on the identity hostname
|
||||
debug:
|
||||
msg: "well-known is configured correctly for `{{ hostname_identity }}` (checked endpoint: `{{ well_known_url_identity }}`)"
|
83
roles/matrix-nginx-proxy/tasks/setup_nginx_proxy.yml
Normal file
83
roles/matrix-nginx-proxy/tasks/setup_nginx_proxy.yml
Normal file
@ -0,0 +1,83 @@
|
||||
---
|
||||
|
||||
#
|
||||
# Generic tasks that we always want to happen, regardless
|
||||
# if the user wants matrix-nginx-proxy or not.
|
||||
#
|
||||
# If the user would set up their own nginx proxy server,
|
||||
# the config files from matrix-nginx-proxy can be reused.
|
||||
#
|
||||
# It doesn't hurt to put them in place, even if they turn out
|
||||
# to be unnecessary.
|
||||
#
|
||||
- name: Ensure Matrix nginx-proxy paths exist
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
mode: 0750
|
||||
owner: root
|
||||
group: root
|
||||
with_items:
|
||||
- "{{ matrix_nginx_proxy_data_path }}"
|
||||
- "{{ matrix_nginx_proxy_confd_path }}"
|
||||
|
||||
- name: Ensure Matrix nginx-proxy configured
|
||||
template:
|
||||
src: "{{ role_path }}/templates/nginx-conf.d/{{ item }}.j2"
|
||||
dest: "{{ matrix_nginx_proxy_confd_path }}/{{ item }}"
|
||||
mode: 0644
|
||||
with_items:
|
||||
- "nginx-http.conf"
|
||||
- "matrix-synapse.conf"
|
||||
- "matrix-riot-web.conf"
|
||||
|
||||
|
||||
#
|
||||
# Tasks related to setting up matrix-nginx-proxy
|
||||
#
|
||||
- name: Ensure nginx Docker image is pulled
|
||||
docker_image:
|
||||
name: "{{ matrix_nginx_proxy_docker_image }}"
|
||||
when: matrix_nginx_proxy_enabled
|
||||
|
||||
- name: Allow access to nginx proxy ports in firewalld
|
||||
firewalld:
|
||||
service: "{{ item }}"
|
||||
state: enabled
|
||||
immediate: yes
|
||||
permanent: yes
|
||||
with_items:
|
||||
- "http"
|
||||
- "https"
|
||||
when: "ansible_os_family == 'RedHat' and matrix_nginx_proxy_enabled"
|
||||
|
||||
- name: Ensure matrix-nginx-proxy.service installed
|
||||
template:
|
||||
src: "{{ role_path }}/templates/systemd/matrix-nginx-proxy.service.j2"
|
||||
dest: "/etc/systemd/system/matrix-nginx-proxy.service"
|
||||
mode: 0644
|
||||
when: matrix_nginx_proxy_enabled
|
||||
|
||||
|
||||
#
|
||||
# Tasks related to getting rid of matrix-nginx-proxy (if it was previously enabled)
|
||||
#
|
||||
|
||||
- name: Check existence of matrix-nginx-proxy service
|
||||
stat:
|
||||
path: "/etc/systemd/system/matrix-nginx-proxy.service"
|
||||
register: matrix_nginx_proxy_service_stat
|
||||
|
||||
- name: Ensure matrix-nginx-proxy is stopped
|
||||
service:
|
||||
name: matrix-nginx-proxy
|
||||
state: stopped
|
||||
daemon_reload: yes
|
||||
register: stopping_result
|
||||
when: "not matrix_nginx_proxy_enabled and matrix_nginx_proxy_service_stat.stat.exists"
|
||||
|
||||
- name: Ensure matrix-nginx-proxy.service doesn't exist
|
||||
file:
|
||||
path: "/etc/systemd/system/matrix-nginx-proxy.service"
|
||||
state: absent
|
||||
when: "not matrix_nginx_proxy_enabled and matrix_nginx_proxy_service_stat.stat.exists"
|
24
roles/matrix-nginx-proxy/tasks/setup_well_known.yml
Normal file
24
roles/matrix-nginx-proxy/tasks/setup_well_known.yml
Normal file
@ -0,0 +1,24 @@
|
||||
- set_fact:
|
||||
matrix_well_known_file_path: "{{ matrix_static_files_base_path }}/.well-known/matrix/client"
|
||||
|
||||
# We need others to be able to read these directories too,
|
||||
# so that matrix-nginx-proxy's nginx user can access the files.
|
||||
#
|
||||
# For running with another webserver, we recommend being part of the `matrix` group.
|
||||
- name: Ensure Matrix static-files path exists
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
mode: 0755
|
||||
owner: "{{ matrix_user_username }}"
|
||||
group: "{{ matrix_user_username }}"
|
||||
with_items:
|
||||
- "{{ matrix_static_files_base_path }}/.well-known/matrix"
|
||||
|
||||
- name: Ensure Matrix /.well-known/matrix/client configured
|
||||
template:
|
||||
src: "{{ role_path }}/templates/well-known/matrix-client.j2"
|
||||
dest: "{{ matrix_static_files_base_path }}/.well-known/matrix"
|
||||
mode: 0644
|
||||
owner: "{{ matrix_user_username }}"
|
||||
group: "{{ matrix_user_username }}"
|
38
roles/matrix-nginx-proxy/tasks/ssl/main.yml
Normal file
38
roles/matrix-nginx-proxy/tasks/ssl/main.yml
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
|
||||
- name: Fail if using unsupported SSL certificate retrieval method
|
||||
fail:
|
||||
msg: "The `matrix_ssl_retrieval_method` variable contains an unsupported value"
|
||||
when: "matrix_ssl_retrieval_method not in ['lets-encrypt', 'self-signed', 'manually-managed']"
|
||||
|
||||
|
||||
# Common tasks, required by any method below.
|
||||
|
||||
- name: Determine domains that we require certificates for (Matrix)
|
||||
set_fact:
|
||||
domains_requiring_certificates: "['{{ hostname_matrix }}']"
|
||||
|
||||
- name: Determine domains that we require certificates for (Riot)
|
||||
set_fact:
|
||||
domains_requiring_certificates: "{{ domains_requiring_certificates + [hostname_riot] }}"
|
||||
when: "matrix_riot_web_enabled"
|
||||
|
||||
- name: Ensure SSL certificate paths exists
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
mode: 0770
|
||||
owner: "{{ matrix_user_username }}"
|
||||
group: "{{ matrix_user_username }}"
|
||||
with_items:
|
||||
- "{{ matrix_ssl_log_dir_path }}"
|
||||
- "{{ matrix_ssl_config_dir_path }}"
|
||||
|
||||
|
||||
# Method specific tasks follow
|
||||
|
||||
- import_tasks: tasks/ssl/setup_ssl_lets_encrypt.yml
|
||||
|
||||
- import_tasks: tasks/ssl/setup_ssl_self_signed.yml
|
||||
|
||||
- import_tasks: tasks/ssl/setup_ssl_manually_managed.yml
|
114
roles/matrix-nginx-proxy/tasks/ssl/setup_ssl_lets_encrypt.yml
Normal file
114
roles/matrix-nginx-proxy/tasks/ssl/setup_ssl_lets_encrypt.yml
Normal file
@ -0,0 +1,114 @@
|
||||
---
|
||||
|
||||
# This is a cleanup/migration task, because of to the new way we manage cronjobs (`cron` module) and the new script name.
|
||||
# This migration task can be removed some time in the future.
|
||||
- name: (Migration) Remove deprecated Let's Encrypt SSL certificate management files
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
with_items:
|
||||
- /usr/local/bin/matrix-ssl-certificates-renew
|
||||
- /etc/cron.d/matrix-ssl-certificate-renewal
|
||||
- /etc/cron.d/matrix-nginx-proxy-periodic-restarter
|
||||
|
||||
|
||||
#
|
||||
# Tasks related to setting up Let's Encrypt's management of certificates
|
||||
#
|
||||
|
||||
- name: (Deprecation) Fail if using outdated configuration
|
||||
fail:
|
||||
msg: "You're using the `host_specific_matrix_ssl_support_email` variable, which has been superseded by `host_specific_matrix_ssl_lets_encrypt_support_email`. Please change your configuration to use the new name!"
|
||||
when: "matrix_ssl_retrieval_method == 'lets-encrypt' and host_specific_matrix_ssl_support_email is defined"
|
||||
|
||||
- name: Allow access to HTTP/HTTPS in firewalld
|
||||
firewalld:
|
||||
service: "{{ item }}"
|
||||
state: enabled
|
||||
immediate: yes
|
||||
permanent: yes
|
||||
with_items:
|
||||
- http
|
||||
- https
|
||||
when: "matrix_ssl_retrieval_method == 'lets-encrypt' and ansible_os_family == 'RedHat'"
|
||||
|
||||
- name: Ensure certbot Docker image is pulled
|
||||
docker_image:
|
||||
name: "{{ matrix_ssl_lets_encrypt_certbot_docker_image }}"
|
||||
when: "matrix_ssl_retrieval_method == 'lets-encrypt'"
|
||||
|
||||
- name: Obtain Let's Encrypt certificates
|
||||
include_tasks: "{{ role_path }}/tasks/ssl/setup_ssl_lets_encrypt_obtain_for_domain.yml"
|
||||
with_items: "{{ domains_requiring_certificates }}"
|
||||
loop_control:
|
||||
loop_var: domain_name
|
||||
when: "matrix_ssl_retrieval_method == 'lets-encrypt'"
|
||||
|
||||
- name: Ensure Let's Encrypt SSL renewal script installed
|
||||
template:
|
||||
src: "{{ role_path }}/templates/usr-local-bin/matrix-ssl-lets-encrypt-certificates-renew.j2"
|
||||
dest: /usr/local/bin/matrix-ssl-lets-encrypt-certificates-renew
|
||||
mode: 0750
|
||||
when: "matrix_ssl_retrieval_method == 'lets-encrypt'"
|
||||
|
||||
- block:
|
||||
- name: Ensure periodic SSL renewal cronjob configured (MAILTO)
|
||||
cron:
|
||||
user: root
|
||||
cron_file: matrix-ssl-lets-encrypt
|
||||
env: yes
|
||||
name: MAILTO
|
||||
value: "{{ matrix_ssl_lets_encrypt_support_email }}"
|
||||
|
||||
- name: Ensure periodic SSL renewal cronjob configured (matrix-ssl-lets-encrypt-certificates-renew)
|
||||
cron:
|
||||
user: root
|
||||
cron_file: matrix-ssl-lets-encrypt
|
||||
name: matrix-ssl-lets-encrypt-certificates-renew
|
||||
state: present
|
||||
hour: 4
|
||||
minute: 15
|
||||
day: "*/5"
|
||||
job: /usr/local/bin/matrix-ssl-lets-encrypt-certificates-renew
|
||||
|
||||
- name: Ensure periodic reloading of matrix-nginx-proxy is configured for SSL renewal (matrix-nginx-proxy-reload)
|
||||
cron:
|
||||
user: root
|
||||
cron_file: matrix-ssl-lets-encrypt
|
||||
name: matrix-nginx-proxy-reload
|
||||
state: present
|
||||
hour: 4
|
||||
minute: 20
|
||||
day: "*/5"
|
||||
job: /usr/bin/systemctl reload matrix-nginx-proxy.service
|
||||
when: matrix_nginx_proxy_enabled
|
||||
when: "matrix_ssl_retrieval_method == 'lets-encrypt'"
|
||||
|
||||
|
||||
#
|
||||
# Tasks related to getting rid of Let's Encrypt's management of certificates
|
||||
#
|
||||
|
||||
# When nginx-proxy is disabled, make sure its reloading cronjob is gone.
|
||||
# Other cronjobs can potentially remain there (see below).
|
||||
- name: Ensure matrix-nginx-proxy-reload cronjob removed
|
||||
cron:
|
||||
user: root
|
||||
cron_file: matrix-ssl-lets-encrypt
|
||||
name: matrix-nginx-proxy-reload
|
||||
state: absent
|
||||
when: "not matrix_nginx_proxy_enabled"
|
||||
|
||||
# When Let's Encrypt is not used at all, remove all cronjobs in that cron file.
|
||||
- name: Ensure matrix-ssl-lets-encrypt-renew cronjob removed
|
||||
cron:
|
||||
user: root
|
||||
cron_file: matrix-ssl-lets-encrypt
|
||||
state: absent
|
||||
when: "matrix_ssl_retrieval_method != 'lets-encrypt'"
|
||||
|
||||
- name: Ensure Let's Encrypt SSL renewal script removed
|
||||
file:
|
||||
path: /usr/local/bin/matrix-ssl-lets-encrypt-certificates-renew
|
||||
state: absent
|
||||
when: "matrix_ssl_retrieval_method != 'lets-encrypt'"
|
@ -0,0 +1,70 @@
|
||||
- debug:
|
||||
msg: "Dealing with SSL certificate retrieval for domain: {{ domain_name }}"
|
||||
|
||||
- set_fact:
|
||||
domain_name_certificate_path: "{{ matrix_ssl_config_dir_path }}/live/{{ domain_name }}/cert.pem"
|
||||
|
||||
- name: Check if a certificate for the domain already exists
|
||||
stat:
|
||||
path: "{{ domain_name_certificate_path }}"
|
||||
register: domain_name_certificate_path_stat
|
||||
|
||||
- set_fact:
|
||||
domain_name_needs_cert: "{{ not domain_name_certificate_path_stat.stat.exists }}"
|
||||
|
||||
# This will fail if there is something running on port 80 (like matrix-nginx-proxy).
|
||||
# We suppress the error, as we'll try another method below.
|
||||
- name: Attempt initial SSL certificate retrieval with standalone authenticator (directly)
|
||||
shell: >-
|
||||
/usr/bin/docker run
|
||||
--rm
|
||||
--name=matrix-certbot
|
||||
--net=host
|
||||
-v {{ matrix_ssl_config_dir_path }}:/etc/letsencrypt
|
||||
-v {{ matrix_ssl_log_dir_path }}:/var/log/letsencrypt
|
||||
{{ matrix_ssl_lets_encrypt_certbot_docker_image }}
|
||||
certonly
|
||||
--non-interactive
|
||||
{% if matrix_ssl_lets_encrypt_staging %}--staging{% endif %}
|
||||
--standalone
|
||||
--preferred-challenges http
|
||||
--agree-tos
|
||||
--email={{ matrix_ssl_lets_encrypt_support_email }}
|
||||
-d {{ domain_name }}
|
||||
when: "domain_name_needs_cert"
|
||||
register: result_certbot_direct
|
||||
ignore_errors: true
|
||||
|
||||
# If matrix-nginx-proxy is configured from a previous run of this playbook,
|
||||
# and it's running now, it may be able to proxy requests to `matrix_ssl_lets_encrypt_certbot_standalone_http_port`.
|
||||
- name: Attempt initial SSL certificate retrieval with standalone authenticator (via proxy)
|
||||
shell: >-
|
||||
/usr/bin/docker run
|
||||
--rm
|
||||
--name=matrix-certbot
|
||||
-p 127.0.0.1:{{ matrix_ssl_lets_encrypt_certbot_standalone_http_port }}:80
|
||||
--network={{ matrix_docker_network }}
|
||||
-v {{ matrix_ssl_config_dir_path }}:/etc/letsencrypt
|
||||
-v {{ matrix_ssl_log_dir_path }}:/var/log/letsencrypt
|
||||
{{ matrix_ssl_lets_encrypt_certbot_docker_image }}
|
||||
certonly
|
||||
--non-interactive
|
||||
{% if matrix_ssl_lets_encrypt_staging %}--staging{% endif %}
|
||||
--standalone
|
||||
--preferred-challenges http
|
||||
--agree-tos
|
||||
--email={{ matrix_ssl_lets_encrypt_support_email }}
|
||||
-d {{ domain_name }}
|
||||
when: "domain_name_needs_cert and result_certbot_direct.failed"
|
||||
register: result_certbot_proxy
|
||||
ignore_errors: true
|
||||
|
||||
- name: Fail if all SSL certificate retrieval attempts failed
|
||||
fail:
|
||||
msg: |
|
||||
Failed to obtain a certificate directly (by listening on port 80)
|
||||
and also failed to obtain by relying on the server at port 80 to proxy the request.
|
||||
See above for details.
|
||||
You may wish to set up proxying of /.well-known/acme-challenge to {{ matrix_ssl_lets_encrypt_certbot_standalone_http_port }} or,
|
||||
more easily, stop the server on port 80 while this playbook runs.
|
||||
when: "domain_name_needs_cert and result_certbot_direct.failed and result_certbot_proxy.failed"
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
|
||||
- name: Verify certificates
|
||||
include_tasks: "{{ role_path }}/tasks/ssl/setup_ssl_manually_managed_verify_for_domain.yml"
|
||||
with_items: "{{ domains_requiring_certificates }}"
|
||||
loop_control:
|
||||
loop_var: domain_name
|
||||
when: "matrix_ssl_retrieval_method == 'manually-managed'"
|
@ -0,0 +1,23 @@
|
||||
---
|
||||
|
||||
- set_fact:
|
||||
matrix_ssl_certificate_verification_cert_path: "{{ matrix_ssl_config_dir_path }}/live/{{ domain_name }}/fullchain.pem"
|
||||
matrix_ssl_certificate_verification_cert_key_path: "{{ matrix_ssl_config_dir_path }}/live/{{ domain_name }}/privkey.pem"
|
||||
|
||||
- name: Check if SSL certificate file exists
|
||||
stat:
|
||||
path: "{{ matrix_ssl_certificate_verification_cert_path }}"
|
||||
register: matrix_ssl_certificate_verification_cert_path_stat_result
|
||||
|
||||
- fail:
|
||||
msg: "Failed finding a certificate file (for domain `{{ domain_name }}`) at `{{ matrix_ssl_certificate_verification_cert_path }}`"
|
||||
when: "not matrix_ssl_certificate_verification_cert_path_stat_result.stat.exists"
|
||||
|
||||
- name: Check if SSL certificate key file exists
|
||||
stat:
|
||||
path: "{{ matrix_ssl_certificate_verification_cert_key_path }}"
|
||||
register: matrix_ssl_certificate_verification_cert_key_path_stat_result
|
||||
|
||||
- fail:
|
||||
msg: "Failed finding a certificate key file (for domain `{{ domain_name }}`) at `{{ matrix_ssl_certificate_verification_cert_key_path }}`"
|
||||
when: "not matrix_ssl_certificate_verification_cert_key_path_stat_result.stat.exists"
|
24
roles/matrix-nginx-proxy/tasks/ssl/setup_ssl_self_signed.yml
Normal file
24
roles/matrix-nginx-proxy/tasks/ssl/setup_ssl_self_signed.yml
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
|
||||
- name: Ensure OpenSSL installed (RedHat)
|
||||
yum:
|
||||
name:
|
||||
- openssl
|
||||
state: present
|
||||
update_cache: no
|
||||
when: "matrix_ssl_retrieval_method == 'self-signed' and ansible_os_family == 'RedHat'"
|
||||
|
||||
- name: Ensure APT usage dependencies are installed (Debian)
|
||||
apt:
|
||||
name:
|
||||
- openssl
|
||||
state: present
|
||||
update_cache: no
|
||||
when: "matrix_ssl_retrieval_method == 'self-signed' and ansible_os_family == 'Debian'"
|
||||
|
||||
- name: Generate self-signed certificates
|
||||
include_tasks: "{{ role_path }}/tasks/ssl/setup_ssl_self_signed_obtain_for_domain.yml"
|
||||
with_items: "{{ domains_requiring_certificates }}"
|
||||
loop_control:
|
||||
loop_var: domain_name
|
||||
when: "matrix_ssl_retrieval_method == 'self-signed'"
|
@ -0,0 +1,40 @@
|
||||
---
|
||||
|
||||
- set_fact:
|
||||
matrix_ssl_certificate_csr_path: "{{ matrix_ssl_config_dir_path }}/live/{{ domain_name }}/csr.csr"
|
||||
matrix_ssl_certificate_cert_path: "{{ matrix_ssl_config_dir_path }}/live/{{ domain_name }}/fullchain.pem"
|
||||
matrix_ssl_certificate_cert_key_path: "{{ matrix_ssl_config_dir_path }}/live/{{ domain_name }}/privkey.pem"
|
||||
|
||||
- name: Check if SSL certificate file exists
|
||||
stat:
|
||||
path: "{{ matrix_ssl_certificate_cert_path }}"
|
||||
register: matrix_ssl_certificate_cert_path_stat_result
|
||||
|
||||
# In order to do any sort of generation (below), we need to ensure the directory exists first
|
||||
- name: Ensure SSL certificate directory exists
|
||||
file:
|
||||
path: "{{ matrix_ssl_certificate_csr_path|dirname }}"
|
||||
state: directory
|
||||
mode: 0750
|
||||
owner: "{{ matrix_user_username }}"
|
||||
group: "{{ matrix_user_username }}"
|
||||
when: "not matrix_ssl_certificate_cert_path_stat_result.stat.exists"
|
||||
|
||||
# The proper way to do this is by using a sequence of
|
||||
# `openssl_privatekey`, `openssl_csr` and `openssl_certificate`.
|
||||
#
|
||||
# Unfortunately, `openssl_csr` and `openssl_certificate` require `PyOpenSSL>=0.15` to work,
|
||||
# which is not available on CentOS 7 (at least).
|
||||
#
|
||||
# We'll do it in a more manual way.
|
||||
- name: Generate SSL certificate
|
||||
command: |
|
||||
openssl req -x509 \
|
||||
-sha256 \
|
||||
-newkey rsa:4096 \
|
||||
-nodes \
|
||||
-subj "/CN={{ domain_name }}" \
|
||||
-keyout {{ matrix_ssl_certificate_cert_key_path }} \
|
||||
-out {{ matrix_ssl_certificate_cert_path }} \
|
||||
-days 3650
|
||||
when: "not matrix_ssl_certificate_cert_path_stat_result.stat.exists"
|
@ -0,0 +1,55 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name {{ hostname_riot }};
|
||||
|
||||
server_tokens off;
|
||||
|
||||
location /.well-known/acme-challenge {
|
||||
{% if matrix_nginx_proxy_enabled %}
|
||||
{# Use the embedded DNS resolver in Docker containers to discover the service #}
|
||||
resolver 127.0.0.11 valid=5s;
|
||||
set $backend "matrix-certbot:80";
|
||||
proxy_pass http://$backend;
|
||||
{% else %}
|
||||
{# Generic configuration for use outside of our container setup #}
|
||||
proxy_pass http://localhost:{{ matrix_ssl_lets_encrypt_certbot_standalone_http_port }};
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$http_host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
server_name {{ hostname_riot }};
|
||||
|
||||
server_tokens off;
|
||||
root /dev/null;
|
||||
|
||||
gzip on;
|
||||
gzip_types text/plain application/json application/javascript text/css image/x-icon font/ttf image/gif;
|
||||
|
||||
ssl_certificate {{ matrix_ssl_config_dir_path }}/live/{{ hostname_riot }}/fullchain.pem;
|
||||
ssl_certificate_key {{ matrix_ssl_config_dir_path }}/live/{{ hostname_riot }}/privkey.pem;
|
||||
ssl_protocols {{ matrix_nginx_proxy_ssl_protocols }};
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
|
||||
location / {
|
||||
{% if matrix_nginx_proxy_enabled %}
|
||||
{# Use the embedded DNS resolver in Docker containers to discover the service #}
|
||||
resolver 127.0.0.11 valid=5s;
|
||||
set $backend "matrix-riot-web:80";
|
||||
proxy_pass http://$backend;
|
||||
{% else %}
|
||||
{# Generic configuration for use outside of our container setup #}
|
||||
proxy_pass http://localhost:8765;
|
||||
{% endif %}
|
||||
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name {{ hostname_matrix }};
|
||||
|
||||
server_tokens off;
|
||||
|
||||
location /.well-known/acme-challenge {
|
||||
{% if matrix_nginx_proxy_enabled %}
|
||||
{# Use the embedded DNS resolver in Docker containers to discover the service #}
|
||||
resolver 127.0.0.11 valid=5s;
|
||||
set $backend "matrix-certbot:80";
|
||||
proxy_pass http://$backend;
|
||||
{% else %}
|
||||
{# Generic configuration for use outside of our container setup #}
|
||||
proxy_pass http://localhost:{{ matrix_ssl_lets_encrypt_certbot_standalone_http_port }};
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$http_host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
server_name {{ hostname_matrix }};
|
||||
|
||||
server_tokens off;
|
||||
root /dev/null;
|
||||
|
||||
gzip on;
|
||||
gzip_types text/plain application/json;
|
||||
|
||||
ssl_certificate {{ matrix_ssl_config_dir_path }}/live/{{ hostname_matrix }}/fullchain.pem;
|
||||
ssl_certificate_key {{ matrix_ssl_config_dir_path }}/live/{{ hostname_matrix }}/privkey.pem;
|
||||
ssl_protocols {{ matrix_nginx_proxy_ssl_protocols }};
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
|
||||
location /.well-known/matrix/client {
|
||||
root {{ matrix_static_files_base_path }};
|
||||
expires 1m;
|
||||
default_type application/json;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
}
|
||||
|
||||
{% if matrix_corporal_enabled and matrix_corporal_http_api_enabled %}
|
||||
location /_matrix/corporal {
|
||||
{% if matrix_nginx_proxy_enabled %}
|
||||
{# Use the embedded DNS resolver in Docker containers to discover the service #}
|
||||
resolver 127.0.0.11 valid=5s;
|
||||
set $backend "matrix-corporal:41081";
|
||||
proxy_pass http://$backend;
|
||||
{% else %}
|
||||
{# Generic configuration for use outside of our container setup #}
|
||||
proxy_pass http://localhost:41081;
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if matrix_mxisd_enabled %}
|
||||
location /_matrix/identity {
|
||||
{% if matrix_nginx_proxy_enabled %}
|
||||
{# Use the embedded DNS resolver in Docker containers to discover the service #}
|
||||
resolver 127.0.0.11 valid=5s;
|
||||
set $backend "matrix-mxisd:8090";
|
||||
proxy_pass http://$backend;
|
||||
{% else %}
|
||||
{# Generic configuration for use outside of our container setup #}
|
||||
proxy_pass http://localhost:8090;
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if matrix_mautrix_telegram_enabled %}
|
||||
location {{ matrix_mautrix_telegram_public_endpoint }} {
|
||||
{% if matrix_nginx_proxy_enabled %}
|
||||
{# Use the embedded DNS resolver in Docker containers to discover the service #}
|
||||
resolver 127.0.0.11 valid=5s;
|
||||
set $backend "matrix-mautrix-telegram:8080";
|
||||
proxy_pass http://$backend;
|
||||
{% else %}
|
||||
{# Generic configuration for use outside of our container setup #}
|
||||
proxy_pass http://localhost:8080;
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
location /_matrix {
|
||||
{% if matrix_nginx_proxy_enabled %}
|
||||
{# Use the embedded DNS resolver in Docker containers to discover the service #}
|
||||
resolver 127.0.0.11 valid=5s;
|
||||
set $backend "{{ matrix_nginx_proxy_matrix_client_api_addr_with_proxy_container }}";
|
||||
proxy_pass http://$backend;
|
||||
{% else %}
|
||||
{# Generic configuration for use outside of our container setup #}
|
||||
proxy_pass http://{{ matrix_nginx_proxy_matrix_client_api_addr_sans_proxy_container }};
|
||||
{% endif %}
|
||||
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
|
||||
client_body_buffer_size 25M;
|
||||
client_max_body_size {{ matrix_synapse_max_upload_size_mb }}M;
|
||||
proxy_max_temp_file_size 0;
|
||||
}
|
||||
|
||||
location / {
|
||||
rewrite ^/$ /_matrix/static/ last;
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
# The default is aligned to the CPU's cache size,
|
||||
# which can sometimes be too low to handle our 2 vhosts (Synapse and Riot).
|
||||
#
|
||||
# Thus, we ensure a larger bucket size value is used.
|
||||
server_names_hash_bucket_size 64;
|
@ -0,0 +1,36 @@
|
||||
[Unit]
|
||||
Description=Matrix nginx proxy server
|
||||
After=docker.service
|
||||
Requires=docker.service
|
||||
Wants=matrix-synapse.service
|
||||
{% if matrix_corporal_enabled %}
|
||||
Wants=matrix-corporal.service
|
||||
{% endif %}
|
||||
{% if matrix_riot_web_enabled %}
|
||||
Wants=matrix-riot-web.service
|
||||
{% endif %}
|
||||
{% if matrix_mxisd_enabled %}
|
||||
Wants=matrix-mxisd.service
|
||||
{% endif %}
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStartPre=-/usr/bin/docker kill matrix-nginx-proxy
|
||||
ExecStartPre=-/usr/bin/docker rm matrix-nginx-proxy
|
||||
ExecStart=/usr/bin/docker run --rm --name matrix-nginx-proxy \
|
||||
--log-driver=none \
|
||||
--network={{ matrix_docker_network }} \
|
||||
-p 80:80 \
|
||||
-p 443:443 \
|
||||
-v {{ matrix_nginx_proxy_confd_path }}:/etc/nginx/conf.d:ro \
|
||||
-v {{ matrix_ssl_config_dir_path }}:{{ matrix_ssl_config_dir_path }}:ro \
|
||||
-v {{ matrix_static_files_base_path }}:{{ matrix_static_files_base_path }}:ro \
|
||||
{{ matrix_nginx_proxy_docker_image }}
|
||||
ExecStop=-/usr/bin/docker kill matrix-nginx-proxy
|
||||
ExecStop=-/usr/bin/docker rm matrix-nginx-proxy
|
||||
ExecReload=/usr/bin/docker exec matrix-nginx-proxy /usr/sbin/nginx -s reload
|
||||
Restart=always
|
||||
RestartSec=30
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
# For renewal to work, matrix-nginx-proxy (or another webserver, if matrix-nginx-proxy is disabled)
|
||||
# need to forward requests for `/.well-known/acme-challenge` to the certbot container.
|
||||
#
|
||||
# This can happen inside the container network by proxying to `http://matrix-certbot:80`
|
||||
# or outside (on the host) by proxying to `http://localhost:{{ matrix_ssl_lets_encrypt_certbot_standalone_http_port }}`.
|
||||
|
||||
docker run \
|
||||
--rm \
|
||||
--name=matrix-certbot \
|
||||
--network="{{ matrix_docker_network }}" \
|
||||
-p 127.0.0.1:{{ matrix_ssl_lets_encrypt_certbot_standalone_http_port }}:80 \
|
||||
-v {{ matrix_ssl_config_dir_path }}:/etc/letsencrypt \
|
||||
-v {{ matrix_ssl_log_dir_path }}:/var/log/letsencrypt \
|
||||
{{ matrix_ssl_lets_encrypt_certbot_docker_image }} \
|
||||
renew \
|
||||
--non-interactive \
|
||||
{% if matrix_ssl_lets_encrypt_staging %}
|
||||
--staging \
|
||||
{% endif %}
|
||||
--quiet \
|
||||
--standalone \
|
||||
--preferred-challenges http \
|
||||
--agree-tos \
|
||||
--email={{ matrix_ssl_lets_encrypt_support_email }}
|
Reference in New Issue
Block a user