From aae6e69d5cca04c0fff0f367cc24a61d4c602451 Mon Sep 17 00:00:00 2001 From: Nick Janetakis Date: Thu, 27 Oct 2016 17:43:31 -0400 Subject: [PATCH] Completely re-write role and support Ansible 2.0+ --- .travis.yml | 61 +-- CHANGES.md | 74 ++++ LICENSE | 22 + README.md | 408 +++++++++--------- defaults/main.yml | 108 +++-- files/etc/nginx/ssl/selfsigned.key | 28 ++ files/etc/nginx/ssl/selfsigned.pem | 21 + handlers/main.yml | 27 +- meta/main.yml | 16 +- tasks/main.yml | 117 +++-- templates/etc/nginx/nginx.conf.j2 | 40 ++ .../etc/nginx/sites-available/default.conf.j2 | 123 ++++++ templates/nginx_conf.j2 | 56 --- templates/nginx_sites-available.conf.j2 | 83 ---- tests/inventory | 1 - tests/main.yml | 16 + tests/server.js | 5 - tests/test.yml | 15 - 18 files changed, 738 insertions(+), 483 deletions(-) create mode 100644 CHANGES.md create mode 100644 LICENSE create mode 100644 files/etc/nginx/ssl/selfsigned.key create mode 100644 files/etc/nginx/ssl/selfsigned.pem create mode 100644 templates/etc/nginx/nginx.conf.j2 create mode 100644 templates/etc/nginx/sites-available/default.conf.j2 delete mode 100644 templates/nginx_conf.j2 delete mode 100644 templates/nginx_sites-available.conf.j2 delete mode 100644 tests/inventory create mode 100644 tests/main.yml delete mode 100644 tests/server.js delete mode 100644 tests/test.yml diff --git a/.travis.yml b/.travis.yml index b6ded3c..60444d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,39 +1,50 @@ --- -language: "python" -python: "2.7" + +sudo: required env: - - SITE_AND_INVENTORY="tests/test.yml -i tests/inventory" + - distro: 'ubuntu1604' + init: '/lib/systemd/systemd' + run_opts: '--privileged --volume=/sys/fs/cgroup:/sys/fs/cgroup:ro' + - distro: 'debian8' + init: '/lib/systemd/systemd' + run_opts: '--privileged --volume=/sys/fs/cgroup:/sys/fs/cgroup:ro' + +services: + - docker before_install: - - "sudo apt-get update -qq" + - 'docker pull geerlingguy/docker-${distro}-ansible:latest' -install: - - "pip install ansible==1.8.3" - - "echo '[defaults]' > ansible.cfg" - - "echo 'roles_path = ../' >> ansible.cfg" +script: + - container_id=$(mktemp) + - > + docker run + --detach + --volume="${PWD}":/etc/ansible/roles/this_role:ro ${run_opts} + geerlingguy/docker-${distro}-ansible:latest "${init}" > "${container_id}" -before_script: - - "cd tests && node server &" - - "sleep 3" - - "chmod 777 /tmp/testproject.sock" - - "openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -subj '/C=US/ST=Foo/L=Bar/O=Baz/CN=qux.com' -keyout /tmp/sslkey.key -out /tmp/sslcert.crt" + - > + docker exec --tty "$(cat ${container_id})" env TERM=xterm + ansible-playbook /etc/ansible/roles/this_role/tests/main.yml + --syntax-check + - > + docker exec --tty "$(cat ${container_id})" env TERM=xterm + ansible-playbook /etc/ansible/roles/this_role/tests/main.yml -script: - - "ansible-playbook $SITE_AND_INVENTORY --syntax-check" - - "ansible-playbook $SITE_AND_INVENTORY --connection=local -vvvv" + - idempotence=$(mktemp) + - > + docker exec "$(cat ${container_id})" + ansible-playbook /etc/ansible/roles/this_role/tests/main.yml + | tee -a ${idempotence} - > - ansible-playbook $SITE_AND_INVENTORY --connection=local + tail ${idempotence} | grep -q 'changed=0.*failed=0' && (echo 'Idempotence test: pass' && exit 0) || (echo 'Idempotence test: fail' && exit 1) + - > - curl -s -o /dev/null -w "%{http_code}" http://localhost:8080 - | grep -q '200' - && (echo 'HTTP test: pass' && exit 0) - || (echo 'HTTP test: fail' && exit 1) - - > - curl -k -s -o /dev/null -w "%{http_code}" https://localhost:8081 + curl -k -s -o /dev/null -w "%{http_code}" https://localhost | grep -q '200' - && (echo 'HTTPs test: pass' && exit 0) - || (echo 'HTTPs test: fail' && exit 1) + && (echo 'HTTPS test: pass' && exit 0) + || (echo 'HTTPS test: fail' && exit 1) diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..d67c6f7 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,74 @@ +# Changelog + +### v0.3.0 + +*Released: October 27nd 2016* + +- Support for multiple vhosts +- Support for 0 or 1 more optionally load balanced upstreams +- Add many more configurable `nginx.conf` variables +- Add more optional customizations for vhosts +- Generate self signed SSL certificates for non-production environments +- Forces HTTPS (seamless integration with Let's Encrypt with 3rd party roles) +- Generate a unique `dhparam.pem` file when it doesn't exist +- Test against Ubuntu 16.04 LTS and Debian Jessie on Travis-CI +- Update to Ansible 2.0+ + +### v0.2.0 + +*Released: February 18th 2014* + +- SSL protocols can be configured +- Redirect properly sets trailing forward slash + +Thanks to PRs https://github.com/nickjj/ansible-nginx/pull/4 and https://github.com/nickjj/ansible-nginx/pull/5. + +### v0.1.6 + +*Released: February 18th 2014* + +- Option to disable the custom PPA +- Option to disable spdy +- Option to configure `server_names_hash_bucket_size` + +Thanks to this PR https://github.com/nickjj/ansible-nginx/pull/3. + +### v0.1.5 + +*Released: June 12th 2014* + +- Merged #1 which introduces `nginx_ssl_manage_certs` (true / false) + - Now you can enable ssl but you can use whatever means necessary to transfer the certs + +### v0.1.4 + +*Released: August 18th 2014* + +- Fixed a bug that caused the handlers not to execute + +### v0.1.3 + +*Released: June 2nd 2014* + +- Fix a bug that caused testproj to be hard coded as the sites-available name +- Change nginx_extra_locations to take a text block so it's easier to add location block + +### v0.1.2 + +*Released: June 1st 2014* + +- Use a variable to store the apt-update cache time + +### v0.1.1 + +*Released: May 9th 2014* + +- Add a section linking to the Ansible Galaxy +- Update a few sentences and fix grammar mistakes +- Reload nginx if the SSL cert/key change + +### v0.1.0 + +*Released: May 9th 2014* + +- Initial release diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7b168ac --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016 Nick Janetakis nick.janetakis@gmail.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index e48b0ea..11891d7 100644 --- a/README.md +++ b/README.md @@ -1,249 +1,247 @@ -## WARNING: This role will be deprecated very soon - -All of the functionality provided by this role and more is available in the [DebOps project](http://debops.org). If you are using some of my roles in conjunction with each other, you will find the move to DebOps most pleasurable. +## What is ansible-nginx? [![Build Status](https://secure.travis-ci.org/nickjj/ansible-nginx.png)](http://travis-ci.org/nickjj/ansible-nginx) -This role will be **removed** from the **galaxy** and from **github** anywhere from 42 microseconds to 2-3 weeks after you read this message. +It is an [Ansible](http://www.ansible.com/home) role to install and configure +nginx. It has first class support for Let's Encrypt but works out of the box +with self signed SSL certificates for non-production environments. ---- +##### Supported platforms: +- Ubuntu 16.04 LTS (Xenial) +- Debian 8 (Jessie) -## What is ansible-nginx? [![Build Status](https://secure.travis-ci.org/nickjj/ansible-nginx.png)](http://travis-ci.org/nickjj/ansible-nginx) +### What problem does it solve and why is it useful? -It is an [ansible](http://www.ansible.com/home) role to install the latest version of nginx stable, configure a backend (upstream) and optionally configure ssl. +I wasn't happy with any of the nginx roles that I came across. They were either +overly complex or were missing features that I really wanted. -### What problem does it solve and why is it useful? +Here's what you get with this role: -I wasn't happy with any of the nginx roles that I came across. They were either overly complex, tried to be too modular by allowing you to define an entire backend using yaml syntax or were missing features that I really wanted. - -Here is a feature list of this role: - -- Configure an nginx server with sane defaults in less than 5 lines of yaml settings -- Change the listen ports for both http and https -- Toggle the ability to serve static assets and supply your own asset matching regex -- Toggle the ability to redirect a server to the www variant -- Add as many location blocks as you want with the least amount of pain -- Setup any number of error pages using the most simple syntax possible - - This is useful if you want custom 404, 500 or maintenance pages -- Define a root path and upsteam name/server location -- Optionally support ssl - - Toggle a single variable to turn ssl on or off - - Toggle whether or not http requests should redirect to https - - Transfer your cert/key to the server - - Choose the ssl type - - Pick the cipher and curve - - Support and set the strict transport header with tweakable values - - Support session caching and timeout with tweakable values +- Configure 1 or more sites-enabled (virtual hosts) +- Configure 0 or more upstreams per virtual host +- Configure a working site in as little as 3 lines of YAML +- Forced HTTPS with A+ certificate ratings (bearing your certificate authority) +- Self signed certs are generated to work out of the box for non-production environments +- First class support for Let's Encrypt SSL certificates for production environments +- Tune a bunch of `nginx.conf` settings for performance +- Allow you to optionally declare custom nginx and vhost directives easily +- Allow you to easily customize your upstream's proxy settings ## Role variables Below is a list of default values along with a description of what they do. ``` -# What port should nginx listen on for http requests? -nginx_listen: 80 - -# Your domain name. -nginx_base_domain: "{{ ansible_fqdn }}" - -# The server name. This could be the base domain or perhaps -# foo.{{ nginx_base_domain }} or www.{{ nginx_base_domain }} -nginx_server_name: "{{ nginx_base_domain }}" - -# Should it automatically redirect the base domain to the www version? -nginx_base_redirect_to_www: false - -# What type of backend are you using and what is its location? -nginx_upstream_name: testproject -nginx_upstream_server: unix:///srv/{{ nginx_upstream_name }}/tmp/puma.sock -nginx_backend_name: puma - -# Where are your public files stored? -nginx_root_path: /srv/{{ nginx_upstream_name }}/public - -# Should nginx serve static assets? -nginx_assets_enabled: true - -# The regex to match for serving static assets. -nginx_assets_regex: "~ ^/(system|assets)/" - -# A dict containing an array of error pages. -# If you have none then set the nginx_error_pages to be an empty string. -nginx_error_pages: - - { error_code: 404, error_page: 404.html } - - { error_code: 500, error_page: 500.html } - - { error_code: 502 503 504, error_page: 502.html } - -# By default there are no extra locations but you can add as many as you want. -# Don't forget the | to enable text blocks, feel free to use template tags too. -# The values must be valid nginx syntax, don't forget the semi-colons! -nginx_extra_locations: | -# location / { -# return; -# } -# -# location ~ ^/(images|javascript|js|css|flash|media|static)/ { -# # directive 1 would go here; -# # directive 2 would go here; -# # ... add as many directives as you want; -# } - -# If this is false then none of the ssl values are output to your nginx config. -nginx_ssl: false - -# Set this to false if you have a separate role that manages copying -# SSL certificates/keys to the server, and don't want this role -# to attempt copying your SSL keys over -nginx_ssl_manage_certs: true - -# What port should nginx listen on for https requests? -nginx_listen_ssl: 443 - -# Should all requests be redirected to https? -nginx_server_redirect_to_ssl: false - -# Legal values are: selfsigned, signed or wildcard -nginx_ssl_type: selfsigned - -# Perfect forward secrecy cipher. -nginx_ssl_ciphers: "EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4" - -# Best practice according to https://bettercrypto.org/. -nginx_ssl_ecdh_curve: secp384r1 - -# If you are using a wildcard certificate then which domain will be used? -nginx_ssl_wildcard_domain: "{{ ansible_domain }}" - -# http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security -nginx_ssl_strict_transport_header_age: 15768000 - -# Non-default values to increase performance, the nginx default is: -# nginx_ssl_session_cache: none -nginx_ssl_session_cache: shared:SSL:10m - -# Non-default values to increase performance, the nginx default is: -# nginx_ssl_session_timeout: 5m -nginx_ssl_session_timeout: 10m - -# What local path contains your cert and key? -nginx_ssl_local_path: /home/yourname/dev/testproject/secrets - -# What are the file names for both your cert and key? -nginx_ssl_cert_name: sslcert.crt -nginx_ssl_key_name: sslkey.key - -# Whicb SSL protocols should we support? -nginx_ssl_protocols: "TLSv1 TLSv1.1 TLSv1.2" - -# The amount in seconds to cache apt-update. -apt_cache_valid_time: 86400 - -# Should we install the Custom PPA for nginx? -# Disable this if you are not using Ubuntu. If you set nginx_configure_ppa to false, -# you will probably need to set 'nginx_spdy_enabled: false' too, since only the PPA version -# includes spdy. nginx_names_hash_bucket_size will also need to be set to 64 in most cases -nginx_configure_ppa: true - -# Should the SPDY extension be enabled? -nginx_spdy_enabled: true +--- -# Configure server_names_hash_bucket_size -nginx_names_hash_bucket_size: 32 +# Should nginx itself be installed? You may want to set this to False in +# situations where you use Ansible to provision a server but run everything +# inside of Docker containers. You could use this role to manage your configs +# but not run nginx by setting this to False. +nginx_install_service: True + +# Which user/group should nginx belong to? +nginx_user: 'www-data' + +# Various nginx config values set up to be efficient and secure, feel free to +# Google each one as needed for details. +nginx_worker_processes: 'auto' +nginx_worker_rlimit_nofile: 4096 +nginx_events_worker_connections: 1024 +nginx_http_server_tokens: 'off' +nginx_http_add_headers: + - 'X-Frame-Options SAMEORIGIN' + - 'X-Content-Type-Options nosniff' + - 'X-XSS-Protection "1; mode=block"' +nginx_http_server_names_hash_bucket_size: 64 +nginx_http_server_names_hash_max_size: 512 +nginx_http_sendfile: 'on' +nginx_http_tcp_nopush: 'on' +nginx_http_keepalive_timeout: 60 +nginx_http_client_max_body_size: '1m' +nginx_http_types_hash_max_size: 2048 +nginx_http_gzip: 'on' +nginx_http_gzip_disable: 'msie6' + +# Add your own custom nginx.conf directives in a list. +# Example: +# nginx_http_directives: +# - 'auth_http_header X-Auth-Key "secret_string"' +nginx_http_directives: [] + +# How many bits should we use to generate a dhparam? +# Technically 2048 is 'good enough' but 4096 combined with a few other +# things will get you to a perfect 100 A+ SSL rating, do not go below 2048. +# +# Time to generate on a 512MB DO droplet: 2048 = 40 seconds, 4096 = 40 minutes. +nginx_ssl_dhparam_bits: 2048 + +# Default values for your virtual hosts and upstreams. +nginx_default_sites: + # Name of the virtual host and file name of the config, example: default.conf. + default: + # 1 or more domains to be set for server_name. If you wish to support both + # www and no www then supply them like so: domains: ['foo.com', 'www.foo.com']. + # In the above case, www.foo.com will redirect to foo.com. + # If you want www in your URL then swap the order in the domains list. + domains: [] + # Will this virtual host be the default server? You should set this to + # True so that if someone accesses your server's IP address directly, it + # will automatically redirect to this vhost. + default_server: False + # Listen ports for both HTTP and HTTPS. + listen_http: 80 + listen_https: 443 + # Where are your public files located? + # If you're using an upstream, this will likely need to change to your web + # framework's public path, such as: /path/to/myapp/public. + root: '/usr/share/nginx/html' + # Do you have any custom directives for this vhost? + # Example: + # nginx_directives: + # - 'access_log logs/access.log combined' + directives: [] + ssl: + # Default SSL settings that get you an A+ rating as long as you chain your + # certificate with an intermediate certificate. + protocols: 'TLSv1 TLSv1.1 TLSv1.2' + ciphers: 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4' + prefer_server_ciphers: 'on' + session_cache: 'shared:SSL:50m' + session_timeout: '5m' + ssl_stapling: 'on' + ssl_stapling_verify: 'on' + resolver: '8.8.8.8' + resolver_timeout: '5s' + # You may want to consider adding ;preload once you're 100% confident + # that your server is working over HTTPS and you won't use HTTP for 2 years. + # See: https://www.owasp.org/index.php/HTTP_Strict_Transport_Security_Cheat_Sheet + sts_header: 'Strict-Transport-Security "max-age=63072000; includeSubdomains;"' + cache_all_locations: + # Shall we cache all requests for a bit of time? If so, how long? + enabled: True + duration: '30s' + error_pages: + # You will need to supply your own 404.html and 500.html files if you enable + # this. It's enabled by default because 99.9% of the time you do want these. + # You can disable this by setting, error_pages: []. + - { code: 404, page: '404.html' } + - { code: 500, page: '500.html' } + serve_assets: + # Let's serve assets through nginx, adjust the pattern depending on what web + # framework you use. Caching is set to maximum time because most frameworks + # have a way for you to md5 tag assets to cache bust them in one way or another. + # If your framework does not have that capability, disable the cache setting, + # or set it to a lower amount of your choosing. + enabled: True + pattern: ' ~ ^/assets/' + expires: 'max' + # Perhaps you'd like to include your own location blocks, no problem. Just add + # in your location block(s) as you would inside of an nginx config. Example: + # custom_locations: | + # location ~ / { + # return; + # } + custom_locations: '' + disallow_hidden_files: + # Block all hidden files and directories, disable at your own risk. + enabled: True + # Configure 0 or more upstreams in a list, the first item in the list will + # be the default try_files fall-back endpoint, for example: + # upstreams: + - name: 'myapp' + servers: ['localhost:3000'] + - name: 'websocketapp' + servers: ['localhost:3001'] + add_proxy_settings: + - 'proxy_http_version 1.1' + - 'proxy_set_header Upgrade $http_upgrade' + # The template that generates this config expects you to define at least + # the name and servers. It will blow up if you don't. + upstreams: [] + +# Customize the upstream's proxy settings if you want, these are the defaults +# and they will be pre-pended to your list of optional upstream proxy settings. +nginx_default_upstream_proxy_settings: + - 'proxy_set_header X-Real-IP $remote_addr' + - 'proxy_set_header X-Forwarded-Proto $scheme' + - 'proxy_set_header Host $http_host' + - 'proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for' + - 'proxy_redirect off' + +# If you're using Let's Encrypt, you can configure nginx to accept challenges to +# validate your domain(s). An HTTP based challenge is already set up for you. +# +# If you're using this role along with my LE role you don't need to touch this. +# +# That role can be found here: https://github.com/nickjj/ansible-letsencrypt +nginx_letsencrypt_root: '/usr/share/nginx/challenges' +# This is the value you'll set in your inventory to override any of the defaults +# from nginx_default_sites. A complete example is shown later on in this README. +nginx_sites: {} ``` -## Example playbook without ssl +## Example playbook -For the sake of this example let's assume you have a group called **app** and you have a typical `site.yml` file. +For the sake of this example let's assume you have a group called **app** and +you have a typical `site.yml` file. To use this role edit your `site.yml` file to look something like this: ``` --- -- name: ensure app servers are configured -- hosts: app + +- name: Configure app server(s) + hosts: app + become: True roles: - { role: nickjj.nginx, tags: nginx } ``` -Let's say you want to edit a few defaults, you can do this by opening or creating `group_vars/app.yml` which is located relative to your `inventory` directory and then making it look something like this: +Let's say you want to accomplish the following goals: -``` ---- -nginx_upstream_name: awesomeapp -nginx_base_redirect_to_www: true -``` - -## Example playbook with ssl - -First things first, make sure you read the section above because setting up the ssl version of this role is the same as the non-ssl version except it requires a few more defaults to be changed. - -#### Do you need an ssl certificate and key? - -If you just want to mess around and ensure your server responds correctly to https requests then you can use self signed keys. The downside to using self signed keys is that users of your site will see a giant warning saying your domain cannot be trusted because the keys are not verified. - -This is fine for testing because you can just click the proceed button and your site will work as planned. - -To generate your own self signed keys, open a terminal and goto some directory, let's say `~/tmp`. Within this directory enter the following command: - -`$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout sslkey.key -out sslcert.crt` - -That will generate both a certificate and key using 2048 bit encryption. Keep note of the path of where you created these files. - -#### Do you have a signed ssl certificate and key from a trusted source? - -Excellent, put them somewhere and keep note of their file names. - -#### You are ready to change a few defaults +- Set up your main site to work on non-www and www +- Have all www requests get redirected to non-www +- Set up the main host as the default server +- Set up an upstream to serve a back-end using your web framework of choice +- Load balance between 2 upstream servers +- Configure a blog sub-domain with assets being served by a CDN -Overwrite at least the following default value(s) in `group_vars/all.yml`: +Start by opening or creating `group_vars/app.yml` which is located relative +to your `inventory` directory and then making it look like this: ``` -nginx_ssl: true - -nginx_ssl_local_path: PUT_YOUR_CERT_AND_KEY_PATH_HERE - -# If you are using a signed key from a trusted source then you need to also change: -# nginx_ssl_type: signed +--- -# If your files are not called `sslcert.crt` and `sslkey.key` then overwrite them: -# nginx_ssl_cert_name: sslcert.crt -# nginx_ssl_key_name: sslkey.key +nginx_sites: + default: + domains: ['example.com', 'www.example.com'] + default_server: True + upstreams: + - name: 'myapp' + servers: ['localhost:3000', 'localhost:3001'] + blog: + domains: ['blog.example.com'] + serve_assets: + enabled: False ``` ## Installation `$ ansible-galaxy install nickjj.nginx` -## Requirements - -Tested on ubuntu 12.04 LTS but it should work on other versions that are similar. - -## Troubleshooting common errors - -#### The server hangs when trying to connect to either http or https -Assuming you have no syntax errors in your nginx config and the ansible run completed successfully then the most common error would be that you have a firewall blocking port 80 and/or port 443. - -If that's not the case then make sure your backend is working as intended and check any relevant log files. +## Ansible Galaxy -#### The ansible run finished without errors but you do not see any changes -This is likely due to their being a syntax error in your nginx config. Check your regular expressions, paths and if you are using extra locations then make sure they are all good. +You can find it on the official +[Ansible Galaxy](https://galaxy.ansible.com/nickjj/nginx/) if you want to +rate it. -Chances are you forgot a trailing semi-colon in one of the directives or some path didn't exist. - -You can ssh into the server manually and run `$ sudo service nginx reload`. If it fails then you can be sure there is a syntax error somewhere. - -#### None of my assets are being updated -I made an assumption that you are minifying, concatinating and tagging each asset with an md5 of their contents as well as gzipping them with maximum compression before hand as part of your build process. - -This is common for rails apps and apps developed with other web frameworks. With that said, I automatically set them to be cached for a year and turned `gzip_static on` for just those assets. - -If your web application does not perform the above tasks then you should start doing them but if you're stubborn or do not have the ability to make this decision then set `nginx_assets_enabled` to false and write your own location block with `nginx_extra_locations`. - -## Ansible galaxy +## License -You can find it on the official [ansible galaxy](https://galaxy.ansible.com/list#/roles/856) if you want to rate it. +MIT -## License +## Special thanks -MIT \ No newline at end of file +Thanks to [Maciej Delmanowski](https://twitter.com/drybjed) for helping me debug +a few tricky issues with this role. He is the creator of [DebOps](https://debops.org/). diff --git a/defaults/main.yml b/defaults/main.yml index e162a05..ed1efeb 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,54 +1,70 @@ --- -nginx_listen: 80 -nginx_configure_ppa: true -nginx_spdy_enabled: true -nginx_names_hash_bucket_size: 32 +nginx_install_service: True -nginx_base_domain: "{{ ansible_fqdn }}" -nginx_server_name: "{{ nginx_base_domain }}" -nginx_base_redirect_to_www: false +nginx_user: 'www-data' +nginx_worker_processes: 'auto' +nginx_worker_rlimit_nofile: 4096 +nginx_events_worker_connections: 1024 +nginx_http_server_tokens: 'off' +nginx_http_add_headers: + - 'X-Frame-Options SAMEORIGIN' + - 'X-Content-Type-Options nosniff' + - 'X-XSS-Protection "1; mode=block"' +nginx_http_server_names_hash_bucket_size: 64 +nginx_http_server_names_hash_max_size: 512 +nginx_http_sendfile: 'on' +nginx_http_tcp_nopush: 'on' +nginx_http_keepalive_timeout: 60 +nginx_http_client_max_body_size: '1m' +nginx_http_types_hash_max_size: 2048 +nginx_http_gzip: 'on' +nginx_http_gzip_disable: 'msie6' +nginx_http_directives: [] -nginx_upstream_name: testproject -nginx_upstream_server: unix:///srv/{{ nginx_upstream_name }}/tmp/puma.sock -nginx_backend_name: puma +nginx_ssl_dhparam_bits: 2048 -nginx_root_path: /srv/{{ nginx_upstream_name }}/public -nginx_assets_enabled: true -nginx_assets_regex: ~ ^/(system|assets)/ +nginx_default_sites: + default: + domains: [] + default_server: False + listen_http: 80 + listen_https: 443 + root: '/usr/share/nginx/html' + directives: [] + ssl: + protocols: 'TLSv1 TLSv1.1 TLSv1.2' + ciphers: 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4' + prefer_server_ciphers: 'on' + session_cache: 'shared:SSL:50m' + session_timeout: '5m' + ssl_stapling: 'on' + ssl_stapling_verify: 'on' + resolver: '8.8.8.8' + resolver_timeout: '5s' + sts_header: 'Strict-Transport-Security "max-age=63072000; includeSubdomains;"' + cache_all_locations: + enabled: True + duration: '30s' + error_pages: + - { code: 404, page: '404.html' } + - { code: 500, page: '500.html' } + serve_assets: + enabled: True + pattern: ' ~ ^/assets/' + expires: 'max' + custom_locations: '' + disallow_hidden_files: + enabled: True + upstreams: [] -nginx_error_pages: - - { error_code: 404, error_page: 404.html } - - { error_code: 500, error_page: 500.html } - - { error_code: 502 503 504, error_page: 502.html } +nginx_upstream_proxy_settings: + - 'proxy_set_header X-Real-IP $remote_addr' + - 'proxy_set_header X-Forwarded-Proto $scheme' + - 'proxy_set_header Host $http_host' + - 'proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for' + - 'proxy_redirect off' -nginx_extra_locations: | -# location / { -# return; -# } -# -# location ~ ^/(images|javascript|js|css|flash|media|static)/ { -# # directive 1 would go here; -# # directive 2 would go here; -# # ... add as many directives as you want; -# } +nginx_letsencrypt_root: '/usr/share/nginx/challenges' -nginx_ssl: false -nginx_listen_ssl: 443 -nginx_server_redirect_to_ssl: false - -nginx_ssl_type: selfsigned -nginx_ssl_ciphers: "EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4" -nginx_ssl_ecdh_curve: secp384r1 -nginx_ssl_wildcard_domain: "{{ ansible_domain }}" -nginx_ssl_strict_transport_header_age: 15768000 -nginx_ssl_session_cache: shared:SSL:10m -nginx_ssl_session_timeout: 10m - -nginx_ssl_manage_certs: true -nginx_ssl_local_path: /home/yourname/dev/testproject/secrets -nginx_ssl_cert_name: sslcert.crt -nginx_ssl_key_name: sslkey.key -nginx_ssl_protocols: "TLSv1 TLSv1.1 TLSv1.2" - -apt_cache_valid_time: 86400 +nginx_sites: {} diff --git a/files/etc/nginx/ssl/selfsigned.key b/files/etc/nginx/ssl/selfsigned.key new file mode 100644 index 0000000..c8f9c31 --- /dev/null +++ b/files/etc/nginx/ssl/selfsigned.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCmR93Cq3gETcqq +0PsIr8BCw8MYn7eL3WCzr8tRX5jTs1R45rrj/sof0Pp/yFMk0oFWIpdDKH+BK9l4 +YNuO1l2YPz6Dsiaw5TzBTkk0xctaCeSOKIMS6irZNZY5GNHgwhxPZPlmJNUTL/34 +WJ9vSpVWVC9mn2YmSD+gIJERnrTUbqcwruy0zOiM+NfBwJmOin0tfLqNrjj0XbWQ +TBzs5HYh2VngIyZ7qylLdjhnJtx6MrVbLfbWU4g9bZsGV3ux+oXLcM5EPabjPGfA +NJc3yNT6t8STI0fxglDAt8VkS2UG9b9ogMAXVvAn5B4IORPtts+TPh6qYVGX6oSo +TqWYj27fAgMBAAECggEBAI14K1ZKqGuQ+9Lkxg+X581l3IEAshqPGI0IDcWHvfCv +bDkIpQ0BY1o6ZEV/XC3B40QzXdpHhGOTuQxP67zU6QB1HmzRj1WFU3Frd6Esf1x1 +ejzwfsQC8r2md87QLRA6Vfe+gunCgH44oK1ASTVYkUHHkiSPjUsYwPkte/8vtc3d +j85MDIEj9t+baVOin/kO7yYCdmw09ypeEOnum9+fZMo3tC7NwNPINyJQyzsbbDDT +0Ng8R/A1xZCNCMugyhmQKacNg+d6Syqahgkf+LNEZzdPkKNEChybNKNwex8QCaGL +0PHUmGyNdYfKJSSHeepvwO2wqBmx+/DqSwO45HFwOdECgYEA0EyqJCjEyjE1v9kl +tHcOpZG5CWDK3RNMGZ3TrC3/KqcI3gdaJc4gyxUC0P7zakNmZnTfrvSRplXrwXM6 +ueg9KxmXrJjo07Od7qvYJttqqwB5OP5Qm+TrBe0X5kdqRrdJLcRIKl3KX4q66G/h +7bnlMsgz710r5r8tGupVoJxyGH0CgYEAzFvlu8l4TTWwodgKPCcga3+C9AVqSj4Z +weOwU4RAC0JEG8SAULvAEo4pqTpZe8NDappl0vL8MU3jyOC06bPyw3Y/hYiz/WTe +uGK0276y1X2DqZYILCIp9ZKwi2EcB8d412chuBuu8//+f0EafMHm2G1VeS7EpfWu +o4ALzmJJH4sCgYEAl2xD+0lP1ZR0eGTJDinGkgIfO3wLvS68EZs0N2SwrDcFMTKz +C+yO1lMN2xSbq1IX7L9lpG/SOdMYMWcs99ymKuDN7AC0sMFQPCLcXVMAdhNADHiD +7PA7EfHLf/HGhmXTYtvfgjzwUwgs27AJ06FhxsrXRli7A2FSztAvMzTHlJkCgYEA +iywqkHDslOhzmkTe84hR8+Oq8zSc5mLUd87wTnBKjWBbse1o1ZKHhBt9E9rBBiA8 +0WTE45zHU2yQLEWb72y1b5ggOniW24LOixPtx5lfgTUxbVTXy/aYTL3RrZo81K9s +BIYf2JpB07oLP+6+cyg6ZjpPc2/+TGe8v2x8ndkho3ECgYBhhyiFasxHrBF3ZvBh +SHOvD5GpKw353smBtcLeyUnvzF3YBYmGhivgkmeZd1OHktFe/0wvFxzUY9x5SXnd +kiHItnewvWXV6i7ZuE+BQBrOhGtRm/zmYKg/q19NTHjeknCt/Pk4x71nWcCFw+pX +bibjeog95hRDI1bCGrh2biYcNw== +-----END PRIVATE KEY----- diff --git a/files/etc/nginx/ssl/selfsigned.pem b/files/etc/nginx/ssl/selfsigned.pem new file mode 100644 index 0000000..705ac79 --- /dev/null +++ b/files/etc/nginx/ssl/selfsigned.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIJAKl4fCPxEeAUMA0GCSqGSIb3DQEBCwUAMEoxCzAJBgNV +BAYTAlVTMQswCQYDVQQIDAJOWTELMAkGA1UEBwwCTlkxDTALBgNVBAoMBE5vbmUx +EjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xNjEwMjIxNTAyMjNaFw0xNzEwMjIxNTAy +MjNaMEoxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOWTELMAkGA1UEBwwCTlkxDTAL +BgNVBAoMBE5vbmUxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKZH3cKreARNyqrQ+wivwELDwxift4vdYLOvy1FfmNOz +VHjmuuP+yh/Q+n/IUyTSgVYil0Mof4Er2Xhg247WXZg/PoOyJrDlPMFOSTTFy1oJ +5I4ogxLqKtk1ljkY0eDCHE9k+WYk1RMv/fhYn29KlVZUL2afZiZIP6AgkRGetNRu +pzCu7LTM6Iz418HAmY6KfS18uo2uOPRdtZBMHOzkdiHZWeAjJnurKUt2OGcm3Hoy +tVst9tZTiD1tmwZXe7H6hctwzkQ9puM8Z8A0lzfI1Pq3xJMjR/GCUMC3xWRLZQb1 +v2iAwBdW8CfkHgg5E+22z5M+HqphUZfqhKhOpZiPbt8CAwEAAaNQME4wHQYDVR0O +BBYEFLVq2BfQuxPL5j+GSIPAdOewcw9MMB8GA1UdIwQYMBaAFLVq2BfQuxPL5j+G +SIPAdOewcw9MMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAGwUZ9kE +yqqdVJa7RjMhW6lAdFaWLEu/7fZo8/3XYw5Vg++oCHPfbYVaEUlPbRWiR8gt/JrY +g+SNs5jvSUCOo82kkKlfC4QHBTlxUEUzU56bJnIkqbOJuLO0USoTPm1qNfr4XdnM +fnHDNBABLhOzPUw5YyF5pqaUEHvGgDGPtrFWSTqDlt7tB3f3KYSKQM3VxnJKpeYf +kFLv/GB8K0xyy+1hZRwXHjv1ylFSV7FdjpoLAblydq0BWHIg3SNSOGGO0s5hKI5q +EG95oGaKg1phLAqhwDn7SbT/j9WA33jmKoxy/W5jJQgr2noCkJKanXQfNrWwdRwF +0UDbE5LjvpabqwM= +-----END CERTIFICATE----- diff --git a/handlers/main.yml b/handlers/main.yml index 641767a..c1f0b61 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -1,6 +1,25 @@ --- -- name: restart nginx - service: name=nginx state=restarted -- name: reload nginx - service: name=nginx state=reloaded \ No newline at end of file +- name: Test nginx and restart + command: nginx -t + when: nginx_install_service + notify: + - 'Restart nginx' + +- name: Test nginx and reload + command: nginx -t + when: nginx_install_service + notify: + - 'Reload nginx' + +- name: Restart nginx + service: + name: 'nginx' + state: 'restarted' + when: nginx_install_service + +- name: Reload nginx + service: + name: 'nginx' + state: 'reloaded' + when: nginx_install_service diff --git a/meta/main.yml b/meta/main.yml index 58136a9..599f20e 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -1,19 +1,21 @@ ---- galaxy_info: author: Nick Janetakis - description: Install the latest stable version of nginx, configure sites-available and ssl. - company: - license: license (MIT) - min_ansible_version: 1.5 + description: Install and configure nginx (SSL A+ by default). + company: + license: license MIT + min_ansible_version: 2.0 platforms: - name: Ubuntu versions: - - all + - xenial + - name: Debian + versions: + - jessie categories: - system - networking - web -dependencies: [] \ No newline at end of file +dependencies: [] diff --git a/tasks/main.yml b/tasks/main.yml index 21b7cc1..d00192e 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,52 +1,97 @@ --- -- name: ensure ansible's apt_repository dependency is installed - apt: pkg=python-apt state=latest update_cache=true cache_valid_time={{ apt_cache_valid_time }} - when: nginx_configure_ppa -- name: ensure nginx apt repository is up to date - apt_repository: repo='ppa:nginx/stable' - when: nginx_configure_ppa - -- name: ensure nginx latest stable is installed - apt: pkg=nginx state=latest update_cache=true cache_valid_time={{ apt_cache_valid_time }} +- name: Install nginx + apt: + name: 'nginx' + state: 'present' + when: nginx_install_service notify: - - restart nginx + - Test nginx and restart + +- name: Create default nginx directories + file: + path: '{{ item }}' + state: 'directory' + owner: 'root' + group: 'root' + mode: '0755' + with_items: + - '/usr/share/nginx/html' + - '{{ nginx_letsencrypt_root }}' + - '/etc/nginx/sites-available' + - '/etc/nginx/sites-enabled' + - '/etc/nginx/conf.d' + - '/etc/nginx/ssl' -- name: ensure the default site is removed - file: path=/etc/nginx/sites-{{ item }}/default state=absent +- name: Remove default site + file: + path: '{{ item }}' + state: 'absent' with_items: - - enabled - - available + - '/var/www/html' + - '/etc/nginx/sites-enabled/default' + - '/etc/nginx/sites-available/default' notify: - - restart nginx + - Test nginx and reload -- name: ensure nginx ssl directory is created - file: path=/etc/nginx/ssl state=directory - when: nginx_ssl +- name: Configure nginx + template: + src: 'etc/nginx/nginx.conf.j2' + dest: '/etc/nginx/nginx.conf' + group: 'root' + owner: 'root' + mode: '0644' + register: nginx_register_nginx_config + notify: + - Test nginx and reload -- name: ensure nginx ssl certificate and key are created - copy: src={{ nginx_ssl_local_path }}/{{ item }} dest=/etc/nginx/ssl/{{ item }} mode=0600 - with_items: - - "{{ nginx_ssl_cert_name }}" - - "{{ nginx_ssl_key_name }}" - when: nginx_ssl and nginx_ssl_manage_certs +- name: Generate self signed SSL certificates + command: > + openssl req + -new + -newkey rsa:4096 + -days 365 + -nodes + -x509 + -subj "/C=US/ST=NY/L=NY/O=NA/CN=localhost" + -keyout /etc/nginx/ssl/{{ item.value.domains[0] }}.key + -out /etc/nginx/ssl/{{ item.value.domains[0] }}.pem + args: + creates: '/etc/nginx/ssl/{{ item.value.domains[0] }}.pem' + with_dict: '{{ nginx_sites }}' notify: - - reload nginx + - Test nginx and restart -- name: ensure nginx is configured - template: src=nginx_conf.j2 dest=/etc/nginx/nginx.conf group=root owner=root +- name: Generate X bit dhparam.pem file (this may take a while) + command: openssl dhparam -out /etc/nginx/ssl/dhparam.pem {{ nginx_ssl_dhparam_bits }} + args: + creates: '/etc/nginx/ssl/dhparam.pem' notify: - - reload nginx + - Test nginx and restart -- name: ensure sites-available is configured - template: src=nginx_sites-available.conf.j2 dest=/etc/nginx/sites-available/{{ nginx_upstream_name }} group=root owner=root +- name: Configure sites-enabled (vhosts) + template: + src: 'etc/nginx/sites-available/default.conf.j2' + dest: '/etc/nginx/sites-available/{{ item.key }}.conf' + group: 'root' + owner: 'root' + mode: '0644' + with_dict: '{{ nginx_sites }}' + register: nginx_register_vhost_config notify: - - reload nginx + - Test nginx and reload -- name: ensure sites-available is symlinked to sites-enabled - file: src=/etc/nginx/sites-available/{{ nginx_upstream_name }} dest=/etc/nginx/sites-enabled/{{ nginx_upstream_name }} state=link +- name: Symlink sites-available to sites-enabled + file: + src: '/etc/nginx/sites-available/{{ item.key }}.conf' + dest: '/etc/nginx/sites-enabled/{{ item.key }}.conf' + state: 'link' + with_dict: '{{ nginx_sites }}' notify: - - restart nginx + - Test nginx and restart -- name: ensure nginx starts on a fresh reboot - service: name=nginx state=started enabled=yes +- name: Forcefully restart nginx + service: + name: 'nginx' + state: 'restarted' + when: (nginx_register_nginx_config | changed) and (nginx_register_vhost_config | changed) diff --git a/templates/etc/nginx/nginx.conf.j2 b/templates/etc/nginx/nginx.conf.j2 new file mode 100644 index 0000000..708ce41 --- /dev/null +++ b/templates/etc/nginx/nginx.conf.j2 @@ -0,0 +1,40 @@ +# {{ ansible_managed }} + +user {{ nginx_user }}; +worker_processes {{ nginx_worker_processes }}; +worker_rlimit_nofile {{ nginx_worker_rlimit_nofile }}; + +events { + worker_connections {{ nginx_events_worker_connections }}; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + server_tokens {{ nginx_http_server_tokens }}; + {% if nginx_http_add_headers is iterable %} + {%- for header in nginx_http_add_headers -%} + add_header {{ header }}; + {% endfor -%} + {% endif %} + + server_names_hash_bucket_size {{ nginx_http_server_names_hash_bucket_size }}; + server_names_hash_max_size {{ nginx_http_server_names_hash_max_size }}; + sendfile {{ nginx_http_sendfile }}; + tcp_nopush {{ nginx_http_tcp_nopush }}; + keepalive_timeout {{ nginx_http_keepalive_timeout }}; + types_hash_max_size {{ nginx_http_types_hash_max_size }}; + client_max_body_size {{ nginx_http_client_max_body_size }}; + gzip {{ nginx_http_gzip }}; + gzip_disable "{{ nginx_http_gzip_disable }}"; + + {% if nginx_http_directives is iterable -%} + {% for key in nginx_http_directives %} + {{ key }}; + {% endfor %} + {% endif %} + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; +} diff --git a/templates/etc/nginx/sites-available/default.conf.j2 b/templates/etc/nginx/sites-available/default.conf.j2 new file mode 100644 index 0000000..4d6f47d --- /dev/null +++ b/templates/etc/nginx/sites-available/default.conf.j2 @@ -0,0 +1,123 @@ +# {{ ansible_managed }} + +{% set item = (nginx_default_sites['default'] | combine(item.value, recursive=True)) %} + +{% if item.upstreams %} +{%- for upstream in item.upstreams %} + +upstream {{ upstream.name }} { +{% for server in upstream.servers %} + server {{ server }}; +{% endfor %} +} +{% endfor %} +{% endif %} + +server { + listen {{ item.listen_http }}{{ ' default deferred' if item.default_server else '' }}; + server_name {{ item.domains | join(' ') }}; + root {{ nginx_letsencrypt_root }}; + + location /.well-known/acme-challenge/ { + default_type "text/plain"; + + try_files $uri =404; + } + + location / { + return 301 https://{{ item.domains[0] }}$request_uri; + } +} + +{% if (item.domains | length) > 1 %} +server { + listen {{ item.listen_https }} ssl; + server_name {{ item.domains[1] }}; + + return 301 https://{{ item.domains[0] }}$request_uri; +} +{% endif %} + +server { + listen {{ item.listen_https }} ssl{{ ' default deferred' if item.default_server else '' }}; + server_name {{ item.domains[0] }}; + root {{ item.root }}; +{% if item.directives is iterable %} +{% for directive in item.directives %} +{{ directive | indent(2, True) }}; +{% endfor %} +{% endif %} + + ssl_protocols {{ item.ssl.protocols }}; + ssl_ciphers "{{ item.ssl.ciphers }}"; + ssl_prefer_server_ciphers {{ item.ssl.prefer_server_ciphers }}; + ssl_session_cache {{ item.ssl.session_cache }}; + ssl_session_timeout {{ item.ssl.session_timeout }}; + ssl_stapling {{ item.ssl.ssl_stapling }}; + ssl_stapling_verify {{ item.ssl.ssl_stapling_verify }}; + resolver {{ item.ssl.resolver }}; + resolver_timeout {{ item.ssl.resolver_timeout }}; + add_header {{ item.ssl.sts_header }}; + + ssl_dhparam /etc/nginx/ssl/dhparam.pem; + ssl_certificate /etc/nginx/ssl/{{ item.domains[0] }}.pem; + ssl_certificate_key /etc/nginx/ssl/{{ item.domains[0] }}.key; + ssl_trusted_certificate /etc/nginx/ssl/{{ item.domains[0] }}.pem; + +{% if item.cache_all_locations.enabled %} + expires {{ item.cache_all_locations.duration }}; + add_header Cache-Control public; + add_header ETag ""; +{% endif %} + +{% if item.error_pages is iterable %} +{% for error in item.error_pages %} + error_page {{ error.code }} /{{ error.page }}; +{% endfor %} +{% endif %} +{% if item.serve_assets.enabled %} + + location {{ item.serve_assets.pattern }} { + expires {{ item.serve_assets.expires }}; + } +{% endif %} +{% if item.custom_locations %} + {{ item.custom_locations|indent(2) }} +{% endif %} + +{% if item.disallow_hidden_files.enabled %} + location ~ /\. { + return 404; + access_log off; + log_not_found off; + } +{% endif %} + + location = /favicon.ico { + try_files /favicon.ico =204; + access_log off; + log_not_found off; + } + + location / { + try_files $uri $uri.html $uri/{{ (' @' + item.upstreams[0].name) if (item.upstreams) else '' }} =404; + } +{% if item.upstreams %} +{% for upstream in item.upstreams %} + + location @{{ upstream.name }} { +{% if nginx_upstream_proxy_settings is iterable -%} +{% for key in nginx_upstream_proxy_settings %} + {{ key }}; +{% endfor %} +{% endif %} +{% if upstream.add_proxy_settings is defined -%} +{% for setting in upstream.add_proxy_settings %} + {{ setting }}; +{% endfor %} +{% endif %} + proxy_pass http://{{ upstream.name }}; + } +{% endfor %} +{% endif %} +} diff --git a/templates/nginx_conf.j2 b/templates/nginx_conf.j2 deleted file mode 100644 index 1d76aac..0000000 --- a/templates/nginx_conf.j2 +++ /dev/null @@ -1,56 +0,0 @@ -# {{ ansible_managed }} -# Manual customization of this file is not recommended. -user www-data; -worker_processes {{ ansible_processor_cores }}; -pid /run/nginx.pid; - -events { - worker_connections 1024; - # multi_accept on; -} - -http { - - ## - # Basic Settings - ## - - server_names_hash_bucket_size {{ nginx_names_hash_bucket_size }}; - - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 20; - types_hash_max_size 2048; - - include /etc/nginx/mime.types; - default_type application/octet-stream; - - ## - # Logging Settings - ## - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - ## - # Gzip Settings - ## - - gzip on; - gzip_disable "msie6"; - - gzip_vary on; - gzip_proxied any; - gzip_comp_level 6; - gzip_buffers 16 8k; - gzip_http_version 1.1; - gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; - - ## - # Virtual Host Configs - ## - - include /etc/nginx/conf.d/*.conf; - include /etc/nginx/sites-enabled/*; -} diff --git a/templates/nginx_sites-available.conf.j2 b/templates/nginx_sites-available.conf.j2 deleted file mode 100644 index 901c3c7..0000000 --- a/templates/nginx_sites-available.conf.j2 +++ /dev/null @@ -1,83 +0,0 @@ -# {{ ansible_managed }} -# Manual customization of this file is not recommended. -upstream {{ nginx_upstream_name }} { - server {{ nginx_upstream_server }}; -} - -{% if nginx_ssl %} -map $scheme $sts { - https "max-age={{ nginx_ssl_strict_transport_header_age }}; includeSubdomains;"; -} -{% endif %} - -{% if (nginx_base_redirect_to_www) %} -server { - listen {{ nginx_listen }}; - server_name {{ nginx_base_domain }}; - return 301 $scheme://www.{{ nginx_base_domain }}$request_uri; -} -{% endif %} - -{% if nginx_ssl %} -{% if (nginx_server_redirect_to_ssl) %} -server { - listen {{ nginx_listen }}; - server_name {{ nginx_server_name }}; - return 301 https://{{ nginx_server_name }}$request_uri; -} -{% endif %} -{% endif %} - -server { - listen {{ nginx_listen }}; -{% if nginx_ssl %} - listen {{ nginx_listen_ssl }} ssl{{ ' spdy' if nginx_spdy_enabled else ''}}; -{% endif %} - server_name {{ nginx_server_name }}; - root {{ nginx_root_path }}; - -{% if nginx_ssl %} - ssl_certificate /etc/nginx/ssl/{{ nginx_ssl_cert_name }}; - ssl_certificate_key /etc/nginx/ssl/{{ nginx_ssl_key_name }}; - ssl_session_cache {{ nginx_ssl_session_cache }}; - ssl_session_timeout {{ nginx_ssl_session_timeout }}; - ssl_prefer_server_ciphers on; - ssl_protocols {{ nginx_ssl_protocols }}; - ssl_ciphers {{ nginx_ssl_ciphers }}; - ssl_ecdh_curve {{ nginx_ssl_ecdh_curve }}; - add_header Strict-Transport-Security $sts; -{% endif %} - -{% if nginx_error_pages is iterable %} -{% for key in nginx_error_pages %} - error_page {{ key.error_code }} /{{ key.error_page }}; -{% endfor %} -{% endif %} - - location / { - try_files $uri @{{ nginx_backend_name }}; - } - - {{ nginx_extra_locations|indent(2) }} - -{% if nginx_assets_enabled %} - location {{ nginx_assets_regex }} { - gzip_static on; - - expires 1y; - add_header Cache-Control public; - add_header Last-Modified ""; - add_header ETag ""; - } -{% endif %} - - location @{{ nginx_backend_name }} { - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $http_host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_redirect off; - - proxy_pass http://{{ nginx_upstream_name }}; - } -} \ No newline at end of file diff --git a/tests/inventory b/tests/inventory deleted file mode 100644 index d18580b..0000000 --- a/tests/inventory +++ /dev/null @@ -1 +0,0 @@ -localhost \ No newline at end of file diff --git a/tests/main.yml b/tests/main.yml new file mode 100644 index 0000000..b7d4315 --- /dev/null +++ b/tests/main.yml @@ -0,0 +1,16 @@ +--- + +- hosts: all + vars: + nginx_ssl_dhparam_bits: 2048 + nginx_sites: + default: + domains: ['localhost'] + + pre_tasks: + - name: Update APT cache + apt: + update_cache: True + + roles: + - this_role diff --git a/tests/server.js b/tests/server.js deleted file mode 100644 index 36e178c..0000000 --- a/tests/server.js +++ /dev/null @@ -1,5 +0,0 @@ -var http = require('http'); -http.createServer(function (req, res) { - res.writeHead(200, {'Content-Type': 'text/plain'}); - res.end('Hello World'); -}).listen('/tmp/testproject.sock'); \ No newline at end of file diff --git a/tests/test.yml b/tests/test.yml deleted file mode 100644 index 33d8807..0000000 --- a/tests/test.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -- hosts: localhost - remote_user: travis - sudo: true - vars: - nginx_listen: 8080 - nginx_base_domain: localhost - nginx_upstream_server: unix:///tmp/testproject.sock - nginx_root_path: /tmp - nginx_listen_ssl: 8081 - nginx_ssl: true - nginx_ssl_local_path: /tmp - - roles: - - ansible-nginx \ No newline at end of file