diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f4db606 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.git/ +.gitignore +node_modules/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4207093 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,58 @@ +#@IgnoreInspection BashAddShebang +FROM debian:jessie + +MAINTAINER Franz Josef Kaiser + +ENV DEBIAN_FRONTEND noninteractive +ENV NGINX_VERSION 1.9.10-1~jessie +ENV TIMEZONE Europe/Vienna + +# @TODO NGX_PAGESPEED https://github.com/yappabe/docker-nginx/blob/master/1.9-pagespeed/Dockerfile + +# Install nginx, reduce image size +# Remove man pages +# (not yet) Exchange full i18n with English-only debconf +# Remove not needed APT lists and temp files +RUN apt-key adv \ + --keyserver hkp://pgp.mit.edu:80 \ + --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 \ + && echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list \ + && apt-get update \ + && apt-get install -y -q --no-install-recommends \ + lsb-release \ + ca-certificates \ + nginx=${NGINX_VERSION} \ + gettext-base \ + && apt-get clean \ + && rm -rf /usr/share/man/?? \ + /usr/share/man/??_* \ + /var/lib/apt/lists/* \ + /tmp/* \ + /var/tmp/* + +# Sets timezone +# Add logs folder for nginx +# Forward request and error logs to docker log collector +RUN echo ${TIMEZONE} > /etc/timezone \ + && dpkg-reconfigure --frontend noninteractive tzdata + +# Add Logs directory +# Symlink StdOut/StdErr to files for use in volumes +RUN mkdir /etc/nginx/logs \ + && ln -sf /dev/stdout /var/log/nginx/access.log \ + && ln -sf /dev/stderr /var/log/nginx/error.log + +RUN mkdir /var/cache/nginx/temp + +# Add available and enabled sites dir +# Symlink all available sites to enable them +RUN mkdir /etc/nginx/sites-available/ \ + && ln -sf /etc/nginx/sites-available/ /etc/nginx/sites-enabled + +VOLUME [ "/var/www", "/var/log/nginx" , "/etc/nginx" ] + +#WORKDIR /etc/nginx + +EXPOSE 80 + +CMD [ "nginx", "-g", "daemon off;" ] \ No newline at end of file diff --git a/Dockspec.rb b/Dockspec.rb new file mode 100644 index 0000000..dc4d680 --- /dev/null +++ b/Dockspec.rb @@ -0,0 +1,92 @@ +require "serverspec" +require "docker-api" + +describe "Dockerfile" do + before( :all ) do + print "Running Tests for Docker\n" + print " ---> Docker Version " + Docker.version["Version"] + "\n\n" + + @image = Docker::Image.build_from_dir( "." ) + + set :os, family: :debian, :release => '8' + set :backend, :docker + set :docker_image, @image.id + + @container = Docker::Container.create( + 'Image' => @image.id + ) + @container.start + + print " ---> Details\n" + print " OS: " + host_inventory["platform"] + print " " + host_inventory["platform_version"] + "\n" + print " Docker Container: " + host_inventory["hostname"] + "\n" + print " Memory: " + host_inventory["memory"]["total"] + "\n\n" + + print " ---> Running tests\n" + end + + after( :all ) do + print "\n\n ---> Cleaning up. Removing container." + @container.stop + @container.kill + @container.delete( :force => true ) + @image.remove( :force => true ) + end + + it "Image should exist" do + expect( @image ).to_not be_nil + end + + it "Installs the right OS" do + expect( command( "lsb_release -a" ).stdout ).to include( "Debian" ) + expect( command( "lsb_release -a" ).stdout ).to include( "jessie" ) + end + + it "Installs the right OS Version" do + expect( command( "cat /etc/debian_version" ).stdout ).to include( "8" ) + end + + it "Installs 'lsb-release' package" do + expect( package( "lsb-release" ) ).to be_installed + end + + it "Installs 'ca-certificates' package" do + expect( package( "ca-certificates" ) ).to be_installed + end + + it "Installs 'gettext-base' package" do + expect( package( "gettext-base" ) ).to be_installed + end + + it "Installs Nginx" do + expect( package( "nginx" ) ).to be_installed + end + + it "Nginx service should be enabled and running" do + expect( service( "nginx" ) ).to be_enabled + expect( service( "nginx" ) ).to be_running + end + + it "Nginx process should be running" do + expect( process( "nginx" ) ).to be_running + end + + it "Has a logs directory and routes stdout to log files" do + expect( file( "/etc/nginx/logs" ) ).to exist + expect( file( "/etc/nginx/logs" ) ).to be_directory + expect( file( "/var/log/nginx/access.log" ) ).to be_symlink + expect( file( "/var/log/nginx/error.log" ) ).to be_symlink + end + + it "Has a cache directory" do + expect( file( "/var/cache/nginx/temp" ) ).to exist + expect( file( "/var/cache/nginx/temp" ) ).to be_directory + end + + it "Has a sites config and sites enabled directory" do + expect( file( "/etc/nginx/sites-available" ) ).to exist + expect( file( "/etc/nginx/sites-available" ) ).to be_directory + expect( file( "/etc/nginx/sites-enabled" ) ).to be_symlink + end +end diff --git a/README.md b/README.md new file mode 100644 index 0000000..9178f70 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +## How To + +Test Nginx `.conf` file syntax + + docker exec nginx -t + +should print + +```shell +nginx: the configuration file /etc/nginx/nginx.conf syntax is ok +nginx: configuration file /etc/nginx/nginx.conf test is successful +``` + +Restart Nginx after `.conf` file changes + + docker exec nginx -s reload + +## Tests + +Currently there are acceptance tests shipped with this package. The specs +are run using Ruby and the following Gems: + + * rspec + * serverspec + * docker-api + +To run tests, you need Ruby and the listed Gems installed. The test can +be run on the command line: + +```shell +$ Print progress bar/dots while running tests +$ rspec --format progress Dockspec.rb +# Short notation +$ rspec -f p Dockspec.rb +# Verbose output (Print spec titles) while running tests +$ rspec --format documentation Dockspec.rb +# Short notation +$ rspec -f d Dockspec.rb +``` \ No newline at end of file diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..09a6344 --- /dev/null +++ b/compose.yml @@ -0,0 +1,15 @@ +version: '2' + +services: + nginx: + container_name: nginx + build: + context: . + volumes: + - ./sites-available/:/etc/nginx/sites-available/ + - ./nginx.conf:/etc/nginx/nginx.conf + - ./global:/etc/nginx/global/ + ports: + - "80:80" # Static file server + - "3000:3000" # Nodejs + restart: on-failure:3 \ No newline at end of file diff --git a/default.ssl b/default.ssl new file mode 100644 index 0000000..4bf8ba2 --- /dev/null +++ b/default.ssl @@ -0,0 +1,10 @@ +server { + listen 443; + + root /var/www/${NGINX_ROOT}; + index index.html index.htm; + + ssl on; + ssl_certificate /etc/nginx/ssl/server.crt; + ssl_certificate_key /etc/nginx/ssl/server.key; +} \ No newline at end of file diff --git a/global/basic.conf b/global/basic.conf new file mode 100644 index 0000000..cd73f6b --- /dev/null +++ b/global/basic.conf @@ -0,0 +1,8 @@ +# Basic configuration + +include global/directive-only/x-ua-compatible.conf; +include global/location/expires.conf; +include global/location/cross-domain-fonts.conf; +include global/location/protect-system-files.conf; +include global/location/robots.conf; +include global/location/favicons.conf; diff --git a/global/directive-only/cache-file-descriptors.conf b/global/directive-only/cache-file-descriptors.conf new file mode 100644 index 0000000..6957f80 --- /dev/null +++ b/global/directive-only/cache-file-descriptors.conf @@ -0,0 +1,19 @@ +# This tells Nginx to cache open file handles, "not found" errors, metadata about files and their permissions, etc. +# +# The upside of this is that Nginx can immediately begin sending data when a popular file is requested, +# and will also know to immediately send a 404 if a file is missing on disk, and so on. +# +# However, it also means that the server won't react immediately to changes on disk, which may be undesirable. +# +# In the below configuration, inactive files are released from the cache after 20 seconds, whereas +# active (recently requested) files are re-validated every 30 seconds. +# +# Descriptors will not be cached unless they are used at least 2 times within 20 seconds (the inactive time). +# +# A maximum of the 1000 most recently used file descriptors can be cached at any time. +# +# Production servers with stable file collections will definitely want to enable the cache. +open_file_cache max=1000 inactive=20s; +open_file_cache_valid 30s; +open_file_cache_min_uses 2; +open_file_cache_errors on; \ No newline at end of file diff --git a/global/directive-only/charset.conf b/global/directive-only/charset.conf new file mode 100644 index 0000000..c83569b --- /dev/null +++ b/global/directive-only/charset.conf @@ -0,0 +1,13 @@ +# Specify a charset +charset utf-8; + +# Update charset_types due to updated mime-types +charset_types + text/plain + text/xml + text/vnd.wap.wml + application/x-javascript + application/rss+xml + text/css + application/javascript + application/json; \ No newline at end of file diff --git a/global/directive-only/cookies.conf b/global/directive-only/cookies.conf new file mode 100644 index 0000000..57b6dde --- /dev/null +++ b/global/directive-only/cookies.conf @@ -0,0 +1,4 @@ + +# for "Set-Cookie" header field responses +proxy_cookie_domain www.$host $host; +proxy_cookie_domain localhost $host; \ No newline at end of file diff --git a/global/directive-only/cross-domain-insecure.conf b/global/directive-only/cross-domain-insecure.conf new file mode 100644 index 0000000..8935fac --- /dev/null +++ b/global/directive-only/cross-domain-insecure.conf @@ -0,0 +1,14 @@ +# Cross domain AJAX requests + +# http://www.w3.org/TR/cors/#access-control-allow-origin-response-header + +# **Security Warning** +# Do not use this without understanding the consequences. +# This will permit access from any other website. +# +add_header "Access-Control-Allow-Origin" "*"; + +# Instead of using this file, consider using a specific rule such as: +# +# Allow access based on [sub]domain: +# add_header "Access-Control-Allow-Origin" "subdomain.example.com"; \ No newline at end of file diff --git a/global/directive-only/extra-security.conf b/global/directive-only/extra-security.conf new file mode 100644 index 0000000..4074a0d --- /dev/null +++ b/global/directive-only/extra-security.conf @@ -0,0 +1,25 @@ +# The X-Frame-Options header indicates whether a browser should be allowed +# to render a page within a frame or iframe. +add_header X-Frame-Options SAMEORIGIN; + +# MIME type sniffing security protection +# There are very few edge cases where you wouldn't want this enabled. +add_header X-Content-Type-Options nosniff; + +# The X-XSS-Protection header is used by Internet Explorer version 8+ +# The header instructs IE to enable its inbuilt anti-cross-site scripting filter. +add_header X-XSS-Protection "1; mode=block"; + +# CSP/Content-Security-Policy to prevent Cross-site scripting (XSS) +# attacks and malicious eval executions +# @link http://www.html5rocks.com/en/tutorials/security/content-security-policy/ + +# with Content Security Policy (CSP) enabled (and a browser that supports it (http://caniuse.com/#feat=contentsecuritypolicy), +# you can tell the browser that it can only download content from the domains you explicitly allow +# CSP can be quite difficult to configure, and cause real issues if you get it wrong +# There is website that helps you generate a policy here http://cspisawesome.com/ + +# Add logs +add_header Content-Security-Policy-Report-Only "default-src 'self'; report-uri /$log_root/csp.warn.log;"; + +# add_header Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' https://www.google-analytics.com;"; \ No newline at end of file diff --git a/global/directive-only/gzip.conf b/global/directive-only/gzip.conf new file mode 100644 index 0000000..1d8c2d3 --- /dev/null +++ b/global/directive-only/gzip.conf @@ -0,0 +1,45 @@ +# Compression + +gzip on; + +# Enable compression both for HTTP/1.0 and HTTP/1.1 +gzip_http_version 1.0; + +# Tell proxies to cache both the gzipped and regular version of a resource +# whenever the client's Accept-Encoding capabilities header varies; +# Avoids the issue where a non-gzip capable client (which is extremely rare +# today) would display gibberish if their proxy gave them the gzipped version +gzip_vary on; + +# Compression level (1-9). +# 5 is a perfect compromise between size and cpu usage, offering about +# 75% reduction for most ascii files (almost identical to level 9) +gzip_comp_level 5; + +# Enable Gzip compression for files larger than 0.25Mb in file size +gzip_min_length 256; + +# Compress data even for clients that are connecting to us via proxies, +# identified by the "Via" header (required for CloudFront). +gzip_proxied any; + +# Compress all output labeled with one of the following MIME-types +gzip_types + text/plain + text/css + # application/rss+xml + # application/atom+xml + # application/xhtml+xml + # application/xml + # text/xml + application/vnd.ms-fontobject + application/x-font-ttf + font/opentype + image/svg+xml + text/javascript + application/javascript + application/x-javascript + image/x-icon; + +# Ignore what Microsoft ignores itself: Internet Explorer +gzip_disable "MSIE [1-6]\."; \ No newline at end of file diff --git a/global/directive-only/log.cache.conf b/global/directive-only/log.cache.conf new file mode 100644 index 0000000..22853f2 --- /dev/null +++ b/global/directive-only/log.cache.conf @@ -0,0 +1,8 @@ +# Stores the file descriptors of frequently used logs whose names contain variables +# At least 2 file uses in 20 seconds to keep the descriptor stay open in cache +# Maximum 1000 descriptors; Oldest get dropped first +open_log_file_cache + max=1000 + inactive=20s + valid=1m + min_uses=2; \ No newline at end of file diff --git a/global/directive-only/log.format.conf b/global/directive-only/log.format.conf new file mode 100644 index 0000000..fe6dc3a --- /dev/null +++ b/global/directive-only/log.format.conf @@ -0,0 +1,30 @@ +# Default logs - only used when not overriden by server {} directives +# Only allowed in "http" block. +# Only usable for "access_log" directives. + +# @TODO set to your own IP, to restrict public access +#debug_connection 1.2.3.4; + +## Log formats +# Main +log_format main + '$remote_addr - $remote_user [$time_iso8601] ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" ' + '"$http_x_forwarded_for" "$http_cookie"'; +# Full +log_format full + '$remote_addr $remote_user [$time_local] ' + '"$host"->$proxy_host->$upstream_addr ' + '"$request" $status($upstream_status) ' + '$bytes_sent/$gzip_ratio($sent_http_content_type) ' + '$request_time($upstream_response_time)'; +# Performance +log_format perf + '$request_time($upstream_response_time) ' + '$bytes_sent/$gzip_ratio($sent_http_content_type) ' + '$status "$upstream_addr$uri"'; +# GZip +log_format gzip + '$bytes_sent/$gzip_ratio($sent_http_content_type) ' + '[$http_accept_encoding]"$http_user_agent"'; \ No newline at end of file diff --git a/global/directive-only/log.verbose.conf b/global/directive-only/log.verbose.conf new file mode 100644 index 0000000..8826dfd --- /dev/null +++ b/global/directive-only/log.verbose.conf @@ -0,0 +1,10 @@ +# The following directives can be added to {http|server|location} blocks +# to enable more verbose and detailed logging. +# Should not be used on production servers. + +# Enable of not found files to error log +log_not_found on; +# Enable logging of sub requests into access log +log_subrequest on; +# Enable rewrite module logs into error log at [notice] level +rewrite_log on; \ No newline at end of file diff --git a/global/directive-only/no-transform.conf b/global/directive-only/no-transform.conf new file mode 100644 index 0000000..90171a9 --- /dev/null +++ b/global/directive-only/no-transform.conf @@ -0,0 +1,11 @@ +# Prevent mobile network providers from modifying your site +# +# (!) If you are using `ngx_pagespeed`, please note that setting +# the `Cache-Control: no-transform` response header will prevent +# `PageSpeed` from rewriting `HTML` files, and, if +# `pagespeed DisableRewriteOnNoTransform off` is not used, also +# from rewriting other resources. +# +# https://developers.google.com/speed/pagespeed/module/configuration#notransform + +add_header "Cache-Control" "no-transform"; \ No newline at end of file diff --git a/global/directive-only/proxy-cache.conf b/global/directive-only/proxy-cache.conf new file mode 100644 index 0000000..5530524 --- /dev/null +++ b/global/directive-only/proxy-cache.conf @@ -0,0 +1,43 @@ +# Do only cache GET and HEAD, but not POST requests +proxy_cache_methods GET HEAD; + +# "static" Proxy File Cache Path: +# cleared after 24h/once daily, +# 10Mb zone size (equals 80k keys) +# and 100Mb total size. When exceeded, removes least recently used data. +proxy_cache_path /var/cache/nginx + levels=1:2 + keys_zone=static:10m + inactive=24h + use_temp_path=off + max_size=100m; +proxy_max_temp_file_size 100m; +proxy_temp_path /var/tmp; + +# Enable to split cache between multiple HDs (Raid like) +#split_clients $request_uri $static { +# 100% "my_cache_hdd"; +#} + +# Only one request at a time will be allowed to populate a new cache element +# identified according to the proxy_cache_key directive by passing a request to a proxied server +proxy_cache_lock on; +# Time to keep the lock up until new update requests are allowed +proxy_cache_lock_age 3s; +proxy_cache_min_uses 2; +# Enable revalidation of cache keys +proxy_cache_revalidate on; +proxy_cache_valid 200 302 10m; +proxy_cache_valid 301 1h; +proxy_cache_valid any 1m; + +# The browser will send a Cache-Control: no-cache request header +# when reloaded holding the *shift* key +# In order to properly bypass the cache when requested to, +# nginx will honor Cache-Control headers +proxy_cache_bypass $http_cache_control; +# Do not cache Cookie requests +proxy_cache_bypass $cookie_nocache $arg_nocache; + +# Add proxy cache header to indicate cache status "{HIT,MISS,REVALIDATE}" +add_header X-Proxy-Cache $upstream_cache_status; \ No newline at end of file diff --git a/global/directive-only/proxy-defaults.conf b/global/directive-only/proxy-defaults.conf new file mode 100644 index 0000000..ba4a6f7 --- /dev/null +++ b/global/directive-only/proxy-defaults.conf @@ -0,0 +1,33 @@ +# Version 1.1 is recommended for use with keepalive connections +proxy_http_version 1.1; +# Needs to get cleared to enable keepalive connections to upstream servers +proxy_set_header Connection ""; + +# Set header to pass IP to the backend servers +proxy_set_header Host $host; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + +## Timeouts, Retries +# Timeout length for establishing a connection (max 75sec) +proxy_connect_timeout 5s; +# Defines a timeout for reading a response from the proxied server +proxy_read_timeout 10s; +proxy_send_timeout 10s; +# Try two times, then pass request to the next server +proxy_next_upstream_tries 2; +# Cases in which the request gets passed to the next server +proxy_next_upstream timeout invalid_header error http_502 http_503 http_504; +# Limits the time allowed to pass a request to the next server +proxy_next_upstream_timeout 5s; + +client_max_body_size 10m; +client_body_buffer_size 128k; + +## Cache for slow clients +# esponse is stored in the internal buffers and +# is not sent to the client until the whole response is received +proxy_buffer_size 4k; +proxy_buffers 4 32k; +proxy_busy_buffers_size 64k; +proxy_temp_file_write_size 64k; \ No newline at end of file diff --git a/global/directive-only/spdy.conf b/global/directive-only/spdy.conf new file mode 100644 index 0000000..35c2750 --- /dev/null +++ b/global/directive-only/spdy.conf @@ -0,0 +1,12 @@ +# Nginx's spdy module is compiled by default from 1.6 +# SPDY only works on HTTPS connections + +# Inform browser of SPDY availability +add_header Alternate-Protocol 443:npn-spdy/3; + +# Adjust connection keepalive for SPDY clients: +# up from 180 secs default +spdy_keepalive_timeout 300; + +# enable SPDY header compression +spdy_headers_comp 6; \ No newline at end of file diff --git a/global/directive-only/ssl-stapling.conf b/global/directive-only/ssl-stapling.conf new file mode 100644 index 0000000..36f083a --- /dev/null +++ b/global/directive-only/ssl-stapling.conf @@ -0,0 +1,15 @@ +# OCSP stapling... +# Fetch OCSP records from URL in ssl_certificate and cache them +ssl_stapling on; +ssl_stapling_verify on; + +# Trusted cert must be made up of your intermediate certificate followed by root certificate +# ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates.crt; + +# resolver ; +resolver 8.8.8.8 8.8.4.4 + 216.146.35.35 + 216.146.36.36 + valid=60s; + +resolver_timeout 2s; \ No newline at end of file diff --git a/global/directive-only/ssl.conf b/global/directive-only/ssl.conf new file mode 100644 index 0000000..adc19e6 --- /dev/null +++ b/global/directive-only/ssl.conf @@ -0,0 +1,53 @@ +# Settings according to Mozilla TLS recommendations +# Settings-Level: Medium +# @link https://wiki.mozilla.org/Security/Server_Side_TLS + +# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits +#ssl_dhparam /path/to/dhparam.pem; + +# Protect against the BEAST and POODLE attacks by not using SSLv3 at all. If you need to support older browsers (IE6) you may need to add +# SSLv3 to the list of protocols below. +ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + +# Ciphers set to best allow protection from Beast, while providing forwarding secrecy, as defined by Mozilla (Intermediate Set) - https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx +ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA; +ssl_prefer_server_ciphers on; + +# Optimize SSL by caching session parameters for 10 minutes. This cuts down on the number of expensive SSL handshakes. +# The handshake is the most CPU-intensive operation, and by default it is re-negotiated on every new/parallel connection. +# By enabling a cache (of type "shared between all Nginx workers"), we tell the client to re-use the already negotiated state. +# Further optimization can be achieved by raising keepalive_timeout, but that shouldn't be done unless you serve primarily HTTPS. +# A 1mb cache can hold about 4000 sessions, so we can hold 40000 sessions +ssl_session_cache shared:SSL:10m; +ssl_session_timeout 24h; + +# SSL buffer size was added in 1.5.9 +#ssl_buffer_size 1400; # 1400 bytes to fit in one MTU + +# Session tickets appeared in version 1.5.9 +# +# nginx does not auto-rotate session ticket keys: only a HUP / restart will do so and +# when a restart is performed the previous key is lost, which resets all previous +# sessions. The fix for this is to setup a manual rotation mechanism: +# http://trac.nginx.org/nginx/changeset/1356a3b9692441e163b4e78be4e9f5a46c7479e9/nginx +# +# Note that you'll have to define and rotate the keys securely by yourself. In absence +# of such infrastructure, consider turning off session tickets: +#ssl_session_tickets off; + +# Use a higher keepalive timeout to reduce the need for repeated handshakes +# up from 75 secs default +keepalive_timeout 300; + +# HSTS (HTTP Strict Transport Security) +# This header tells browsers to cache the certificate for a year and to connect exclusively via HTTPS. +#add_header Strict-Transport-Security "max-age=31536000;"; +# This version tells browsers to treat all subdomains the same as this site and to load exclusively over HTTPS +#add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; + +# This default SSL certificate will be served whenever the client lacks support for SNI (Server Name Indication). +# Make it a symlink to the most important certificate you have, so that users of IE 8 and below on WinXP can see your main site without SSL errors. +#ssl_certificate /etc/nginx/default_ssl.crt; +#ssl_certificate_key /etc/nginx/default_ssl.key; + +# Consider using OCSP Stapling as shown in ./ssl-stapling.conf \ No newline at end of file diff --git a/global/directive-only/x-ua-compatible.conf b/global/directive-only/x-ua-compatible.conf new file mode 100644 index 0000000..3f8cc52 --- /dev/null +++ b/global/directive-only/x-ua-compatible.conf @@ -0,0 +1,2 @@ +# Force the latest IE version +add_header "X-UA-Compatible" "IE=Edge"; \ No newline at end of file diff --git a/global/location/cache-busting.conf b/global/location/cache-busting.conf new file mode 100644 index 0000000..dab9d0e --- /dev/null +++ b/global/location/cache-busting.conf @@ -0,0 +1,10 @@ +# Built-in filename-based cache busting + +# https://github.com/h5bp/html5-boilerplate/blob/5370479476dceae7cc3ea105946536d6bc0ee468/.htaccess#L403 +# This will route all requests for /css/style.20120716.css to /css/style.css +# Read also this: github.com/h5bp/html5-boilerplate/wiki/cachebusting +# This is not included by default, because it'd be better if you use the build +# script to manage the file names. +location ~* (.+)\.(?:\d+)\.(js|css|png|jpg|jpeg|gif)$ { + try_files $uri $1.$2; +} \ No newline at end of file diff --git a/global/location/cross-domain-fonts.conf b/global/location/cross-domain-fonts.conf new file mode 100644 index 0000000..6d37b49 --- /dev/null +++ b/global/location/cross-domain-fonts.conf @@ -0,0 +1,13 @@ +# Cross domain webfont access +location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ { + include global/directive-only/cross-domain-insecure.conf; + + # Also, set cache rules for webfonts. + # + # See http://wiki.nginx.org/HttpCoreModule#location + # And https://github.com/h5bp/server-configs/issues/85 + # And https://github.com/h5bp/server-configs/issues/86 + expires 1M; + access_log off; + add_header Cache-Control "public"; +} \ No newline at end of file diff --git a/global/location/expires.conf b/global/location/expires.conf new file mode 100644 index 0000000..5ffb4e3 --- /dev/null +++ b/global/location/expires.conf @@ -0,0 +1,46 @@ +# Expire rules for static content + +# No default expire rule. This config mirrors that of apache as outlined in the +# html5-boilerplate .htaccess file. However, nginx applies rules by location, +# the apache rules are defined by type. A consequence of this difference is that +# if you use no file extension in the url and serve html, with apache you get an +# expire time of 0s, with nginx you'd get an expire header of one month in the +# future (if the default expire rule is 1 month). Therefore, do not use a +# default expire rule with nginx unless your site is completely static + +# cache.appcache, your document html and data +location ~* \.(?:manifest|appcache|html?|xml|json)$ { + expires -1; + access_log logs/static.log; +} + +# Feed +location ~* \.(?:rss|atom)$ { + expires 1h; + # Verbose, public "{MISS,HIT,REVALIDATE}" + add_header Cache-Control "public"; +} + +# Media: images, icons, video, audio, HTC +location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ { + expires 1M; + access_log off; + # Verbose, public "{MISS,HIT,REVALIDATE}" + add_header Cache-Control "public"; +} + +# CSS and Javascript +location ~* \.(?:css|js)$ { + expires modified +1y; + access_log off; + # Verbose, public "{MISS,HIT,REVALIDATE}" + add_header Cache-Control "public"; +} + +# WebFonts +# If you are NOT using cross-domain-fonts.conf, uncomment the following directive +# location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ { +# expires 1M; +# access_log off; +# add_header Cache-Control "public"; +# } \ No newline at end of file diff --git a/global/location/fastcgi.conf b/global/location/fastcgi.conf new file mode 100644 index 0000000..e69de29 diff --git a/global/location/favicons.conf b/global/location/favicons.conf new file mode 100644 index 0000000..decd8c6 --- /dev/null +++ b/global/location/favicons.conf @@ -0,0 +1,6 @@ + +# Don't spam logs in case there's no favicon (yet) +location /favicon.ico { + log_not_found off; + access_log off; +} \ No newline at end of file diff --git a/global/location/protect-system-files.conf b/global/location/protect-system-files.conf new file mode 100644 index 0000000..7f74747 --- /dev/null +++ b/global/location/protect-system-files.conf @@ -0,0 +1,16 @@ +# Prevent clients from accessing hidden files (starting with a dot) +# This is particularly important if you store .htpasswd files in the site hierarchy +# This includes our precious `.env` files +# Access to `/.well-known/` is allowed. +# https://www.mnot.net/blog/2010/04/07/well-known +# https://tools.ietf.org/html/rfc5785 +location ~* /\.(?!well-known\/) { + access_log off; + log_not_found off; + deny all; +} + +# Prevent clients from accessing to backup/config/source files +location ~* (?:\.(?:bak|conf|dist|fla|in[ci]|log|psd|sh|sql|sw[op])|~)$ { + deny all; +} \ No newline at end of file diff --git a/global/location/proxy.conf b/global/location/proxy.conf new file mode 100644 index 0000000..6ef83f5 --- /dev/null +++ b/global/location/proxy.conf @@ -0,0 +1,48 @@ +# Enable the following line to pass the upstream server Server-header +# instead of the proxy server header +# proxy_pass_header Server; + +# Turn off text that should be changed in the “Location” +# and “Refresh” header fields of a proxied server response +proxy_redirect off; + +# Version 1.1 is recommended for use with keepalive connections +proxy_http_version 1.1; + +# Needs to get cleared to enable keepalive connections to upstream servers +proxy_set_header Connection ""; +# Pass the real guest IP to the backend +proxy_set_header Host $host; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-By $server_addr:$server_port; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Proto http; + +# (!) The following will *not* work with HTTPs load balancer and HTTP app servers +# proxy_set_header X-Forwarded-Proto $scheme; +# The proxy interface to the backend should not compress the data (lan connection). +proxy_set_header Accept-Encoding ""; +# or… +# (i) Only set the following header when Nginx is compiled +# with the "gunzip" module "--with-http_gunzip_module" +# proxy_set_header Accept-Encoding "gzip"; + +# Hide Headers +proxy_hide_header Server; +proxy_hide_header X-Powered-By; + +## Timeouts, Retries +# Timeout length for establishing a connection (max 75sec) +proxy_connect_timeout 5s; +# Defines a timeout for reading a response from the proxied server +proxy_read_timeout 10s; +proxy_send_timeout 10s; +# Cases in which the request gets passed to the next server +proxy_next_upstream timeout invalid_header error http_502 http_503 http_504; +# Try two times, then pass request to the next server +proxy_next_upstream_tries 2; +# Limits the time allowed to pass a request to the next server +proxy_next_upstream_timeout 5s; + +## Buffer +proxy_buffers 32 4k; \ No newline at end of file diff --git a/global/location/restrictions.conf b/global/location/restrictions.conf new file mode 100644 index 0000000..b4d14c1 --- /dev/null +++ b/global/location/restrictions.conf @@ -0,0 +1,23 @@ + +# Add 1 month expires header for static assets +location ~* \.(jpg|jpeg|gif|png|css|js|ico)$ { + access_log off; + log_not_found off; + expires 30d; +} + +# WordPress specific: +# 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; +} + +# Directives to send expires headers and turn off 404 error logging. +location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ { + access_log off; + log_not_found off; + expires max; +} \ No newline at end of file diff --git a/global/location/robots.conf b/global/location/robots.conf new file mode 100644 index 0000000..1e02579 --- /dev/null +++ b/global/location/robots.conf @@ -0,0 +1,8 @@ + +# Give access to the (adorable, ignorable) crawler directives +# Don't spam logs in case there's nothing to see +location = /robots.txt { + allow all; + log_not_found off; + access_log off; +} \ No newline at end of file diff --git a/global/location/wordpress-ms-subdir.conf b/global/location/wordpress-ms-subdir.conf new file mode 100644 index 0000000..e69de29 diff --git a/global/location/wordpress-ms-subdomain.conf b/global/location/wordpress-ms-subdomain.conf new file mode 100644 index 0000000..e69de29 diff --git a/global/location/wordpress.conf b/global/location/wordpress.conf new file mode 100644 index 0000000..5365e3b --- /dev/null +++ b/global/location/wordpress.conf @@ -0,0 +1,27 @@ +# WordPress single site 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; +} + +# Add trailing slash to */wp-admin requests. +rewrite /wp-admin$ $scheme://$host$uri/ permanent; + +# Pass all .php files onto a php-fpm/php-fcgi server. +location ~ [^/]\.php(/|$) { + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + if (!-f $document_root$fastcgi_script_name) { + return 404; + } + # This is a robust solution for path info security issue + # and works with "cgi.fix_pathinfo = 1" in /etc/php.ini (default) + + include fastcgi_params; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + # fastcgi_intercept_errors on; + fastcgi_pass php; +} \ No newline at end of file diff --git a/global/mime.types b/global/mime.types new file mode 100644 index 0000000..ddc507e --- /dev/null +++ b/global/mime.types @@ -0,0 +1,110 @@ +# MIME Types nginx configuration +# @link https://github.com/h5bp/server-configs-nginx +types { + + # Audio + audio/midi mid midi kar; + audio/mp4 aac f4a f4b m4a; + audio/mpeg mp3; + audio/ogg oga ogg; + audio/x-realaudio ra; + audio/x-wav wav; + + # Images + image/bmp bmp; + image/gif gif; + image/jpeg jpeg jpg; + image/png png; + image/tiff tif tiff; + image/vnd.wap.wbmp wbmp; + image/webp webp; + image/x-icon ico cur; + image/x-jng jng; + + # JavaScript + application/javascript js; + application/json json; + + # Manifest files + application/x-web-app-manifest+json webapp; + text/cache-manifest manifest appcache; + + # Microsoft Office + application/msword doc; + application/vnd.ms-excel xls; + application/vnd.ms-powerpoint ppt; + application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; + application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; + + # Video + video/3gpp 3gpp 3gp; + video/mp4 mp4 m4v f4v f4p; + video/mpeg mpeg mpg; + video/ogg ogv; + video/quicktime mov; + video/webm webm; + video/x-flv flv; + video/x-mng mng; + video/x-ms-asf asx asf; + video/x-ms-wmv wmv; + video/x-msvideo avi; + + # Web feeds + application/xml atom rdf rss xml; + + # Web fonts + application/font-woff woff; + application/vnd.ms-fontobject eot; + application/x-font-ttf ttc ttf; + font/opentype otf; + image/svg+xml svg svgz; + + # Other + application/java-archive jar war ear; + application/mac-binhex40 hqx; + application/pdf pdf; + application/postscript ps eps ai; + application/rtf rtf; + application/vnd.wap.wmlc wmlc; + application/xhtml+xml xhtml; + application/vnd.google-earth.kml+xml kml; + application/vnd.google-earth.kmz kmz; + application/x-7z-compressed 7z; + application/x-chrome-extension crx; + application/x-opera-extension oex; + application/x-xpinstall xpi; + 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-bittorrent torrent; + 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; + application/octet-stream safariextz; + + text/css css; + text/html html htm shtml; + text/mathml mml; + text/plain txt; + text/vnd.sun.j2me.app-descriptor jad; + text/vnd.wap.wml wml; + text/vtt vtt; + text/x-component htc; + text/x-vcard vcf; + +} \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..c528af0 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,208 @@ +# nginx config file + +# @TODO https://www.nginx.com/resources/wiki/start/topics/examples/SSL-Offloader/ + +# How many worker threads to run; +# "auto" sets it to the number of CPU cores available in the system, and +# offers the best performance. Don't set it higher than the number of CPU +# cores if changing this parameter. +worker_processes auto; +# Better priority than other processes +worker_priority 0; +# In case the amount of CPUs is known, we can explicitly point a worker to a CPU +# @see http://nginx.org/en/docs/ngx_core_module.html#worker_cpu_affinity +worker_cpu_affinity auto; + +# Maximum open file descriptors per process; +# should be > worker_connections. +worker_rlimit_nofile 8192; + +pid /var/run/nginx.pid; + +events { + worker_connections 4096; + multi_accept on; + use epoll; +} + +stream { + + upstream mongodb_servers { + server mongodb:28017; + } + + server { + listen 28017; + proxy_pass mongodb_servers; + } + + +} + +http { + + # Hide nginx version information. + server_tokens off; + + default_type application/octet-stream; + include global/mime.types; + include global/directive-only/charset.conf; + #include global/directive-only/gzip.conf; + include global/directive-only/log.format.conf; + #include global/directive-only/cookies.conf; + #include global/directive-only/proxy-cache.conf; + #include global/directive-only/extra-security.conf; + + # Enable nginx error pages for response code ≥ 300 using "error_page" directive + #proxy_intercept_errors on; + + # Speed up file transfers by using sendfile() to copy directly + # between descriptors rather than using read()/write() + # @DEBUG Set to `off` when debugging to avoid cache + sendfile off; + + ## Timeouts + # How long the connection is allowed to stay idle and alive + keepalive_timeout 30 30; + client_header_timeout 10; + client_body_timeout 30; + # Between two operations + send_timeout 30; + + # Maximum upload size + #client_max_body_size ${NGINX_UPLOAD_LIMIT}; + + # Tell Nginx not to send out partial frames; this increases throughput + # since TCP frames are filled up before being sent out. (adds TCP_CORK) + tcp_nopush on; + + # Tell Nginx to enable the Nagle buffering algorithm for TCP packets, which + # collates several smaller packets together into one larger packet, thus saving + # bandwidth at the cost of a nearly imperceptible increase to latency. (removes TCP_NODELAY) + tcp_nodelay off; + + # Nginx will silently drop HTTP headers with underscores + # This is done in order to prevent ambiguities when mapping headers to CGI variables as both dashes + # and underscores are mapped to underscores during that process. + underscores_in_headers on; + + # this seems to be required for some vhosts + server_names_hash_bucket_size 128; + + disable_symlinks off; + + # Index order + index index.php index.html index.htm; + + upstream web_servers { + least_conn; + server docker.dev:80 max_fails=2 fail_timeout=10s; + server docker.dev:81 max_fails=2 fail_timeout=10s; + # Activate the cache for connections to upstream servers + # Sets the maximum number of idle keepalive connections to upstream servers + # that are preserved in the cache of each worker process + keepalive 25; + } + + upstream phpfpm_servers { + least_conn; + server php:9000 max_fails=2 fail_timeout=10s; + server php:9001 max_fails=2 fail_timeout=10s; + # Only allowed after setting the load balancing method + keepalive 25; + } + + upstream nodejs_servers { + least_conn; + server docker.dev:3000 max_fails=2 fail_timeout=10s; + keepalive 25; + } + + server { + listen 80 default_server; + listen [::]:80 default_server ipv6only=on; + + # Respond to all requests + server_name _; + + include global/location/favicons.conf; + + set $site_root /var/www/$host; + set $log_root var/log/nginx/$host; + + include global/directive-only/log.cache.conf; + include global/directive-only/log.verbose.conf; + + # Not possible to use variables for error_log + error_log /var/log/nginx/proxy.error.log debug; + access_log /$log_root/proxy.access.log full; + + error_page 404 =404 /40x.html; + + #client_max_body_size 10m; + #client_header_buffer_size 1k; + #client_body_buffer_size 128k; + + location /node { + proxy_pass http://nodejs_servers; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + } + + location ~* (\.php)$ { + root /$site_root; + + fastcgi_pass phpfpm_servers; + + #if (!-f $document_root$fastcgi_script_name) { + # return 404; + #} + fastcgi_keep_conn on; + + fastcgi_index index.php; + try_files $uri $uri/ /index.php; + #fastcgi_split_path_info ^(.+?\.php)(/.*)$; + + include /etc/nginx/fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + # Fixes $_SERVER["REMOTE_ADDR"] to equal "HTTP_X_REAL_IP" and "HTTP_X_FORWARDED_FOR" values + fastcgi_param REMOTE_ADDR $http_x_real_ip; + + #include global/location/proxy.conf; + } + + location /40x.html { + root /$site_root/errors; + internal; + error_page 404 =404 @fallback_404; + } + + # In case there were no site-specific error files + location @fallback_404 { + root /$site_root; + try_files /40x.html =404; + internal; + } + + location / { + root $site_root; + try_files $uri $uri/ @webproxy; + } + + location @webproxy { + # Add cache zone and header to show the cache status + #proxy_cache static; + + # Send requests to upstream servers array + proxy_pass http://web_servers; + + #include global/location/proxy.conf; + } + } + + # server{} configuration files should be placed in the sites-available folder + #include sites-enabled/*; +} \ No newline at end of file diff --git a/sites-available/docker.dev b/sites-available/docker.dev new file mode 100644 index 0000000..4c1c30f --- /dev/null +++ b/sites-available/docker.dev @@ -0,0 +1,32 @@ +# Redirect www. to non-www variant +# Permanent redirect to not get nuked by search engines +server { + listen 8080; + server_name www.docker.dev; + rewrite ^(.*) $scheme://docker.dev$1 permanent; +} + +# The actual HTTP server +server { + listen 8080; + listen [::]:8080 ipv6only=on; + + server_name docker.dev; + + # Add cache zones + proxy_cache static; + + error_log /var/log/nginx/docker.dev/error.log debug; + access_log /var/log/nginx/$host/access.log full; + + #root /var/www/docker.dev; + #error_page 502 /50x.html; + error_page 404 /40x.html; + + include global/basic.conf; + + location / { + default_type "text/html"; + try_files $uri $uri/ /index.php /index.html; + } +} \ No newline at end of file