├── .ansible-lint ├── .clog.toml ├── .editorconfig ├── .gitignore ├── .travis.yml ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── defaults └── main.yml ├── files └── etc │ └── nginx │ └── rules │ ├── cache_busting.conf │ ├── cors_ajax.conf │ ├── cors_web_fonts.conf │ ├── expires.conf │ ├── gzip.conf │ ├── gzip_static.conf │ ├── no_transform.conf │ ├── security.conf │ └── ssl.conf ├── handlers └── main.yml ├── meta ├── main.yml └── readme.yml ├── tasks ├── config.yml ├── install.yml ├── main.yml ├── manage.yml └── service.yml ├── templates └── etc │ └── nginx │ ├── nginx.conf.j2 │ └── sites-available │ ├── site-body.j2 │ ├── site-redirect.j2 │ └── site.j2 └── tests └── main.yml /.ansible-lint: -------------------------------------------------------------------------------- 1 | exclude_paths: 2 | - ./meta/readme.yml 3 | -------------------------------------------------------------------------------- /.clog.toml: -------------------------------------------------------------------------------- 1 | [clog] 2 | changelog = "CHANGELOG.md" 3 | repository = "https://github.com/weareinteractive/ansible-nginx" 4 | from-latest-tag = true 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | # Change these settings to your own preference 9 | indent_size = 2 10 | indent_style = space 11 | 12 | # We recommend you to keep these unchanged 13 | charset = utf-8 14 | end_of_line = lf 15 | insert_final_newline = true 16 | trim_trailing_whitespace = true 17 | 18 | [Makefile] 19 | indent_style = tab 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.retry 3 | .DS_Store 4 | .vagrant 5 | .vscode/* 6 | !.vscode/settings.json 7 | !.vscode/extensions.json 8 | .idea 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | sudo: required 3 | language: python 4 | services: 5 | - docker 6 | env: 7 | global: 8 | - role: weareinteractive.nginx 9 | matrix: 10 | - distribution: Ubuntu 11 | distribution_version: "18.04" 12 | init: /lib/systemd/systemd 13 | run_opts: "--privileged --volume=/sys/fs/cgroup:/sys/fs/cgroup:ro" 14 | # Skipping due to: AttributeError: 'module' object has no attribute 'SSL_ST_INIT' 15 | #- distribution: Ubuntu 16 | # distribution_version: "16.04" 17 | # init: /lib/systemd/systemd 18 | # run_opts: "--privileged --volume=/sys/fs/cgroup:/sys/fs/cgroup:ro" 19 | - distribution: Debian 20 | distribution_version: "9" 21 | init: /lib/systemd/systemd 22 | run_opts: "--privileged --volume=/sys/fs/cgroup:/sys/fs/cgroup:ro" 23 | - distribution: Debian 24 | distribution_version: "8" 25 | init: /lib/systemd/systemd 26 | run_opts: "--privileged --volume=/sys/fs/cgroup:/sys/fs/cgroup:ro" 27 | 28 | before_install: 29 | - sudo apt-get update 30 | - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce 31 | - docker pull ansiblecheck/ansiblecheck:"${distribution,,}"-"${distribution_version}" 32 | 33 | script: 34 | - container_id=$(mktemp) 35 | # Start The Built Container In The Background 36 | - 'docker run --detach --volume="${PWD}":/etc/ansible/roles/${role}:ro ${run_opts} ansiblecheck/ansiblecheck:"${distribution,,}"-"${distribution_version}" "${init}" > "${container_id}"' 37 | 38 | # Install dependencies 39 | - 'docker exec --tty "$(cat ${container_id})" env TERM=xterm ansible-galaxy install -c weareinteractive.apt weareinteractive.openssl weareinteractive.htpasswd' 40 | 41 | # Ansible syntax check. 42 | - 'docker exec --tty "$(cat ${container_id})" env TERM=xterm ansible-playbook /etc/ansible/roles/${role}/tests/main.yml --syntax-check' 43 | 44 | # Test role. 45 | - 'docker exec "$(cat ${container_id})" env ANSIBLE_FORCE_COLOR=1 ansible-playbook /etc/ansible/roles/${role}/tests/main.yml' 46 | 47 | # Test Idempotence 48 | - idempotence=$(mktemp) 49 | - docker exec "$(cat ${container_id})" ansible-playbook /etc/ansible/roles/${role}/tests/main.yml | tee -a ${idempotence} 50 | - > 51 | tail ${idempotence} 52 | | grep -q 'changed=0.*failed=0' 53 | && (echo 'Idempotence test: pass' && exit 0) 54 | || (echo 'Idempotence test: fail' && exit 1) 55 | 56 | notifications: 57 | webhooks: https://galaxy.ansible.com/api/v1/notifications/ 58 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "vscoss.vscode-ansible" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.yml": "ansible" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ### 2.0.1 (2020-05-04) 3 | 4 | 5 | 6 | 7 | 8 | ## 2.0.0 (2020-05-04) 9 | 10 | 11 | #### Features 12 | 13 | * move files to fit conventions ([fc20b264](https://github.com/weareinteractive/ansible-nginx/commit/fc20b2640014d08192c8b0000e5898de4969bf7b)) 14 | 15 | #### Breaking changes 16 | 17 | In order to upgrade from 1.x to 2.x you need to: 18 | 19 | * add extensions to `nginx_sites[].ssl.key_name` and `nginx_sites[].ssl.cert_name` i.e. `server.key` 20 | * in case of custom rules, change the location from `files/etc-nginx-rules` to `files/etc/nginx/rules` 21 | 22 | 23 | ## 1.5.0 (2019-10-18) 24 | 25 | 26 | #### Features 27 | 28 | * rename role ([95bb2d51](https://github.com/weareinteractive/ansible-nginx/commit/95bb2d51398f6e61c6330d2378a38e29438569c3)) 29 | * ensure config folders ([e27ebc86](https://github.com/weareinteractive/ansible-nginx/commit/e27ebc86c522fff78c088b84ca6e411ec93854e4)) 30 | * add depencies ([299f3844](https://github.com/weareinteractive/ansible-nginx/commit/299f38446f76359ca85d75db91cb7adcaca22f2e)) 31 | * ensure sites-enabled folder ([731d3546](https://github.com/weareinteractive/ansible-nginx/commit/731d354692b6c98af0412a8e97b89888cbb46dc2)) 32 | * bump ansible min version ([67b2c245](https://github.com/weareinteractive/ansible-nginx/commit/67b2c245f3f4594595fb281b9352295daa861e9a)) 33 | * update apt repository ([95a17572](https://github.com/weareinteractive/ansible-nginx/commit/95a17572b23145f68ee9376d4604093d967ad7af)) 34 | * use import_tasks ([0f2ad490](https://github.com/weareinteractive/ansible-nginx/commit/0f2ad4906914081ac244c707f7b3b221382edd79)) 35 | 36 | #### Bug Fixes 37 | 38 | * add apt key ([fe5c5ca6](https://github.com/weareinteractive/ansible-nginx/commit/fe5c5ca66aaa7d6dc6e64be7f67b22636fd99637)) 39 | 40 | 41 | 42 | 43 | ## 1.4.0 (2016-08-15) 44 | 45 | 46 | #### Features 47 | 48 | * readd restart handler ([6cb85d7d](https://github.com/weareinteractive/ansible-nginx/commit/6cb85d7d08d206a5d35fef833ac6974228a62dc7)) 49 | * use reload instead of restart ([8dd51d3f](https://github.com/weareinteractive/ansible-nginx/commit/8dd51d3fe4dfbf5a6b843562d5f4995810dd121f)) 50 | 51 | 52 | 53 | 54 | ## 1.3.0 (2016-07-27) 55 | 56 | 57 | #### Features 58 | 59 | * update syntax for ansible 2.0 ([669ceaf9](https://github.com/weareinteractive/ansible-nginx/commit/669ceaf9cdf3bef2d4b4d71bab0db75d6fa89019)) 60 | * add CHANGELOG ([34ed15ac](https://github.com/weareinteractive/ansible-nginx/commit/34ed15ac8998e491c8f79a1311ddca518f5c0899)) 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) We Are Interactive 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PWD=$(shell pwd) 2 | ROLE_NAME=weareinteractive.nginx 3 | ROLE_PATH=/etc/ansible/roles/$(ROLE_NAME) 4 | TEST_VERSION=ansible --version 5 | TEST_DEPS=ansible-galaxy install -c weareinteractive.apt weareinteractive.openssl weareinteractive.htpasswd 6 | TEST_SYNTAX=ansible-playbook -v -i 'localhost,' -c local $(ROLE_PATH)/tests/main.yml --syntax-check 7 | TEST_PLAYBOOK=ansible-playbook -vvvv -i 'localhost,' -c local $(ROLE_PATH)/tests/main.yml 8 | TEST_IDEMPOTENT=$(TEST_PLAYBOOK) | grep -q 'changed=0.*failed=0' && (echo 'Idempotence test: pass' && exit 0) || (echo 'Idempotence test: fail' && exit 1) 9 | TEST_CMD=$(TEST_DEPS); $(TEST_VERSION); $(TEST_SYNTAX); $(TEST_PLAYBOOK); $(TEST_IDEMPOTENT) 10 | 11 | docs: 12 | ansible-role docgen 13 | 14 | lint: 15 | ansible-lint . 16 | 17 | ubuntu%: TEST_DEPS+=\ 18 | && apt-get update \ 19 | && apt-get install -y python-setuptools python-openssl python-pip 20 | 21 | ubuntu18.04: dist=ubuntu-18.04 22 | ubuntu18.04: .run 23 | 24 | ubuntu16.04: dist=ubuntu-16.04 25 | ubuntu16.04: .run 26 | 27 | debian%: TEST_DEPS+=\ 28 | && apt-get update 29 | 30 | debian9: dist=debian-9 31 | debian9: .run 32 | 33 | debian8: dist=debian-8 34 | debian8: .run 35 | 36 | .run: 37 | @echo "RUN:" 38 | @echo " docker run -it --rm -v $(PWD):$(ROLE_PATH) ansiblecheck/ansiblecheck:$(dist) /bin/bash" 39 | @echo " $(TEST_CMD)" 40 | @docker run -it --rm -v $(PWD):$(ROLE_PATH) ansiblecheck/ansiblecheck:$(dist) /bin/bash -c "$(TEST_CMD)" 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible weareinteractive.nginx role 2 | 3 | [![Build Status](https://img.shields.io/travis/weareinteractive/ansible-nginx.svg)](https://travis-ci.org/weareinteractive/ansible-nginx) 4 | [![Galaxy](http://img.shields.io/badge/galaxy-weareinteractive.nginx-blue.svg)](https://galaxy.ansible.com/weareinteractive/nginx) 5 | [![GitHub Tags](https://img.shields.io/github/tag/weareinteractive/ansible-nginx.svg)](https://github.com/weareinteractive/ansible-nginx) 6 | [![GitHub Stars](https://img.shields.io/github/stars/weareinteractive/ansible-nginx.svg)](https://github.com/weareinteractive/ansible-nginx) 7 | 8 | > `weareinteractive.nginx` is an [Ansible](http://www.ansible.com) role which: 9 | > 10 | > * installs nginx 11 | > * configures nginx 12 | > * creates sites 13 | > * enables/disables sites 14 | > * optionally removes default host 15 | > * adds rules 16 | > * configures service 17 | 18 | **Note:** 19 | 20 | > Since Ansible Galaxy supports [organization](https://www.ansible.com/blog/ansible-galaxy-2-release) now, this role has moved from `franklinkim.nginx` to `weareinteractive.nginx`! 21 | 22 | ## Installation 23 | 24 | Using `ansible-galaxy`: 25 | 26 | ```shell 27 | $ ansible-galaxy install weareinteractive.nginx 28 | ``` 29 | 30 | Using `requirements.yml`: 31 | 32 | ```yaml 33 | - src: weareinteractive.nginx 34 | ``` 35 | 36 | Using `git`: 37 | 38 | ```shell 39 | $ git clone https://github.com/weareinteractive/ansible-nginx.git weareinteractive.nginx 40 | ``` 41 | 42 | ## Dependencies 43 | 44 | * Ansible >= 2.4 45 | ## Related (see example) 46 | 47 | * [weareinteractive.openssl](https://github.com/weareinteractive/ansible-openssl) 48 | * [weareinteractive.htpasswd](https://github.com/weareinteractive/ansible-htpasswd) 49 | 50 | ## Variables 51 | 52 | Here is a list of all the default variables for this role, which are also available in `defaults/main.yml`. 53 | 54 | ```yaml 55 | --- 56 | 57 | # nginx_sites: 58 | # - id: foo (required) 59 | # name: foo.com (required) 60 | # ip: '*' 61 | # port: 80 62 | # state: present 63 | # add_webroot: no 64 | # template: path/to/template.j2 65 | # aliases: [] 66 | # redirects: [] 67 | # ssl: 68 | # port: 443 69 | # key_name: mykey.key 70 | # key_path: path/to/key 71 | # cert_name: mycert.crt 72 | # cert_path: path/to/cert 73 | # rules: [] 74 | # auth: 75 | # name: foo 76 | # file: foo 77 | # append: '' 78 | # 79 | 80 | # dependencies packages to install package 81 | nginx_dependencies: 82 | - ca-certificates 83 | - gnupg2 84 | # apt repository 85 | nginx_repo: "deb http://nginx.org/packages/{{ ansible_distribution|lower }}/ {{ ansible_distribution_release }} nginx" 86 | # apt repository key 87 | nginx_repo_key: ABF5BD827BD9BF62 88 | # package name (version) 89 | nginx_package: nginx 90 | # run as a less privileged user for security reasons. 91 | nginx_user: www-data 92 | # number or auto 93 | nginx_worker_processes: 1 94 | nginx_worker_connections: 1024 95 | # default settings 96 | nginx_sendfile: 'on' 97 | nginx_tcp_nopush: 'on' 98 | nginx_tcp_nodelay: 'on' 99 | nginx_keepalive_timeout: 15 100 | nginx_types_hash_max_size: 2048 101 | nginx_server_names_hash_bucket_size: 128 102 | nginx_server_tokens: 'off' 103 | # remove default site 104 | nginx_remove_default: no 105 | # start on boot 106 | nginx_service_enabled: yes 107 | # current state: started, stopped 108 | nginx_service_state: started 109 | # enabled/disabled sites 110 | nginx_sites: [] 111 | # add rules 112 | nginx_add_rules: yes 113 | 114 | ``` 115 | 116 | ## Handlers 117 | 118 | These are the handlers that are defined in `handlers/main.yml`. 119 | 120 | ```yaml 121 | --- 122 | 123 | - name: restart nginx 124 | service: name=nginx state=restarted 125 | when: nginx_service_state != 'stopped' 126 | 127 | - name: reload nginx 128 | service: name=nginx state=reloaded 129 | when: nginx_service_state != 'stopped' 130 | 131 | ``` 132 | 133 | ## Rules 134 | 135 | If `nginx_add_rules` is `yes`, it will copy some configuration rules to `/etc/nginx/rules`: 136 | 137 | * cache_busting.conf 138 | * cors_web_fonts.conf 139 | * gzip.conf 140 | * no_transform.conf 141 | * ssl.conf 142 | * cors_ajax.con 143 | * expires.conf 144 | * gzip_static.conf 145 | * security.conf 146 | 147 | ## Usage 148 | 149 | This is an example playbook: 150 | 151 | ```yaml 152 | --- 153 | 154 | - hosts: all 155 | become: yes 156 | roles: 157 | - weareinteractive.apt 158 | - weareinteractive.openssl 159 | - weareinteractive.htpasswd 160 | - weareinteractive.nginx 161 | vars: 162 | htpasswd: 163 | - name: foobar 164 | users: 165 | - { name: foobar, password: foobar } 166 | openssl_generate_csr: yes 167 | openssl_self_signed: 168 | - name: fooboar.local 169 | subject: 170 | C: DE 171 | ST: Bavaria 172 | L: Munich 173 | O: Foo Bar Inc 174 | CN: foobar.local 175 | emailAddress: null@foobar.local 176 | nginx_sites: 177 | - id: foobar 178 | add_webroot: yes 179 | name: foobar.local 180 | ssl: 181 | key_name: foobar.local.key 182 | cert_name: foobar.local.crt 183 | rules: 184 | - gzip 185 | - security 186 | auth: 187 | name: Foo Bar 188 | file: foobar 189 | nginx_worker_processes: 1 190 | nginx_remove_default: yes 191 | # do not start service as we're running in docker 192 | nginx_service_state: stopped 193 | nginx_service_enabled: no 194 | 195 | ``` 196 | 197 | 198 | ## Testing 199 | 200 | ```shell 201 | $ git clone https://github.com/weareinteractive/ansible-nginx.git 202 | $ cd ansible-nginx 203 | $ make test 204 | ``` 205 | 206 | ## Contributing 207 | In lieu of a formal style guide, take care to maintain the existing coding style. Add unit tests and examples for any new or changed functionality. 208 | 209 | 1. Fork it 210 | 2. Create your feature branch (`git checkout -b my-new-feature`) 211 | 3. Commit your changes (`git commit -am 'Add some feature'`) 212 | 4. Push to the branch (`git push origin my-new-feature`) 213 | 5. Create new Pull Request 214 | 215 | *Note: To update the `README.md` file please install and run `ansible-role`:* 216 | 217 | ```shell 218 | $ gem install ansible-role 219 | $ ansible-role docgen 220 | ``` 221 | 222 | ## License 223 | Copyright (c) We Are Interactive under the MIT license. 224 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # nginx_sites: 4 | # - id: foo (required) 5 | # name: foo.com (required) 6 | # ip: '*' 7 | # port: 80 8 | # state: present 9 | # add_webroot: no 10 | # template: path/to/template.j2 11 | # aliases: [] 12 | # redirects: [] 13 | # ssl: 14 | # port: 443 15 | # key_name: mykey.key 16 | # key_path: path/to/key 17 | # cert_name: mycert.crt 18 | # cert_path: path/to/cert 19 | # rules: [] 20 | # auth: 21 | # name: foo 22 | # file: foo 23 | # append: '' 24 | # 25 | 26 | # dependencies packages to install package 27 | nginx_dependencies: 28 | - ca-certificates 29 | - gnupg2 30 | # apt repository 31 | nginx_repo: "deb http://nginx.org/packages/{{ ansible_distribution|lower }}/ {{ ansible_distribution_release }} nginx" 32 | # apt repository key 33 | nginx_repo_key: ABF5BD827BD9BF62 34 | # package name (version) 35 | nginx_package: nginx 36 | # run as a less privileged user for security reasons. 37 | nginx_user: www-data 38 | # number or auto 39 | nginx_worker_processes: 1 40 | nginx_worker_connections: 1024 41 | # default settings 42 | nginx_sendfile: 'on' 43 | nginx_tcp_nopush: 'on' 44 | nginx_tcp_nodelay: 'on' 45 | nginx_keepalive_timeout: 15 46 | nginx_types_hash_max_size: 2048 47 | nginx_server_names_hash_bucket_size: 128 48 | nginx_server_tokens: 'off' 49 | # remove default site 50 | nginx_remove_default: no 51 | # start on boot 52 | nginx_service_enabled: yes 53 | # current state: started, stopped 54 | nginx_service_state: started 55 | # enabled/disabled sites 56 | nginx_sites: [] 57 | # add rules 58 | nginx_add_rules: yes 59 | -------------------------------------------------------------------------------- /files/etc/nginx/rules/cache_busting.conf: -------------------------------------------------------------------------------- 1 | # Built-in filename-based cache busting 2 | 3 | # https://github.com/h5bp/html5-boilerplate/blob/5370479476dceae7cc3ea105946536d6bc0ee468/.htaccess#L403 4 | # This will route all requests for /css/style.20120716.css to /css/style.css 5 | # Read also this: github.com/h5bp/html5-boilerplate/wiki/cachebusting 6 | # This is not included by default, because it'd be better if you use the build 7 | # script to manage the file names. 8 | location ~* (.+)\.(?:\d+)\.(js|css|png|jpg|jpeg|gif)$ { 9 | try_files $uri $1.$2; 10 | } 11 | -------------------------------------------------------------------------------- /files/etc/nginx/rules/cors_ajax.conf: -------------------------------------------------------------------------------- 1 | # Cross domain AJAX requests 2 | add_header "Access-Control-Allow-Origin" "*"; 3 | -------------------------------------------------------------------------------- /files/etc/nginx/rules/cors_web_fonts.conf: -------------------------------------------------------------------------------- 1 | # Cross domain webfont access 2 | location ~* \.(?:ttf|ttc|otf|eot|woff)$ { 3 | add_header "Access-Control-Allow-Origin" "*"; 4 | 5 | # Also, set cache rules for webfonts. 6 | # 7 | # See http://wiki.nginx.org/HttpCoreModule#location 8 | # And https://github.com/h5bp/server-configs/issues/85 9 | # And https://github.com/h5bp/server-configs/issues/86 10 | expires 1M; 11 | access_log off; 12 | add_header Cache-Control "public"; 13 | } 14 | -------------------------------------------------------------------------------- /files/etc/nginx/rules/expires.conf: -------------------------------------------------------------------------------- 1 | # Expire rules for static content 2 | 3 | # No default expire rule. This config mirrors that of apache as outlined in the 4 | # html5-boilerplate .htaccess file. However, nginx applies rules by location, 5 | # the apache rules are defined by type. A concequence of this difference is that 6 | # if you use no file extension in the url and serve html, with apache you get an 7 | # expire time of 0s, with nginx you'd get an expire header of one month in the 8 | # future (if the default expire rule is 1 month). Therefore, do not use a 9 | # default expire rule with nginx unless your site is completely static 10 | 11 | # cache.appcache, your document html and data 12 | location ~* \.(?:manifest|appcache|html?|xml|json)$ { 13 | expires -1; 14 | access_log /var/log/nginx/static.log; 15 | } 16 | 17 | # Feed 18 | location ~* \.(?:rss|atom)$ { 19 | expires 1h; 20 | add_header Cache-Control "public"; 21 | } 22 | 23 | # Media: images, icons, video, audio, HTC 24 | location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ { 25 | expires 1M; 26 | access_log off; 27 | add_header Cache-Control "public"; 28 | } 29 | 30 | # CSS and Javascript 31 | location ~* \.(?:css|js)$ { 32 | expires 1y; 33 | access_log off; 34 | add_header Cache-Control "public"; 35 | } 36 | 37 | # WebFonts 38 | # If you are NOT using cross-domain-fonts.conf, uncomment the following directive 39 | # location ~* \.(?:ttf|ttc|otf|eot|woff)$ { 40 | # expires 1M; 41 | # access_log off; 42 | # add_header Cache-Control "public"; 43 | # } 44 | -------------------------------------------------------------------------------- /files/etc/nginx/rules/gzip.conf: -------------------------------------------------------------------------------- 1 | # Enable compression both for HTTP/1.0 and HTTP/1.1 (required for CloudFront). 2 | gzip_http_version 1.0; 3 | 4 | # Compression level (1-9). 5 | # 5 is a perfect compromise between size and cpu usage, offering about 6 | # 75% reduction for most ascii files (almost identical to level 9). 7 | gzip_comp_level 5; 8 | 9 | # Don't compress anything that's already small and unlikely to shrink much 10 | # if at all (the default is 20 bytes, which is bad as that usually leads to 11 | # larger files after gzipping). 12 | gzip_min_length 256; 13 | 14 | # Compress data even for clients that are connecting to us via proxies, 15 | # identified by the "Via" header (required for CloudFront). 16 | gzip_proxied any; 17 | 18 | # Tell proxies to cache both the gzipped and regular version of a resource 19 | # whenever the client's Accept-Encoding capabilities header varies; 20 | # Avoids the issue where a non-gzip capable client (which is extremely rare 21 | # today) would display gibberish if their proxy gave them the gzipped version. 22 | gzip_vary on; 23 | 24 | # Compress all output labeled with one of the following MIME-types. 25 | gzip_types 26 | application/atom+xml 27 | application/javascript 28 | application/json 29 | application/rss+xml 30 | application/vnd.ms-fontobject 31 | application/x-font-ttf 32 | application/x-web-app-manifest+json 33 | application/xhtml+xml 34 | application/xml 35 | font/opentype 36 | image/svg+xml 37 | image/x-icon 38 | text/css 39 | text/plain 40 | text/x-component; 41 | # text/html is always compressed by HttpGzipModule -------------------------------------------------------------------------------- /files/etc/nginx/rules/gzip_static.conf: -------------------------------------------------------------------------------- 1 | # This should be turned on if you are going to have pre-compressed copies (.gz) of 2 | # static files available. If not it should be left off as it will cause extra I/O 3 | # for the check. It is best if you enable this in a location{} block for 4 | # a specific directory, or on an individual server{} level. 5 | gzip_static on; -------------------------------------------------------------------------------- /files/etc/nginx/rules/no_transform.conf: -------------------------------------------------------------------------------- 1 | # Prevent mobile network providers from modifying your site 2 | add_header "Cache-Control" "no-transform"; 3 | -------------------------------------------------------------------------------- /files/etc/nginx/rules/security.conf: -------------------------------------------------------------------------------- 1 | # Block access to hidden files and directories. 2 | # This includes directories used by version control systems such as Git and SVN. 3 | location ~* (?:^|/)\. { 4 | deny all; 5 | access_log off; 6 | log_not_found off; 7 | } 8 | 9 | # Block access to backup and source files. 10 | # These files may be left by some text editors and can pose a great security 11 | # danger when anyone has access to them. 12 | location ~* (?:\.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$ { 13 | deny all; 14 | access_log off; 15 | log_not_found off; 16 | } 17 | -------------------------------------------------------------------------------- /files/etc/nginx/rules/ssl.conf: -------------------------------------------------------------------------------- 1 | # Protect against the BEAST attack by preferring RC4-SHA when using SSLv3 and TLS protocols. 2 | # Note that TLSv1.1 and TLSv1.2 are immune to the beast attack but only work with OpenSSL v1.0.1 and higher and has limited client support. 3 | ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; 4 | ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES"; 5 | ssl_prefer_server_ciphers on; 6 | 7 | # Optimize SSL by caching session parameters for 10 minutes. This cuts down on the number of expensive SSL handshakes. 8 | # The handshake is the most CPU-intensive operation, and by default it is re-negotiated on every new/parallel connection. 9 | # By enabling a cache (of type "shared between all Nginx workers"), we tell the client to re-use the already negotiated state. 10 | # Further optimization can be achieved by raising keepalive_timeout, but that shouldn't be done unless you serve primarily HTTPS. 11 | ssl_session_cache shared:SSL:10m; # a 1mb cache can hold about 4000 sessions, so we can hold 40000 sessions 12 | ssl_session_timeout 10m; -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: restart nginx 4 | service: name=nginx state=restarted 5 | when: nginx_service_state != 'stopped' 6 | 7 | - name: reload nginx 8 | service: name=nginx state=reloaded 9 | when: nginx_service_state != 'stopped' 10 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: franklin 4 | company: We Are Interactive 5 | description: Installs and configures nginx 6 | min_ansible_version: 2.4 7 | license: MIT 8 | # Optionally specify the branch Galaxy will use when accessing the GitHub 9 | # repo for this role. During role install, if no tags are available, 10 | # Galaxy will use this branch. During import Galaxy will access files on 11 | # this branch. If travis integration is cofigured, only notification for this 12 | # branch will be accepted. Otherwise, in all cases, the repo's default branch 13 | # (usually master) will be used. 14 | github_branch: master 15 | # 16 | # Below are all platforms currently available. Just uncomment 17 | # the ones that apply to your role. If you don't see your 18 | # platform on this list, let us know and we'll get it added! 19 | # 20 | platforms: 21 | #- name: EL 22 | # versions: 23 | # - all 24 | # - 5 25 | # - 6 26 | # - 7 27 | #- name: GenericUNIX 28 | # versions: 29 | # - all 30 | # - any 31 | #- name: Solaris 32 | # versions: 33 | # - all 34 | # - 10 35 | # - 11.0 36 | # - 11.1 37 | # - 11.2 38 | # - 11.3 39 | #- name: Fedora 40 | # versions: 41 | # - all 42 | # - 16 43 | # - 17 44 | # - 18 45 | # - 19 46 | # - 20 47 | # - 21 48 | # - 22 49 | # - 23 50 | #- name: Windows 51 | # versions: 52 | # - all 53 | # - 2012R2 54 | #- name: SmartOS 55 | # versions: 56 | # - all 57 | # - any 58 | #- name: opensuse 59 | # versions: 60 | # - all 61 | # - 12.1 62 | # - 12.2 63 | # - 12.3 64 | # - 13.1 65 | # - 13.2 66 | #- name: Amazon 67 | # versions: 68 | # - all 69 | # - 2013.03 70 | # - 2013.09 71 | #- name: GenericBSD 72 | # versions: 73 | # - all 74 | # - any 75 | #- name: FreeBSD 76 | # versions: 77 | # - all 78 | # - 10.0 79 | # - 10.1 80 | # - 10.2 81 | # - 8.0 82 | # - 8.1 83 | # - 8.2 84 | # - 8.3 85 | # - 8.4 86 | # - 9.0 87 | # - 9.1 88 | # - 9.1 89 | # - 9.2 90 | # - 9.3 91 | - name: Ubuntu 92 | versions: 93 | - all 94 | # - lucid 95 | # - maverick 96 | # - natty 97 | # - oneiric 98 | # - precise 99 | # - quantal 100 | # - raring 101 | # - saucy 102 | # - trusty 103 | # - utopic 104 | # - vivid 105 | # - wily 106 | #- name: SLES 107 | # versions: 108 | # - all 109 | # - 10SP3 110 | # - 10SP4 111 | # - 11 112 | # - 11SP1 113 | # - 11SP2 114 | # - 11SP3 115 | #- name: GenericLinux 116 | # versions: 117 | # - all 118 | # - any 119 | - name: Debian 120 | versions: 121 | - all 122 | # - etch 123 | # - jessie 124 | # - lenny 125 | # - squeeze 126 | # - wheezy categories: 127 | # 128 | # List tags for your role here, one per line. A tag is 129 | # a keyword that describes and categorizes the role. 130 | # Users find roles by searching for tags. Be sure to 131 | # remove the '[]' above if you add tags to this list. 132 | # 133 | # NOTE: A tag is limited to a single word comprised of 134 | # alphanumeric characters. Maximum 20 tags per role. 135 | galaxy_tags: 136 | - web 137 | - nginx 138 | # List your role dependencies here, one per line. Only 139 | # dependencies available via galaxy should be listed here. 140 | # Be sure to remove the '[]' above if you add dependencies 141 | # to this list. 142 | dependencies: [] 143 | -------------------------------------------------------------------------------- /meta/readme.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | galaxy_name: weareinteractive.nginx 4 | github_user: weareinteractive 5 | github_name: ansible-nginx 6 | badges: | 7 | [![Build Status](https://img.shields.io/travis/weareinteractive/ansible-nginx.svg)](https://travis-ci.org/weareinteractive/ansible-nginx) 8 | [![Galaxy](http://img.shields.io/badge/galaxy-weareinteractive.nginx-blue.svg)](https://galaxy.ansible.com/weareinteractive/nginx) 9 | [![GitHub Tags](https://img.shields.io/github/tag/weareinteractive/ansible-nginx.svg)](https://github.com/weareinteractive/ansible-nginx) 10 | [![GitHub Stars](https://img.shields.io/github/stars/weareinteractive/ansible-nginx.svg)](https://github.com/weareinteractive/ansible-nginx) 11 | description: | 12 | > * installs nginx 13 | > * configures nginx 14 | > * creates sites 15 | > * enables/disables sites 16 | > * optionally removes default host 17 | > * adds rules 18 | > * configures service 19 | 20 | **Note:** 21 | 22 | > Since Ansible Galaxy supports [organization](https://www.ansible.com/blog/ansible-galaxy-2-release) now, this role has moved from `franklinkim.nginx` to `weareinteractive.nginx`! 23 | after_dependencies: | 24 | ## Related (see example) 25 | 26 | * [weareinteractive.openssl](https://github.com/weareinteractive/ansible-openssl) 27 | * [weareinteractive.htpasswd](https://github.com/weareinteractive/ansible-htpasswd) 28 | after_handlers: | 29 | ## Rules 30 | 31 | If `nginx_add_rules` is `yes`, it will copy some configuration rules to `/etc/nginx/rules`: 32 | 33 | * cache_busting.conf 34 | * cors_web_fonts.conf 35 | * gzip.conf 36 | * no_transform.conf 37 | * ssl.conf 38 | * cors_ajax.con 39 | * expires.conf 40 | * gzip_static.conf 41 | * security.conf 42 | -------------------------------------------------------------------------------- /tasks/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Configuring nginx 4 | template: 5 | src: etc/nginx/nginx.conf.j2 6 | dest: /etc/nginx/nginx.conf 7 | owner: root 8 | group: root 9 | mode: "0644" 10 | notify: reload nginx 11 | 12 | - name: Ensure folders 13 | file: 14 | path: "{{ item }}" 15 | state: directory 16 | group: root 17 | owner: root 18 | mode: "0644" 19 | with_items: 20 | - /etc/nginx/sites-enabled 21 | - /etc/nginx/sites-available 22 | 23 | - name: Disabling default site 24 | file: 25 | path: /etc/nginx/sites-enabled/default 26 | state: absent 27 | when: nginx_remove_default 28 | notify: reload nginx 29 | 30 | - name: Removing default host 31 | file: 32 | path: "{{ item }}" 33 | state: absent 34 | with_items: 35 | - /etc/nginx/sites-available/default 36 | - /var/www/html 37 | when: nginx_remove_default 38 | 39 | - name: Adding rules 40 | copy: 41 | src: etc/nginx/rules/ 42 | dest: /etc/nginx/rules/ 43 | owner: root 44 | group: root 45 | mode: "0644" 46 | when: nginx_add_rules 47 | -------------------------------------------------------------------------------- /tasks/install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Installing dependencies 4 | apt: 5 | pkg: "{{ nginx_dependencies }}" 6 | state: present 7 | 8 | - name: Importing APT key 9 | apt_key: 10 | id: "{{ nginx_repo_key }}" 11 | keyserver: keyserver.ubuntu.com 12 | state: present 13 | 14 | - name: Adding APT repository 15 | apt_repository: 16 | repo: "{{ nginx_repo }}" 17 | update_cache: yes 18 | 19 | - name: Installing packages 20 | package: 21 | name: "{{ nginx_package }}" 22 | state: present 23 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - import_tasks: install.yml 4 | tags: 5 | - web 6 | - nginx 7 | - install 8 | - nginx-install 9 | 10 | - import_tasks: config.yml 11 | tags: 12 | - web 13 | - nginx 14 | - config 15 | - nginx-config 16 | 17 | - import_tasks: manage.yml 18 | when: nginx_sites | length 19 | tags: 20 | - web 21 | - nginx 22 | - manage 23 | - nginx-manage 24 | 25 | - import_tasks: service.yml 26 | tags: 27 | - web 28 | - nginx 29 | - service 30 | - nginx-service 31 | -------------------------------------------------------------------------------- /tasks/manage.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Creating webroots 4 | file: 5 | dest: "/var/www/{{ item.id }}/htdocs" 6 | state: directory 7 | when: item.add_webroot is defined and item.add_webroot 8 | with_items: "{{ nginx_sites }}" 9 | 10 | - name: Configuring sites 11 | template: 12 | src: "{{ item.template|default('etc/nginx/sites-available/site.j2') }}" 13 | dest: "/etc/nginx/sites-available/{{ item.id }}" 14 | owner: root 15 | group: root 16 | mode: "0644" 17 | with_items: "{{ nginx_sites }}" 18 | notify: reload nginx 19 | 20 | - name: Enabling sites 21 | file: 22 | src: "/etc/nginx/sites-available/{{ item.id }}" 23 | dest: "/etc/nginx/sites-enabled/{{ item.id }}" 24 | state: link 25 | when: item.state is not defined or item.state == 'present' 26 | with_items: "{{ nginx_sites }}" 27 | notify: reload nginx 28 | 29 | - name: Disabling sites 30 | file: 31 | src: "/etc/nginx/sites-available/{{ item.id }}" 32 | dest: "/etc/nginx/sites-enabled/{{ item.id }}" 33 | state: absent 34 | when: item.state is defined and item.state == 'absent' 35 | with_items: "{{ nginx_sites }}" 36 | notify: restart nginx 37 | -------------------------------------------------------------------------------- /tasks/service.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Configuring service 4 | service: 5 | name: nginx 6 | state: "{{ nginx_service_state }}" 7 | enabled: "{{ nginx_service_enabled }}" 8 | -------------------------------------------------------------------------------- /templates/etc/nginx/nginx.conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | 3 | # Run as a less privileged user for security reasons. 4 | user {{ nginx_user }}; 5 | 6 | # How many worker threads to run; 7 | # "auto" sets it to the number of CPU cores available in the system, and 8 | # offers the best performance. Don't set it higher than the number of CPU 9 | # cores if changing this parameter. 10 | 11 | # The maximum number of connections for Nginx is calculated by: 12 | # max_clients = worker_processes * worker_connections 13 | worker_processes {{ nginx_worker_processes }}; 14 | pid /run/nginx.pid; 15 | 16 | events { 17 | # When you need > 8000 * cpu_cores connections, you start optimizing your OS, 18 | # and this is probably the point at which you hire people who are smarter than 19 | # you, as this is *a lot* of requests. 20 | worker_connections {{ nginx_worker_connections }}; 21 | # multi_accept on; 22 | } 23 | 24 | http { 25 | 26 | ## 27 | # Basic Settings 28 | ## 29 | 30 | sendfile {{ nginx_sendfile }}; 31 | tcp_nopush {{ nginx_tcp_nopush }}; 32 | tcp_nodelay {{ nginx_tcp_nodelay }}; 33 | keepalive_timeout {{ nginx_keepalive_timeout }}; 34 | types_hash_max_size {{ nginx_types_hash_max_size }}; 35 | server_tokens {{ nginx_server_tokens }}; 36 | 37 | server_names_hash_bucket_size {{ nginx_server_names_hash_bucket_size }}; 38 | # server_name_in_redirect off; 39 | 40 | include /etc/nginx/mime.types; 41 | default_type application/octet-stream; 42 | 43 | ## 44 | # Logging Settings 45 | ## 46 | 47 | access_log /var/log/nginx/access.log; 48 | error_log /var/log/nginx/error.log; 49 | 50 | ## 51 | # Gzip Settings 52 | ## 53 | 54 | gzip on; 55 | gzip_disable "msie6"; 56 | 57 | gzip_vary on; 58 | gzip_proxied any; 59 | gzip_comp_level 6; 60 | gzip_buffers 16 8k; 61 | gzip_min_length 10; 62 | gzip_http_version 1.1; 63 | gzip_types 64 | text/plain 65 | text/css 66 | application/json 67 | application/x-javascript 68 | application/javascript 69 | text/xml 70 | application/xml 71 | application/xml+rss 72 | text/javascript 73 | image/png 74 | image/gif 75 | image/jpeg; 76 | 77 | ## 78 | # nginx-naxsi config 79 | ## 80 | # Uncomment it if you installed nginx-naxsi 81 | ## 82 | 83 | #include /etc/nginx/naxsi_core.rules; 84 | 85 | ## 86 | # nginx-passenger config 87 | ## 88 | # Uncomment it if you installed nginx-passenger 89 | ## 90 | 91 | #passenger_root /usr; 92 | #passenger_ruby /usr/bin/ruby; 93 | ## 94 | # Virtual Host Configs 95 | ## 96 | 97 | include /etc/nginx/conf.d/*.conf; 98 | include /etc/nginx/sites-enabled/*; 99 | } 100 | -------------------------------------------------------------------------------- /templates/etc/nginx/sites-available/site-body.j2: -------------------------------------------------------------------------------- 1 | server { 2 | server_name {{ item.name }}{% for value in item.aliases|default([]) %} {{ value }}{% endfor %}; 3 | root /var/www/{{ item.id }}/htdocs; 4 | 5 | # --- listen ---------------------------------------------------------------- 6 | 7 | listen {{ item.ip|default('*') }}:{{item.port|default(80)}}; 8 | {% if item.ssl is defined %} 9 | listen {{ item.ip|default('*') }}:{{item.ssl.port|default(443)}} ssl; 10 | {% endif %} 11 | 12 | {% if item.ssl is defined %} 13 | # --- ssl ------------------------------------------------------------------- 14 | include rules/ssl.conf; 15 | 16 | ssl_certificate {{ item.ssl.cert_path|default(openssl_certs_path) }}/{{ item.ssl.cert_name|default('server.crt') }}; 17 | ssl_certificate_key {{ item.ssl.key_path|default(openssl_keys_path) }}/{{ item.ssl.key_name|default('server.key') }}; 18 | {% endif %} 19 | 20 | {% if item.rules is defined %} 21 | # --- rule ------------------------------------------------------------------ 22 | {% for value in item.rules %} 23 | include rules/{{ value }}.conf; 24 | {% endfor %} 25 | {% endif %} 26 | 27 | {% if item.auth is defined %} 28 | # --- auth ------------------------------------------------------------------ 29 | 30 | auth_basic "{{ item.auth.name|default(item.id) }}"; 31 | auth_basic_user_file /etc/htpasswd/{{ item.auth.file|default(item.id) }}; 32 | {% endif %} 33 | 34 | # --- locations ------------------------------------------------------------- 35 | 36 | location / { 37 | try_files $uri $uri/ =404; 38 | } 39 | 40 | # --- logging --------------------------------------------------------------- 41 | 42 | error_log /var/log/nginx/error-{{ item.id }}.log; 43 | access_log /var/log/nginx/access-{{ item.id }}.log; 44 | 45 | {% if item.append is defined %} 46 | # --- appended -------------------------------------------------------------- 47 | 48 | {{ item.append }} 49 | {% endif %} 50 | } 51 | -------------------------------------------------------------------------------- /templates/etc/nginx/sites-available/site-redirect.j2: -------------------------------------------------------------------------------- 1 | {% for value in item.redirects|default([]) %} 2 | server { 3 | server_name {{ value }}; 4 | listen {{ item.ip|default('*') }}:{{item.port|default(80)}}; 5 | {% if item.ssl is defined %} 6 | listen {{ item.ip|default('*') }}:{{item.ssl.port|default(443)}} ssl; 7 | {% endif %} 8 | 9 | {% if item.ssl is defined %} 10 | # --- ssl ------------------------------------------------------------------- 11 | 12 | include rules/ssl.conf; 13 | 14 | ssl_certificate {{ item.ssl.cert_path|default(openssl_certs_path) }}/{{ item.ssl.cert_name|default('server.crt') }}; 15 | ssl_certificate_key {{ item.ssl.key_path|default(openssl_keys_path) }}/{{ item.ssl.key_name|default('server.key') }}; 16 | {% endif %} 17 | 18 | # --- redirects -------------------------------------------------------------- 19 | 20 | rewrite ^/(.*)$ $scheme://{{ item.name }}/$1 permanent; 21 | } 22 | {% endfor %} 23 | -------------------------------------------------------------------------------- /templates/etc/nginx/sites-available/site.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | 3 | {% include "etc/nginx/sites-available/site-redirect.j2" %} 4 | 5 | {% include "etc/nginx/sites-available/site-body.j2" %} 6 | -------------------------------------------------------------------------------- /tests/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: all 4 | become: yes 5 | roles: 6 | - weareinteractive.apt 7 | - weareinteractive.openssl 8 | - weareinteractive.htpasswd 9 | - weareinteractive.nginx 10 | vars: 11 | htpasswd: 12 | - name: foobar 13 | users: 14 | - { name: foobar, password: foobar } 15 | openssl_generate_csr: yes 16 | openssl_self_signed: 17 | - name: fooboar.local 18 | subject: 19 | C: DE 20 | ST: Bavaria 21 | L: Munich 22 | O: Foo Bar Inc 23 | CN: foobar.local 24 | emailAddress: null@foobar.local 25 | nginx_sites: 26 | - id: foobar 27 | add_webroot: yes 28 | name: foobar.local 29 | ssl: 30 | key_name: foobar.local.key 31 | cert_name: foobar.local.crt 32 | rules: 33 | - gzip 34 | - security 35 | auth: 36 | name: Foo Bar 37 | file: foobar 38 | nginx_worker_processes: 1 39 | nginx_remove_default: yes 40 | # do not start service as we're running in docker 41 | nginx_service_state: stopped 42 | nginx_service_enabled: no 43 | --------------------------------------------------------------------------------