diff --git a/ops/ansible/inventories/legislation.demo.openfisca.org.yml b/ops/ansible/inventories/legislation.demo.openfisca.org.yml index 3d036da2..0b108617 100644 --- a/ops/ansible/inventories/legislation.demo.openfisca.org.yml +++ b/ops/ansible/inventories/legislation.demo.openfisca.org.yml @@ -22,7 +22,7 @@ all: # Reverse proxy - host_name: legislation.demo.openfisca.org + reverse_proxy_host_name: legislation.demo.openfisca.org letsencrypt_email: contact@openfisca.org letsencrypt_environment: production diff --git a/ops/ansible/inventories/legislation.fr.openfisca.org.yml b/ops/ansible/inventories/legislation.fr.openfisca.org.yml index 02f81f64..a7089e5d 100644 --- a/ops/ansible/inventories/legislation.fr.openfisca.org.yml +++ b/ops/ansible/inventories/legislation.fr.openfisca.org.yml @@ -22,7 +22,7 @@ all: # Reverse proxy - host_name: legislation.fr.openfisca.org + reverse_proxy_host_name: legislation.fr.openfisca.org letsencrypt_email: contact@openfisca.org letsencrypt_environment: production diff --git a/ops/ansible/roles/legislation_explorer/defaults/main.yml b/ops/ansible/roles/legislation_explorer/defaults/main.yml index f23d5eae..9014bdf5 100644 --- a/ops/ansible/roles/legislation_explorer/defaults/main.yml +++ b/ops/ansible/roles/legislation_explorer/defaults/main.yml @@ -13,15 +13,6 @@ ui_strings: | repo_url: https://github.com/openfisca/legislation-explorer.git branch: master -# Reverse proxy -host_name: localhost -base_path: / - -# Optional: SSL certificate -# An SSL certificate is issued from Let's Encrypt if `letsencrypt_email` is defined. -letsencrypt_email: null -letsencrypt_environment: staging # switch to `production` after testing to avoid reaching your Let's Encrypt quota - # Optional: Matomo tracker # See more on https://github.com/openfisca/openfisca-tracker matomo_url: null diff --git a/ops/ansible/roles/legislation_explorer/tasks/main.yml b/ops/ansible/roles/legislation_explorer/tasks/main.yml index 633c1647..20a6d2ca 100644 --- a/ops/ansible/roles/legislation_explorer/tasks/main.yml +++ b/ops/ansible/roles/legislation_explorer/tasks/main.yml @@ -12,7 +12,6 @@ name: - acl # Provides "setfacl" command, used by Ansible to become another Unix user - git - - nginx - nodejs=10.19.0~dfsg-3ubuntu1 - npm=6.14.4+ds-1ubuntu2 state: present @@ -52,7 +51,7 @@ - name: Copy the environment file for Legislation Explorer ansible.builtin.template: - src: systemd/legislation-explorer.env.j2 + src: legislation-explorer.env.j2 dest: "{{ source_dir_path }}/.env" - name: Build the application @@ -64,7 +63,7 @@ block: - name: Copy the systemd service file ansible.builtin.template: - src: systemd/legislation-explorer.service.j2 + src: legislation-explorer.service.j2 dest: "/etc/systemd/system/{{ systemd_service_file_name }}" - name: Enable and start the systemd service @@ -84,54 +83,3 @@ until: this.status == 200 retries: 5 # times delay: 5 # Every 5 seconds - -- name: Copy the nginx vhost file to the sites-available directory of Nginx - ansible.builtin.template: - src: nginx/legislation-explorer.conf.j2 - dest: "/etc/nginx/sites-available/{{ host_name }}.conf" - -- name: Link the nginx vhost file to the sites-enabled directory of Nginx - ansible.builtin.file: - src: "/etc/nginx/sites-available/{{ host_name }}.conf" - dest: "/etc/nginx/sites-enabled/{{ host_name }}.conf" - state: link - notify: Reload nginx - -- name: Set SSL up - when: letsencrypt_email - block: - - name: Install Certbot and its Nginx plugin - ansible.builtin.apt: - install_recommends: no - name: - - certbot - - python3-certbot-nginx - state: present - update_cache: no - - - name: Use Let's Encrypt staging environment - when: letsencrypt_environment == "staging" - ansible.builtin.set_fact: - certbot_staging_option: "--staging" - - - name: Reinstall or renew an SSL certificate from Let's Encrypt using the certbot client - ansible.builtin.command: > - certbot - --non-interactive --email {{ letsencrypt_email }} --agree-tos - --nginx --redirect - --domain {{ host_name }} - --cert-name {{ host_name }} - --keep-until-expiring - {{ certbot_staging_option | default() }} - become_user: root - register: certbot_result - - - name: Enable HTTP/2 - ansible.builtin.lineinfile: - backrefs: yes - line: '\1\2 http2;\3' - path: "/etc/nginx/sites-available/{{ host_name }}.conf" - regexp: "^(.*)(listen 443 ssl);(.+)$" - notify: Reload nginx - tags: - - http2 diff --git a/ops/ansible/roles/legislation_explorer/templates/systemd/legislation-explorer.env.j2 b/ops/ansible/roles/legislation_explorer/templates/legislation-explorer.env.j2 similarity index 89% rename from ops/ansible/roles/legislation_explorer/templates/systemd/legislation-explorer.env.j2 rename to ops/ansible/roles/legislation_explorer/templates/legislation-explorer.env.j2 index ad9e630f..d9299e28 100644 --- a/ops/ansible/roles/legislation_explorer/templates/systemd/legislation-explorer.env.j2 +++ b/ops/ansible/roles/legislation_explorer/templates/legislation-explorer.env.j2 @@ -2,7 +2,7 @@ NODE_ENV=production HOST={{ app_host }} PORT={{ app_port }} -PATHNAME={{ base_path }} +PATHNAME={{ reverse_proxy_base_path }} API_URL={{ api_url | quote }} CHANGELOG_URL={{ changelog_url | quote }} diff --git a/ops/ansible/roles/legislation_explorer/templates/systemd/legislation-explorer.service.j2 b/ops/ansible/roles/legislation_explorer/templates/legislation-explorer.service.j2 similarity index 100% rename from ops/ansible/roles/legislation_explorer/templates/systemd/legislation-explorer.service.j2 rename to ops/ansible/roles/legislation_explorer/templates/legislation-explorer.service.j2 diff --git a/ops/ansible/roles/legislation_explorer/templates/nginx/legislation-explorer.conf.j2 b/ops/ansible/roles/legislation_explorer/templates/nginx/legislation-explorer.conf.j2 deleted file mode 100644 index 1a7a162d..00000000 --- a/ops/ansible/roles/legislation_explorer/templates/nginx/legislation-explorer.conf.j2 +++ /dev/null @@ -1,12 +0,0 @@ -server { - listen 80; - server_name {{ host_name }}; - - access_log /var/log/nginx/{{ host_name }}-access.log; - error_log /var/log/nginx/{{ host_name }}-error.log; - - location ~ ^{{ base_path }}(.*)$ { - proxy_pass http://127.0.0.1:{{ app_port }}/$1; - include /etc/nginx/proxy_params; - } -} diff --git a/ops/ansible/roles/reverse_proxy/defaults/main.yml b/ops/ansible/roles/reverse_proxy/defaults/main.yml new file mode 100644 index 00000000..8823aed7 --- /dev/null +++ b/ops/ansible/roles/reverse_proxy/defaults/main.yml @@ -0,0 +1,11 @@ +# To activate the Nginx reverse proxy, set `reverse_proxy_host_name` to the host name it will listen to +reverse_proxy_host_name: null +reverse_proxy_base_path: / + +# Optional: SSL certificate +# An SSL certificate is issued from Let's Encrypt if `letsencrypt_email` is defined. +letsencrypt_email: null +letsencrypt_environment: staging # switch to `production` only after testing to avoid reaching your Let's Encrypt quota + +# Fully managed by Ansible, you should not need to edit this unless you have a naming collision +nginx_conf_file_name: "{{ reverse_proxy_host_name }}.conf" diff --git a/ops/ansible/roles/legislation_explorer/handlers/main.yml b/ops/ansible/roles/reverse_proxy/handlers/main.yml similarity index 100% rename from ops/ansible/roles/legislation_explorer/handlers/main.yml rename to ops/ansible/roles/reverse_proxy/handlers/main.yml diff --git a/ops/ansible/roles/reverse_proxy/tasks/main.yml b/ops/ansible/roles/reverse_proxy/tasks/main.yml new file mode 100644 index 00000000..8b7b9e7a --- /dev/null +++ b/ops/ansible/roles/reverse_proxy/tasks/main.yml @@ -0,0 +1,61 @@ +- name: Install the reverse-proxy + when: reverse_proxy_host_name + block: + - name: Install the Nginx Ubuntu package + ansible.builtin.apt: + install_recommends: no + name: + - nginx + state: present + update_cache: no + + - name: Copy the nginx vhost file to the sites-available directory of Nginx + ansible.builtin.template: + src: legislation-explorer.conf.j2 + dest: "/etc/nginx/sites-available/{{ nginx_conf_file_name }}" + + - name: Link the nginx vhost file to the sites-enabled directory of Nginx + ansible.builtin.file: + src: "/etc/nginx/sites-available/{{ nginx_conf_file_name }}" + dest: "/etc/nginx/sites-enabled/{{ nginx_conf_file_name }}" + state: link + notify: Reload nginx + + - name: Set SSL up + when: letsencrypt_email + block: + - name: Install Certbot and its Nginx plugin + ansible.builtin.apt: + install_recommends: no + name: + - certbot + - python3-certbot-nginx + state: present + update_cache: no + + - name: Use Let's Encrypt staging environment + when: letsencrypt_environment == "staging" + ansible.builtin.set_fact: + certbot_staging_option: "--staging" + + - name: Issue or renew an SSL certificate with Let's Encrypt + ansible.builtin.command: > + certbot + --non-interactive --email {{ letsencrypt_email }} --agree-tos + --nginx --redirect + --cert-name {{ reverse_proxy_host_name }} + --domain {{ reverse_proxy_host_name }} + --keep-until-expiring + {{ certbot_staging_option | default() }} + become_user: root + register: certbot_result + + - name: Enable HTTP/2 + ansible.builtin.lineinfile: + backrefs: yes + line: '\1\2 http2;\3' + path: "/etc/nginx/sites-available/{{ nginx_conf_file_name }}" + regexp: "^(.*)(listen 443 ssl);(.+)$" + notify: Reload nginx + tags: + - http2 diff --git a/ops/ansible/roles/reverse_proxy/templates/legislation-explorer.conf.j2 b/ops/ansible/roles/reverse_proxy/templates/legislation-explorer.conf.j2 new file mode 100644 index 00000000..d6f01e8b --- /dev/null +++ b/ops/ansible/roles/reverse_proxy/templates/legislation-explorer.conf.j2 @@ -0,0 +1,12 @@ +server { + listen 80; + server_name {{ reverse_proxy_host_name }}; + + access_log /var/log/nginx/{{ reverse_proxy_host_name }}-access.log; + error_log /var/log/nginx/{{ reverse_proxy_host_name }}-error.log; + + location ~ ^{{ reverse_proxy_base_path }}(.*)$ { + proxy_pass http://127.0.0.1:{{ app_port }}/$1; + include /etc/nginx/proxy_params; + } +} diff --git a/ops/ansible/site.yml b/ops/ansible/site.yml index 93b74c9c..66c79057 100644 --- a/ops/ansible/site.yml +++ b/ops/ansible/site.yml @@ -4,3 +4,4 @@ hosts: all roles: - legislation_explorer + - reverse_proxy diff --git a/ops/docs/Install-instance.md b/ops/docs/Install-instance.md index d1d0a4ca..c275e4c4 100644 --- a/ops/docs/Install-instance.md +++ b/ops/docs/Install-instance.md @@ -41,7 +41,7 @@ all: ansible_user: root # define here the username to use when connecting over SSH # adjust the variables defined in `ansible/roles/*/defaults/main.yml` below: api_url: https://my-openfisca-api.example/ - host_name: my-legislation-explorer.example + reverse_proxy_host_name: my-legislation-explorer.example ``` ## 4. Install and start the Legislation Explorer @@ -50,7 +50,7 @@ all: 2. Navigate to the freshly downloaded folder: `cd legislation-explorer`. 3. Type the following command: `ansible-playbook --inventory ansible/inventories/YOUR_INVENTORY.yml ansible/site.yml`. -Once the command is done, your target machine should run the Legislation Explorer. Just open `http://HOST_NAME/` in your browser. You can change the port and path through the configuration file, by changing the variables `app_port` or `base_path`. +Once the command is done, your target machine should run the Legislation Explorer. Just open `http://HOST_NAME/` in your browser. You can change the port and path through the configuration file, by changing the variables `app_port` or `reverse_proxy_base_path`. ### Optional: enable Matomo diff --git a/ops/docs/Serve-local-instance.md b/ops/docs/Serve-local-instance.md index 6ecc00e7..b9813a1b 100644 --- a/ops/docs/Serve-local-instance.md +++ b/ops/docs/Serve-local-instance.md @@ -49,4 +49,4 @@ Thanks to Vagrant port forwarding, the port 80 inside the virtual machine is for > On such a local virtual machine, the application is by default served over HTTP instead of HTTPS, as SSL certificates cannot be automatically provisioned by Let’s Encrypt. -> The `base_path` variable won't have any effect when using this local virtual machine setup. When using Vagrant, by default the app is accessed directly, with no reverse proxy. +> The `reverse_proxy_base_path` variable won't have any effect when using this local virtual machine setup. When using Vagrant, by default the app is accessed directly, with no reverse proxy.