├── Dockerfile ├── Procfile ├── README.md ├── config ├── 00_mod_security.conf ├── modsecurity.d │ ├── 50_basic_asl_rules.conf │ ├── sql.txt │ ├── tortix_waf.conf │ └── trusted-domains.conf └── tortix-common.repo ├── dhparam.pem.default ├── docker-entrypoint.sh ├── generate-dhparam.sh └── nginx.tmpl /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:latest 2 | MAINTAINER Support 3 | 4 | RUN yum -y update 5 | RUN yum -y install wget && yum clean all 6 | 7 | RUN cd /root; NON_INT=1 wget -q -O - https://updates.atomicorp.com/installers/atomic |sh 8 | 9 | COPY config/tortix-common.repo /etc/yum.repos.d/tortix-common.repo 10 | 11 | RUN yum -y install nginx nginx-module-modsecurity http-tools roadsend-php-libs aum 12 | 13 | # Special condition for aum 14 | RUN ln -sf /var/asl/bin/aum.dynamic /var/asl/bin/aum 15 | 16 | # Configure Nginx and apply fix for very long server names 17 | RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ 18 | && sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf 19 | 20 | # Enable WAF 21 | RUN sed -i '1s@^@load_module modules/ngx_http_modsecurity_module.so;\n@' /etc/nginx/nginx.conf 22 | RUN mkdir -p /var/asl/data/audit 23 | RUN mkdir -p /etc/asl && touch /etc/asl/whitelist 24 | COPY config/00_mod_security.conf /etc/nginx/conf.d/ 25 | COPY config/modsecurity.d /etc/httpd/modsecurity.d 26 | 27 | 28 | 29 | # Install Forego 30 | ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego 31 | RUN chmod u+x /usr/local/bin/forego 32 | 33 | 34 | ENV DOCKER_GEN_VERSION 0.7.3 35 | 36 | RUN wget https://github.com/jwilder/docker-gen/releases/download/$DOCKER_GEN_VERSION/docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \ 37 | && tar -C /usr/local/bin -xvzf docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \ 38 | && rm /docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz 39 | 40 | COPY . /app/ 41 | WORKDIR /app/ 42 | 43 | ENV DOCKER_HOST unix:///tmp/docker.sock 44 | 45 | VOLUME ["/etc/nginx/certs", "/etc/nginx/dhparam", "/etc/httpd/modsecurity.d"] 46 | 47 | ENTRYPOINT ["/app/docker-entrypoint.sh"] 48 | CMD ["forego", "start", "-r"] 49 | 50 | 51 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | dockergen: docker-gen -watch -notify "nginx -s reload" /app/nginx.tmpl /etc/nginx/conf.d/default.conf 2 | nginx: nginx 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **About** 2 | 3 | This container implements the Atomicorp NGINX Web Application Firewall (ModSecurity v3). It is designed to act as a reverse proxy, and supports automatic container detection and configuration. Rule policies are shared with the container over a volume 4 | 5 | 6 | **Installation** 7 | 8 | 1) Register for WAF rule updates at https://atomicorp.com/pricing/ 9 | 10 | 11 | 2) Create volume directories for /etc/nginx/conf.d and /etc/httpd/modsecurity.d 12 | 13 | 14 | mkdir -p ~/waf/conf.d 15 | mkdir -p ~/waf/modsecurity.d 16 | 17 | 3) Download nginx ruleset at: https://updates.atomicorp.com/channels/rules/nginx-latest/, and extract the archive: 18 | 19 | tar xvf nginx-waf-201802271105.tar.gz 20 | 21 | 4) Copy the master nginx config: 22 | 23 | cp rules/conf/00_mod_security.conf ~/waf/conf.d 24 | cp rules/conf/tortix_waf.conf ~/waf/modsecurity.d/ 25 | cp rules/* ~/waf/modsecurity.d/ 26 | 27 | 28 | 29 | **Usage** 30 | 31 | 32 | 33 | **Basic** 34 | 35 | 36 | DEFAULT_HOST declares the nginx default host 37 | 38 | docker run -d -p 80:80 -e DEFAULT_HOST=www.example.com -v /var/run/docker.sock:/tmp/docker.sock:ro -v ~/waf/conf.d:/etc/nginx/conf.d -v ~/waf/modsecurity.d:/etc/httpd/modsecurity.d atomicorp/nginx-waf-docker 39 | 40 | 41 | 42 | **With SSL certificates** 43 | 44 | docker run -d -p 80:80 -p 443:443 -v /path/to/certs:/etc/nginx/certs -v /var/run/docker.sock:/tmp/docker.sock:ro -v ~/waf/conf.d:/etc/nginx/conf.d -v ~/waf/modsecurity.d:/etc/httpd/modsecurity.d atomicorp/nginx-waf-proxy 45 | 46 | 47 | **Name-Based virtual host support** 48 | 49 | available with the environmental variable -e VIRTUAL_HOST=www.example.com. Note that name based virtual host certificates (if used)use naming convention .key and .crt Example: www.example.com.key and www.example.com.crt 50 | 51 | docker run -e VIRTUAL_HOST=www.example.com -d -p 80:80 -p 443:443 -v /path/to/certs:/etc/nginx/certs -v /var/run/docker.sock:/tmp/docker.sock:ro -v ~/waf/conf.d:/etc/nginx/conf.d -v ~/waf/modsecurity.d:/etc/httpd/modsecurity.d atomicorp/nginx-waf-proxy 52 | 53 | 54 | **Thanks:** 55 | 56 | This project is a CentOS/RHEL based derivative of the project at: 57 | 58 | https://github.com/jwilder/nginx-proxy 59 | -------------------------------------------------------------------------------- /config/00_mod_security.conf: -------------------------------------------------------------------------------- 1 | modsecurity on; 2 | modsecurity_rules_file /etc/httpd/modsecurity.d/tortix_waf.conf; 3 | modsecurity_rules_file /etc/httpd/modsecurity.d/50_basic_asl_rules.conf; 4 | -------------------------------------------------------------------------------- /config/modsecurity.d/50_basic_asl_rules.conf: -------------------------------------------------------------------------------- 1 | # http://www.atomicorp.com/ 2 | # Atomicorp (Gotroot.com) ModSecurity rules 3 | # Application Security Rules for modsec 2.x 4 | # 5 | # Copyright 2018 by Atomicorp, Inc., all rights reserved. 6 | # Redistribution is strictly prohibited in any form, including whole or in part. 7 | # 8 | # Distribution of this work or derivative of this work in any form is 9 | # prohibited unless prior written permission is obtained from the 10 | # copyright holder. 11 | # 12 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS 13 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 16 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 17 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 18 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 19 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 20 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 21 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 22 | # THE POSSIBILITY OF SUCH DAMAGE. 23 | # 24 | #---ASL-CONFIG-FILE--- 25 | # 26 | 27 | # Do not edit this file! 28 | # This file is generated and changes will be overwritten. 29 | # 30 | # If you need to make changes to the rules, please follow the procedure here: 31 | # http://www.atomicorp.com/wiki/index.php/Mod_security 32 | 33 | ###############FILE PROTECTION RULES#################### 34 | 35 | 36 | # Rule placeholder 37 | 38 | -------------------------------------------------------------------------------- /config/modsecurity.d/sql.txt: -------------------------------------------------------------------------------- 1 | # example placeholder 2 | -------------------------------------------------------------------------------- /config/modsecurity.d/tortix_waf.conf: -------------------------------------------------------------------------------- 1 | SecRuleEngine on 2 | SecRequestBodyAccess On 3 | SecResponseBodyMimeType (null) text/html text/plain text/xml 4 | SecUploadDir /tmp 5 | SecUploadKeepFiles off 6 | SecAuditEngine RelevantOnly 7 | SecAuditLogRelevantStatus "^(?:5|4(?!04))" 8 | SecAuditLogType Concurrent 9 | SecAuditLog /var/log/nginx/audit_log 10 | SecAuditLogParts ABIFHZ 11 | SecCookieFormat 0 12 | SecDataDir /tmp 13 | SecTmpDir /tmp 14 | SecAuditLogStorageDir /var/asl/data/audit 15 | SecRequestBodyLimit 134217728 16 | SecResponseBodyLimitAction ProcessPartial 17 | SecRequestBodyNoFilesLimit 1048576 18 | SecAuditLogDirMode 0770 19 | SecPcreMatchLimit 150000 20 | SecPcreMatchLimitRecursion 150000 21 | SecResponseBodyAccess on 22 | SecCollectionTimeout 86400 23 | 24 | -------------------------------------------------------------------------------- /config/modsecurity.d/trusted-domains.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atomicorp/nginx-waf-docker/12bebb27517dc2994d5e149467cfe6949fb87389/config/modsecurity.d/trusted-domains.conf -------------------------------------------------------------------------------- /config/tortix-common.repo: -------------------------------------------------------------------------------- 1 | [tortix-common] 2 | name=Atomicorp - Centos 7 - Atomic Secured Linux 3 | mirrorlist=http://updates.atomicorp.com/channels/mirrorlist/tortix-common/centos-$releasever-$basearch 4 | priority=1 5 | enabled=1 6 | gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY.atomicorp.txt 7 | gpgcheck=1 8 | 9 | -------------------------------------------------------------------------------- /dhparam.pem.default: -------------------------------------------------------------------------------- 1 | -----BEGIN DH PARAMETERS----- 2 | MIIBCAKCAQEAzB2nIGzpVq7afJnKBm1X0d64avwOlP2oneiKwxRHdDI/5+6TpH1P 3 | F8ipodGuZBUMmupoB3D34pu2Qq5boNW983sm18ww9LMz2i/pxhSdB+mYAew+A6h6 4 | ltQ5pNtyn4NaKw1SDFkqvde3GNPhaWoPDbZDJhpHGblR3w1b/ag+lTLZUvVwcD8L 5 | jYS9f9YWAC6T7WxAxh4zvu1Z0I1EKde8KYBxrreZNheXpXHqMNyJYZCaY2Hb/4oI 6 | EL65qZq1GCWezpWMjhk6pOnV5gbvqfhoazCv/4OdRv6RoWOIYBNs9BmGho4AtXqV 7 | FYLdYDhOvN4aVs9Ir+G8ouwiRnix24+UewIBAg== 8 | -----END DH PARAMETERS----- 9 | -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Warn if the DOCKER_HOST socket does not exist 5 | if [[ $DOCKER_HOST = unix://* ]]; then 6 | socket_file=${DOCKER_HOST#unix://} 7 | if ! [ -S $socket_file ]; then 8 | cat >&2 <<-EOT 9 | ERROR: you need to share your Docker host socket with a volume at $socket_file 10 | Typically you should run your jwilder/nginx-proxy with: \`-v /var/run/docker.sock:$socket_file:ro\` 11 | See the documentation at http://git.io/vZaGJ 12 | EOT 13 | socketMissing=1 14 | fi 15 | fi 16 | 17 | # Generate dhparam file if required 18 | # Note: if $DHPARAM_BITS is not defined, generate-dhparam.sh will use 2048 as a default 19 | /app/generate-dhparam.sh $DHPARAM_BITS 20 | 21 | # Compute the DNS resolvers for use in the templates 22 | export RESOLVERS=$(awk '$1 == "nameserver" {print $2}' ORS=' ' /etc/resolv.conf | sed 's/ *$//g') 23 | if [ "x$RESOLVERS" = "x" ]; then 24 | echo "Warning: unable to determine DNS resolvers for nginx" >&2 25 | unset RESOLVERS 26 | fi 27 | 28 | # If the user has run the default command and the socket doesn't exist, fail 29 | if [ "$socketMissing" = 1 -a "$1" = forego -a "$2" = start -a "$3" = '-r' ]; then 30 | exit 1 31 | fi 32 | 33 | exec "$@" 34 | -------------------------------------------------------------------------------- /generate-dhparam.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # The first argument is the bit depth of the dhparam, or 2048 if unspecified 4 | DHPARAM_BITS=${1:-2048} 5 | 6 | # If a dhparam file is not available, use the pre-generated one and generate a new one in the background. 7 | # Note that /etc/nginx/dhparam is a volume, so this dhparam will persist restarts. 8 | PREGEN_DHPARAM_FILE="/app/dhparam.pem.default" 9 | DHPARAM_FILE="/etc/nginx/dhparam/dhparam.pem" 10 | GEN_LOCKFILE="/tmp/dhparam_generating.lock" 11 | 12 | # The hash of the pregenerated dhparam file is used to check if the pregen dhparam is already in use 13 | PREGEN_HASH=$(md5sum $PREGEN_DHPARAM_FILE | cut -d" " -f1) 14 | if [[ -f $DHPARAM_FILE ]]; then 15 | CURRENT_HASH=$(md5sum $DHPARAM_FILE | cut -d" " -f1) 16 | if [[ $PREGEN_HASH != $CURRENT_HASH ]]; then 17 | # There is already a dhparam, and it's not the default 18 | echo "Custom dhparam.pem file found, generation skipped" 19 | exit 0 20 | fi 21 | 22 | if [[ -f $GEN_LOCKFILE ]]; then 23 | # Generation is already in progress 24 | exit 0 25 | fi 26 | fi 27 | 28 | cat >&2 <<-EOT 29 | WARNING: $DHPARAM_FILE was not found. A pre-generated dhparam.pem will be used for now while a new one 30 | is being generated in the background. Once the new dhparam.pem is in place, nginx will be reloaded. 31 | EOT 32 | 33 | # Put the default dhparam file in place so we can start immediately 34 | cp $PREGEN_DHPARAM_FILE $DHPARAM_FILE 35 | touch $GEN_LOCKFILE 36 | 37 | # Generate a new dhparam in the background in a low priority and reload nginx when finished (grep removes the progress indicator). 38 | ( 39 | ( 40 | nice -n +5 openssl dhparam -out $DHPARAM_FILE $DHPARAM_BITS 2>&1 \ 41 | && echo "dhparam generation complete, reloading nginx" \ 42 | && nginx -s reload 43 | ) | grep -vE '^[\.+]+' 44 | rm $GEN_LOCKFILE 45 | ) &disown 46 | -------------------------------------------------------------------------------- /nginx.tmpl: -------------------------------------------------------------------------------- 1 | {{ $CurrentContainer := where $ "ID" .Docker.CurrentContainerID | first }} 2 | 3 | {{ define "upstream" }} 4 | {{ if .Address }} 5 | {{/* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}} 6 | {{ if and .Container.Node.ID .Address.HostPort }} 7 | # {{ .Container.Node.Name }}/{{ .Container.Name }} 8 | server {{ .Container.Node.Address.IP }}:{{ .Address.HostPort }}; 9 | {{/* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} 10 | {{ else if .Network }} 11 | # {{ .Container.Name }} 12 | server {{ .Network.IP }}:{{ .Address.Port }}; 13 | {{ end }} 14 | {{ else if .Network }} 15 | # {{ .Container.Name }} 16 | server {{ .Network.IP }} down; 17 | {{ end }} 18 | {{ end }} 19 | 20 | # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the 21 | # scheme used to connect to this server 22 | map $http_x_forwarded_proto $proxy_x_forwarded_proto { 23 | default $http_x_forwarded_proto; 24 | '' $scheme; 25 | } 26 | 27 | # If we receive X-Forwarded-Port, pass it through; otherwise, pass along the 28 | # server port the client connected to 29 | map $http_x_forwarded_port $proxy_x_forwarded_port { 30 | default $http_x_forwarded_port; 31 | '' $server_port; 32 | } 33 | 34 | # If we receive Upgrade, set Connection to "upgrade"; otherwise, delete any 35 | # Connection header that may have been passed to this server 36 | map $http_upgrade $proxy_connection { 37 | default upgrade; 38 | '' close; 39 | } 40 | 41 | # Apply fix for very long server names 42 | server_names_hash_bucket_size 128; 43 | 44 | # Default dhparam 45 | ssl_dhparam /etc/nginx/dhparam/dhparam.pem; 46 | 47 | # Set appropriate X-Forwarded-Ssl header 48 | map $scheme $proxy_x_forwarded_ssl { 49 | default off; 50 | https on; 51 | } 52 | 53 | gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 54 | 55 | log_format vhost '$host $remote_addr - $remote_user [$time_local] ' 56 | '"$request" $status $body_bytes_sent ' 57 | '"$http_referer" "$http_user_agent"'; 58 | 59 | access_log off; 60 | 61 | {{ if $.Env.RESOLVERS }} 62 | resolver {{ $.Env.RESOLVERS }}; 63 | {{ end }} 64 | 65 | {{ if (exists "/etc/nginx/proxy.conf") }} 66 | include /etc/nginx/proxy.conf; 67 | {{ else }} 68 | # HTTP 1.1 support 69 | proxy_http_version 1.1; 70 | proxy_buffering off; 71 | proxy_set_header Host $http_host; 72 | proxy_set_header Upgrade $http_upgrade; 73 | proxy_set_header Connection $proxy_connection; 74 | proxy_set_header X-Real-IP $remote_addr; 75 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 76 | proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; 77 | proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; 78 | proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; 79 | 80 | # Mitigate httpoxy attack (see README for details) 81 | proxy_set_header Proxy ""; 82 | {{ end }} 83 | 84 | {{ $enable_ipv6 := eq (or ($.Env.ENABLE_IPV6) "") "true" }} 85 | server { 86 | server_name _; # This is just an invalid value which will never trigger on a real hostname. 87 | listen 80; 88 | {{ if $enable_ipv6 }} 89 | listen [::]:80; 90 | {{ end }} 91 | access_log /var/log/nginx/access.log vhost; 92 | return 503; 93 | } 94 | 95 | {{ if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} 96 | server { 97 | server_name _; # This is just an invalid value which will never trigger on a real hostname. 98 | listen 443 ssl http2; 99 | {{ if $enable_ipv6 }} 100 | listen [::]:443 ssl http2; 101 | {{ end }} 102 | access_log /var/log/nginx/access.log vhost; 103 | return 503; 104 | 105 | ssl_session_tickets off; 106 | ssl_certificate /etc/nginx/certs/default.crt; 107 | ssl_certificate_key /etc/nginx/certs/default.key; 108 | } 109 | {{ end }} 110 | 111 | {{ range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }} 112 | 113 | {{ $host := trim $host }} 114 | {{ $is_regexp := hasPrefix "~" $host }} 115 | {{ $upstream_name := when $is_regexp (sha1 $host) $host }} 116 | 117 | # {{ $host }} 118 | upstream {{ $upstream_name }} { 119 | 120 | {{ range $container := $containers }} 121 | {{ $addrLen := len $container.Addresses }} 122 | 123 | {{ range $knownNetwork := $CurrentContainer.Networks }} 124 | {{ range $containerNetwork := $container.Networks }} 125 | {{ if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} 126 | ## Can be connect with "{{ $containerNetwork.Name }}" network 127 | 128 | {{/* If only 1 port exposed, use that */}} 129 | {{ if eq $addrLen 1 }} 130 | {{ $address := index $container.Addresses 0 }} 131 | {{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork) }} 132 | {{/* If more than one port exposed, use the one matching VIRTUAL_PORT env var, falling back to standard web port 80 */}} 133 | {{ else }} 134 | {{ $port := coalesce $container.Env.VIRTUAL_PORT "80" }} 135 | {{ $address := where $container.Addresses "Port" $port | first }} 136 | {{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork) }} 137 | {{ end }} 138 | {{ end }} 139 | {{ end }} 140 | {{ end }} 141 | {{ end }} 142 | } 143 | 144 | {{ $default_host := or ($.Env.DEFAULT_HOST) "" }} 145 | {{ $default_server := index (dict $host "" $default_host "default_server") $host }} 146 | 147 | {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}} 148 | {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} 149 | 150 | {{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} 151 | {{ $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) "redirect" }} 152 | 153 | {{/* Get the first cert name defined by containers w/ the same vhost */}} 154 | {{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }} 155 | 156 | {{/* Get the best matching cert by name for the vhost. */}} 157 | {{ $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host))}} 158 | 159 | {{/* vhostCert is actually a filename so remove any suffixes since they are added later */}} 160 | {{ $vhostCert := trimSuffix ".crt" $vhostCert }} 161 | {{ $vhostCert := trimSuffix ".key" $vhostCert }} 162 | 163 | {{/* Use the cert specified on the container or fallback to the best vhost match */}} 164 | {{ $cert := (coalesce $certName $vhostCert) }} 165 | 166 | {{ $is_https := (and (ne $https_method "nohttps") (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }} 167 | 168 | {{ if $is_https }} 169 | 170 | {{ if eq $https_method "redirect" }} 171 | server { 172 | server_name {{ $host }}; 173 | listen 80 {{ $default_server }}; 174 | {{ if $enable_ipv6 }} 175 | listen [::]:80 {{ $default_server }}; 176 | {{ end }} 177 | access_log /var/log/nginx/access.log vhost; 178 | return 301 https://$host$request_uri; 179 | } 180 | {{ end }} 181 | 182 | server { 183 | server_name {{ $host }}; 184 | listen 443 ssl http2 {{ $default_server }}; 185 | {{ if $enable_ipv6 }} 186 | listen [::]:443 ssl http2 {{ $default_server }}; 187 | {{ end }} 188 | access_log /var/log/nginx/access.log vhost; 189 | 190 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 191 | ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS'; 192 | 193 | ssl_prefer_server_ciphers on; 194 | ssl_session_timeout 5m; 195 | ssl_session_cache shared:SSL:50m; 196 | ssl_session_tickets off; 197 | 198 | ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }}; 199 | ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }}; 200 | 201 | {{ if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }} 202 | ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; 203 | {{ end }} 204 | 205 | {{ if (exists (printf "/etc/nginx/certs/%s.chain.crt" $cert)) }} 206 | ssl_stapling on; 207 | ssl_stapling_verify on; 208 | ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.crt" $cert }}; 209 | {{ end }} 210 | 211 | {{ if (ne $https_method "noredirect") }} 212 | add_header Strict-Transport-Security "max-age=31536000"; 213 | {{ end }} 214 | 215 | {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} 216 | include {{ printf "/etc/nginx/vhost.d/%s" $host }}; 217 | {{ else if (exists "/etc/nginx/vhost.d/default") }} 218 | include /etc/nginx/vhost.d/default; 219 | {{ end }} 220 | 221 | location / { 222 | {{ if eq $proto "uwsgi" }} 223 | include uwsgi_params; 224 | uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; 225 | {{ else }} 226 | proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; 227 | {{ end }} 228 | 229 | {{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }} 230 | auth_basic "Restricted {{ $host }}"; 231 | auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }}; 232 | {{ end }} 233 | {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} 234 | include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; 235 | {{ else if (exists "/etc/nginx/vhost.d/default_location") }} 236 | include /etc/nginx/vhost.d/default_location; 237 | {{ end }} 238 | } 239 | } 240 | 241 | {{ end }} 242 | 243 | {{ if or (not $is_https) (eq $https_method "noredirect") }} 244 | 245 | server { 246 | server_name {{ $host }}; 247 | listen 80 {{ $default_server }}; 248 | {{ if $enable_ipv6 }} 249 | listen [::]:80 {{ $default_server }}; 250 | {{ end }} 251 | access_log /var/log/nginx/access.log vhost; 252 | 253 | {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} 254 | include {{ printf "/etc/nginx/vhost.d/%s" $host }}; 255 | {{ else if (exists "/etc/nginx/vhost.d/default") }} 256 | include /etc/nginx/vhost.d/default; 257 | {{ end }} 258 | 259 | location / { 260 | {{ if eq $proto "uwsgi" }} 261 | include uwsgi_params; 262 | uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; 263 | {{ else }} 264 | proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; 265 | {{ end }} 266 | {{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }} 267 | auth_basic "Restricted {{ $host }}"; 268 | auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }}; 269 | {{ end }} 270 | {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} 271 | include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; 272 | {{ else if (exists "/etc/nginx/vhost.d/default_location") }} 273 | include /etc/nginx/vhost.d/default_location; 274 | {{ end }} 275 | } 276 | } 277 | 278 | {{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} 279 | server { 280 | server_name {{ $host }}; 281 | listen 443 ssl http2 {{ $default_server }}; 282 | {{ if $enable_ipv6 }} 283 | listen [::]:443 ssl http2 {{ $default_server }}; 284 | {{ end }} 285 | access_log /var/log/nginx/access.log vhost; 286 | return 500; 287 | 288 | ssl_certificate /etc/nginx/certs/default.crt; 289 | ssl_certificate_key /etc/nginx/certs/default.key; 290 | } 291 | {{ end }} 292 | 293 | {{ end }} 294 | {{ end }} 295 | --------------------------------------------------------------------------------