mirror of
https://git.lapiole.org/dani/ansible-roles.git
synced 2025-07-31 03:35:45 +02:00
Update to 2021-12-01 19:13
This commit is contained in:
116
roles/nginx/defaults/main.yml
Normal file
116
roles/nginx/defaults/main.yml
Normal file
@@ -0,0 +1,116 @@
|
||||
---
|
||||
|
||||
nginx_ports:
|
||||
- 80
|
||||
nginx_ssl_ports:
|
||||
- 443
|
||||
nginx_src_ip:
|
||||
- 0.0.0.0/0
|
||||
|
||||
# If true, will install openresty as an nginx replacement
|
||||
nginx_openresty: False
|
||||
|
||||
nginx_modules:
|
||||
- stream
|
||||
- http_image_filter
|
||||
- http_perl
|
||||
|
||||
nginx_log_format: combined_virtual
|
||||
|
||||
# The root domaine.
|
||||
# Some special vhost names can be derived from it. Eg downtime.{{ nginx_primary_domain }}
|
||||
nginx_primary_domain: "{{ ansible_domain }}"
|
||||
|
||||
nginx_cert_path: /etc/nginx/ssl/cert.pem
|
||||
nginx_key_path: /etc/nginx/ssl/key.pem
|
||||
# OR
|
||||
#
|
||||
# nginx_letsencrypt_cert:
|
||||
|
||||
nginx_vhosts: []
|
||||
nginx_default_vhost_base:
|
||||
aliases: []
|
||||
port: 80 # can also be a list of ports
|
||||
ssl:
|
||||
enabled: True
|
||||
forced: True
|
||||
compat: False
|
||||
port: 443 # can also be a list of ports
|
||||
auth: none
|
||||
# htpasswd_file:
|
||||
maintenance: False
|
||||
acme_http: False
|
||||
redirect_aliases: True
|
||||
document_root: /var/www/html
|
||||
csp: "default-src 'self' 'unsafe-inline'; img-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'"
|
||||
perf: True
|
||||
limits: True
|
||||
max_body_size: 10m
|
||||
location: /
|
||||
proxy:
|
||||
backend: False
|
||||
websocket: True
|
||||
cache: False
|
||||
timeout: 60s
|
||||
headers:
|
||||
X-Forwarded-For: '$proxy_add_x_forwarded_for'
|
||||
X-Real-IP: '$remote_addr'
|
||||
X-Forwarded-Proto: '$scheme'
|
||||
X-Scheme: '$scheme'
|
||||
X-Forwarded-Host: '$host'
|
||||
X-Forwarded-Port: '$server_port'
|
||||
Host: '$host'
|
||||
allowed_methods:
|
||||
- GET
|
||||
- HEAD
|
||||
- POST
|
||||
headers:
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
X-Content-Type-Options: nosniff
|
||||
X-XSS-Protection: 1; mode=block
|
||||
Strict-Transport-Security: $hsts_header
|
||||
logs:
|
||||
gelf: True
|
||||
src_ip: []
|
||||
deny_ip: []
|
||||
custom_pre: '# No custom configuration defined'
|
||||
custom_begin: '# No custom configuration defined'
|
||||
custom_end: '# No custom configuration defined'
|
||||
custom_location_begin: '# No custom configuration defined'
|
||||
custom_location_end: '# No custom configuration defined'
|
||||
|
||||
nginx_default_vhost_extra: {}
|
||||
nginx_default_vhost: "{{ nginx_default_vhost_base | combine(nginx_default_vhost_extra,recursive=True) }}"
|
||||
|
||||
# List of IP addresses which won't be affected by maintenance redirections
|
||||
nginx_maintenance_ip: []
|
||||
|
||||
nginx_ssl_ciphers_modern: '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'
|
||||
nginx_ssl_ciphers_compat: '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:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA'
|
||||
nginx_ssl_protocols:
|
||||
- TLSv1.2
|
||||
- TLSv1.3
|
||||
|
||||
# List of ip/cidr which won't have any DOS limit
|
||||
nginx_dos_whitelisted_ip: []
|
||||
|
||||
# Max number of request per second, per IP address for non whitelisted IP
|
||||
nginx_req_per_sec: 30
|
||||
|
||||
# Max size of the cache on disk
|
||||
nginx_cache_size: 2g
|
||||
|
||||
# If true, a letsencrypt cert will be created for every vhost, automatically
|
||||
nginx_auto_letsencrypt_cert: False
|
||||
|
||||
# Can be used to deploy htpasswd files
|
||||
nginx_htpasswd: []
|
||||
# nginx_htpasswd:
|
||||
# - path: /etc/nginx/customers.htpasswd
|
||||
# users:
|
||||
# - login: client1
|
||||
# password: s3crEt.
|
||||
# state: present
|
||||
# - login: client2
|
||||
# state: absent
|
||||
|
3
roles/nginx/files/dehydrated_deploy_hook
Normal file
3
roles/nginx/files/dehydrated_deploy_hook
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
/sbin/service nginx reload
|
138
roles/nginx/files/lasagna.pl
Normal file
138
roles/nginx/files/lasagna.pl
Normal file
@@ -0,0 +1,138 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2018 Dimitri Gence
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use URI;
|
||||
use URI::QueryParam;
|
||||
use Getopt::Long;
|
||||
|
||||
my %replacements = ("\"" => "\\\"", "&" => "\", \"", "=" => "\": \"");
|
||||
my %rules = ();
|
||||
|
||||
my @rgxlist = @{[]};
|
||||
|
||||
|
||||
GetOptions(
|
||||
"help" => \(my $help),
|
||||
"output=s" => \(my $output),
|
||||
"regex=s" => \(my $regex)
|
||||
) or exit(-1);
|
||||
|
||||
my ($filnam) = @ARGV;
|
||||
|
||||
|
||||
if($help) {
|
||||
print("lasagna - lazy naxsi rules generator\n".
|
||||
"usage: $0 [<options>] [file]\n\n".
|
||||
"options:\n".
|
||||
" -h, --help show this message and exit\n".
|
||||
" -o FILE, --output FILE\n".
|
||||
" write rules to FILE\n".
|
||||
" -r FILE, --regex FILE\n".
|
||||
" use regular expressions from FILE to generate rules\n");
|
||||
exit;
|
||||
}
|
||||
|
||||
if(defined $regex) {
|
||||
if ($regex eq "-") {
|
||||
*FILE = *STDIN
|
||||
} else {
|
||||
open(FILE, "<$regex")
|
||||
}
|
||||
|
||||
while (<FILE>) {
|
||||
substr($_, -1) = '';
|
||||
push(@rgxlist, $_);
|
||||
}
|
||||
|
||||
close(FILE);
|
||||
}
|
||||
|
||||
|
||||
if(defined $filnam) {open(FILE, "<$filnam")} else {*FILE = *STDIN}
|
||||
|
||||
while(<FILE>) {
|
||||
if(!($_ =~ /NAXSI_FMT/)){ next; }
|
||||
$_ =~ s/^.*NAXSI_FMT/NAXSI_FMT/;
|
||||
|
||||
my $url = URI->new("/?".@{[split(/, |: /, $_)]}[1]);
|
||||
my $exceptions = $url->query_form_hash;
|
||||
|
||||
if($exceptions->{"learning"} ne "1") { next; }
|
||||
|
||||
for my $id (grep /^id[0-9]+$/, keys %$exceptions) {
|
||||
my $n = substr($id, 2);
|
||||
my $mz = "mz:";
|
||||
|
||||
|
||||
for my $rgx (@rgxlist) {
|
||||
if ($exceptions->{"uri"} =~ /$rgx/) {
|
||||
$mz .= "\$URL_X:".$rgx."|";
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
if (!($mz =~ /\$URL/)) {
|
||||
$mz .= "\$URL:".$exceptions->{"uri"}."|";
|
||||
}
|
||||
|
||||
if(my $varnam = $exceptions->{"var_name$n"}) {
|
||||
my $zone = $exceptions->{"zone$n"};
|
||||
|
||||
if($zone eq "HEADERS" and $varnam eq "cookie") {
|
||||
$mz =~ s/\$URL(_X)?:.*\|//;
|
||||
}
|
||||
|
||||
if ($mz =~ /\$URL_X/) {
|
||||
$zone =~ s/(ARGS|BODY|HEADERS)(.*)/\$$1_VAR_X:^$varnam$2\$/;
|
||||
} else {
|
||||
$zone =~ s/(ARGS|BODY|HEADERS)(.*)/\$$1_VAR:$varnam$2/;
|
||||
}
|
||||
|
||||
$mz .= $zone;
|
||||
} else {
|
||||
$mz .= $exceptions->{"zone$n"};
|
||||
}
|
||||
|
||||
$mz =~ s/"/\\"/g;
|
||||
push(@{$rules{$mz}}, $exceptions->{"id$n"});
|
||||
}
|
||||
}
|
||||
|
||||
if(defined $filnam) {close(FILE)}
|
||||
|
||||
|
||||
if(defined $output) {open(OUTPUT, ">>$output")} else {*OUTPUT = *STDOUT}
|
||||
|
||||
for(keys %rules; my ($mz, $ids) = each(%rules);) {
|
||||
my %ids = map {$_ => 1} @{$ids};
|
||||
my @ids = keys(%ids);
|
||||
print(OUTPUT "BasicRule wl:".join(",", sort(@ids))." \"$mz\";\n");
|
||||
}
|
||||
|
||||
if(defined $output) {close(OUTPUT)}
|
||||
|
||||
|
||||
exit(0);
|
15
roles/nginx/handlers/main.yml
Normal file
15
roles/nginx/handlers/main.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
|
||||
- name: reload nginx
|
||||
command: nginx -t
|
||||
notify: really reload nginx
|
||||
|
||||
- name: really reload nginx
|
||||
service: name=nginx state=reloaded
|
||||
|
||||
- name: restart nginx
|
||||
command: nginx -t
|
||||
notify: really restart nginx
|
||||
|
||||
- name: really restart nginx
|
||||
service: name=nginx state=restarted
|
6
roles/nginx/meta/main.yml
Normal file
6
roles/nginx/meta/main.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
|
||||
dependencies:
|
||||
- role: repo_openresty
|
||||
when: nginx_openresty
|
||||
- role: mkdir
|
67
roles/nginx/tasks/conf.yml
Normal file
67
roles/nginx/tasks/conf.yml
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
- name: Deploy configuration
|
||||
template: src={{ item }}.j2 dest=/etc/nginx/{{ item }}
|
||||
with_items:
|
||||
- nginx.conf
|
||||
- mime.types
|
||||
- ansible_modules.d/10-common.conf
|
||||
- ansible_location.d/10-status.conf
|
||||
- ansible_conf.d/09-cacheable.conf
|
||||
- ansible_conf.d/maintenance.inc
|
||||
- ansible_conf.d/perf.inc
|
||||
- ansible_conf.d/force_ssl.inc
|
||||
- ansible_conf.d/acme.inc
|
||||
- ansible_conf.d/custom.inc
|
||||
- ansible_conf.d/cache.inc
|
||||
- ansible_conf.d/10-cache.conf
|
||||
- ansible_conf.d/10-perf.conf
|
||||
- ansible_conf.d/10-limits.conf
|
||||
- ansible_conf.d/10-ws.conf
|
||||
- ansible_conf.d/10-ssl.conf
|
||||
- ansible_conf.d/30-vhosts.conf
|
||||
notify: reload nginx
|
||||
tags: [web,conf]
|
||||
|
||||
- name: Remove naxsi configuration
|
||||
file: path=/etc/nginx/{{ item }} state=absent
|
||||
loop:
|
||||
- ansible_conf.d/naxsi.inc
|
||||
- ansible_conf.d/10-naxsi_rules.conf
|
||||
notify: reload nginx
|
||||
tags: web,conf
|
||||
|
||||
- name: Remove obsolete configuration
|
||||
file: path=/etc/nginx/{{ item }} state=absent
|
||||
with_items:
|
||||
- ansible_conf.d/filter.inc
|
||||
- ansible_conf.d/10-filter.conf
|
||||
- ansible_conf.d/headers.inc
|
||||
notify: reload nginx
|
||||
tags: [web,conf]
|
||||
|
||||
# TODO make it configurable
|
||||
- name: Create dummy white and blacklist files for nginx
|
||||
copy:
|
||||
content: "# TODO"
|
||||
dest: /etc/nginx/bots.d/{{ item }}
|
||||
with_items:
|
||||
- bad-referrer-words.conf
|
||||
- blacklist-domains.conf
|
||||
- blacklist-ips.conf
|
||||
- blacklist-user-agents.conf
|
||||
- custom-bad-referrers.conf
|
||||
- whitelist-domains.conf
|
||||
- whitelist-ips.conf
|
||||
tags: web
|
||||
|
||||
- name: Configure log rotation
|
||||
template: src=logrotate.conf.j2 dest=/etc/logrotate.d/nginx
|
||||
tags: web
|
||||
|
||||
- name: Ensure log files has correct permission
|
||||
file: path=/var/log/nginx/{{ item }} owner=nginx group=nginx state=touch
|
||||
loop:
|
||||
- error.log
|
||||
- access.log
|
||||
changed_when: False
|
||||
tags: web
|
17
roles/nginx/tasks/dir.yml
Normal file
17
roles/nginx/tasks/dir.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
- name: Create default root dir
|
||||
file: path=/var/www/html state=directory
|
||||
tags: web
|
||||
|
||||
- name: Create ansible conf directory
|
||||
file: path=/etc/nginx/{{ item }} state=directory
|
||||
with_items:
|
||||
- ansible_conf.d
|
||||
- ansible_modules.d
|
||||
- ansible_location.d
|
||||
- bots.d
|
||||
tags: web
|
||||
|
||||
- name: Create cache directory
|
||||
file: path=/var/cache/nginx state=directory mode=700 owner=nginx group=nginx
|
||||
tags: web
|
32
roles/nginx/tasks/facts.yml
Normal file
32
roles/nginx/tasks/facts.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
- name: List http ports
|
||||
set_fact: nginx_ports={{ nginx_ports + (nginx_vhosts | selectattr('port','defined') | map(attribute='port') | list) | flatten | unique }}
|
||||
tags: [firewall,web]
|
||||
|
||||
- name: List https ports
|
||||
set_fact: nginx_ssl_ports={{ nginx_ssl_ports + (nginx_vhosts | selectattr('ssl','defined') | selectattr('ssl.port','defined') | map(attribute='ssl.port') | list) | flatten | unique }}
|
||||
tags: [firewall,web]
|
||||
|
||||
- set_fact: nginx_cert_path={{ '/var/lib/dehydrated/certificates/certs/' + nginx_letsencrypt_cert + '/fullchain.pem' }}
|
||||
when: nginx_letsencrypt_cert is defined
|
||||
tags: [web,conf]
|
||||
- set_fact: nginx_key_path={{ '/var/lib/dehydrated/certificates/certs/' + nginx_letsencrypt_cert + '/privkey.pem' }}
|
||||
when: nginx_letsencrypt_cert is defined
|
||||
tags: [web,conf]
|
||||
|
||||
- name: Merge vhosts settings with defaults
|
||||
set_fact: nginx_vhosts_conf={{ nginx_vhosts_conf | default([]) + [ nginx_default_vhost | combine(item, recursive=True) ] }}
|
||||
with_items: "{{ nginx_vhosts }}"
|
||||
tags: [web,conf]
|
||||
- set_fact: nginx_vhosts={{ nginx_vhosts_conf | default([]) }}
|
||||
tags: [web,conf]
|
||||
|
||||
- name: Check if Lemonldap::NG is installed
|
||||
stat: path=/etc/lemonldap-ng/lemonldap-ng.ini
|
||||
register: nginx_llng
|
||||
tags: web
|
||||
|
||||
- name: Check if llng_header.inc conf is installed
|
||||
stat: path=/etc/nginx/ansible_conf.d/llng_headers.inc
|
||||
register: nginx_llng_headers
|
||||
tags: web
|
4
roles/nginx/tasks/filebeat.yml
Normal file
4
roles/nginx/tasks/filebeat.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
- name: Deploy filebeat module
|
||||
template: src=filebeat.yml.j2 dest=/etc/filebeat/ansible_modules.d/nginx.yml
|
||||
tags: web,log
|
15
roles/nginx/tasks/htpasswd.yml
Normal file
15
roles/nginx/tasks/htpasswd.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
- name: Create or update htpasswd files
|
||||
htpasswd:
|
||||
path: "{{ item[0].path }}"
|
||||
name: "{{ item[1].login }}"
|
||||
password: "{{ item[1].pass | default(omit) }}"
|
||||
owner: root
|
||||
group: nginx
|
||||
mode: 0640
|
||||
state: "{{ (item[1].state | default('present')) }}"
|
||||
with_subelements:
|
||||
- "{{ nginx_htpasswd }}"
|
||||
- users
|
||||
tags: web
|
||||
|
8
roles/nginx/tasks/install.yml
Normal file
8
roles/nginx/tasks/install.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
|
||||
- include: install_openresty.yml
|
||||
when: nginx_openresty
|
||||
|
||||
- include: install_nginx.yml
|
||||
when: not nginx_openresty
|
||||
|
28
roles/nginx/tasks/install_nginx.yml
Normal file
28
roles/nginx/tasks/install_nginx.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
|
||||
- name: Remove openresty
|
||||
yum:
|
||||
name:
|
||||
- openresty
|
||||
state: absent
|
||||
tags: web
|
||||
|
||||
- name: Enable 1.16 module
|
||||
shell: |
|
||||
yum -y module reset nginx
|
||||
yum -y module enable nginx:1.16
|
||||
args:
|
||||
warn: False
|
||||
changed_when: False
|
||||
when:
|
||||
- ansible_os_family == 'RedHat'
|
||||
- ansible_distribution_major_version is version('8', '>=')
|
||||
tags: web
|
||||
|
||||
- name: Install nginx
|
||||
yum:
|
||||
name:
|
||||
- nginx
|
||||
- nginx-all-modules
|
||||
tags: web
|
||||
|
69
roles/nginx/tasks/install_openresty.yml
Normal file
69
roles/nginx/tasks/install_openresty.yml
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
|
||||
- name: Check if nginx is installed
|
||||
stat: path=/lib/systemd/system/nginx.service
|
||||
register: nginx_nginx_service
|
||||
tags: web
|
||||
|
||||
- name: Stop nginx
|
||||
service: name=nginx state=stopped
|
||||
when: nginx_nginx_service.stat.exists
|
||||
tags: web
|
||||
|
||||
- name: Create the nginx user account
|
||||
user:
|
||||
name: nginx
|
||||
system: True
|
||||
shell: /sbin/nologin
|
||||
home: /var/lib/nginx
|
||||
tags: web
|
||||
|
||||
- name: Prepare directories
|
||||
file: path={{ item.dir }} state=directory owner={{ item.owner | default(omit) }} group={{ item.group | default(omit) }} mode={{ item.mode | default(omit) }}
|
||||
loop:
|
||||
- dir: /var/lib/nginx/tmp
|
||||
owner: nginx
|
||||
group: nginx
|
||||
mode: '700'
|
||||
- dir: /var/cache/nginx
|
||||
owner: nginx
|
||||
group: nginx
|
||||
mode: '700'
|
||||
- dir: /var/log/nginx
|
||||
owner: nginx
|
||||
group: nginx
|
||||
mode: '700'
|
||||
- dir: /usr/share/nginx
|
||||
- dir: /etc/nginx
|
||||
- dir: /usr/local/openresty/nginx
|
||||
tags: web
|
||||
|
||||
# Create links so openresty uses nginx compatible paths
|
||||
- name: Prepare links
|
||||
file: src={{ item.src }} dest={{ item.dest }} state=link
|
||||
loop:
|
||||
- src: /etc/nginx
|
||||
dest: /usr/local/openresty/nginx/conf
|
||||
- src: /var/log/nginx
|
||||
dest: /usr/local/openresty/nginx/logs
|
||||
- src: /usr/share/nginx
|
||||
dest: /usr/local/openresty/nginx/html
|
||||
tags: web
|
||||
|
||||
- name: Remove nginx
|
||||
yum:
|
||||
name:
|
||||
- nginx
|
||||
state: absent
|
||||
tags: web
|
||||
|
||||
- name: Install packages
|
||||
yum:
|
||||
name:
|
||||
- openresty
|
||||
tags: web
|
||||
|
||||
- name: Add a link to nginx in /sbin
|
||||
file: src=/usr/local/openresty/nginx/sbin/nginx dest=/sbin/nginx state=link
|
||||
tags: web
|
||||
|
8
roles/nginx/tasks/iptables.yml
Normal file
8
roles/nginx/tasks/iptables.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
- name: Handle HTTP and HTTPS ports
|
||||
iptables_raw:
|
||||
name: nginx_ports
|
||||
state: "{{ (nginx_src_ip | length > 0) | ternary('present','absent') }}"
|
||||
rules: "-A INPUT -m state --state NEW -p tcp -m multiport --dports {{ (nginx_ports + nginx_ssl_ports) | join(',') }} -s {{ nginx_src_ip | join(',') }} -j ACCEPT\n"
|
||||
when: iptables_manage | default(True)
|
||||
tags: [firewall,web]
|
95
roles/nginx/tasks/letsencrypt.yml
Normal file
95
roles/nginx/tasks/letsencrypt.yml
Normal file
@@ -0,0 +1,95 @@
|
||||
---
|
||||
- name: Create dehydrated hook dir
|
||||
file: path=/etc/dehydrated/hooks_deploy_cert.d/ state=directory
|
||||
tags: web
|
||||
|
||||
- name: Deploy dehydrated deploy hook
|
||||
copy: src=dehydrated_deploy_hook dest=/etc/dehydrated/hooks_deploy_cert.d/11nginx.sh mode=755
|
||||
tags: web
|
||||
|
||||
- name: Check if Let's Encrypt cert for the default vhost exists
|
||||
stat: path=/var/lib/dehydrated/certificates/certs/{{ nginx_letsencrypt_cert }}/fullchain.pem
|
||||
register: nginx_letsencrypt_default_cert
|
||||
when: nginx_letsencrypt_cert is defined
|
||||
tags: web
|
||||
|
||||
- name: Create directory for the default certificate
|
||||
file: path=/var/lib/dehydrated/certificates/certs/{{ nginx_letsencrypt_cert }}/ state=directory
|
||||
when: nginx_letsencrypt_cert is defined
|
||||
tags: web
|
||||
|
||||
- name: Link certificate to the self signed default one
|
||||
file: src=/etc/nginx/ssl/{{ item.src }}.pem dest=/var/lib/dehydrated/certificates/certs/{{ nginx_letsencrypt_cert }}/{{ item.dest }}.pem state=link
|
||||
with_items:
|
||||
- src: cert
|
||||
dest: fullchain
|
||||
- src: key
|
||||
dest: privkey
|
||||
when:
|
||||
- nginx_letsencrypt_cert is defined
|
||||
- nginx_letsencrypt_default_cert.stat is defined
|
||||
- not nginx_letsencrypt_default_cert.stat.exists
|
||||
tags: web
|
||||
|
||||
- name: Check if Let's Encrypt's cert exist
|
||||
stat: path=/var/lib/dehydrated/certificates/certs/{{ item.ssl.letsencrypt_cert }}/fullchain.pem
|
||||
register: nginx_letsencrypt_certs
|
||||
with_items: "{{ nginx_vhosts }}"
|
||||
when: item.ssl.letsencrypt_cert is defined
|
||||
tags: web
|
||||
|
||||
- name: Create directories for missing Let's Encrypt cert
|
||||
file: path=/var/lib/dehydrated/certificates/certs/{{ item.item.ssl.letsencrypt_cert }} state=directory
|
||||
with_items: "{{ nginx_letsencrypt_certs.results }}"
|
||||
when:
|
||||
- item.stat is defined
|
||||
- not item.stat.exists
|
||||
tags: web
|
||||
|
||||
- name: Link missing Let's Encrypt cert to the default one
|
||||
file: src={{ nginx_cert_path }} dest=/var/lib/dehydrated/certificates/certs/{{ item.item.ssl.letsencrypt_cert }}/fullchain.pem state=link
|
||||
with_items: "{{ nginx_letsencrypt_certs.results }}"
|
||||
when:
|
||||
- item.stat is defined
|
||||
- not item.stat.exists
|
||||
tags: web
|
||||
|
||||
- name: Link missing Let's Encrypt key to the default one
|
||||
file: src={{ nginx_key_path }} dest=/var/lib/dehydrated/certificates/certs/{{ item.item.ssl.letsencrypt_cert }}/privkey.pem state=link
|
||||
with_items: "{{ nginx_letsencrypt_certs.results }}"
|
||||
when:
|
||||
- item.stat is defined
|
||||
- not item.stat.exists
|
||||
tags: web
|
||||
|
||||
- name: Check if Let's Encrypt's cert exist (auto certificates)
|
||||
stat: path=/var/lib/dehydrated/certificates/certs/{{ item.name }}/fullchain.pem
|
||||
register: nginx_letsencrypt_certs
|
||||
with_items: "{{ nginx_vhosts }}"
|
||||
when: item.ssl.cert is not defined and item.ssl.letsencrypt_cert is not defined and nginx_auto_letsencrypt_cert
|
||||
tags: web
|
||||
|
||||
- name: Create directories for missing Let's Encrypt cert (auto certificates)
|
||||
file: path=/var/lib/dehydrated/certificates/certs/{{ item.item.name }} state=directory
|
||||
with_items: "{{ nginx_letsencrypt_certs.results }}"
|
||||
when:
|
||||
- item.stat is defined
|
||||
- not item.stat.exists
|
||||
tags: web
|
||||
|
||||
- name: Link missing Let's Encrypt cert to the default one (auto certificates)
|
||||
file: src={{ nginx_cert_path }} dest=/var/lib/dehydrated/certificates/certs/{{ item.item.name }}/fullchain.pem state=link
|
||||
with_items: "{{ nginx_letsencrypt_certs.results }}"
|
||||
when:
|
||||
- item.stat is defined
|
||||
- not item.stat.exists
|
||||
tags: web
|
||||
|
||||
- name: Link missing Let's Encrypt key to the default one (auto certificates)
|
||||
file: src={{ nginx_key_path }} dest=/var/lib/dehydrated/certificates/certs/{{ item.item.name }}/privkey.pem state=link
|
||||
with_items: "{{ nginx_letsencrypt_certs.results }}"
|
||||
when:
|
||||
- item.stat is defined
|
||||
- not item.stat.exists
|
||||
tags: web
|
||||
|
12
roles/nginx/tasks/main.yml
Normal file
12
roles/nginx/tasks/main.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- include: install.yml
|
||||
- include: facts.yml
|
||||
- include: ssl.yml
|
||||
- include: dir.yml
|
||||
- include: conf.yml
|
||||
- include: letsencrypt.yml
|
||||
- include: selinux.yml
|
||||
- include: iptables.yml
|
||||
- include: htpasswd.yml
|
||||
- include: service.yml
|
||||
- include: filebeat.yml
|
24
roles/nginx/tasks/selinux.yml
Normal file
24
roles/nginx/tasks/selinux.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
- name: Allow network connections in SELinux
|
||||
seboolean: name={{ item }} state=True persistent=True
|
||||
with_items:
|
||||
- httpd_can_network_connect
|
||||
when: ansible_selinux.status == 'enabled'
|
||||
tags: web
|
||||
|
||||
- name: Allow nginx to bind on ports
|
||||
seport: ports={{ (nginx_ports + nginx_ssl_ports ) | join(',') }} proto=tcp setype=http_port_t state=present
|
||||
when: ansible_selinux.status == 'enabled'
|
||||
tags: web
|
||||
|
||||
- name: Ensure correct context on cache
|
||||
sefcontext:
|
||||
target: '/var/cache/nginx(/.*)?'
|
||||
setype: httpd_cache_t
|
||||
register: nginx_cache_context
|
||||
tags: web
|
||||
|
||||
- name: Restore context of cache files
|
||||
command: restorecon -R /var/cache/nginx
|
||||
changed_when: nginx_cache_context.changed
|
||||
tags: web
|
42
roles/nginx/tasks/service.yml
Normal file
42
roles/nginx/tasks/service.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
|
||||
- name: Customize systemd unit
|
||||
copy:
|
||||
content: |
|
||||
[Unit]
|
||||
Description=The nginx HTTP and reverse proxy server
|
||||
After=syslog.target network-online.target remote-fs.target nss-lookup.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
PIDFile=/run/nginx.pid
|
||||
ExecStartPre={{ nginx_openresty | ternary('/usr/local/openresty/nginx/sbin/nginx','/sbin/nginx') }} -t
|
||||
ExecStartPre=/bin/rm -f /run/nginx.pid
|
||||
ExecStart={{ nginx_openresty | ternary('/usr/local/openresty/nginx/sbin/nginx','/sbin/nginx') }}
|
||||
ExecReload=/bin/kill -s HUP $MAINPID
|
||||
ExecStop=/bin/kill -s QUIT $MAINPID
|
||||
PrivateTmp=true
|
||||
Restart=on-failure
|
||||
StartLimitInterval=0
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
dest: /etc/systemd/system/nginx.service
|
||||
register: nginx_unit
|
||||
notify: restart nginx
|
||||
tags: web
|
||||
|
||||
- name: Remove obsolete unit conf
|
||||
file: path=/etc/systemd/system/nginx.service.d/ansible.conf state=absent
|
||||
tags: web
|
||||
|
||||
- name: Reload systemd
|
||||
systemd: daemon_reload=True
|
||||
when: nginx_unit.changed
|
||||
tags: web
|
||||
|
||||
- name: Start and enable the service
|
||||
service: name=nginx state=started enabled=True
|
||||
tags: web
|
14
roles/nginx/tasks/ssl.yml
Normal file
14
roles/nginx/tasks/ssl.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
- import_tasks: ../includes/create_selfsigned_cert.yml
|
||||
vars:
|
||||
- cert_path: /etc/nginx/ssl/cert.pem
|
||||
- cert_key_path: /etc/nginx/ssl/key.pem
|
||||
- cert_user: nginx
|
||||
tags: web
|
||||
|
||||
- name: Create DH param
|
||||
command: openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048
|
||||
args:
|
||||
creates: /etc/nginx/ssl/dhparam.pem
|
||||
tags: web
|
||||
|
16
roles/nginx/templates/ansible_conf.d/09-cacheable.conf.j2
Normal file
16
roles/nginx/templates/ansible_conf.d/09-cacheable.conf.j2
Normal file
@@ -0,0 +1,16 @@
|
||||
map $upstream_http_content_type $is_cacheable {
|
||||
default 0;
|
||||
~image/ 1;
|
||||
~audio/ 1;
|
||||
~video/ 1;
|
||||
text/css 1;
|
||||
application/javascript 1;
|
||||
application/x-javascript 1;
|
||||
application/pdf 1;
|
||||
application/font-sfnt 1;
|
||||
font/ttf 1;
|
||||
font/opentype 1;
|
||||
application/font-woff 1;
|
||||
application/vnd.ms-fontobject 1;
|
||||
application/vnd.ms-opentype 1;
|
||||
}
|
11
roles/nginx/templates/ansible_conf.d/10-cache.conf.j2
Normal file
11
roles/nginx/templates/ansible_conf.d/10-cache.conf.j2
Normal file
@@ -0,0 +1,11 @@
|
||||
proxy_cache_path /var/cache/nginx
|
||||
levels=1:2
|
||||
keys_zone=cache_std:5m
|
||||
max_size={{ nginx_cache_size }}
|
||||
inactive=300m
|
||||
use_temp_path=off;
|
||||
|
||||
map $is_cacheable $no_cache {
|
||||
default 1;
|
||||
1 0;
|
||||
}
|
18
roles/nginx/templates/ansible_conf.d/10-limits.conf.j2
Normal file
18
roles/nginx/templates/ansible_conf.d/10-limits.conf.j2
Normal file
@@ -0,0 +1,18 @@
|
||||
geo $limit {
|
||||
default 1;
|
||||
127.0.0.1 0;
|
||||
{% for ip in trusted_ip | default([]) %}
|
||||
{{ ip }} 0;
|
||||
{% endfor %}
|
||||
{% for ip in nginx_dos_whitelisted_ip | default([])%}
|
||||
{{ ip }} 0;
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
map $limit $limit_key {
|
||||
0 "";
|
||||
1 $binary_remote_addr;
|
||||
}
|
||||
|
||||
limit_req_zone $limit_key zone=limit_req_std:3m rate={{ nginx_req_per_sec }}r/s;
|
||||
limit_conn_zone $limit_key zone=limit_conn_std:3m;
|
@@ -0,0 +1 @@
|
||||
include /etc/nginx/naxsi_core.rules;
|
8
roles/nginx/templates/ansible_conf.d/10-perf.conf.j2
Normal file
8
roles/nginx/templates/ansible_conf.d/10-perf.conf.j2
Normal file
@@ -0,0 +1,8 @@
|
||||
map $is_cacheable $custom_expires {
|
||||
default epoch;
|
||||
1 7d;
|
||||
}
|
||||
map $is_cacheable $custom_cache_control {
|
||||
default "no-cache, no-store, private";
|
||||
1 "public, max-age=604800, must-revalidate, proxy-revalidate";
|
||||
}
|
12
roles/nginx/templates/ansible_conf.d/10-ssl.conf.j2
Normal file
12
roles/nginx/templates/ansible_conf.d/10-ssl.conf.j2
Normal file
@@ -0,0 +1,12 @@
|
||||
ssl_certificate {{ nginx_cert_path }};
|
||||
ssl_certificate_key {{ nginx_key_path }};
|
||||
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
|
||||
ssl_ciphers {{ nginx_ssl_ciphers_modern }};
|
||||
ssl_protocols {{ nginx_ssl_protocols | join(' ') }};
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 1h;
|
||||
ssl_session_tickets off;
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
ssl_trusted_certificate /etc/pki/tls/cert.pem;
|
4
roles/nginx/templates/ansible_conf.d/10-ws.conf.j2
Normal file
4
roles/nginx/templates/ansible_conf.d/10-ws.conf.j2
Normal file
@@ -0,0 +1,4 @@
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
244
roles/nginx/templates/ansible_conf.d/30-vhosts.conf.j2
Normal file
244
roles/nginx/templates/ansible_conf.d/30-vhosts.conf.j2
Normal file
@@ -0,0 +1,244 @@
|
||||
# {{ ansible_managed }}
|
||||
{% for vhost in nginx_vhosts %}
|
||||
|
||||
#####################################
|
||||
## Begin vhost for {{ vhost.name }}
|
||||
#####################################
|
||||
|
||||
{{ vhost.custom_pre }}
|
||||
|
||||
server {
|
||||
{% if vhost.port is iterable %}
|
||||
{% for port in vhost.port %}
|
||||
listen {{ port }}{% if vhost.name == '_' %} default_server{% endif %};
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
listen {{ vhost.port }}{% if vhost.name == '_' %} default_server{% endif %};
|
||||
{% endif %}
|
||||
{% if vhost.ssl.enabled %}
|
||||
{% if vhost.ssl.port is iterable %}
|
||||
{% for port in vhost.ssl.port %}
|
||||
listen {{ port }} ssl http2{% if vhost.name == '_' %} default_server{% endif %};
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
listen {{ vhost.ssl.port }} ssl http2{% if vhost.name == '_' %} default_server{% endif %};
|
||||
{% endif %}
|
||||
|
||||
{% if vhost.ssl.cert is defined and vhost.ssl.key is defined %}
|
||||
ssl_certificate {{ vhost.ssl.cert }};
|
||||
ssl_certificate_key {{ vhost.ssl.key }};
|
||||
{% elif vhost.ssl.letsencrypt_cert is defined %}
|
||||
ssl_certificate /var/lib/dehydrated/certificates/certs/{{ vhost.ssl.letsencrypt_cert }}/fullchain.pem;
|
||||
ssl_certificate_key /var/lib/dehydrated/certificates/certs/{{ vhost.ssl.letsencrypt_cert }}/privkey.pem;
|
||||
{% elif nginx_auto_letsencrypt_cert %}
|
||||
ssl_certificate /var/lib/dehydrated/certificates/certs/{{ vhost.name }}/fullchain.pem;
|
||||
ssl_certificate_key /var/lib/dehydrated/certificates/certs/{{ vhost.name }}/privkey.pem;
|
||||
{% endif %}
|
||||
|
||||
{% if vhost.ssl.compat %}
|
||||
ssl_ciphers {{ nginx_ssl_ciphers_compat }};
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
{% else %}
|
||||
ssl_ciphers {{ nginx_ssl_ciphers_modern }};
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
server_name {{ vhost.name }} {{ vhost.aliases | join(' ') }};
|
||||
|
||||
access_log /var/log/nginx/access.log {{ nginx_log_format + (vhost.auth is string and vhost.auth is search('^llng')) | ternary('_llng','') }};
|
||||
|
||||
{% if vhost.full_config is defined %}
|
||||
{{ vhost.full_config | indent(2, true) }}
|
||||
{% else %}
|
||||
|
||||
root {{ vhost.document_root }};
|
||||
|
||||
{{ vhost.custom_begin | indent(2, true) }}
|
||||
|
||||
client_max_body_size {{ vhost.max_body_size }};
|
||||
|
||||
{% if vhost.maintenance %}
|
||||
include /etc/nginx/ansible_conf.d/maintenance.inc;
|
||||
{% endif %}
|
||||
|
||||
{% if vhost.acme_http %}
|
||||
include /etc/nginx/ansible_conf.d/acme.inc;
|
||||
{% endif %}
|
||||
|
||||
# Include a custom fragment. Can be used to insert ACME challenges support during
|
||||
# dehydrated hooks for example
|
||||
include /etc/nginx/ansible_conf.d/custom.inc;
|
||||
|
||||
{% if vhost.ssl.forced and vhost.ssl.enabled %}
|
||||
include /etc/nginx/ansible_conf.d/force_ssl.inc;
|
||||
{% endif %}
|
||||
|
||||
{% if vhost.auth == 'llng' or vhost.auth == 'llng_basic' %}
|
||||
## lmauth endpoint for llng authentication
|
||||
location = /lmauth {
|
||||
internal;
|
||||
include /etc/nginx/fastcgi_params;
|
||||
fastcgi_pass unix:/var/run/llng-fastcgi-server/llng-fastcgi.sock;
|
||||
# Drop post datas
|
||||
fastcgi_pass_request_body off;
|
||||
fastcgi_param CONTENT_LENGTH "";
|
||||
# Keep original hostname
|
||||
fastcgi_param HOST $http_host;
|
||||
# Keep original request (LLNG server will received /llauth)
|
||||
fastcgi_param X_ORIGINAL_URI $request_uri;
|
||||
# Use bigger buffers (see GLPI #49915)
|
||||
fastcgi_buffers 16 32k;
|
||||
fastcgi_buffer_size 64k;
|
||||
{% if vhost.auth == 'llng_basic' %}
|
||||
# Use basic auth on this vhost
|
||||
fastcgi_param VHOSTTYPE AuthBasic;
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
if ($request_method !~ ^({{ vhost.allowed_methods | join('|') }})$ ) {
|
||||
return 405;
|
||||
}
|
||||
|
||||
location {{ vhost.location }} {
|
||||
|
||||
{{ vhost.custom_location_begin | indent(4, True) }}
|
||||
|
||||
{% if vhost.redirect_aliases and vhost.aliases | length > 0 %}
|
||||
set $redirect_alias 0;
|
||||
if ($host != '{{ vhost.name }}'){
|
||||
set $redirect_alias 1;
|
||||
}
|
||||
# Only GET and HEAD should be redirected
|
||||
if ($request_method !~ ^(GET|HEAD)$){
|
||||
set $redirect_alias 0;
|
||||
}
|
||||
if ($redirect_alias = 1){
|
||||
rewrite ^/(.*)$ http{{ vhost.ssl.enabled | ternary('s','') }}://{{ vhost.name }}{% if vhost.ssl.enabled and vhost.ssl.port | int != 443 %}:{{ vhost.ssl.port }}{% elif not vhost.ssl.enabled and vhost.port | int != 80 %}:{{ vhost.port }}{% endif %}/$1 permanent;
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if vhost.limits %}
|
||||
limit_req zone=limit_req_std burst=200 nodelay;
|
||||
limit_conn limit_conn_std 80;
|
||||
{% endif %}
|
||||
|
||||
{% if vhost.perf %}
|
||||
include /etc/nginx/ansible_conf.d/perf.inc;
|
||||
{% endif %}
|
||||
|
||||
{% for header in vhost.headers.keys() %}
|
||||
{% if vhost.headers[header] != False %}
|
||||
add_header {{ header }} "{{ vhost.headers[header] }}";
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if vhost.csp %}
|
||||
add_header Content-Security-Policy "{{ vhost.csp + (vhost.csp is search('connect-src') and vhost.proxy.websocket) | ternary('', '; connect-src \'self\' wss://' + vhost.name) }}";
|
||||
{% endif %}
|
||||
|
||||
{% if vhost.auth == 'llng' or vhost.auth == 'llng_basic' %}
|
||||
auth_request /lmauth;
|
||||
auth_request_set $lmremote_user $upstream_http_lm_remote_user;
|
||||
auth_request_set $lmlocation $upstream_http_location;
|
||||
auth_request_set $lmlocation $upstream_http_location;
|
||||
auth_request_set $cookie_value $upstream_http_set_cookie;
|
||||
{% if vhost.auth != 'llng_basic' %}
|
||||
error_page 401 $lmlocation;
|
||||
{% endif %}
|
||||
{% if nginx_llng_headers.stat.exists %}
|
||||
include /etc/nginx/ansible_conf.d/llng_headers.inc;
|
||||
{% endif %}
|
||||
fastcgi_param REMOTE_USER $lmremote_user;
|
||||
{% elif vhost.auth == 'basic' and vhost.htpasswd_file is defined %}
|
||||
auth_basic "Authentication required for {{ vhost.name }}";
|
||||
auth_basic_user_file {{ vhost.htpasswd_file }};
|
||||
{% endif %}
|
||||
|
||||
{% if vhost.proxy.backend is string %}
|
||||
|
||||
{% if vhost.proxy.cache %}
|
||||
include /etc/nginx/ansible_conf.d/cache.inc;
|
||||
{% endif %}
|
||||
|
||||
# Send info about the original request to the backend
|
||||
{% for header in vhost.proxy.headers.keys() %}
|
||||
{% if vhost.proxy.headers[header] != False %}
|
||||
proxy_set_header {{ header }} "{{ vhost.proxy.headers[header] }}";
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if vhost.proxy.websocket %}
|
||||
# Handle websocket proxying
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_http_version 1.1;
|
||||
{% endif %}
|
||||
|
||||
# Hide some headers sent by the backend
|
||||
proxy_hide_header X-Powered-By;
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
{% if vhost.perf %}
|
||||
# Cache control and expiration is managed by the proxy
|
||||
proxy_hide_header Cache-Control;
|
||||
proxy_hide_header Pragma;
|
||||
proxy_hide_header Expires;
|
||||
{% endif %}
|
||||
{% for header in vhost.headers.keys() %}
|
||||
proxy_hide_header {{ header }};
|
||||
{% endfor %}
|
||||
|
||||
# Set the timeout to read responses from the backend
|
||||
proxy_read_timeout {{ vhost.proxy.timeout }};
|
||||
|
||||
# Enable Keep Alive to the backend
|
||||
proxy_socket_keepalive on;
|
||||
|
||||
# Disable buffering large files
|
||||
proxy_max_temp_file_size 5m;
|
||||
|
||||
# Proxy requests to the backend
|
||||
proxy_pass {{ vhost.proxy.backend }};
|
||||
{% endif %}
|
||||
|
||||
{% if vhost.deny_ip | length > 0 %}
|
||||
# per vhost IP blacklist
|
||||
{% for ip in vhost.deny_ip %}
|
||||
deny {{ ip }};
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
{% if vhost.src_ip | length > 0 %}
|
||||
# per vhost IP restriction
|
||||
{% for ip in vhost.src_ip | flatten %}
|
||||
allow {{ ip }};
|
||||
{% endfor %}
|
||||
deny all;
|
||||
|
||||
{% endif %}
|
||||
{{ vhost.custom_location_end | indent(4, True) }}
|
||||
|
||||
}
|
||||
|
||||
location = /RequestDenied {
|
||||
return 403;
|
||||
}
|
||||
|
||||
{% if vhost.location != '/' %}
|
||||
location / {
|
||||
return 403;
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{{ vhost.custom_end | indent(2, true) }}
|
||||
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
#####################################
|
||||
## End vhost for {{ vhost.name }}
|
||||
#####################################
|
||||
|
||||
{% endfor %}
|
8
roles/nginx/templates/ansible_conf.d/acme.inc.j2
Normal file
8
roles/nginx/templates/ansible_conf.d/acme.inc.j2
Normal file
@@ -0,0 +1,8 @@
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
default_type "text/plain";
|
||||
alias /var/lib/dehydrated/challenges/;
|
||||
allow all;
|
||||
}
|
||||
location = /.well-known/acme-challenge/ {
|
||||
return 404;
|
||||
}
|
9
roles/nginx/templates/ansible_conf.d/cache.inc.j2
Normal file
9
roles/nginx/templates/ansible_conf.d/cache.inc.j2
Normal file
@@ -0,0 +1,9 @@
|
||||
proxy_cache_convert_head off;
|
||||
proxy_cache_methods GET HEAD;
|
||||
proxy_cache_key $scheme$request_method$proxy_host$request_uri;
|
||||
proxy_cache cache_std;
|
||||
proxy_cache_valid 200 120m;
|
||||
proxy_cache_valid 404 500 502 503 504 20s;
|
||||
proxy_no_cache $no_cache;
|
||||
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
|
||||
add_header X-Proxy-Cache $upstream_cache_status;
|
1
roles/nginx/templates/ansible_conf.d/custom.inc.j2
Normal file
1
roles/nginx/templates/ansible_conf.d/custom.inc.j2
Normal file
@@ -0,0 +1 @@
|
||||
# {{ ansible_managed }}
|
15
roles/nginx/templates/ansible_conf.d/force_ssl.inc.j2
Normal file
15
roles/nginx/templates/ansible_conf.d/force_ssl.inc.j2
Normal file
@@ -0,0 +1,15 @@
|
||||
set $ssl 1;
|
||||
if ($scheme = 'https') {
|
||||
set $ssl 0;
|
||||
}
|
||||
if ($remote_addr = '127.0.0.1'){
|
||||
set $ssl 0;
|
||||
}
|
||||
{% for ip in ansible_all_ipv4_addresses %}
|
||||
if ($remote_addr = '{{ ip }}'){
|
||||
set $ssl 0;
|
||||
}
|
||||
{% endfor %}
|
||||
if ($ssl = 1){
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
4
roles/nginx/templates/ansible_conf.d/headers.inc.j2
Normal file
4
roles/nginx/templates/ansible_conf.d/headers.inc.j2
Normal file
@@ -0,0 +1,4 @@
|
||||
add_header X-Frame-Options SAMEORIGIN;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Strict-Transport-Security $hsts_header;
|
9
roles/nginx/templates/ansible_conf.d/maintenance.inc.j2
Normal file
9
roles/nginx/templates/ansible_conf.d/maintenance.inc.j2
Normal file
@@ -0,0 +1,9 @@
|
||||
set $maintenance 1;
|
||||
{% for ip in nginx_maintenance_ip %}
|
||||
if ($remote_addr ~ "^{{ ip | replace('.','\.') }}") {
|
||||
set $maintenance 0;
|
||||
}
|
||||
{% endfor %}
|
||||
if ($maintenance = 1) {
|
||||
rewrite (.*) https://downtime.{{ nginx_primary_domain | default(ansible_domain) }}/ redirect;
|
||||
}
|
9
roles/nginx/templates/ansible_conf.d/naxsi.inc.j2
Normal file
9
roles/nginx/templates/ansible_conf.d/naxsi.inc.j2
Normal file
@@ -0,0 +1,9 @@
|
||||
SecRulesEnabled;
|
||||
DeniedUrl "/RequestDenied";
|
||||
CheckRule "$SQL >= 8" BLOCK;
|
||||
CheckRule "$RFI >= 8" BLOCK;
|
||||
CheckRule "$TRAVERSAL >= 4" BLOCK;
|
||||
CheckRule "$EVADE >= 4" BLOCK;
|
||||
CheckRule "$XSS >= 8" BLOCK;
|
||||
# This rule blocks unkown Content-Type which is just too common
|
||||
BasicRule wl:11 "mz:BODY";
|
18
roles/nginx/templates/ansible_conf.d/perf.inc.j2
Normal file
18
roles/nginx/templates/ansible_conf.d/perf.inc.j2
Normal file
@@ -0,0 +1,18 @@
|
||||
gzip on;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/json
|
||||
image/svg+xml
|
||||
application/xml
|
||||
application/json
|
||||
application/xhtml+xml
|
||||
application/rss+xml
|
||||
application/atom_xml
|
||||
application/x-javascript
|
||||
application/javascript;
|
||||
gzip_vary on;
|
||||
gzip_disable "msie6";
|
||||
expires $custom_expires;
|
||||
add_header Cache-Control $custom_cache_control;
|
@@ -0,0 +1,6 @@
|
||||
location /nginx-status {
|
||||
stub_status on;
|
||||
access_log off;
|
||||
allow 127.0.0.1;
|
||||
deny all;
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
{% for module in nginx_modules %}
|
||||
load_module "/usr/lib64/nginx/modules/{{ (module is search('\.so$')) | ternary(module,'ngx_' + module + '_module.so') }}";
|
||||
{% endfor %}
|
10
roles/nginx/templates/filebeat.yml.j2
Normal file
10
roles/nginx/templates/filebeat.yml.j2
Normal file
@@ -0,0 +1,10 @@
|
||||
- module: nginx
|
||||
access:
|
||||
enabled: True
|
||||
input:
|
||||
exclude_files: [ '\.[gx]z$' ]
|
||||
|
||||
error:
|
||||
enabled: True
|
||||
input:
|
||||
exclude_files: [ '\.[gx]z$' ]
|
12
roles/nginx/templates/logrotate.conf.j2
Normal file
12
roles/nginx/templates/logrotate.conf.j2
Normal file
@@ -0,0 +1,12 @@
|
||||
/var/log/nginx/*log {
|
||||
create 0644 nginx nginx
|
||||
daily
|
||||
rotate 60
|
||||
missingok
|
||||
notifempty
|
||||
compress
|
||||
sharedscripts
|
||||
postrotate
|
||||
/bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
|
||||
endscript
|
||||
}
|
98
roles/nginx/templates/mime.types.j2
Normal file
98
roles/nginx/templates/mime.types.j2
Normal file
@@ -0,0 +1,98 @@
|
||||
types {
|
||||
text/html html htm shtml;
|
||||
text/css css;
|
||||
text/xml xml;
|
||||
image/gif gif;
|
||||
image/jpeg jpeg jpg;
|
||||
application/javascript js;
|
||||
application/atom+xml atom;
|
||||
application/rss+xml rss;
|
||||
|
||||
text/mathml mml;
|
||||
text/plain txt;
|
||||
text/vnd.sun.j2me.app-descriptor jad;
|
||||
text/vnd.wap.wml wml;
|
||||
text/x-component htc;
|
||||
|
||||
image/png png;
|
||||
image/svg+xml svg svgz;
|
||||
image/tiff tif tiff;
|
||||
image/vnd.wap.wbmp wbmp;
|
||||
image/webp webp;
|
||||
image/x-icon ico;
|
||||
image/x-jng jng;
|
||||
image/x-ms-bmp bmp;
|
||||
|
||||
font/woff woff;
|
||||
font/woff2 woff2;
|
||||
|
||||
application/java-archive jar war ear;
|
||||
application/json json;
|
||||
application/mac-binhex40 hqx;
|
||||
application/msword doc;
|
||||
application/pdf pdf;
|
||||
application/postscript ps eps ai;
|
||||
application/rtf rtf;
|
||||
application/vnd.apple.mpegurl m3u8;
|
||||
application/vnd.google-earth.kml+xml kml;
|
||||
application/vnd.google-earth.kmz kmz;
|
||||
application/vnd.ms-excel xls;
|
||||
application/vnd.ms-fontobject eot;
|
||||
application/vnd.ms-powerpoint ppt;
|
||||
application/vnd.oasis.opendocument.graphics odg;
|
||||
application/vnd.oasis.opendocument.presentation odp;
|
||||
application/vnd.oasis.opendocument.spreadsheet ods;
|
||||
application/vnd.oasis.opendocument.text odt;
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||
pptx;
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
xlsx;
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
docx;
|
||||
application/vnd.wap.wmlc wmlc;
|
||||
application/x-7z-compressed 7z;
|
||||
application/x-cocoa cco;
|
||||
application/x-java-archive-diff jardiff;
|
||||
application/x-java-jnlp-file jnlp;
|
||||
application/x-makeself run;
|
||||
application/x-perl pl pm;
|
||||
application/x-pilot prc pdb;
|
||||
application/x-rar-compressed rar;
|
||||
application/x-redhat-package-manager rpm;
|
||||
application/x-sea sea;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-stuffit sit;
|
||||
application/x-tcl tcl tk;
|
||||
application/x-x509-ca-cert der pem crt;
|
||||
application/x-xpinstall xpi;
|
||||
application/xhtml+xml xhtml;
|
||||
application/xspf+xml xspf;
|
||||
application/zip zip;
|
||||
|
||||
application/octet-stream bin exe dll;
|
||||
application/octet-stream deb;
|
||||
application/octet-stream dmg;
|
||||
application/octet-stream iso img;
|
||||
application/octet-stream msi msp msm;
|
||||
|
||||
audio/midi mid midi kar;
|
||||
audio/mpeg mp3;
|
||||
audio/ogg ogg;
|
||||
audio/x-m4a m4a;
|
||||
audio/x-realaudio ra;
|
||||
|
||||
video/3gpp 3gpp 3gp;
|
||||
video/mp2t ts;
|
||||
video/mp4 mp4;
|
||||
video/mpeg mpeg mpg;
|
||||
video/quicktime mov;
|
||||
video/webm webm;
|
||||
video/x-flv flv;
|
||||
video/x-m4v m4v;
|
||||
video/x-mng mng;
|
||||
video/x-ms-asf asx asf;
|
||||
video/x-ms-wmv wmv;
|
||||
video/x-msvideo avi;
|
||||
|
||||
application/wasm wasm;
|
||||
}
|
105
roles/nginx/templates/nginx.conf.j2
Normal file
105
roles/nginx/templates/nginx.conf.j2
Normal file
@@ -0,0 +1,105 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log;
|
||||
pid /run/nginx.pid;
|
||||
|
||||
{% if nginx_openresty %}
|
||||
# Openresty uses builtin modules, not dynamic ones
|
||||
{% else %}
|
||||
include /etc/nginx/ansible_modules.d/*.conf;
|
||||
{% endif %}
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
|
||||
{% if nginx_openresty %}
|
||||
# Set nginx compatible paths for openresty
|
||||
client_body_temp_path /var/lib/nginx/tmp/client_body;
|
||||
fastcgi_temp_path /var/lib/nginx/tmp/fastcgi;
|
||||
proxy_temp_path /var/lib/nginx/tmp/proxy;
|
||||
scgi_temp_path /var/lib/nginx/tmp/scgi;
|
||||
uwsgi_temp_path /var/lib/nginx/tmp/uwsgi;
|
||||
{% endif %}
|
||||
|
||||
log_format combined_virtual
|
||||
'$server_name $remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" scheme="$scheme"';
|
||||
|
||||
log_format combined_virtual_backend
|
||||
'$server_name $http_x_forwarded_for - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" scheme="$scheme"';
|
||||
|
||||
{% if nginx_llng.stat.exists %}
|
||||
log_format combined_virtual_llng
|
||||
'$server_name $remote_addr - $lmremote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" scheme="$scheme"';
|
||||
|
||||
log_format combined_virtual_backend_llng
|
||||
'$server_name $http_x_forwarded_for - $lmremote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" scheme="$scheme"';
|
||||
{% else %}
|
||||
# LL::NG not installed, just make those log formats aliases of the non llng formats
|
||||
log_format combined_virtual_llng
|
||||
'$server_name $remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" scheme="$scheme"';
|
||||
|
||||
log_format combined_virtual_backend_llng
|
||||
'$server_name $http_x_forwarded_for - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" scheme="$scheme"';
|
||||
{% endif %}
|
||||
|
||||
access_log /var/log/nginx/access.log {{ nginx_log_format }};
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
client_max_body_size 10m;
|
||||
|
||||
server_tokens off;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
include /etc/nginx/ansible_conf.d/*.conf;
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https 'max-age=31536000';
|
||||
}
|
||||
|
||||
{% if '_' not in nginx_vhosts | map(attribute='name') | list %}
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen 443 default_server ssl http2;
|
||||
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
# Load location fragments in the default vhost
|
||||
include /etc/nginx/ansible_location.d/*.conf;
|
||||
|
||||
add_header X-Frame-Options SAMEORIGIN;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Strict-Transport-Security $hsts_header;
|
||||
|
||||
include /etc/nginx/ansible_conf.d/acme.inc;
|
||||
|
||||
location / {
|
||||
}
|
||||
|
||||
location ~ \.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
Reference in New Issue
Block a user