diff --git a/roles/nginx/tasks/main.yml b/roles/nginx/tasks/main.yml index 91b67b5e..e61e59a2 100644 --- a/roles/nginx/tasks/main.yml +++ b/roles/nginx/tasks/main.yml @@ -19,7 +19,7 @@ when: nginx_strong_dh_group is defined and nginx_strong_dh_group - name: Create the Nginx configuration file - template: src={{ application_name }}.j2 + template: src=nginx_config.j2 dest=/etc/nginx/sites-available/{{ application_name }} backup=yes notify: reload nginx diff --git a/roles/nginx/templates/nginx_config.j2 b/roles/nginx/templates/nginx_config.j2 new file mode 100644 index 00000000..9d270338 --- /dev/null +++ b/roles/nginx/templates/nginx_config.j2 @@ -0,0 +1,119 @@ +upstream {{ application_name }}_wsgi_server { + # fail_timeout=0 means we always retry an upstream even if it failed + # to return a good HTTP response (in case the Unicorn master nukes a + # single worker for timing out). + + server unix:{{ virtualenv_path }}/run/gunicorn.sock fail_timeout=0; +} + +server { + listen 80; + server_name {{ nginx_server_name }}; + server_tokens off; + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl; + server_name {{ nginx_server_name }}; + server_tokens off; + {% if nginx_use_letsencrypt %} + ssl_certificate {{ letsencrypt_dir }}/{{ letsencrypt_cert_filename }}; + ssl_certificate_key {{ letsencrypt_dir }}/{{ letsencrypt_privkey_filename }}; + {% else %} + ssl_certificate {{ nginx_ssl_dest_dir }}/{{ application_name }}.crt; + ssl_certificate_key {{ nginx_ssl_dest_dir }}/{{ application_name }}.key; + {% endif %} + ssl_protocols TLSv1.2; + ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; + ssl_prefer_server_ciphers on; + {% if nginx_strong_dh_group %} + ssl_dhparam /etc/ssl/certs/dhparams.pem; + {% endif %} + + # Prevent MIME type sniffing for security + add_header X-Content-Type-Options "nosniff"; + + # Enable XSS Protection in case user's browser has disabled it + add_header X-XSS-Protection "1; mode=block"; + + + # ----------- Recommended headers (without default settings) ----------- # + # It is recommended that all web applications set these headers. # + # However, this template does not prescribe any defaults. # + + #### Content-Security-Policy #### + # Recommended security-conscious defaults: + # --------------------- -------------------------------------------------- + # default-src https: By default, all content must be loaded over HTTPS + # form-action 'self' Disallow form submission to external URLs + # frame-ancestors 'none' Disable loading the site in a frame (similar to `X-Frame-Options: DENY) + # + # If all content is self-hosted (no JavaScript, CSS, fonts, etc. loaded from CDNs), + # it's wise to use your CSP to prevent content loading from other sources: + # script-src: 'self'; style-src: 'self'; font-src: 'self'; media-src: 'self'; object-src: 'self' + # + # For more information (including additional directives not defined here), see: + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy + # + # Alternatively, set Content-Security-Policy-Report-Only to report violations, but not block content loading + # add_header Content-Security-Policy "default-src https:; form-action 'self'; frame-ancestors 'none'"; + + #### Referrer-Policy #### + # Recommended reading on the security concerns behind a default referrer policy: + # https://developer.mozilla.org/en-US/docs/Web/Security/Referer_header:_privacy_and_security_concerns + # Don't leak referring URL when following external links (protects user privacy by reducing tracking opportunities) + # Setting "no-referrer" is the most privacy-conscious choice. + # However, some frameworks (e.g. Django) rely on same-origin referrer information for CSRF protection + #add_header Referrer-Policy "same-origin"; + + #### Feature-Policy #### + # This experimental header enumerates exactly which browser features your application will and will not use. + # Feature policies apply to embedded content and can thus help protect your users from malicious third parties. + # Note that there is currently no way to deny all features by default. + # The below policy disables all known features at time of writing. Consult MDN for an up-to-date feature list: + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy + #add_header Feature-Policy "accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; camera 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; speaker 'none'; usb 'none'; vr 'none';"; + + # ---------------------- End recommended headers ---------------------- # + + + client_max_body_size 4G; + + location /static/ { + alias {{ nginx_static_dir }}; + } + + location /media/ { + alias {{ nginx_media_dir }}; + } + + location / { + if (-f {{ virtualenv_path }}/maintenance_on.html) { + return 503; + } + + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $http_host; + proxy_redirect off; + + # Try to serve static files from nginx, no point in making an + # *application* server like Unicorn/Rainbows! serve static files. + if (!-f $request_filename) { + proxy_pass http://{{ application_name }}_wsgi_server; + break; + } + } + + # Error pages + error_page 500 502 504 /500.html; + location = /500.html { + root {{ project_path }}/{{ application_name }}/templates/; + } + + error_page 503 /maintenance_on.html; + location = /maintenance_on.html { + root {{ virtualenv_path }}/; + } +} diff --git a/roles/nginx/templates/youtubeadl.j2 b/roles/nginx/templates/youtubeadl.j2 deleted file mode 100644 index 1f8decae..00000000 --- a/roles/nginx/templates/youtubeadl.j2 +++ /dev/null @@ -1,74 +0,0 @@ -upstream {{ application_name }}_wsgi_server { - # fail_timeout=0 means we always retry an upstream even if it failed - # to return a good HTTP response (in case the Unicorn master nukes a - # single worker for timing out). - - server unix:{{ virtualenv_path }}/run/gunicorn.sock fail_timeout=0; -} - -server { - listen 80; - server_name {{ nginx_server_name }}; - rewrite ^ https://$server_name$request_uri? permanent; -} - -server { - listen 443; - server_name {{ nginx_server_name }}; - ssl on; - {% if nginx_use_letsencrypt %} - ssl_certificate {{ letsencrypt_dir }}/{{ letsencrypt_cert_filename }}; - ssl_certificate_key {{ letsencrypt_dir }}/{{ letsencrypt_privkey_filename }}; - {% else %} - ssl_certificate {{ nginx_ssl_dest_dir }}/{{ application_name }}.crt; - ssl_certificate_key {{ nginx_ssl_dest_dir }}/{{ application_name }}.key; - {% endif %} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; - ssl_prefer_server_ciphers on; - {% if nginx_strong_dh_group %} - ssl_dhparam /etc/ssl/certs/dhparams.pem; - {% endif %} - - client_max_body_size 4G; - - access_log {{ nginx_access_log_file }}; - error_log {{ nginx_error_log_file }}; - - location /static/ { - alias {{ nginx_static_dir }}; - } - - location /media/ { - alias {{ nginx_media_dir }}; - } - - location / { - if (-f {{ virtualenv_path }}/maintenance_on.html) { - return 503; - } - - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto https; - proxy_set_header Host $http_host; - proxy_redirect off; - - # Try to serve static files from nginx, no point in making an - # *application* server like Unicorn/Rainbows! serve static files. - if (!-f $request_filename) { - proxy_pass http://{{ application_name }}_wsgi_server; - break; - } - } - - # Error pages - error_page 500 502 504 /500.html; - location = /500.html { - root {{ project_path }}/{{ application_name }}/templates/; - } - - error_page 503 /maintenance_on.html; - location = /maintenance_on.html { - root {{ virtualenv_path }}/; - } -}