Browse Source

Migration commit; fresh start

selfsigned
muppeth 2 months ago
parent
commit
2841af5dae
Signed by: muppeth GPG Key ID: 0EBC7B9848D04031
  1. 2
      LICENSE
  2. 48
      README.MD
  3. 65
      defaults/main.yml
  4. 11
      handlers/main.yml
  5. 15
      tasks/config.yml
  6. 8
      tasks/install.yml
  7. 13
      tasks/main.yml
  8. 50
      tasks/ssl.yml
  9. 46
      tasks/vhost.yml
  10. 12
      templates/etc/nginx/conf.d/ssl.conf.j2
  11. 55
      templates/etc/nginx/nginx.conf.j2
  12. 45
      templates/etc/nginx/sites-available/base.j2
  13. 42
      templates/etc/nginx/sites-available/conversejs.j2
  14. 222
      templates/etc/nginx/sites-available/core.j2
  15. 179
      templates/etc/nginx/sites-available/cryptpad.j2
  16. 16
      templates/etc/nginx/sites-available/expired.j2
  17. 51
      templates/etc/nginx/sites-available/framadate.j2
  18. 47
      templates/etc/nginx/sites-available/grav.j2
  19. 65
      templates/etc/nginx/sites-available/hubzilla.j2
  20. 14
      templates/etc/nginx/sites-available/letsencrypt.j2
  21. 33
      templates/etc/nginx/sites-available/lufi.j2
  22. 6
      templates/etc/nginx/sites-available/maintenance.j2
  23. 21
      templates/etc/nginx/sites-available/mumble-web.j2
  24. 137
      templates/etc/nginx/sites-available/nextcloud.j2
  25. 55
      templates/etc/nginx/sites-available/privatebin.j2
  26. 133
      templates/etc/nginx/sites-available/proxy.j2
  27. 33
      templates/etc/nginx/sites-available/pwm.j2
  28. 40
      templates/etc/nginx/sites-available/roundcube.j2
  29. 20
      templates/etc/nginx/sites-available/searx.j2
  30. 35
      templates/etc/nginx/sites-available/taiga.j2
  31. 48
      templates/etc/nginx/sites-available/ttrss.j2
  32. 34
      templates/etc/nginx/sites-available/wp.j2
  33. 73
      templates/etc/nginx/sites-available/wpfarm.j2
  34. 10
      templates/etc/nginx/sites-available/zabbix_check.j2

2
LICENSE

@ -1,4 +1,4 @@
MIT License Copyright (c) <year> <copyright holders>
MIT License Copyright (c) 2021 "Stichting Disroot.org"
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

48
README.MD

@ -0,0 +1,48 @@
# Nginx role
This role, installs nginx webserver and manages all vhosts. The role is released under MIT Licence and we give no warranty for this piece of software. Currently supported OS - Debian.
Apart from installing and configuring nginx, you can also make use of bundeled vhost templates for many FLOSS services which helps out setup your server. Check `templates/etc/nginx/sites-available` for more details.
Multiple Vhosts can be deployed and make use of templates. By default role does not deploy any Vhost.
Example vhosts:
```
nginx_vhosts:
- name: 'devchat'
template: 'conversejs'
proto: 'http'
listen: '80'
root: 'conversejs'
index: 'index.php'
use_access_log: 'true'
use_error_log: 'true'
nginx_error_log_level: 'warn'
http_upload_url: 'https://example.org'
bosh_url: 'https://example.org'
headers: 'none'
state: 'enable'
letsencrypt: 'false'
- name: 'framadate'
template: 'framadate'
proto: 'http'
listen: '80'
root: 'framadate/{{ framadate_version }}/framadate'
index: 'index.php'
use_access_log: 'true'
use_error_log: 'true'
nginx_error_log_level: 'warn'
upstream_params:
- 'fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;'
- 'fastcgi_index index.php;'
- 'include /etc/nginx/fastcgi_params;'
- 'fastcgi_pass unix:{{ pool_listen }};'
state: 'enable'
letsencrypt: 'false'
```
## Changelog
- **04.03.2021** - Modyfied header info for proxy (locations), and core templates
- **26.01.2021** - Rewritten templates structure
- **02.12.2020** - conversejs template
- **14.12.2019** - Start changelog
- **14.12.2019** - Updated hubzilla,privatebin, framadate template

65
defaults/main.yml

@ -0,0 +1,65 @@
---
nginx_ssl_dir: '/etc/letsencrypt/live'
#nginx_ssl_dir: '/mnt'
nginx_etc_dir: '/etc/nginx'
nginx_user: 'www-data'
nginx_worker_processes: '4'
nginx_pid: '/run/nginx.pid'
nginx_events_worker_connections: '10000'
nginx_events_multi_accept: 'on'
nginx_root: "/srv/www"
nginx_log_dir: '/var/log/nginx'
nginx_events_use: 'epoll'
nginx_www_dir: '/var/www/'
nginx_HSTS_policy: 'false'
nginx_http_types_hash_max_size: 4096
nginx_http_default_type: 'application/octet-stream'
nginx_http_access_log: 'off'
nginx_http_error_log: 'off'
nginx_http_client_body_buffer_size: '1M'
nginx_http_client_header_buffer_size: '1M'
nginx_http_client_max_body_size: '10M'
nginx_http_large_client_header_buffers: '8 8k'
nginx_http_client_body_timeout: '60'
nginx_http_client_header_timeout: '60'
nginx_http_keepalive_timeout: '30 30'
nginx_http_send_timeout: '120'
nginx_http_ignore_invalid_headers: 'on'
nginx_http_keepalive_requests: '100'
nginx_http_recursive_error_pages: 'on'
nginx_http_sendfile: 'on'
nginx_http_server_name_in_redirect: 'off'
nginx_http_server_tokens: 'off'
nginx_http_tcp_nodelay: 'on'
nginx_http_tcp_nopush: 'on'
nginx_http_reset_timedout_connection: 'on'
nginx_proxy_buffers: '16 16k'
nginx_proxy_buffer_size: '16k'
nginx_http_gzip: 'on'
nginx_http_gzip_buffers: '16 8k'
nginx_http_gzip_comp_level: '9'
nginx_http_gzip_http_version: '1.0'
nginx_http_gzip_min_length: '0'
nginx_http_gzip_types: 'text/plain text/css application/json application/x-javascript application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml'
nginx_http_gzip_vary: 'on'
nginx_http_gzip_disable: '"msie6"'
nginx_gen_dh: 'false'
nginx_dh_path: '{{ nginx_ssl_dir }}/dhparam.pem'
nginx_dh_length: 4096
nginx_ssl_protocols: 'TLSv1.2'
nginx_ssl_ciphers: 'EECDH+AESGCM:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305'
nginx_ssl_ecdh_curve: 'secp384r1'
letsencrypt_webroot_path: ''
install_letsencrypt: 'false'
letsencrypt_domains:
- name: ''
letsencrypt_copy_certs: 'false'
letsencrypt_copy_cert_from:
- name: ''
letsencrypt_dest: ''

11
handlers/main.yml

@ -0,0 +1,11 @@
---
# Check nginx config and if ok, reload
- name: reload nginx
command: nginx -t
notify: real-reload nginx
- name: real-reload nginx
systemd:
name: nginx
state: reloaded

15
tasks/config.yml

@ -0,0 +1,15 @@
---
- name: "[NGINX] - Deploy nginx.conf"
template:
src: etc/nginx/nginx.conf.j2
dest: "{{ nginx_etc_dir }}/nginx.conf"
notify:
- reload nginx
- name: "[NGINX] - Deploy ssl.conf"
template:
src: etc/nginx/conf.d/ssl.conf.j2
dest: "{{ nginx_etc_dir }}/conf.d/ssl.conf"
notify:
- reload nginx

8
tasks/install.yml

@ -0,0 +1,8 @@
---
- name: '[APT] - Install nginx and dependencies'
apt:
name: nginx
state: latest
update_cache: yes
cache_valid_time: 3600

13
tasks/main.yml

@ -0,0 +1,13 @@
---
- name: "[NGINX] - Install packages"
include: install.yml
- name: "[NGINX] - Configure nginx"
include: config.yml
- name: "[NGINX] - Set SSL configuration"
include: ssl.yml
- name: "[NGINX] - Create Vhosts configuration"
include: vhost.yml

50
tasks/ssl.yml

@ -0,0 +1,50 @@
---
- name: "[NGINX] - Create local ssl Directory"
file:
path: "{{ nginx_ssl_dir }}"
state: directory
mode: 0755
- name: "[NGINX] - Generate DH file"
command: openssl dhparam -out {{ nginx_dh_path }} {{ nginx_dh_length }}
args:
creates: "{{ nginx_dh_path }}"
when: nginx_gen_dh == 'true'
notify:
- reload nginx
- name: "[NGINX] - Deploy DH file from vars"
copy:
content: "{{ nginx_dh }}"
dest: "{{ nginx_dh_path }}"
when: nginx_dh is defined
notify:
- reload nginx
- name: "[NGINX] - Create SSL keys subfolder"
file:
path: "{{ nginx_ssl_dir }}/{{ item.ssl_name }}"
state: directory
mode: 0755
with_items: "{{ nginx_vhosts }}"
when: item.copy_ssl is defined
notify: reload nginx
- name: "[NGINX] - Deploy SSL keys"
copy:
src: "{{ ssl_src_path }}/{{ item.ssl_name }}/privkey.pem"
dest: "{{ nginx_ssl_dir}}/{{ item.ssl_name }}/privkey.pem"
mode: 0700
with_items: "{{ nginx_vhosts }}"
when: item.copy_ssl is defined
notify: reload nginx
- name: "[NGINX] - Deploy SSL certs"
copy:
src: "{{ ssl_src_path }}/{{ item.ssl_name }}/fullchain.pem"
dest: "{{ nginx_ssl_dir}}/{{ item.ssl_name }}/fullchain.pem"
mode: 0644
with_items: "{{ nginx_vhosts }}"
when: item.copy_ssl is defined
notify: reload nginx

46
tasks/vhost.yml

@ -0,0 +1,46 @@
---
- name: "[NGINX] - Create vhosts"
template:
src: etc/nginx/sites-available/{{ item.template }}.j2
dest: "{{ nginx_etc_dir }}/sites-available/{{ item.name }}"
with_items: "{{ nginx_vhosts }}"
notify:
- reload nginx
when: item.state is defined and item.state != 'delete'
- name: "[NGINX] - Delete vhosts"
file:
path: "{{ nginx_etc_dir }}/sites-available/{{ item.name }}"
state: absent
with_items: "{{ nginx_vhosts }}"
notify:
- reload nginx
when: item.state is defined and item.state == 'delete'
- name: "[NGINX] - Enable vhosts"
file:
src: "{{ nginx_etc_dir }}/sites-available/{{ item.name }}"
dest: "{{ nginx_etc_dir }}/sites-enabled/{{ item.name }}"
state: link
with_items: "{{ nginx_vhosts }}"
notify:
- reload nginx
when: item.state is defined and item.state == 'enable'
- name: "[NGINX] - Disable vhosts"
file:
path: "{{ nginx_etc_dir}}/sites-enabled/{{ item.name }}"
state: absent
with_items: "{{ nginx_vhosts }}"
notify:
- reload nginx
when: item.state is defined and (item.state == 'disable' or item.state == 'delete')
- name: "[NGINX] - Delete default vhost when explicitely defined"
file:
path: "{{ nginx_etc_dir }}/sites-enabled/default"
state: absent
notify:
- reload nginx
when: nginx_default_vhost is not none

12
templates/etc/nginx/conf.d/ssl.conf.j2

@ -0,0 +1,12 @@
####
# {{ ansible_managed }}
####
ssl_ciphers '{{ nginx_ssl_ciphers }}';
ssl_ecdh_curve {{ nginx_ssl_ecdh_curve }};
ssl_protocols {{ nginx_ssl_protocols }};
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_dhparam {{ nginx_dh_path }};

55
templates/etc/nginx/nginx.conf.j2

@ -0,0 +1,55 @@
####
# {{ ansible_managed }}
####
user {{ nginx_user }};
worker_processes {{ nginx_worker_processes }};
pid {{ nginx_pid }};
{% if nginx_worker_rlimit_nofile is defined %}
worker_rlimit_nofile {{ nginx_worker_rlimit_nofile }};
{% endif %}
events {
worker_connections {{ nginx_events_worker_connections }};
multi_accept {{ nginx_events_multi_accept }};
use {{ nginx_events_use }};
}
http {
types_hash_max_size {{ nginx_http_types_hash_max_size }};
include {{ nginx_etc_dir }}/mime.types;
default_type {{ nginx_http_default_type }};
access_log {{ nginx_http_access_log }};
error_log {{ nginx_http_error_log }};
client_body_buffer_size {{ nginx_http_client_body_buffer_size }};
client_header_buffer_size {{ nginx_http_client_header_buffer_size }};
client_max_body_size {{ nginx_http_client_max_body_size }};
large_client_header_buffers {{ nginx_http_large_client_header_buffers }};
client_body_timeout {{ nginx_http_client_body_timeout }};
client_header_timeout {{ nginx_http_client_header_timeout }};
keepalive_timeout {{ nginx_http_keepalive_timeout }};
send_timeout {{ nginx_http_send_timeout }};
ignore_invalid_headers {{ nginx_http_ignore_invalid_headers }};
keepalive_requests {{ nginx_http_keepalive_requests }};
recursive_error_pages {{ nginx_http_recursive_error_pages }};
sendfile {{ nginx_http_sendfile }};
server_name_in_redirect {{ nginx_http_server_name_in_redirect }};
server_tokens {{ nginx_http_server_tokens }};
tcp_nodelay {{ nginx_http_tcp_nodelay }};
tcp_nopush {{ nginx_http_tcp_nopush }};
reset_timedout_connection {{ nginx_http_reset_timedout_connection }};
proxy_buffers {{ nginx_proxy_buffers }};
proxy_buffer_size {{ nginx_proxy_buffer_size }};
gzip {{ nginx_http_gzip }};
gzip_buffers {{ nginx_http_gzip_buffers }};
gzip_comp_level {{ nginx_http_gzip_comp_level }};
gzip_http_version {{ nginx_http_gzip_http_version }};
gzip_min_length {{ nginx_http_gzip_min_length }};
gzip_types {{ nginx_http_gzip_types }};
gzip_vary {{ nginx_http_gzip_vary }};
gzip_disable {{ nginx_http_gzip_disable }};
include {{ nginx_etc_dir }}/conf.d/*.conf;
include {{ nginx_etc_dir }}/sites-enabled/*;
}

45
templates/etc/nginx/sites-available/base.j2

@ -0,0 +1,45 @@
{% extends "core.j2" %}
{% block root %}
root {{ nginx_www_dir }}{{ item.root }};
index {{ item.index }};
{% endblock %}
{% block location %}
location / {
try_files {{ item.override_try_files | default('$uri $uri/ =404') }};
{% endblock %}
{% block app_root_location %}
{% endblock %}
}
{% block extra_locations %}
{% endblock %}
{% block custom_locations %}
{% endblock %}
{% block local_content %}
{% if item.manage_local_content is not defined %}
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
deny all;
}
{% if item.favicon is defined %}
location /favicon.ico {
alias {{ item.favicon }};
expires 30d;
access_log off;
log_not_found off;
}
{% endif %}
location ~* \.(txt|js|css|png|jpe?g|gif|ico|svg)$ {
expires 30d;
log_not_found off;
}
{% endif %}
{% endblock %}

42
templates/etc/nginx/sites-available/conversejs.j2

@ -0,0 +1,42 @@
{% extends "core.j2" %}
{% block location %}
## LOCATIONS
location / {
root {{ conversejs_app_dir }};
index {{ conversejs_mode }}.html;
}
location ~ /\. {
deny all;
}
{% if item.bosh_url is defined %}
location ^/http-bind {
proxy_pass {{ item.bosh_url }};
}
{% endif %}
location ^/upload {
proxy_pass {{ item.http_upload_url }};
}
{% if item.websocket is defined %}
location ^/xmpp-websocket {
proxy_pass {{ item.websocket_url }};
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
#proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
}
{% endif %}
include mime.types;
location ~ .(ttf|ttc|otf|eot|woff|woff2|font.css|css|js)$ {
add_header Access-Control-Allow-Origin "*"; # Decide here whether you want to allow all or only a particular domain
root {{ conversejs_app_dir }}; # Properly set the path here
}
{% endblock %}

222
templates/etc/nginx/sites-available/core.j2

@ -0,0 +1,222 @@
####
# {{ ansible_managed }}
####
{% block extra_upstreams %}
{% endblock %}
{% block server_info %}
## SERVER INFO
server {
server_name {% if item.name is string %}{{ item.name }}{% else %}{{ item.name | join(' ') }}{% endif %};
{% if item.proto == 'http' %}
listen {{ item.listen }} {% if nginx_default_vhost == item.name %} default_server{% endif %};
{% endif %}
{% if item.proto == 'https' %}
listen {{ item.listen }} ssl {% if item.http2 is defined %}http2{% endif %};
ssl_certificate {{ nginx_ssl_dir + '/' + item.ssl_name + '/' + 'fullchain.pem' + ';' }}
ssl_certificate_key {{ nginx_ssl_dir + '/' + item.ssl_name + '/' + 'privkey.pem;' }}
{% endif %}
server_tokens off;
{% if item.max_upload is defined %}
client_max_body_size {{ item.max_upload }};
{% if item.htpasswd is defined %}
{{ htpasswd(item.htpasswd, 1) }}
{% endif %}
{% endif %}
{% endblock %}
{% block root %}
{% endblock %}
{% block logs %}
## LOGS
{% if item.use_access_log is defined and item.use_access_log == 'true' %}
access_log {{ nginx_log_dir }}/{{ item.name }}_access.log combined;
{% else %}
access_log off;
{% endif %}
{% if item.use_error_log is defined and item.use_error_log == 'true' %}
error_log {{ nginx_log_dir }}/{{ item.name }}_error.log {{ item.nginx_error_log_level }};
{% else %}
error_log off;
{% endif %}
{% endblock %}
{% block headers %}
{% if item.headers is defined and item.headers == 'none' %}
{% else %}
## HEADERS
{% if item.secure_site is defined %}
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy {{ item.referrer | default('no-referrer') }};
{% if item.header_sameorigin is defined %}
add_header X-Frame-Options "SAMEORIGIN";
{% endif %}
{% endif %}
{% if item.nginx_HSTS_policy is defined %}
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
{% endif %}
{% if item.referrer is defined %}
add_header Referrer-Policy no-referrer;
{% endif %}
{% if item.csp is defined %}
add_header Content-Security-Policy "{{ item.csp }}";
{% endif %}
{% if item.cto is defined %}
{% if item.cto == 'none' %}
{% else %}
add_header X-Content-Type-Options {{ item.cto }};
{% endif %}
{% else %}
add_header X-Content-Type-Options nosniff;
{% endif %}
{%if item.xss is defined %}
{% if item.xss == 'none' %}
{% else %}
add_header X-XSS-Protection "{{ item.xss }}";
{% endif %}
{% else %}
add_header X-XSS-Protection "1; mode=block";
{% endif %}
{% if item.robots is defined %}
add_header X-Robots-Tag "{{ item.robots }}";
{% else %}
add_header X-Robots-Tag none;
{% endif %}
{% endif %}
{% endblock %}
{% block location %}
{% endblock %}
{% block extra_locations %}
{% endblock %}
{% block custom_locations %}
{% if item.custom_locations is defined %}
## CUSTOM LOCATIONS
{% for location in item.custom_locations %}
location {{ location.name }} {
{% for item in location.options %}
{{ item }}
{% endfor %}
{% if location.headers is defined %}
{% for item in location.headers %}
{% if item.secure_site is defined %}
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy {{ item.referrer | default('no-referrer') }};
{% if item.header_sameorigin is defined %}
add_header X-Frame-Options "SAMEORIGIN";
{% endif %}
{% endif %}
{% if item.nginx_HSTS_policy is defined %}
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
{% endif %}
{% if item.referrer is defined %}
add_header Referrer-Policy no-referrer;
{% endif %}
{% if item.csp is defined %}
add_header Content-Security-Policy "{{ item.csp }}";
{% endif %}
{% if item.cto is defined %}
{% if item.cto == 'none' %}
{% else %}
add_header X-Content-Type-Options {{ item.cto }};
{% endif %}
{% else %}
add_header X-Content-Type-Options nosniff;
{% endif %}
{%if item.xss is defined %}
{% if item.xss == 'none' %}
{% else %}
add_header X-XSS-Protection "{{ item.xss }}";
{% endif %}
{% else %}
add_header X-XSS-Protection "1; mode=block";
{% endif %}
{% if item.robots is defined %}
add_header X-Robots-Tag {{ item.robots }};
{% else %}
add_header X-Robots-Tag none;
{% endif %}
{% endfor %}
{% endif %}
}
{% endfor %}
{% endif %}
{% endblock %}
{% block local_content %}
{% endblock %}
{% block app_specific %}
{% endblock %}
{% if item.letsencrypt == 'true' %}
location ^~ /.well-known/acme-challenge {
root {{ letsencrypt_webroot_path }};
try_files $uri =404;
}
{% endif %}
{% block extras %}
{% if item.more is defined and item.more is iterable %}
{% for line in item.more %}
{{ line }}
{% endfor %}
{% endif %}
{% endblock %}
}
{% block redirects %}
{% if item.www is defined %}
server {
listen 80;
server_name www.{{ item.name }};
return 301 https://{{ item.name }}$request_uri;
}
{% endif %}
{% if item.redirect_https is defined and item.redirect_https %}
## REDIRECTS
### http to https
server {
listen 80;
server_name {% if item.name is string %}{{ item.name }}{% else %}{{ item.name | join(' ') }}{% endif %};
return 301 https://{{ item.name }}$request_uri;
{% if item.letsencrypt == 'true' %}
location /.well-known/acme-challenge {
root {{ letsencrypt_webroot_path }};
try_files $uri =404;
}
{% endif %}
}
{% if item.www is defined %}
### www to fwdn
server {
listen 443 ssl;
ssl_certificate {{ nginx_ssl_dir + '/www.' + item.ssl_name + '/' + 'fullchain.pem' + ';' }}
ssl_certificate_key {{ nginx_ssl_dir + '/www.' + item.ssl_name + '/' + 'privkey.pem;' }}
server_name www.{% if item.name is string %}{{ item.name }}{% else %}{{ item.name | join(' ') }}{% endif %};
return 301 https://{{ item.name }}{% if '443' not in item.listen %}:item.listen[0]{% endif %}$request_uri;
{% if item.letsencrypt == 'true' %}
location /.well-known/acme-challenge {
root {{ letsencrypt_webroot_path }};
try_files $uri =404;
}
{% endif %}
}
{% endif %}
{% endif %}
{% endblock %}

179
templates/etc/nginx/sites-available/cryptpad.j2

@ -0,0 +1,179 @@
{% extends "core.j2" %}
{% block app_specific %}
# CryptPad serves static assets over these two domains.
# `main_domain` is what users will enter in their address bar.
# Privileged computation such as key management is handled in this scope
# UI content is loaded via the `sandbox_domain`.
# "Content Security Policy" headers prevent content loaded via the sandbox
# from accessing privileged information.
# These variables must be different to take advantage of CryptPad's sandboxing techniques.
# In the event of an XSS vulnerability in CryptPad's front-end code
# this will limit the amount of information accessible to attackers.
set $main_domain "{{ item.ssl_name }}";
set $sandbox_domain "sandbox.{{ item.ssl_name }}";
# CryptPad's dynamic content (websocket traffic and encrypted blobs)
# can be served over separate domains. Using dedicated domains (or subdomains)
# for these purposes allows you to move them to a separate machine at a later date
# if you find that a single machine cannot handle all of your users.
# If you don't use dedicated domains, this can be the same as $main_domain
# If you do, they'll be added as exceptions to any rules which block connections to remote domains.
set $api_domain "{{ item.ssl_name }}";
set $files_domain "{{ item.ssl_name }}";
add_header Access-Control-Allow-Origin "*";
set $coop '';
if ($uri ~ ^\/sheet\/.*$) { set $coop 'same-origin'; }
# Enable SharedArrayBuffer in Firefox (for .xlsx export)
add_header Cross-Origin-Resource-Policy cross-origin;
add_header Cross-Origin-Opener-Policy $coop;
add_header Cross-Origin-Embedder-Policy require-corp;
# any static assets loaded with "ver=" in their URL will be cached for a year
if ($args ~ ver=) {
set $cacheControl max-age=31536000;
}
if ($uri ~ ^/.*(\/|\.html)$) {
set $cacheControl no-cache;
}
# Will not set any header if it is emptystring
add_header Cache-Control $cacheControl;
# CSS can be dynamically set inline, loaded from the same domain, or from $main_domain
set $styleSrc "'unsafe-inline' 'self' ${main_domain}";
# connect-src restricts URLs which can be loaded using script interfaces
set $connectSrc "'self' https://${main_domain} ${main_domain} https://${api_domain} blob: wss://${api_domain} ${api_domain} ${files_domain}";
# fonts can be loaded from data-URLs or the main domain
set $fontSrc "'self' data: ${main_domain}";
# images can be loaded from anywhere, though we'd like to deprecate this as it allows the use of images for tracking
set $imgSrc "'self' data: * blob: ${main_domain}";
# frame-src specifies valid sources for nested browsing contexts.
# this prevents loading any iframes from anywhere other than the sandbox domain
set $frameSrc "'self' ${sandbox_domain} blob:";
# specifies valid sources for loading media using video or audio
set $mediaSrc "'self' data: * blob: ${main_domain}";
# defines valid sources for webworkers and nested browser contexts
# deprecated in favour of worker-src and frame-src
set $childSrc "https://${main_domain}";
# specifies valid sources for Worker, SharedWorker, or ServiceWorker scripts.
# supercedes child-src but is unfortunately not yet universally supported.
set $workerSrc "https://${main_domain}";
# script-src specifies valid sources for javascript, including inline handlers
set $scriptSrc "'self' resource: ${main_domain}";
set $unsafe 0;
# the following assets are loaded via the sandbox domain
# they unfortunately still require exceptions to the sandboxing to work correctly.
if ($uri = "/sheet/inner.html") { set $unsafe 1; }
if ($uri ~ ^\/common\/onlyoffice\/.*\/index\.html.*$) { set $unsafe 1; }
# everything except the sandbox domain is a privileged scope, as they might be used to handle keys
if ($host != $sandbox_domain) { set $unsafe 0; }
# privileged contexts allow a few more rights than unprivileged contexts, though limits are still applied
if ($unsafe) {
set $scriptSrc "'self' 'unsafe-eval' 'unsafe-inline' resource: ${main_domain}";
}
# Finally, set all the rules you composed above.
add_header Content-Security-Policy "default-src 'none'; child-src $childSrc; worker-src $workerSrc; media-src $mediaSrc; style-src $styleSrc; script-src $scriptSrc; connect-src $connectSrc; font-src $fontSrc; img-src $imgSrc; frame-src $frameSrc;";
{% endblock %}
{% block root %}
root {{ nginx_www_dir }}{{ item.root }};
index index.html;
error_page 404 /customize.dist/404.html;
# Finally, serve anything the above exceptions don't govern.
try_files /www/$uri /www/$uri/index.html /customize/$uri;
{% endblock %}
{% block location%}
location ^~ /cryptpad_websocket {
proxy_pass http://{{ item.proxy_pass }}:3000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# WebSocket support (nginx 1.4)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
}
location ^~ /customize.dist/ {
# This is needed in order to prevent infinite recursion between /customize/ and the root
}
# try to load customizeable content via /customize/ and fall back to the default content
# located at /customize.dist/
# This is what allows you to override behaviour.
location ^~ /customize/ {
rewrite ^/customize/(.*)$ $1 break;
try_files /customize/$uri /customize.dist/$uri;
}
# /api/config is loaded once per page load and is used to retrieve
# the caching variable which is applied to every other resource
# which is loaded during that session.
location = /api/config {
proxy_pass http://{{ item.proxy_pass }}:3000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# encrypted blobs are immutable and are thus cached for a year
location ^~ /blob/ {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'application/octet-stream; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
add_header Cache-Control max-age=31536000;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length';
add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length';
try_files $uri =404;
}
# the "block-store" serves encrypted payloads containing users' drive keys
# these payloads are unlocked via login credentials. They are mutable
# and are thus never cached. They're small enough that it doesn't matter, in any case.
location ^~ /block/ {
add_header Cache-Control max-age=0;
try_files $uri =404;
}
# This block provides an alternative means of loading content
# otherwise only served via websocket. This is solely for debugging purposes,
# and is thus not allowed by default.
location ^~ /datastore/ {
add_header Cache-Control max-age=0;
try_files $uri =404;
}
# The nodejs server has some built-in forwarding rules to prevent
# URLs like /pad from resulting in a 404. This simply adds a trailing slash
# to a variety of applications.
location ~ ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media|profile|contacts|todo|filepicker|debug|kanban|sheet|support|admin|notifications|teams)$ {
rewrite ^(.*)$ $1/ redirect;
}
{% endblock %}

16
templates/etc/nginx/sites-available/expired.j2

@ -0,0 +1,16 @@
####
# {{ ansible_managed }}
####
### HTTP
server {
server_name {{ item.name }};
return 301 {{ item.send_to }};
}
server {
server_name www.{{ item.name }};
return 301 $scheme://{{ item.name }}$request_uri;
}

51
templates/etc/nginx/sites-available/framadate.j2

@ -0,0 +1,51 @@
{% extends "core.j2" %}
{% block location %}
## LOCATIONS
location / {
rewrite "^/admin$" "/admin/" permanent;
# Clean URL
rewrite "^/([a-zA-Z0-9-]+)$" "/studs.php?poll=$1" last;
rewrite "^/([a-zA-Z0-9-]+)/action/([a-zA-Z_-]+)/(.+)$" "/studs.php?poll=$1&$2=$3" last;
rewrite "^/([a-zA-Z0-9-]+)/vote/([a-zA-Z0-9]{16})$" "/studs.php?poll=$1&vote=$2" last;
rewrite "^/([a-zA-Z0-9]{24})/admin$" "/adminstuds.php?poll=$1" last;
rewrite "^/([a-zA-Z0-9]{24})/admin/vote/([a-zA-Z0-9]{16})$" "/adminstuds.php?poll=$1&vote=$2" last;
rewrite "^/([a-zA-Z0-9]{24})/admin/action/([a-zA-Z_-]+)(/([A-Za-z0-9]+))?$" "/adminstuds.php?poll=$1&$2=$4" last;
}
location ~^/(\.git)/{
deny all;
}
location ~ /\. {
deny all;
}
location ~ ^/composer\.json.*$|^/composer\.lock.*$|^/php\.ini.*$|^/.*\.sh {
deny all;
}
location /admin/ {
auth_basic "closed site";
auth_basic_user_file {{ nginx_www_dir }}/{{ item.root }}/admin/.htpasswd;
location ~ \.php$ {
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:{{ pool_listen }};
}
try_files $uri $uri/ =401;
}
location ~ \.php$ {
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:{{ pool_listen }};
}
{% endblock %}

47
templates/etc/nginx/sites-available/grav.j2

@ -0,0 +1,47 @@
{% extends "core.j2" %}
{% block root %}
root {{ nginx_www_dir }}{{ item.root }};
index index.html index.php;
{% endblock %}
{% block location %}
## LOCATIONS
location / {
try_files $uri $uri/ /index.php?_url=$uri&$query_string;
}
location /favicon.ico {
alias {{ nginx_www_dir }}{{ item.root }}/favicon.png;
}
# deny all direct access for these folders
location ~* /(.git|cache|bin|logs|backup|tests)/.*$ {
return 403;
}
# deny running scripts inside core system folders
location ~* /(system|vendor)/.*\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$ {
return 403;
}
# deny running scripts inside user folder
location ~* /user/.*\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ {
return 403;
}
# deny access to specific files in the root folder
location ~ /(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess) {
return 403;
}
location ~ \.php$ {
{% if item.upstream_params is defined and item.upstream_params is iterable %}
{% for param in item.upstream_params %}
{{ param }}
{% endfor %}
{% endif %}
}
{% endblock %}

65
templates/etc/nginx/sites-available/hubzilla.j2

@ -0,0 +1,65 @@
{% extends "core.j2" %}
{% block root %}
root {{ nginx_www_dir }}{{ item.root }};
index index.php;
charset utf-8;
include mime.types;
autoindex off
{% endblock %}
{% block location %}
## LOCATIONS
location / {
rewrite ^/\.well\-known/.* /index.php?q=$1;
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?q=$1;
}
}
location ^~ /.well-known/ {
allow all;
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?q=$1;
}
}
location ~* \.(jpg|jpeg|gif|png|ico|css|js|htm|html|map|ttf|woff|woff2|svg)$ {
expires 30d;
try_files $uri /index.php?q=$uri&$args;
}
# block these file types
location ~* \.(tpl|md|tgz|log|out)$ {
deny all;
}
location ~* \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
{% if item.upstream_params is defined and item.upstream_params is iterable %}
{% for param in item.upstream_params %}
{{ param }}
{% endfor %}
{% endif %}
}
location ~ /\. {
deny all;
}
location ~ "(^|/)store" {
deny all;
}
location ~ "(^|/)\.git" {
return 403;
}
location ~ /util {
deny all;
}
{% endblock %}

14
templates/etc/nginx/sites-available/letsencrypt.j2

@ -0,0 +1,14 @@
####
# {{ ansible_managed }}
####
server {
listen 80;
server_name {{ item.name }};
location /.well-known/acme-challenge {
root {{ letsencrypt_webroot_path }};
try_files $uri =404;
}
}

33
templates/etc/nginx/sites-available/lufi.j2

@ -0,0 +1,33 @@
{% extends "core.j2" %}
{% block location %}
## LOCATIONS
location / {
proxy_pass {{ item.upstream_proto }}://{{ item.upstream_name }}:{{ item.upstream_port}};
# Add cache for static files
if ($request_uri ~* ^/(img|css|font|js)/) {
add_header Expires "Thu, 31 Dec 2037 23:55:55 GMT";
add_header Cache-Control "public, max-age=315360000";
}
# HTTPS only header, improves security
add_header Strict-Transport-Security "max-age=15768000";
# Really important! Lufi uses WebSocket, it won't work without this
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# If you want to log the remote port of the file senders, you'll need that
proxy_set_header X-Remote-Port $remote_port;
proxy_set_header X-Forwarded-Proto $scheme;
# We expect the downstream servers to redirect to the right hostname, so don't do any rewrites here.
proxy_redirect off;
}
{% endblock %}

6
templates/etc/nginx/sites-available/maintenance.j2

@ -0,0 +1,6 @@
{% extends "core.j2" %}
{%location root %}
root {{ nginx_maintenance_page_root }};
index index.html;
{% endblock %}

21
templates/etc/nginx/sites-available/mumble-web.j2

@ -0,0 +1,21 @@
{% extends core.j2 %}
{% block extra_upstreams %}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
{% endblock %}
{% block location %}
location / {
root {{ item.root }};
}
location /server {
proxy_pass {{ item.mumble_proto }}://{{ item.mumble_server }}:{{ item.mumble_port }};
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
{% endblock %}

137
templates/etc/nginx/sites-available/nextcloud.j2

@ -0,0 +1,137 @@
{% extends "core.j2" %}
{% block extra_upstreams %}
upstream php-handler {
server {{ item.fastcgi_pass }};
}
{% endblock %}
{% block root %}
root {{ nginx_www_dir }}{{ item.root }};
index {{ item.index | default('index.html index.htm') }};
error_page 403 /core/templates/403.php;
error_page 404 /core/templates/404.php;
{% endblock %}
{% block headers %}
## HEADERS
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "none" always;
add_header X-XSS-Protection "1; mode=block" always;
# Remove X-Powered-By, which is an information leak
fastcgi_hide_header X-Powered-By;
{% endblock %}
{% block location %}
# Path to the root of your installation
location = /robots.txt {
{% if item.robot_txt is defined %}
allow all;
log_not_found off;
access_log off;
{% else %}
deny all;
log_not_found off;
access_log off;
{% endif %}
}
{% for app in nc_apps %}
{% if app.name == 'user_webfinger' and app.state == 'enabled' %}
# The following 2 rules are only needed for the user_webfinger app.
rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;
{% endif %}
{% if app.name == 'social' and app.state == 'enabled'%}
# The following rule is only needed for the Social app.
rewrite ^/.well-known/webfinger /public.php?service=webfinger last;
{% endif %}
{% endfor %}
location = /.well-known/carddav {
return 301 $scheme://$host:$server_port/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host:$server_port/remote.php/dav;
}
location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ {
deny all;
}
location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
try_files $fastcgi_script_name =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTPS on;
# Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
# Enable pretty urls
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js, css and map files
# Make sure it is BELOW the PHP block
location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
# Before enabling Strict-Transport-Security headers please read into
# this topic first.
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "none" always;
add_header X-XSS-Protection "1; mode=block" always;
# Optional: Don't log access to assets
access_log off;
}
location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ {
try_files $uri /index.php$request_uri;
# Optional: Don't log access to other assets
access_log off;
}
{% endblock %}
{% block app_specific %}
fastcgi_buffers 64 4K;
# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
{% endblock %}

55
templates/etc/nginx/sites-available/privatebin.j2

@ -0,0 +1,55 @@
{% extends "core.j2" %}
{% block root %}
root {{ nginx_www_dir }}{{ item.root }};
index {{ item.index }};
try_files {{ item.override_try_files | default('$uri $uri/ /index.php') }};
{% endblock %}
{% block location %}
## LOCATIONS
location ~ \.php$ {
{% if item.upstream_params is defined and item.upstream_params is iterable %}
{% for param in item.upstream_params %}
{{ param }}
{% endfor %}
{% endif %}
include fastcgi_params;
}
location ~ /\. {
deny all;
}
location ~* \.(txt|js|css|png|jpe?g|gif|ico|svg)$ {
expires 30d;
log_not_found off;
}
{% endblock %}
{% block extra_upstreams %}
map $http_user_agent $pastebin_badagent {
~*bot 1;
~*spider 1;
~*crawl 1;
~https?:// 1;
WhatsApp 1;
SkypeUriPreview 1;
facebookexternalhit 1;
}
{% endblock %}
{% block app_specific %}
if ($pastebin_badagent) {
return 403;
}
location /cfg {
return 403;
}
location /data {
deny all;
}
{% endblock %}

133
templates/etc/nginx/sites-available/proxy.j2

@ -0,0 +1,133 @@
{% extends "core.j2" %}
{% block location %}
## LOCATIONS
# ROOT LOCATION
location / {
proxy_pass {{ item.upstream_proto }}://{{ item.upstream_name }}:{{ item.upstream_port}};
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_redirect off;
{% if item.secure_cookie is defined %}
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
{% endif %}
{% if item.root_custom_headers is defined %}
{% for header in item.root_custom_headers %}
{% if header.secure_site is defined %}
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy {{ item.referrer | default('no-referrer') }};
{% if header.header_sameorigin is defined %}
add_header X-Frame-Options "SAMEORIGIN";
{% endif %}
{% endif %}
{% if header.nginx_HSTS_policy is defined %}
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
{% endif %}
{% if header.referrer is defined %}
add_header Referrer-Policy no-referrer;
{% endif %}
{% if header.csp is defined %}
add_header Content-Security-Policy "{{ header.csp }}";
{% endif %}
{% if header.cto is defined %}
{% if header.cto == 'none' %}
{% else %}
add_header X-Content-Type-Options {{ header.cto }};
{% endif %}
{% else %}
add_header X-Content-Type-Options nosniff;
{% endif %}
{%if header.xss is defined %}
{% if header.xss == 'none' %}
{% else %}
add_header X-XSS-Protection "{{ header.xss }}";
{% endif %}
{% else %}
add_header X-XSS-Protection "1; mode=block";
{% endif %}
{% if header.robots is defined %}
add_header X-Robots-Tag "{{ header.robots }}";
{% else %}
add_header X-Robots-Tag none;
{% endif %}
{% endfor %}
{% endif %}
}
{% if item.favicon is defined %}
location /favicon.ico {
alias {{ item.favicon }};
expires 30d;
access_log off;
log_not_found off;
}
{% endif %}
{% if item.extra_locations is defined %}
# EXTRA LOCATIONS
{% for locations in item.extra_locations %}
location {{ locations.name }} {
proxy_pass {{ locations.upstream_proto }}://{{ locations.upstream_name }}:{{ locations.upstream_port}};
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_redirect off;
{% if item.secure_cookie is defined %}
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
{% endif %}
{% if locations.headers is defined %}
{% for item in locations.headers %}
{% if item.secure_site is defined %}
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy {{ item.referrer | default('no-referrer') }};
{% if item.header_sameorigin is defined %}
add_header X-Frame-Options "SAMEORIGIN";
{% endif %}
{% endif %}
{% if item.nginx_HSTS_policy is defined %}
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
{% endif %}
{% if item.referrer is defined %}
add_header Referrer-Policy no-referrer;
{% endif %}
{% if item.csp is defined %}
add_header Content-Security-Policy "{{ item.csp }}";
{% endif %}
{% if item.cto is defined %}
{% if item.cto == 'none' %}
{% else %}
add_header X-Content-Type-Options {{ item.cto }};
{% endif %}
{% else %}
add_header X-Content-Type-Options nosniff;
{% endif %}
{%if item.xss is defined %}
{% if item.xss == 'none' %}
{% else %}
add_header X-XSS-Protection "{{ item.xss }}";
{% endif %}
{% else %}
add_header X-XSS-Protection "1; mode=block";
{% endif %}
{% if item.robots is defined %}
add_header X-Robots-Tag "{{ item.robots }}";
{% else %}
add_header X-Robots-Tag none;
{% endif %}
{% endfor %}
{% endif %}
}
{% endfor %}
{% endif %}
{% endblock %}
```

33
templates/etc/nginx/sites-available/pwm.j2

@ -0,0 +1,33 @@
{% extends "core.j2" %}
{% block location %}
## LOCATIONS
location / {
rewrite ^ {{ item.proto }}://{{ item.name }}/{{item.root }}/ last;
}
location /pwm {
proxy_pass {{ item.upstream_proto }}://{{ item.upstream_name }}:{{ item.upstream_port}};
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_max_temp_file_size 0;
proxy_buffering off;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
}
{% if ansible_date_time.weekday_number == '6' or ansible_date_time.weekday_number == '7' %}
location /pwm/public/newuser {
root /var/www/out-of-order;
index index.html;
}
{% endif %}
{% endblock %}

40
templates/etc/nginx/sites-available/roundcube.j2

@ -0,0 +1,40 @@
{% extends "core.j2" %}
{% block root %}
root {{ nginx_www_dir }}{{ item.root }};
index {{ item.index }};
{% endblock %}
{% block location %}
## LOCATIONS
location ~ /\. {
deny all;
}
location = /favicon.ico {
expires 30d;
access_log off;
log_not_found off;
}
location ~* \.(txt|js|css|png|jpe?g|gif|ico|svg)$ {
expires 30d;
log_not_found off;
}
location ~ ^/(README.md|INSTALL|LICENSE|CHANGELOG|UPGRADING)$ {
deny all;
}
location ~ ^/(config|temp|logs)/ {
deny all;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass {{ item.fastcgi_pass }};
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
{% endblock %}

20
templates/etc/nginx/sites-available/searx.j2

@ -0,0 +1,20 @@
{% extends "core.j2" %}
{%block root %}
root {{ searx_app_dir }}/searx;
{% endblock %}
{% block location %}
location / {
{% if item.filtron == 'true' %}
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_pass http://127.0.0.1:4004/;
{% else %}
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/app/searx/socket;
{% endif %}
}
{% endblock %}

35
templates/etc/nginx/sites-available/taiga.j2

@ -0,0 +1,35 @@
{% extends "core.j2" %}
{%block app_specific %}
large_client_header_buffers 4 32k;
client_max_body_size 50M;
charset utf-8;
{% endblock %}
{% block location %}
location / {
root {{ taiga_front_dir }};
try_files $uri $uri/ /index.html;
}
location /api {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass {{ taiga_api_url }};
proxy_redirect off;
}
location /static {
alias {{ taiga_back_dir }}/static;
}
location /media {
alias {{ taiga_back_dir }}/media;
}
location /user-settings/user-change-password {
return 301 {{ taiga_user_change_passwd_url }};
}
{% endblock %}

48
templates/etc/nginx/sites-available/ttrss.j2

@ -0,0 +1,48 @@
{% extends "core.j2" %}
{% block root %}
root {{ nginx_www_dir }}{{ item.root }};
index {{ item.index }};
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
{% endblock %}
{% block location %}
## LOCATIONS
location /tt-rss/cache {
aio threads;
deny all;
}
location = /tt-rss/config.php {
deny all;
}
location /tt-rss/backups {
deny all;
}
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
# regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;
# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_pass {{ item.fastcgi_pass }};
}
{% endblock %}

34
templates/etc/nginx/sites-available/wp.j2

@ -0,0 +1,34 @@
{% extends "core.j2" %}
{% block root %}
root {{ nginx_www_dir }}{{ item.root }};
index {{ item.index }};
try_files {{ item.override_try_files | default('$uri $uri/ /index.php') }};
{% endblock %}
{% block location %}
location ~ \.php$ {
{% if item.upstream_params is defined and item.upstream_params is iterable %}
{% for param in item.upstream_params %}
{{ param }}
{% endfor %}
{% endif %}
include fastcgi_params;
}
{% endblock %}
{% block app_specific %}
location ^~ /blogs.dir {
internal;
alias {{ nginx_www_dir }}/{{ item.root }}/wp-content/blogs.dir ;
access_log off;
log_not_found off;
expires max;
}
if (!-e $request_filename) {
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
rewrite ^/[_0-9a-zA-Z-]+(/wp-.*) $1 last;
rewrite ^/[_0-9a-zA-Z-]+(/.*\.php)$ $1 last;
}
{% endblock %}

73
templates/etc/nginx/sites-available/wpfarm.j2

@ -0,0 +1,73 @@
{% extends "core.j2" %}
{% block root %}
root {{ nginx_www_dir }}{{ item.root }};
index {{ item.index }};
try_files {{ item.override_try_files | default('$uri $uri/ /index.php') }};
{% endblock %}
{% block location %}
location ~ \.php$ {
{% if item.upstream_params is defined and item.upstream_params is iterable %}
{% for param in item.upstream_params %}
{{ param }}
{% endfor %}
{% endif %}
include fastcgi_params;
}
{% endblock %}
{% block app_specific %}
# BEGIN W3TC Browser Cache
rewrite ^/wp-content/cache/minify.*/w3tc_rewrite_test$ /wp-content/plugins/w3-total-cache/pub/minify.php?w3tc_rewrite_test=1 last;
rewrite ^/wp-content/cache/minify/(.+/[X]+\.css)$ /wp-content/plugins/w3-total-cache/pub/minify.php?test_file=$1 last;
rewrite ^/wp-content/cache/minify/(.+\.(css|js))$ /wp-content/plugins/w3-total-cache/pub/minify.php?file=$1 last;
# END W3TC Minify core
# WordPress multisite subdirectory rules.
# Designed to be included in any server {} block.
# This order might seem weird - this is attempted to match last if rules below fail.
# http://wiki.nginx.org/HttpCoreModule
#location / {
# try_files $uri $uri/ /index.php?$args;
#}
location ~ ^(/[^/]+/)?files/(.+) {
try_files /wp-content/blogs.dir/$blogid/files/[ /wp-includes/ms-files.php?file=[ ;
access_log off;
log_not_found off;
expires max;
}
# Rewrite multisite '.../wp-.*' and '.../*.php'.
if (!-e $request_filename) {
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
rewrite ^/[_0-9a-zA-Z-]+(/wp-.*) ( last;
rewrite ^/[_0-9a-zA-Z-]+(/.*\.php)$ ( last;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Deny access to any files with a .php extension in the uploads directory
# Works in sub-directory installs and also in multisite network
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
{% endblock %}
{% block extra_upstreams %}
map $http_host $blogid {
default 0;
}
{% endblock %}

10
templates/etc/nginx/sites-available/zabbix_check.j2

@ -0,0 +1,10 @@
server {
listen 10061;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
Loading…
Cancel
Save