From 544498c81a808999099d8bbac340ff16cb398369 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Sat, 9 May 2020 12:52:17 +0200 Subject: [PATCH] New reverse proxy role --- roles/nginx-reverse-proxy/handlers/main.yml | 6 - roles/nginx-reverse-proxy/tasks/main.yml | 64 ----------- .../nginx/nginx-sites-available-main.j2 | 107 ------------------ .../templates/nginx/nginx-sites-available.j2 | 40 ------- .../nginx/snippets/proxy-common-ssl.conf.j2 | 32 ------ .../nginx/snippets/proxy-common.conf.j2 | 12 -- roles/nginx-reverseproxy/handlers/main.yml | 5 + roles/nginx-reverseproxy/tasks/main.yml | 53 +++++++++ .../templates/letsencrypt/dhparam.j2 | 8 ++ .../nginx/sites-available/redirect.j2 | 67 +++++++++++ .../nginx/sites-available/reverseproxy.j2 | 56 +++++++++ .../reverseproxy_redirect_dname.j2 | 37 ++++++ .../nginx/snippets/options-proxypass.conf.j2 | 19 ++++ .../nginx/snippets/options-ssl.conf.j2 | 17 +++ .../templates/update-motd.d/05-service.j2 | 3 + .../templates/www/html/50x.html.j2 | 63 +++++++++++ 16 files changed, 328 insertions(+), 261 deletions(-) delete mode 100644 roles/nginx-reverse-proxy/handlers/main.yml delete mode 100644 roles/nginx-reverse-proxy/tasks/main.yml delete mode 100644 roles/nginx-reverse-proxy/templates/nginx/nginx-sites-available-main.j2 delete mode 100644 roles/nginx-reverse-proxy/templates/nginx/nginx-sites-available.j2 delete mode 100644 roles/nginx-reverse-proxy/templates/nginx/snippets/proxy-common-ssl.conf.j2 delete mode 100644 roles/nginx-reverse-proxy/templates/nginx/snippets/proxy-common.conf.j2 create mode 100644 roles/nginx-reverseproxy/handlers/main.yml create mode 100644 roles/nginx-reverseproxy/tasks/main.yml create mode 100644 roles/nginx-reverseproxy/templates/letsencrypt/dhparam.j2 create mode 100644 roles/nginx-reverseproxy/templates/nginx/sites-available/redirect.j2 create mode 100644 roles/nginx-reverseproxy/templates/nginx/sites-available/reverseproxy.j2 create mode 100644 roles/nginx-reverseproxy/templates/nginx/sites-available/reverseproxy_redirect_dname.j2 create mode 100644 roles/nginx-reverseproxy/templates/nginx/snippets/options-proxypass.conf.j2 create mode 100644 roles/nginx-reverseproxy/templates/nginx/snippets/options-ssl.conf.j2 create mode 100755 roles/nginx-reverseproxy/templates/update-motd.d/05-service.j2 create mode 100644 roles/nginx-reverseproxy/templates/www/html/50x.html.j2 diff --git a/roles/nginx-reverse-proxy/handlers/main.yml b/roles/nginx-reverse-proxy/handlers/main.yml deleted file mode 100644 index aa28cf0..0000000 --- a/roles/nginx-reverse-proxy/handlers/main.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -# Reload NGINX when a site changes -- name: Reload NGINX service - service: - name: nginx - state: reloaded diff --git a/roles/nginx-reverse-proxy/tasks/main.yml b/roles/nginx-reverse-proxy/tasks/main.yml deleted file mode 100644 index aac1af3..0000000 --- a/roles/nginx-reverse-proxy/tasks/main.yml +++ /dev/null @@ -1,64 +0,0 @@ ---- -# nginx is the proxy server -# nginx-light contains less modules -# but also reduces the surface of attack -- name: Install NGINX server - apt: - update_cache: true - name: nginx-light - state: present - register: apt_result - retries: 3 - until: apt_result is succeeded - -# Install proxy snippets -- name: Configure NGINX proxy snippets - template: - src: nginx/snippets/{{ item }}.j2 - dest: /etc/nginx/snippets/{{ item }} - mode: 0644 - loop: - - proxy-common.conf - - proxy-common-ssl.conf - notify: Reload NGINX service - -# Install sites -- name: Configure NGINX sites - template: - src: nginx/nginx-sites-available.j2 - dest: /etc/nginx/sites-available/{{ item.name }} - mode: 0644 - loop: "{{ reversed_proxy_subdomains }}" - notify: Reload NGINX service - -# Desactive useless nginx sites -- name: Deactivate the default NGINX site - file: - path: /etc/nginx/sites-enabled/default - state: absent - notify: Reload NGINX service - -# Activate sites -- name: Activate sites - file: - src: /etc/nginx/sites-available/{{ item.name }} - dest: /etc/nginx/sites-enabled/{{ item.name }} - state: link - loop: "{{ reversed_proxy_subdomains }}" - notify: Reload NGINX service - -# Install main site -- name: Configure NGINX main site - template: - src: nginx/nginx-sites-available-main.j2 - dest: /etc/nginx/sites-available/main - mode: 0644 - notify: Reload NGINX service - -# Activate main site -- name: Activate main site - file: - src: /etc/nginx/sites-available/main - dest: /etc/nginx/sites-enabled/main - state: link - notify: Reload NGINX service diff --git a/roles/nginx-reverse-proxy/templates/nginx/nginx-sites-available-main.j2 b/roles/nginx-reverse-proxy/templates/nginx/nginx-sites-available-main.j2 deleted file mode 100644 index f4ebf9a..0000000 --- a/roles/nginx-reverse-proxy/templates/nginx/nginx-sites-available-main.j2 +++ /dev/null @@ -1,107 +0,0 @@ -# {{ ansible_managed }} - -server { - # Common proxy snippet - include "snippets/proxy-common.conf"; - - # Set witch server name we define - server_name auro.re; - - # Permanentely moved to HTTPS - location / { - return 301 https://$host$request_uri; - } - - # For Matrix Synapse Discord Appservice Media - location /_matrix { - proxy_pass http://synapse.adm.auro.re:8008; - proxy_set_header X-Forwarded-For $remote_addr; - } -} - -server { - # Common proxy snippet - include "snippets/proxy-common-ssl.conf"; - - # Set witch server name we define - server_name auro.re; - - # Separate log files - access_log /var/log/nginx/main.access.log; - error_log /var/log/nginx/main.error.log; - - # Use LetsEncrypt SSL - ssl_certificate /etc/letsencrypt/live/auro.re/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/auro.re/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/auro.re/chain.pem; - - location / { - proxy_redirect off; - proxy_pass http://www.adm.auro.re; - proxy_set_header Host auro.re; - proxy_set_header P-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $remote_addr; - - # "A man is not dead while his name is still spoken." -- Going Postal - add_header X-Clacks-Overhead "GNU Terry Pratchett"; - } - - # For Matrix identity server - location /_matrix/identity { - proxy_pass http://synapse.adm.auro.re:8090/_matrix/identity; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $remote_addr; - } - - # For Matrix Synapse - location /_matrix { - proxy_pass http://synapse.adm.auro.re:8008; - proxy_set_header X-Forwarded-For $remote_addr; - } -} - -server { - listen 8448 ssl; - listen [::]:8448 ssl; - - # Set witch server name we define - server_name auro.re; - - # Separate log files - access_log /var/log/nginx/main.access.log; - error_log /var/log/nginx/main.error.log; - - # Use LetsEncrypt SSL - ssl_certificate /etc/letsencrypt/live/auro.re/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/auro.re/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/auro.re/chain.pem; - - # For Matrix Synapse federation - location / { - proxy_pass http://synapse.adm.auro.re:8008; - proxy_set_header X-Forwarded-For $remote_addr; - } -} - -server { - listen 9442 ssl; - listen [::]:9442 ssl; - - # Set witch server name we define - server_name auro.re; - - # Separate log files - access_log /var/log/nginx/main.access.log; - error_log /var/log/nginx/main.error.log; - - # Use LetsEncrypt SSL - ssl_certificate /etc/letsencrypt/live/auro.re/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/auro.re/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/auro.re/chain.pem; - - # For Matrix Appservice Webhooks - location / { - proxy_pass http://synapse.adm.auro.re:9000; - proxy_set_header X-Forwarded-For $remote_addr; - } -} diff --git a/roles/nginx-reverse-proxy/templates/nginx/nginx-sites-available.j2 b/roles/nginx-reverse-proxy/templates/nginx/nginx-sites-available.j2 deleted file mode 100644 index a733f23..0000000 --- a/roles/nginx-reverse-proxy/templates/nginx/nginx-sites-available.j2 +++ /dev/null @@ -1,40 +0,0 @@ -# {{ ansible_managed }} - -server { - # Common proxy snippet - include "snippets/proxy-common.conf"; - - # Set witch server name we define - server_name {{ item.from }}; - - # Permanentely moved to HTTPS - return 301 https://$host$request_uri; -} - -server { - # Common proxy snippet - include "snippets/proxy-common-ssl.conf"; - - # Set witch server name we define - server_name {{ item.from }}; - - # Separate log files - access_log /var/log/nginx/{{ item.name }}.access.log; - error_log /var/log/nginx/{{ item.name }}.error.log; - - # Use LetsEncrypt SSL - ssl_certificate /etc/letsencrypt/live/auro.re/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/auro.re/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/auro.re/chain.pem; - - location / { - proxy_redirect off; - proxy_pass http://{{ item.to }}; - proxy_set_header Host {{ item.from }}; - proxy_set_header P-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $remote_addr; - - # "A man is not dead while his name is still spoken." -- Going Postal - add_header X-Clacks-Overhead "GNU Terry Pratchett"; - } -} diff --git a/roles/nginx-reverse-proxy/templates/nginx/snippets/proxy-common-ssl.conf.j2 b/roles/nginx-reverse-proxy/templates/nginx/snippets/proxy-common-ssl.conf.j2 deleted file mode 100644 index 50f4977..0000000 --- a/roles/nginx-reverse-proxy/templates/nginx/snippets/proxy-common-ssl.conf.j2 +++ /dev/null @@ -1,32 +0,0 @@ -# {{ ansible_managed }} - -# Listen for IPv4 and IPv6 with HTTP2 -listen [::]:443 ssl http2; -listen 443 ssl http2; - -# Hide NGINX version -server_tokens off; - -# Reverse Proxy Adm -set_real_ip_from 10.128.0.0/16; -real_ip_header P-Real-Ip; - -# SSL based on https://mozilla.github.io/server-side-tls/ssl-config-generator/ -ssl on; -ssl_session_timeout 1d; -ssl_session_cache shared:SSL:50m; -ssl_session_tickets off; -ssl_protocols TLSv1.2; -ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"; -ssl_prefer_server_ciphers on; -add_header Strict-Transport-Security max-age=15768000; - -# OCSP Stapling, -ssl_stapling on; -ssl_stapling_verify on; - -# Use more secure ECDH curve -ssl_ecdh_curve secp521r1:secp384r1; - -# Executer "cd /etc/ssl/certs; openssl dhparam -out dhparam.pem 4096" avant d'activer -ssl_dhparam /etc/ssl/certs/dhparam.pem; diff --git a/roles/nginx-reverse-proxy/templates/nginx/snippets/proxy-common.conf.j2 b/roles/nginx-reverse-proxy/templates/nginx/snippets/proxy-common.conf.j2 deleted file mode 100644 index 6ac4acb..0000000 --- a/roles/nginx-reverse-proxy/templates/nginx/snippets/proxy-common.conf.j2 +++ /dev/null @@ -1,12 +0,0 @@ -# {{ ansible_managed }} - -# Listen for IPv4 and IPv6 -listen 80; -listen [::]:80; - -# Hide NGINX version -server_tokens off; - -# Reverse Proxy Adm -set_real_ip_from 10.128.0.0/16; -real_ip_header P-Real-Ip; diff --git a/roles/nginx-reverseproxy/handlers/main.yml b/roles/nginx-reverseproxy/handlers/main.yml new file mode 100644 index 0000000..6dfcdd7 --- /dev/null +++ b/roles/nginx-reverseproxy/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: Reload nginx + systemd: + name: nginx + state: reloaded diff --git a/roles/nginx-reverseproxy/tasks/main.yml b/roles/nginx-reverseproxy/tasks/main.yml new file mode 100644 index 0000000..b1e3945 --- /dev/null +++ b/roles/nginx-reverseproxy/tasks/main.yml @@ -0,0 +1,53 @@ +--- +- name: Install NGINX + apt: + update_cache: true + name: nginx + register: apt_result + retries: 3 + until: apt_result is succeeded + +- name: Copy snippets + template: + src: "nginx/snippets/{{ item }}.j2" + dest: "/etc/nginx/snippets/{{ item }}" + loop: + - options-ssl.conf + - options-proxypass.conf + +- name: Copy dhparam + template: + src: letsencrypt/dhparam.j2 + dest: /etc/letsencrypt/dhparam + +- name: Copy reverse proxy sites + template: + src: "nginx/sites-available/{{ item }}.j2" + dest: "/etc/nginx/sites-available/{{ item }}" + loop: + - reverseproxy + - reverseproxy_redirect_dname + - redirect + notify: Reload nginx + +- name: Activate sites + file: + src: "/etc/nginx/sites-available/{{ item }}" + dest: "/etc/nginx/sites-enabled/{{ item }}" + state: link + loop: + - reverseproxy + - reverseproxy_redirect_dname + - redirect + notify: Reload nginx + +- name: Copy 50x error page + template: + src: www/html/50x.html.j2 + dest: /var/www/html/50x.html + +- name: Indicate role in motd + template: + src: update-motd.d/05-service.j2 + dest: /etc/update-motd.d/05-nginx + mode: 0755 diff --git a/roles/nginx-reverseproxy/templates/letsencrypt/dhparam.j2 b/roles/nginx-reverseproxy/templates/letsencrypt/dhparam.j2 new file mode 100644 index 0000000..9b182b7 --- /dev/null +++ b/roles/nginx-reverseproxy/templates/letsencrypt/dhparam.j2 @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz ++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a +87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 +YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi +7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD +ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== +-----END DH PARAMETERS----- diff --git a/roles/nginx-reverseproxy/templates/nginx/sites-available/redirect.j2 b/roles/nginx-reverseproxy/templates/nginx/sites-available/redirect.j2 new file mode 100644 index 0000000..9cdb545 --- /dev/null +++ b/roles/nginx-reverseproxy/templates/nginx/sites-available/redirect.j2 @@ -0,0 +1,67 @@ +{{ ansible_header | comment }} + +{% for site in nginx.redirect_sites %} +# Redirect http://{{ site.from }} to http://{{ site.to }} +server { + listen 80; + listen [::]:80; + + server_name {{ site.from }}; + + location / { + return 302 http://{{ site.to }}$request_uri; + } +} + +# Redirect https://{{ site.from }} to https://{{ site.to }} +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name {{ site.from }}; + + # SSL common conf + include "/etc/nginx/snippets/options-ssl.conf"; + + location / { + return 302 https://{{ site.to }}$request_uri; + } +} + +{% endfor %} + +{# Also redirect for DNAMEs #} +{% for dname in nginx.redirect_dnames %} +{% for site in nginx.redirect_sites %} +{% set from = site.from | regex_replace('crans.org', dname) %} +{% if from != site.from %} +# Redirect http://{{ from }} to http://{{ site.to }} +server { + listen 80; + listen [::]:80; + + server_name {{ from }}; + + location / { + return 302 http://{{ site.to }}$request_uri; + } +} + +# Redirect https://{{ from }} to https://{{ site.to }} +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name {{ from }}; + + # SSL common conf + include "/etc/nginx/snippets/options-ssl.conf"; + + location / { + return 302 https://{{ site.to }}$request_uri; + } +} + +{% endif %} +{% endfor %} +{% endfor %} diff --git a/roles/nginx-reverseproxy/templates/nginx/sites-available/reverseproxy.j2 b/roles/nginx-reverseproxy/templates/nginx/sites-available/reverseproxy.j2 new file mode 100644 index 0000000..0898da0 --- /dev/null +++ b/roles/nginx-reverseproxy/templates/nginx/sites-available/reverseproxy.j2 @@ -0,0 +1,56 @@ +{{ ansible_header | comment }} + +# Automatic Connection header for WebSocket support +# See http://nginx.org/en/docs/http/websocket.html +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +{% for site in nginx.reverseproxy_sites %} +# Redirect http://{{ site.from }} to https://{{ site.from }} +server { + listen 80; + listen [::]:80; + + server_name {{ site.from }}; + + location / { + return 302 https://$host$request_uri; + } +} + +# Reverse proxify https://{{ site.from }} to http://{{ site.to }} +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name {{ site.from }}; + + # SSL common conf + include "/etc/nginx/snippets/options-ssl.conf"; + + # Log into separate log files + access_log /var/log/nginx/{{ site.from }}.log; + error_log /var/log/nginx/{{ site.from }}_error.log; + + # Keep the TCP connection open a bit for faster browsing + keepalive_timeout 70; + + # Custom error page + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /var/www/html; + } + + set_real_ip_from 10.231.136.0/24; + set_real_ip_from 2a0c:700:0:2::/64; + real_ip_header P-Real-Ip; + + location / { + proxy_pass http://{{ site.to }}; + include "/etc/nginx/snippets/options-proxypass.conf"; + } +} + +{% endfor %} diff --git a/roles/nginx-reverseproxy/templates/nginx/sites-available/reverseproxy_redirect_dname.j2 b/roles/nginx-reverseproxy/templates/nginx/sites-available/reverseproxy_redirect_dname.j2 new file mode 100644 index 0000000..988b6d1 --- /dev/null +++ b/roles/nginx-reverseproxy/templates/nginx/sites-available/reverseproxy_redirect_dname.j2 @@ -0,0 +1,37 @@ +{{ ansible_header | comment }} + +{% for dname in nginx.redirect_dnames %} +{% for site in nginx.reverseproxy_sites %} +{% set from = site.from | regex_replace('auro.re', dname) %} +{% set to = site.from %} +{% if from != site.from %} +# Redirect http://{{ from }} to http://{{ to }} +server { + listen 80; + listen [::]:80; + + server_name {{ from }}; + + location / { + return 302 http://{{ to }}$request_uri; + } +} + +# Redirect https://{{ from }} to https://{{ to }} +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name {{ from }}; + + # SSL common conf + include "/etc/nginx/snippets/options-ssl.conf"; + + location / { + return 302 https://{{ to }}$request_uri; + } +} + +{% endif %} +{% endfor %} +{% endfor %} diff --git a/roles/nginx-reverseproxy/templates/nginx/snippets/options-proxypass.conf.j2 b/roles/nginx-reverseproxy/templates/nginx/snippets/options-proxypass.conf.j2 new file mode 100644 index 0000000..0b864a6 --- /dev/null +++ b/roles/nginx-reverseproxy/templates/nginx/snippets/options-proxypass.conf.j2 @@ -0,0 +1,19 @@ +{{ ansible_header | comment }} + +proxy_redirect off; +proxy_set_header Host $host; + +# Pass the real client IP +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + +# Tell proxified server that we are HTTPS, fix Wordpress +proxy_set_header X-Forwarded-Proto https; + +# WebSocket support +proxy_http_version 1.1; +proxy_set_header Upgrade $http_upgrade; +proxy_set_header Connection $connection_upgrade; + +# For Owncloud WebDav +client_max_body_size 10G; diff --git a/roles/nginx-reverseproxy/templates/nginx/snippets/options-ssl.conf.j2 b/roles/nginx-reverseproxy/templates/nginx/snippets/options-ssl.conf.j2 new file mode 100644 index 0000000..1a9273a --- /dev/null +++ b/roles/nginx-reverseproxy/templates/nginx/snippets/options-ssl.conf.j2 @@ -0,0 +1,17 @@ +{{ ansible_header | comment }} + +ssl_certificate {{ nginx.ssl.cert }}; +ssl_certificate_key {{ nginx.ssl.cert_key }}; +ssl_session_timeout 1d; +ssl_session_cache shared:MozSSL:10m; +ssl_session_tickets off; +ssl_dhparam /etc/letsencrypt/dhparam; +ssl_protocols TLSv1.2 TLSv1.3; +ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; +ssl_prefer_server_ciphers off; + +# Enable OCSP Stapling, point to certificate chain +ssl_stapling on; +ssl_stapling_verify on; +ssl_trusted_certificate {{ nginx.ssl.trusted_cert }}; + diff --git a/roles/nginx-reverseproxy/templates/update-motd.d/05-service.j2 b/roles/nginx-reverseproxy/templates/update-motd.d/05-service.j2 new file mode 100755 index 0000000..82373d0 --- /dev/null +++ b/roles/nginx-reverseproxy/templates/update-motd.d/05-service.j2 @@ -0,0 +1,3 @@ +#!/usr/bin/tail +14 +{{ ansible_header | comment }} +> NGINX a été déployé sur cette machine. Voir /etc/nginx/. diff --git a/roles/nginx-reverseproxy/templates/www/html/50x.html.j2 b/roles/nginx-reverseproxy/templates/www/html/50x.html.j2 new file mode 100644 index 0000000..e5c8733 --- /dev/null +++ b/roles/nginx-reverseproxy/templates/www/html/50x.html.j2 @@ -0,0 +1,63 @@ + + + + + 502 + + + + +

502

+

Whoops, le service prend trop de temps à répondre…

+

Essayez de rafraîchir la page. Si le problème persiste, pensez + à contacter l'équipe technique d'Aurore.

+ + +