summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'ansible/roles/nginx')
-rw-r--r--ansible/roles/nginx/defaults/main.yml6
-rw-r--r--ansible/roles/nginx/files/conf.d/http.custom.conf84
-rw-r--r--ansible/roles/nginx/files/tls/ssl_ciphers_intermediate10
-rw-r--r--ansible/roles/nginx/files/tls/ssl_ciphers_modern7
-rw-r--r--ansible/roles/nginx/files/tls/ssl_ciphers_tls137
-rw-r--r--ansible/roles/nginx/files/tls/ssl_params55
-rw-r--r--ansible/roles/nginx/handlers/main.yml3
-rw-r--r--ansible/roles/nginx/tasks/main.yml118
-rw-r--r--ansible/roles/nginx/templates/basic-site.conf.j268
9 files changed, 358 insertions, 0 deletions
diff --git a/ansible/roles/nginx/defaults/main.yml b/ansible/roles/nginx/defaults/main.yml
new file mode 100644
index 0000000..34ac696
--- /dev/null
+++ b/ansible/roles/nginx/defaults/main.yml
@@ -0,0 +1,6 @@
1---
2nginx:
3 # Don't disable anything by default, but provide it here
4 # so you don't need to include empty 'disabled' in your own
5 # host configs.
6 disabled: []
diff --git a/ansible/roles/nginx/files/conf.d/http.custom.conf b/ansible/roles/nginx/files/conf.d/http.custom.conf
new file mode 100644
index 0000000..5f70166
--- /dev/null
+++ b/ansible/roles/nginx/files/conf.d/http.custom.conf
@@ -0,0 +1,84 @@
1
2## Proxy options
3proxy_buffering on;
4# proxy_cache_min_uses 3;
5proxy_cache_path /var/nginx/proxy-cache/ levels=1:2 keys_zone=cache:10m inactive=10m max_size=1000M;
6proxy_cache_valid any 10m;
7proxy_ignore_client_abort off;
8proxy_intercept_errors on;
9proxy_next_upstream error timeout invalid_header;
10proxy_redirect off;
11proxy_set_header Host $host;
12proxy_set_header X-Forwarded-For $remote_addr;
13proxy_connect_timeout 60;
14proxy_send_timeout 60;
15proxy_read_timeout 60;
16
17# We used to use this header when we ran dual http/https stacks to verify
18# user login pages were being only requested over https, but now we forward
19# every site to https, so we can assume our schemes are aligned to our interests
20# (as long as all our backend code stopped checking for X-Forwarded-Proto too).
21#proxy_set_header X-Forwarded-Proto $scheme;
22
23## Size Limits
24# May need to override these (server or location blocks) if doing large uploads.
25# Setting to zero disables any size checking.
26client_body_buffer_size 16k;
27client_max_body_size 15m;
28
29# If clients send headers larger than 1k,
30# they get upgraded to large_client_header_buffers.
31client_header_buffer_size 1k;
32large_client_header_buffers 32 64k;
33
34## Timeouts
35client_body_timeout 5s;
36client_header_timeout 5s;
37keepalive_timeout 5s 5s;
38#keepalive_timeout 0;
39send_timeout 5s;
40
41## General Options
42ignore_invalid_headers on;
43recursive_error_pages on;
44#sendfile on; # enabled by top level config
45server_name_in_redirect off;
46server_tokens off;
47
48# For per-client rate limiting, see config options at:
49# https://nginx.org/en/docs/http/ngx_http_limit_conn_module.html
50
51## Compression
52#gzip on; # enabled by top level config
53gzip_static on;
54gzip_buffers 16 32k;
55gzip_comp_level 6;
56gzip_http_version 1.0;
57gzip_min_length 500;
58gzip_types text/plain application/x-javascript text/xml text/css image/x-icon application/xml application/xml+rss text/javascript application/javascript application/json image/svg+xml font/truetype font/opentype application/vnd.ms-fontobject;
59gzip_vary on;
60gzip_proxied any; # required for cloudfront to receive a gzip'd response
61
62## Filesystem Operation Cache (caches fds, sizes, times, errors, etc)
63open_file_cache max=6000 inactive=5m;
64open_file_cache_valid 2m;
65open_file_cache_min_uses 1;
66open_file_cache_errors on;
67
68# For reading a response from disk
69output_buffers 32 32k;
70
71## Optimize Large File Transfers (can be overriden in hosts and locations)
72aio threads; # use default thread pool, create thread pools: threads=NAME;
73aio_write on; # use threaded writes for temporary files and proxied data
74
75# For files larger than 8 MB, use O_DIRECT instead of sendfile()
76directio 8m;
77directio_alignment 512; # if using XFS, set as 4096
78
79## Access Log Caches
80open_log_file_cache max=64 inactive=20s min_uses=1 valid=1m;
81
82log_format main '$remote_addr - $remote_user [$time_local] "$request" '
83 '$status $body_bytes_sent "$http_referer" '
84 '"$http_user_agent" "$http_x_forwarded_for"';
diff --git a/ansible/roles/nginx/files/tls/ssl_ciphers_intermediate b/ansible/roles/nginx/files/tls/ssl_ciphers_intermediate
new file mode 100644
index 0000000..bc79954
--- /dev/null
+++ b/ansible/roles/nginx/files/tls/ssl_ciphers_intermediate
@@ -0,0 +1,10 @@
1# From https://mozilla.github.io/server-side-tls/ssl-config-generator/
2# as of 2018-07-12
3
4# No TLSv1.3 support yet!
5
6ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
7ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
8
9# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
10ssl_dhparam /etc/ssl/ffdhe2048.pem;
diff --git a/ansible/roles/nginx/files/tls/ssl_ciphers_modern b/ansible/roles/nginx/files/tls/ssl_ciphers_modern
new file mode 100644
index 0000000..ab93ffc
--- /dev/null
+++ b/ansible/roles/nginx/files/tls/ssl_ciphers_modern
@@ -0,0 +1,7 @@
1# From https://mozilla.github.io/server-side-tls/ssl-config-generator/
2# as of 2018-07-12
3
4# No TLSv1.3 support yet!
5
6ssl_protocols TLSv1.2;
7ssl_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';
diff --git a/ansible/roles/nginx/files/tls/ssl_ciphers_tls13 b/ansible/roles/nginx/files/tls/ssl_ciphers_tls13
new file mode 100644
index 0000000..db04c36
--- /dev/null
+++ b/ansible/roles/nginx/files/tls/ssl_ciphers_tls13
@@ -0,0 +1,7 @@
1# From https://github.com/cloudflare/sslconfig/blob/796bc5ac7224f1e540394d792323ccafa86aaeea/conf
2
3# nginx >= 1.11.0 (2016-05-24) created the 'ssl_ecdh_curve' parameter
4
5ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
6ssl_ecdh_curve X25519:P-256:P-384:P-224:P-521;
7ssl_ciphers '[ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305]:ECDHE+AES128:RSA+AES128:ECDHE+AES256:RSA+AES256:ECDHE+3DES:RSA+3DES';
diff --git a/ansible/roles/nginx/files/tls/ssl_params b/ansible/roles/nginx/files/tls/ssl_params
new file mode 100644
index 0000000..37798fc
--- /dev/null
+++ b/ansible/roles/nginx/files/tls/ssl_params
@@ -0,0 +1,55 @@
1# Test OCSP with:
2# openssl s_client -connect $site:443 -tls1 -tlsextdebug -status
3#
4# also test with:
5# openssl s_client -connect $site:443 -CAfile /etc/ssl/certs/ca-certificates.crt -showcerts -status -tlsextdebug -cipher RSA </dev/null
6#
7# openssl s_client -connect $site:443 -CAfile /etc/ssl/certs/ca-certificates.crt -showcerts -status -tlsextdebug -cipher ECDSA </dev/null
8
9
10# Duration client SSL session tickets are valid for:
11ssl_session_timeout 1d;
12# NOTE NOTE NOTE NOTE NOTE
13# nginx only regenerates its ssl_session_ticket_key on reload or restart.
14# the ticket key is basically a symmetric key that effectively breaks
15# forward secrecy if leaked.
16# With ssl_session_tickets enabled, you should reload nginx daily to reset
17# the internal cached ticket key.
18# If you are using external ticket keys, those should also be rotated daily.
19# END NOTE END NOTE END NOTE
20
21# Internal cache of SSL sessions
22ssl_session_cache shared:SSL:500m; # 500MB = 2M cached sessions (4k sessions/MB)
23
24# session tickets are reused for the life of the server.
25# For multiple servers serving the same host,
26# have them all share the same key and rotate as necessary:
27# ssl_session_ticket_key [keyfile];
28# Without a ticket key file defined, a reload of nginx resets the key.
29ssl_session_tickets on;
30
31# Individual cipher files are included externally
32# (one of ssl_ciphers_{intermediate,modern})
33ssl_prefer_server_ciphers on;
34
35# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
36add_header Strict-Transport-Security "max-age=15768000; includeSubdomains";
37
38# OCSP Stapling ---
39# fetch OCSP records from URL in ssl_certificate and cache them
40ssl_stapling on;
41ssl_stapling_verify on;
42
43# See: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_trusted_certificate
44ssl_trusted_certificate /etc/ssl/lets-encrypt-x3-cross-signed.pem;
45
46# Instead of using resolver, take response from file:
47# ssl_stapling_file <-- must be set PER domain, but nginx so far has refused
48# to add the ability to have one stapling file per certificate now that nginx
49# supports both RSA and EC per domain. So, this is useless if you have multiple
50# certificates per domain.
51
52# 'valid' ignores DNS TTL and caches lookups for specified duration
53# This should be replaced with a local dnsmasq resolver at 127.0.0.1
54resolver 127.0.0.53 4.2.2.2 8.8.8.8 1.1.1.1 valid=600s ipv6=off;
55resolver_timeout 4s;
diff --git a/ansible/roles/nginx/handlers/main.yml b/ansible/roles/nginx/handlers/main.yml
new file mode 100644
index 0000000..31f8ade
--- /dev/null
+++ b/ansible/roles/nginx/handlers/main.yml
@@ -0,0 +1,3 @@
1---
2- name: reload nginx
3 command: nginx -s reload
diff --git a/ansible/roles/nginx/tasks/main.yml b/ansible/roles/nginx/tasks/main.yml
new file mode 100644
index 0000000..73469a1
--- /dev/null
+++ b/ansible/roles/nginx/tasks/main.yml
@@ -0,0 +1,118 @@
1---
2- name: emerge, nginx with extra modules!
3 apt:
4 pkg: nginx-extras
5 state: latest
6
7# Keep 32 logs
8- name: adjust nginx logrotate keep files
9 lineinfile:
10 state: present
11 path: /etc/logrotate.d/nginx
12 regexp: "^(\\s+)rotate "
13 line: "\\1rotate 32"
14 backrefs: yes
15
16# And only rotate when they grow larger than 1 GB
17- name: adjust nginx logrotate trigger rolls
18 lineinfile:
19 state: present
20 path: /etc/logrotate.d/nginx
21 regexp: "minsize"
22 line: "minsize 1G"
23 insertafter: "rotate \\d+"
24
25- name: verify nginx isn't serving default pages
26 file:
27 path: /etc/nginx/sites-enabled/default
28 state: absent
29 notify:
30 - reload nginx
31
32- name: verify nginx proxy cache dir exists
33 file:
34 path: /var/nginx/proxy-cache
35 owner: www-data
36 state: directory
37
38- name: verify nginx cpu affinity
39 lineinfile:
40 state: present
41 path: /etc/nginx/nginx.conf
42 regexp: "^worker_cpu_affinity "
43 line: "worker_cpu_affinity auto;"
44 insertafter: '^worker_processes '
45 notify:
46 - reload nginx
47
48- name: drop keepalive from nginx conf because we set it custom
49 lineinfile:
50 state: absent
51 path: /etc/nginx/nginx.conf
52 regexp: "^\\s+keepalive_timeout"
53 notify:
54 - reload nginx
55
56- name: copy config extensions
57 copy:
58 src: conf.d
59 dest: /etc/nginx/
60 notify:
61 - reload nginx
62
63- name: copy shared tls settings
64 copy:
65 src: tls/
66 dest: /etc/nginx/
67 notify:
68 - reload nginx
69
70- name: generate our templated basic sites
71 template:
72 src: basic-site.conf.j2
73 dest: "/etc/nginx/sites-available/{{ item.domain }}"
74 loop: "{{ nginx.basic }}"
75 notify:
76 - reload nginx
77
78- name: copy our more complex sites we don't want templated
79 copy:
80 src: "servers/{{ item }}"
81 dest: /etc/nginx/sites-available/
82 loop: "{{ nginx.complex }}"
83 notify:
84 - reload nginx
85
86- name: activate our nginx site configs
87 file:
88 src: "/etc/nginx/sites-available/{{ item }}"
89 dest: "/etc/nginx/sites-enabled/{{ item }}"
90 state: link
91 loop: "{{ nginx.complex }}"
92 notify:
93 - reload nginx
94
95- name: activate our nginx site templates
96 file:
97 src: "/etc/nginx/sites-available/{{ item.domain }}"
98 dest: "/etc/nginx/sites-enabled/{{ item.domain }}"
99 state: link
100 loop: "{{ nginx.basic }}"
101 notify:
102 - reload nginx
103
104- name: remove disabled sites
105 file:
106 src: "/etc/nginx/sites-enabled/{{ item }}"
107 state: absent
108 loop: "{{ nginx.disabled | default([]) }}"
109 notify:
110 - reload nginx
111
112- name: reload if certs newish
113 include_role:
114 name: certreload
115 vars:
116 certreload:
117 notifiers:
118 - reload nginx
diff --git a/ansible/roles/nginx/templates/basic-site.conf.j2 b/ansible/roles/nginx/templates/basic-site.conf.j2
new file mode 100644
index 0000000..454b2bd
--- /dev/null
+++ b/ansible/roles/nginx/templates/basic-site.conf.j2
@@ -0,0 +1,68 @@
1server {
2 listen {{ item.domain }}:443 ssl http2 fastopen=4096 reuseport;
3 server_name {{ item.domain }};
4
5 access_log /var/log/nginx/{{ item.domain }}.access.log main buffer=32k;
6 error_log /var/log/nginx/{{ item.domain }}.error.log error;
7
8 ssl on;
9
10 include /etc/nginx/ssl_params;
11
12{% if nginx.ssl == "modern" %}
13 include /etc/nginx/ssl_ciphers_modern;
14{% elif nginx.ssl == "tls13" %}
15 include /etc/nginx/ssl_ciphers_tls13;
16{% else %}
17 # Default, just use commonly accepted options:
18 include /etc/nginx/ssl_ciphers_intermediate;
19{% endif %}
20
21 ssl_certificate /etc/ssl/{{ item.domain }}-cert-combined.rsa2048.pem;
22 ssl_certificate_key /etc/ssl/private/{{ item.domain }}-key.rsa2048.pem;
23
24 # nginx >= 1.11.0 (2016-05-24) allows loading redundant certs and keys so you
25 # can serve modern EC clients and less modern RSA clients at the same time.
26 ssl_certificate /etc/ssl/{{ item.domain }}-cert-combined.prime256v1.pem;
27 ssl_certificate_key /etc/ssl/private/{{ item.domain }}-key.prime256v1.pem;
28
29 root /srv/web/{{ item.domain }};
30
31{% if nginx.google is defined %}
32 location /{{ nginx.google.siteKey }}.html {
33 root {{ nginx.google.siteKeyServeDir }}};
34 }
35{% endif %}
36
37{% if item.customConfig is defined %}
38{{ item.customConfig }}
39{% endif %}
40
41{% for location in item.uri %}
42 location {{ location.path }} {
43{% if location.appServer is defined %}
44 proxy_pass {{ location.appServer }}/$request_uri;
45 proxy_set_header Host $host;
46{% else %}
47 root /srv/web/{{ item.domain }};
48{% endif %}
49 }
50{% endfor %}
51}
52
53server {
54 listen {{ item.domain }} fastopen=4096 reuseport;
55 server_name www.{{ item.domain }} {{ item.domain }};
56
57 access_log /var/log/nginx/{{ item.domain }}.access.log main buffer=32k;
58 error_log /var/log/nginx/{{ item.domain }}.error.log error;
59
60 location /.well-known/acme-challenge/ {
61 alias /srv/web/challenges/;
62 try_files $uri =404;
63 }
64
65 location / {
66 return 301 https://{{ item.domain }}$request_uri;
67 }
68}
Powered by cgit v1.2.3 (git 2.41.0)