From c545d3eb8571d10eed4e202b1bfdbb3c63f75112 Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Tue, 12 Mar 2019 22:27:18 +0200 Subject: [PATCH] Add support for serving base domain via matrix-nginx-proxy --- CHANGELOG.md | 8 +++ ...onfiguring-playbook-base-domain-serving.md | 29 +++++++++++ docs/configuring-playbook-ssl-certificates.md | 5 +- docs/configuring-playbook.md | 2 + docs/configuring-well-known.md | 8 ++- docs/prerequisites.md | 2 +- group_vars/matrix-servers | 2 + roles/matrix-nginx-proxy/defaults/main.yml | 21 ++++++++ .../tasks/setup_nginx_proxy.yml | 37 +++++++++++++ .../nginx/conf.d/matrix-domain.conf.j2 | 52 +++++++++++++++++++ 10 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 docs/configuring-playbook-base-domain-serving.md create mode 100644 roles/matrix-nginx-proxy/templates/nginx/conf.d/matrix-domain.conf.j2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c4acb224..31d25995f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # 2019-03-12 +## matrix-nginx-proxy support for serving the base domain + +If you don't have a dedicated server for your base domain and want to set up [Server Delegation via a well-known file](docs/howto-server-delegation.md#server-delegation-via-a-well-known-file), the playbook has got you covered now. + +It's now possible for the playbook to obtain an SSL certificate and serve the necessary files for Matrix Server Delegation on your base domain. +Take a look at the new [Serving the base domain](docs/configuring-playbook-base-domain-serving.md) documentation page. + + ## (BC break) matrix-nginx-proxy data variable renamed `matrix_nginx_proxy_data_path` was renamed to `matrix_nginx_proxy_base_path`. diff --git a/docs/configuring-playbook-base-domain-serving.md b/docs/configuring-playbook-base-domain-serving.md new file mode 100644 index 000000000..b937a4bae --- /dev/null +++ b/docs/configuring-playbook-base-domain-serving.md @@ -0,0 +1,29 @@ +# Serving the base domain + +This playbook sets up services on your Matrix server (`matrix.DOMAIN`). +To have this server officially be responsible for Matrix services for the base domain (`DOMAIN`), you need to set up [Server Delegation](howto-server-delegation.md). +This is normally done by [configuring well-known](configuring-well-known.md) files on the base domain. + +People who don't have a separate server to dedicate to the base domain have trouble arranging this. + +Usually, there are 2 options: + +- either get a separate server for the base domain, just for serving the files necessary for [Server Delegation via a well-known file](howto-server-delegation.md#server-delegation-via-a-well-known-file) + +- or, arrange for the Matrix server to serve the base domain. This involves [using your own webserver](configuring-playbook-own-webserver.md) or making the integrated webserver somehow serve your base domain (possible, but complicated). + +To solve this problem, we've created an easy way to let you serve the base domain from the Matrix server via the integrated webserver (`matrix-nginx-proxy`). + +Just **adjust your DNS records**, so that your base domain is pointed to the Matrix server's IP address **and use the following configuration**: + +```yaml +matrix_nginx_proxy_base_domain_serving_enabled: true +``` + +Doing this, the playbook will: + +- obtain an SSL certificate for the base domain, just like it does for all other domains (see [how we handle SSL certificates](configuring-playbook-ssl-certificates.md)) + +- serve the `/.well-known/matrix/*` files which are necessary for [Federation Server Discovery](configuring-well-known.md#introduction-to-client-server-discovery) (also see [Server Delegation](howto-server-delegation.md)) and [Client-Server discovery](configuring-well-known.md#introduction-to-client-server-discovery) + +- serve a simple homepage at `https://DOMAIN` with content `Hello from DOMAIN` (configurable via the `matrix_nginx_proxy_base_domain_homepage_template` variable) diff --git a/docs/configuring-playbook-ssl-certificates.md b/docs/configuring-playbook-ssl-certificates.md index bcaef80ad..28d505424 100644 --- a/docs/configuring-playbook-ssl-certificates.md +++ b/docs/configuring-playbook-ssl-certificates.md @@ -15,7 +15,7 @@ Things discussed in this document: - [Not bothering with SSL certificates](#not-bothering-with-ssl-certificates), if you're using [your own webserver](docs/configuring-playbook-own-webserver.md) and would rather this playbook leaves SSL certificate management to you -- [Obtaining SSL certificates for additional domains](#obtaining-ssl-certificates-for-additional-domains), if you'd like to host additional domains on the Matrix server (perhaps your base domain?) and would like the playbook to help you obtain and renew certificates for those domains automatically. +- [Obtaining SSL certificates for additional domains](#obtaining-ssl-certificates-for-additional-domains), if you'd like to host additional domains on the Matrix server and would like the playbook to help you obtain and renew certificates for those domains automatically ## Using self-signed SSL certificates @@ -64,6 +64,7 @@ By default, it obtains certificates for: - `matrix.` (`matrix_server_fqn_matrix`) - possibly for `riot.`, unless you have disabled the Riot component using `matrix_riot_web_enabled: false` - possibly for `dimension.`, if you have explicitly [set up Dimension](configuring-playbook-dimension.md). +- possibly for your base domain (``), if you have explicitly configured [Serving the base domain](configuring-playbook-base-domain-serving.md) If you are hosting other domains on the Matrix machine, you can make the playbook obtain and renew certificates for those other domains too. To do that, simply define your own custom configuration like this: @@ -85,7 +86,7 @@ After redefining `matrix_ssl_domains_to_obtain_certificates_for`, to actually ob - re-run the SSL part of the playbook and restart all services: `ansible-playbook -i inventory/hosts setup.yml --tags=setup-ssl,start` -The certificate files would be available in `/matrix/ssl/config/live//...`. +The certificate files would be available in `/matrix/ssl/config/live//...`. For automated certificate renewal to work, each port `80` vhost for each domain you are obtaining certificates for needs to forward requests for `/.well-known/acme-challenge` to the certbot container we use for renewal. diff --git a/docs/configuring-playbook.md b/docs/configuring-playbook.md index 4951d8d4e..c56cf11d2 100644 --- a/docs/configuring-playbook.md +++ b/docs/configuring-playbook.md @@ -41,6 +41,8 @@ When you're done with all the configuration you'd like to do, continue with [Ins - [Adjusting SSL certificate retrieval](configuring-playbook-ssl-certificates.md) (optional, advanced) +- [Serving your base domain using this playbook's nginx server](configuring-playbook-base-domain-serving.md) (optional) + - [Using your own webserver, instead of this playbook's nginx proxy](configuring-playbook-own-webserver.md) (optional, advanced) - [Setting up the REST authentication password provider module](configuring-playbook-rest-auth.md) (optional, advanced) diff --git a/docs/configuring-well-known.md b/docs/configuring-well-known.md index 193d380b7..59807f287 100644 --- a/docs/configuring-well-known.md +++ b/docs/configuring-well-known.md @@ -39,7 +39,13 @@ To learn how to set it up, read the Installing section below. ## Installing well-known files on the base domain's server -To implement the two service discovery mechanisms, your base domain's server (e.g. `example.com`) needs to support HTTPS. +To implement the two service discovery mechanisms, your base domain's server (e.g. `example.com`) needs to run an HTTPS-capable webserver. + +If you don't have a server for your base domain at all, you can use the Matrix server for this. +See [Serving the base domain](configuring-playbook-base-domain-serving.md) to learn how the playbook can help you set it up. +If you decide to go this route, you don't need to read ahead in this document. When **Serving the base domain**, the playbook takes care to serve the appropriate well-known files automatically. + +If you're managing the base domain by yourself somehow, you'll need to set up serving of some `/.well-known/matrix/*` files from it via HTTPS. To make things easy for you to set up, this playbook generates and hosts 2 well-known files on the Matrix domain's server (e.g. `https://matrix.example.com/.well-known/matrix/server` and `https://matrix.example.com/.well-known/matrix/client`), even though this is the wrong place to host them. diff --git a/docs/prerequisites.md b/docs/prerequisites.md index cf270e5d8..0fc5f5c97 100644 --- a/docs/prerequisites.md +++ b/docs/prerequisites.md @@ -8,7 +8,7 @@ - either the `dig` tool or `python-dns` installed on your own computer. Used later on, by the playbook's [services check](maintenance-checking-services.md) feature. -- an HTTPS-capable web server at the base domain name (``) which is capable of serving static files (unless you decide to use DNS SRV records for [Server Delegation](howto-server-delegation.md)) +- an HTTPS-capable web server at the base domain name (``) which is capable of serving static files. Unless you decide to [Serve the base domain from the Matrix server](configuring-playbook-base-domain-serving.md) or alternatively, to use DNS SRV records for [Server Delegation](howto-server-delegation.md). - properly configured DNS records for `` (details in [Configuring DNS](configuring-dns.md)) diff --git a/group_vars/matrix-servers b/group_vars/matrix-servers index 9f06d8fef..a93467cae 100755 --- a/group_vars/matrix-servers +++ b/group_vars/matrix-servers @@ -246,6 +246,8 @@ matrix_ssl_domains_to_obtain_certificates_for: | ([matrix_server_fqn_riot] if matrix_riot_web_enabled else []) + ([matrix_server_fqn_dimension] if matrix_dimension_enabled else []) + + + ([matrix_domain] if matrix_nginx_proxy_base_domain_serving_enabled else []) }} ###################################################################### diff --git a/roles/matrix-nginx-proxy/defaults/main.yml b/roles/matrix-nginx-proxy/defaults/main.yml index 19b09f307..8117cb895 100644 --- a/roles/matrix-nginx-proxy/defaults/main.yml +++ b/roles/matrix-nginx-proxy/defaults/main.yml @@ -21,6 +21,27 @@ matrix_nginx_proxy_systemd_wanted_services_list: [] # Contains definition objects like this: `{"src": "/outside", "dst": "/inside", "options": "rw|ro|slave|.."} matrix_nginx_proxy_container_additional_volumes: [] +# Controls whether matrix-nginx-proxy should serve the base domain. +# +# This is useful for when you only have your Matrix server, but you need to serve +# to serve `/.well-known/matrix/*` files from the base domain for the needs of +# Server-Discovery (Federation) and for Client-Discovery. +# +# Besides serving these Matrix files, a homepage would be served with content +# as specified in the `matrix_nginx_proxy_base_domain_homepage_template` variable. +# You can also put additional files to use for this webpage +# in the `{{ matrix_nginx_proxy_data_path }}/matrix-domain` (`/matrix/nginx-proxy/data/matrix-domain`) directory. +matrix_nginx_proxy_base_domain_serving_enabled: false +matrix_nginx_proxy_base_domain_hostname: "{{ matrix_domain }}" +matrix_nginx_proxy_base_domain_homepage_template: |- + + + + + Hello from {{ matrix_domain }}! + + + # Controls whether proxying the riot domain should be done. matrix_nginx_proxy_proxy_riot_enabled: false matrix_nginx_proxy_proxy_riot_hostname: "{{ matrix_server_fqn_riot }}" diff --git a/roles/matrix-nginx-proxy/tasks/setup_nginx_proxy.yml b/roles/matrix-nginx-proxy/tasks/setup_nginx_proxy.yml index ef628e24c..d0075702a 100644 --- a/roles/matrix-nginx-proxy/tasks/setup_nginx_proxy.yml +++ b/roles/matrix-nginx-proxy/tasks/setup_nginx_proxy.yml @@ -66,6 +66,31 @@ mode: 0644 when: "matrix_nginx_proxy_proxy_dimension_enabled" +- name: Ensure Matrix nginx-proxy data directory for base domain exists + file: + path: "{{ matrix_nginx_proxy_data_path }}/matrix-domain" + state: directory + mode: 0750 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_username }}" + when: "matrix_nginx_proxy_base_domain_serving_enabled" + +- name: Ensure Matrix nginx-proxy homepage for base domain exists + copy: + content: "{{ matrix_nginx_proxy_base_domain_homepage_template }}" + dest: "{{ matrix_nginx_proxy_data_path }}/matrix-domain/index.html" + mode: 0644 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_username }}" + when: "matrix_nginx_proxy_base_domain_serving_enabled" + +- name: Ensure Matrix nginx-proxy configuration for base domain exists + template: + src: "{{ role_path }}/templates/nginx/conf.d/matrix-domain.conf.j2" + dest: "{{ matrix_nginx_proxy_confd_path }}/matrix-domain.conf" + mode: 0644 + when: "matrix_nginx_proxy_base_domain_serving_enabled" + # # Tasks related to setting up matrix-nginx-proxy # @@ -145,6 +170,18 @@ state: absent when: "not matrix_nginx_proxy_proxy_dimension_enabled" +- name: Ensure Matrix nginx-proxy homepage for base domain deleted + file: + path: "{{ matrix_nginx_proxy_data_path }}/matrix-domain/index.html" + state: absent + when: "not matrix_nginx_proxy_base_domain_serving_enabled" + +- name: Ensure Matrix nginx-proxy configuration for base domain deleted + file: + path: "{{ matrix_nginx_proxy_confd_path }}/matrix-domain.conf" + state: absent + when: "not matrix_nginx_proxy_base_domain_serving_enabled" + - name: Ensure Matrix nginx-proxy configuration for main config override deleted file: path: "{{ matrix_nginx_proxy_base_path }}/nginx.conf" diff --git a/roles/matrix-nginx-proxy/templates/nginx/conf.d/matrix-domain.conf.j2 b/roles/matrix-nginx-proxy/templates/nginx/conf.d/matrix-domain.conf.j2 new file mode 100644 index 000000000..679f3efa7 --- /dev/null +++ b/roles/matrix-nginx-proxy/templates/nginx/conf.d/matrix-domain.conf.j2 @@ -0,0 +1,52 @@ +server { + listen {{ 8080 if matrix_nginx_proxy_enabled else 80 }}; + server_name {{ matrix_nginx_proxy_base_domain_hostname }}; + + 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:8080"; + proxy_pass http://$backend; + {% else %} + {# Generic configuration for use outside of our container setup #} + proxy_pass http://127.0.0.1:{{ matrix_ssl_lets_encrypt_certbot_standalone_http_port }}; + {% endif %} + } + + location / { + return 301 https://$http_host$request_uri; + } +} + +server { + listen {{ 8443 if matrix_nginx_proxy_enabled else 443 }} ssl http2; + listen [::]:{{ 8443 if matrix_nginx_proxy_enabled else 443 }} ssl http2; + + server_name {{ matrix_nginx_proxy_base_domain_hostname }}; + + server_tokens off; + root /nginx-data/matrix-domain; + + gzip on; + gzip_types text/plain application/json; + + ssl_certificate {{ matrix_ssl_config_dir_path }}/live/{{ matrix_nginx_proxy_base_domain_hostname }}/fullchain.pem; + ssl_certificate_key {{ matrix_ssl_config_dir_path }}/live/{{ matrix_nginx_proxy_base_domain_hostname }}/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 { + root {{ matrix_static_files_base_path }}; + {# + A somewhat long expires value is used to prevent outages + in case this is unreachable due to network failure. + #} + expires 4h; + default_type application/json; + add_header Access-Control-Allow-Origin *; + } +}