├── .github └── workflows │ └── default.yml ├── .gitignore ├── .gitlab-ci.yml ├── .travis.yml ├── .yamllint ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CONTRIBUTORS.md ├── LICENSE.md ├── README.md ├── defaults └── main.yml ├── files └── .gitkeep ├── handlers └── main.yml ├── library └── openssl_csr.py ├── meta └── main.yml ├── molecule ├── centos7 │ ├── INSTALL.rst │ ├── molecule.yml │ └── verify.yml ├── centos8 │ ├── INSTALL.rst │ ├── molecule.yml │ └── verify.yml ├── debian10 │ ├── INSTALL.rst │ ├── molecule.yml │ └── verify.yml ├── debian8 │ ├── INSTALL.rst │ ├── molecule.yml │ └── verify.yml ├── debian9 │ ├── INSTALL.rst │ ├── molecule.yml │ └── verify.yml ├── fedora │ ├── INSTALL.rst │ ├── molecule.yml │ └── verify.yml ├── shared │ ├── converge.yml │ └── verify.yml ├── ubuntu1604 │ ├── INSTALL.rst │ ├── molecule.yml │ └── verify.yml └── ubuntu1804 │ ├── INSTALL.rst │ ├── molecule.yml │ └── verify.yml ├── playbook.yml ├── requirements-dev.txt ├── requirements.txt ├── requirements.yml ├── tasks ├── config.yml ├── debian.yml ├── main.yml └── ssl.yml ├── templates ├── .gitkeep ├── cert.j2 ├── etc │ └── nginx │ │ └── nginx.conf.j2 └── key.j2 └── vars └── main.yml /.github/workflows/default.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Molecule Test 3 | on: push 4 | jobs: 5 | build: 6 | runs-on: ubuntu-latest 7 | strategy: 8 | max-parallel: 4 9 | matrix: 10 | python-version: [3.5, 3.6, 3.7] 11 | 12 | steps: 13 | - uses: actions/checkout@v1 14 | with: 15 | path: ansible-nginx-load-balancer 16 | - name: Set up Python ${{ matrix.python-version }} 17 | uses: actions/setup-python@v1 18 | with: 19 | python-version: ${{ matrix.python-version }} 20 | - name: Install dependencies 21 | run: | 22 | sudo apt install docker 23 | python -m pip install --upgrade pip 24 | pip3 install -r requirements.txt 25 | ansible --version 26 | molecule --version 27 | - name: Test with molecule 28 | run: | 29 | # molecule test --scenario-name centos7 30 | # molecule test --scenario-name centos8 31 | # molecule test --scenario-name debian8 32 | # molecule test --scenario-name debian9 33 | # molecule test --scenario-name debian10 34 | # molecule test --scenario-name fedora 35 | # molecule test --scenario-name ubuntu1604 36 | molecule test --scenario-name ubuntu1804 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | image: docker:git 3 | 4 | services: 5 | - docker:dind 6 | 7 | before_script: 8 | - apk update && apk add --no-cache docker 9 | python3-dev py3-pip docker gcc git curl build-base 10 | autoconf automake py3-cryptography linux-headers 11 | musl-dev libffi-dev openssl-dev openssh 12 | - docker info 13 | - python3 --version 14 | - pip3 install -r requirements.txt 15 | - ansible --version 16 | - molecule --version 17 | 18 | molecule: 19 | stage: test 20 | script: 21 | # - molecule test --scenario-name centos7 22 | # - molecule test --scenario-name centos8 23 | # - molecule test --scenario-name debian8 24 | # - molecule test --scenario-name debian9 25 | # - molecule test --scenario-name debian10 26 | # - molecule test --scenario-name fedora 27 | # - molecule test --scenario-name ubuntu1604 28 | - molecule test --scenario-name ubuntu1804 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | sudo: required 3 | language: python 4 | services: 5 | - docker 6 | before_install: 7 | - sudo apt-get -qq update 8 | install: 9 | - pip3 install -r requirements.txt 10 | - ansible --version 11 | - molecule --version 12 | script: 13 | # - molecule test --scenario-name centos7 14 | # - molecule test --scenario-name centos8 15 | # - molecule test --scenario-name debian8 16 | # - molecule test --scenario-name debian9 17 | # - molecule test --scenario-name debian10 18 | # - molecule test --scenario-name fedora 19 | # - molecule test --scenario-name ubuntu1604 20 | - molecule test --scenario-name ubuntu1804 21 | notifications: 22 | webhooks: https://galaxy.ansible.com/api/v1/notifications/ 23 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | # Based on ansible-lint config 3 | extends: default 4 | 5 | ignore: | 6 | venv/ 7 | 8 | rules: 9 | braces: 10 | max-spaces-inside: 1 11 | level: error 12 | brackets: 13 | max-spaces-inside: 1 14 | level: error 15 | colons: 16 | max-spaces-after: -1 17 | level: error 18 | commas: 19 | max-spaces-after: -1 20 | level: error 21 | comments: disable 22 | comments-indentation: disable 23 | document-start: disable 24 | empty-lines: 25 | max: 3 26 | level: error 27 | hyphens: 28 | level: error 29 | indentation: disable 30 | key-duplicates: enable 31 | line-length: disable 32 | new-line-at-end-of-file: disable 33 | new-lines: 34 | type: unix 35 | trailing-spaces: disable 36 | truthy: disable 37 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | commit 64568550e3f89a5464beb0cd35c7c99ce762817f 2 | Author: Larry Smith Jr 3 | Date: Sat Mar 14 22:30:38 2020 -0400 4 | 5 | Fixing Molecule testing 6 | 7 | commit 7b82e6ca75f93e3814247f7dc47aa3a63f26eae4 8 | Author: Larry Smith Jr 9 | Date: Sat Mar 14 22:24:14 2020 -0400 10 | 11 | Fixing test converge playbook 12 | 13 | commit df0b2b2187d8df5c5bf43fa53ba527ef16ff4d6d 14 | Author: Larry Smith Jr 15 | Date: Sat Mar 14 22:15:07 2020 -0400 16 | 17 | Added: New functionality for defining multiple locations 18 | 19 | commit eceaa2ba7d6c2093123c3d50002d99225ac377cd 20 | Author: Larry Smith Jr 21 | Date: Fri Mar 13 01:01:29 2020 -0400 22 | 23 | Updated: changelog 24 | 25 | commit c297a80aca6ea133ebbd07fe3e08d94c61e55527 26 | Author: Larry Smith Jr 27 | Date: Fri Mar 13 01:00:52 2020 -0400 28 | 29 | Updated: Removed headers config 30 | 31 | Removed headers config and moved to options to allow more control 32 | 33 | commit 9c9928487529b84c19640894fdc98de9493cd089 34 | Author: Larry Smith Jr 35 | Date: Sun Feb 23 00:50:28 2020 -0500 36 | 37 | Disabled Ubuntu 16.04 tests 38 | 39 | - There is an issue with pyopenssl pip install currently 40 | - Will investigate later 41 | 42 | commit 4bcde351dbbf333007d5659df8113c15d34b9739 43 | Author: Larry Smith Jr 44 | Date: Sun Feb 23 00:18:36 2020 -0500 45 | 46 | Added an additional config for HTTP LB 47 | 48 | commit 7318c035dc380d83c7da042263c994bc893b879d 49 | Author: Larry Smith Jr 50 | Date: Sun Feb 23 00:18:14 2020 -0500 51 | 52 | Added required role ansible-bootstrap-python 53 | 54 | - This role ensures Python is setup correctly to ensure pip modules can be installed 55 | 56 | commit b8ced02d341a6b4c696a52fffe5bb339e7867104 57 | Author: Larry Smith Jr 58 | Date: Sat Feb 22 23:42:17 2020 -0500 59 | 60 | Fixed Flake8 linting issues 61 | 62 | commit 82770a7bc8be31024948188ccb58ee2809889c6c 63 | Author: Larry Smith Jr 64 | Date: Sat Feb 22 23:41:57 2020 -0500 65 | 66 | Fixed Ansible linting issue 67 | 68 | commit c47ee7b413bc56ba243e0960acf71404cffc8eb9 69 | Author: Larry Smith Jr 70 | Date: Sat Feb 22 23:33:40 2020 -0500 71 | 72 | Added new Molecule tests, etc. from new structure 73 | 74 | commit 625e35a980142af7c3ef17e90c8dbea0e3245da3 75 | Author: Larry Smith Jr 76 | Date: Sat Feb 22 23:32:43 2020 -0500 77 | 78 | Updated files, etc. after new structure 79 | 80 | commit c7edbc155ad11503b5100fadb988d68383a22f7c 81 | Author: Larry Smith Jr 82 | Date: Sat Feb 22 22:46:21 2020 -0500 83 | 84 | Deleted old tests, etc. not needed 85 | 86 | commit 571bf2e7267ad669e0aed47b789684795f24246d 87 | Author: Larry Smith Jr 88 | Date: Sun Dec 23 00:34:47 2018 -0500 89 | 90 | Disabled Debian as it is failing and needs to be investigated 91 | 92 | commit 38644cd1fd295f976a65f883ce3acd13385c56cb 93 | Author: Larry Smith Jr 94 | Date: Sun Dec 23 00:26:51 2018 -0500 95 | 96 | First commit of refactoring 97 | 98 | Cleaned up code based on Ansible lint and YAML lint 99 | Implemented updated Travis CI testing 100 | 101 | commit 71430d317801634e801d6f7f4607741232de7a19 102 | Author: Larry Smith Jr 103 | Date: Mon Apr 30 19:27:35 2018 -0400 104 | 105 | Added Ubuntu 18.04 supported 106 | 107 | commit 2ee7f80d55592460ca3f3789b5a488a536d1e17a 108 | Author: Larry Smith Jr 109 | Date: Mon Apr 30 19:27:14 2018 -0400 110 | 111 | Disabled all distros other than Ubuntu as this role is only supported 112 | 113 | commit 36a348fab0a2e551357d28d9d46df117fd5c3e10 114 | Author: Larry Smith Jr 115 | Date: Mon Apr 30 18:44:56 2018 -0400 116 | 117 | Skipping task check for ansible-lint as this task is required. 118 | 119 | commit eecc7dfc12d682163fdadc2c9c86b4e632183352 120 | Author: Larry Smith Jr 121 | Date: Mon Apr 30 17:16:45 2018 -0400 122 | 123 | Implemented new Travis-CI testing 124 | 125 | commit b248c768dccad010690ec88d9670f25e1d308a7e 126 | Author: Alexander Pinnecke 127 | Date: Mon Dec 18 16:18:06 2017 +0100 128 | 129 | iRemove protocol when using plain tcp load balancing, fixes #1 130 | 131 | commit 2455fbf8c8c427379c8e3850e4427345db4ef538 132 | Author: Larry Smith Jr 133 | Date: Fri Jul 14 15:59:28 2017 -0400 134 | 135 | Comment Out Default SSL Info 136 | 137 | Commented out the default SSL info in order to clean up and make the 138 | defaults cleaner. 139 | 140 | Signed-off-by: Larry Smith Jr 141 | 142 | commit 68cc9b51ed4dd40d3219054b6fb930af9a58190c 143 | Author: Larry Smith Jr 144 | Date: Thu Jul 13 22:43:54 2017 -0400 145 | 146 | Add HA SSL Cert Sync Ability 147 | 148 | Added HA setup options which includes the ability to define an HA 149 | primary node which will generate SSL certs and those will be synced to 150 | the other load balancers in the HA setup. This will allow for SSL 151 | termination using the same keys across all load balancer nodes. 152 | 153 | Signed-off-by: Larry Smith Jr 154 | 155 | commit fe16bc45e7a47ce7dd68d5363291670a63c7bd8f 156 | Author: Larry Smith Jr 157 | Date: Thu Jul 13 20:35:03 2017 -0400 158 | 159 | Updated Galaxy/Repo Info 160 | 161 | Signed-off-by: Larry Smith Jr 162 | 163 | commit 7802c7bc893bff8a523155cb70f4c2e2f8631a9b 164 | Author: Larry Smith Jr 165 | Date: Thu Jul 13 20:30:05 2017 -0400 166 | 167 | first commit 168 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at mrlesmithjr@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to ansible-nginx-load-balancer 2 | 3 | ## Table Of Contents 4 | 5 | [Code of Conduct](#code-of-conduct) 6 | 7 | ## Code of Conduct 8 | 9 | This project and everyone participating in it is governed by the [ansible-nginx-load-balancer Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [mrlesmithjr@gmail.com](mailto:mrlesmithjr@gmail.com). 10 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | Larry Smith Jr. - mrlesmithjr@gmail.com 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Larry Smith Jr. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ansible-nginx-load-balancer 2 | 3 | Ansible role to install/configure an NGINX load balancer for: 4 | 5 | ## Usages 6 | 7 | - HTTP Load Balancing 8 | - HTTPS Load Balancing 9 | - SSL Termination 10 | - Self Signed Certs 11 | - TCP Load Balancing 12 | - UDP Load Balancing 13 | - HA (Highly Available) Setup 14 | 15 | ## Build Status 16 | 17 | ### GitHub Actions 18 | 19 | ![Molecule Test](https://github.com/mrlesmithjr/ansible-nginx-load-balancer/workflows/Molecule%20Test/badge.svg) 20 | 21 | ### Travis CI 22 | 23 | [![Build Status](https://travis-ci.org/mrlesmithjr/ansible-nginx-load-balancer.svg?branch=master)](https://travis-ci.org/mrlesmithjr/ansible-nginx-load-balancer) 24 | 25 | ## Requirements 26 | 27 | For any required Ansible roles, review: 28 | [requirements.yml](requirements.yml) 29 | 30 | ## Role Variables 31 | 32 | [defaults/main.yml](defaults/main.yml) 33 | 34 | ## Dependencies 35 | 36 | The following Ansible roles **should** be used along with this `ansible-nginx-load-balancer` role. 37 | 38 | - [ansible-etc-hosts](https://github.com/mrlesmithjr/ansible-etc-hosts) 39 | - Provides the ability to update `/etc/hosts` with all hosts which are part of the solution 40 | - [ansible-keepalived](https://github.com/mrlesmithjr/ansible-keepalived) 41 | - Provides the ability to provide the `VIP` for `HA` of multiple `ansible-nginx-load-balancer` nodes. 42 | 43 | You can install the above roles using `ansible-galaxy` and the included [requirements](requirements.yml) 44 | 45 | ```bash 46 | ansible-galaxy install -r requirements.yml 47 | ``` 48 | 49 | ## Example Playbook 50 | 51 | [playbook.yml](playbook.yml) 52 | 53 | ## License 54 | 55 | MIT 56 | 57 | ## Author Information 58 | 59 | Larry Smith Jr. 60 | 61 | - [@mrlesmithjr](https://twitter.com/mrlesmithjr) 62 | - [mrlesmithjr@gmail.com](mailto:mrlesmithjr@gmail.com) 63 | - [http://everythingshouldbevirtual.com](http://everythingshouldbevirtual.com) 64 | 65 | > NOTE: Repo has been created/updated using [https://github.com/mrlesmithjr/cookiecutter-ansible-role](https://github.com/mrlesmithjr/cookiecutter-ansible-role) as a template. 66 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for ansible-nginx-load-balancer 3 | 4 | # NGINX load balancer configs 5 | ## frontend_listen_port 6 | ## 7 | ## location 8 | ## 9 | ## method 10 | ### define the load balancing method 11 | ### round_robin(default), least_conn, ip_hash 12 | #### round_robin 13 | ##### requests to the application servers are distributed in a round-robin fashion 14 | #### 15 | #### least_conn 16 | ##### next request is assigned to the server with the least number of active connections 17 | #### 18 | #### ip_hash 19 | ##### a hash-function is used to determine what server should be selected for 20 | ##### the next request (based on the client’s IP address) 21 | #### 22 | ## protocol 23 | ### http, https 24 | #### Defines backend protocol 25 | ## server_name 26 | ## 27 | ## ssl 28 | ### Defines if SSL listen port for protocol http 29 | ## 30 | ## upstream 31 | ### server 32 | #### Define individual server(s) 33 | ### 34 | ### servers 35 | #### Define Ansible groups to iterate through hosts 36 | ### 37 | ### backend_listen_port 38 | #### Define the backend listen port which application is listening on 39 | nginx_load_balancer_configs: [] 40 | # - name: "{{ inventory_hostname_short+'-letsencrypt' }}" 41 | # frontend_listen_port: 80 42 | # locations: 43 | # - location: /.well-known/acme-challenge 44 | # options: 45 | # - root /var/www/letsencrypt 46 | # - try_files $uri $uri/ =404 47 | # - location: / 48 | # options: 49 | # - "rewrite ^ https://{{ ssl_domain_name }}$request_uri? permanent" 50 | # method: round_robin 51 | # protocol: http 52 | # server_name: 53 | # - "{{ ssl_domain_name }}" 54 | # ssl: false 55 | # upstream: [] 56 | # - name: google_dns 57 | # frontend_listen_port: 53 58 | # method: round_robin 59 | # protocol: udp 60 | # upstream: 61 | # - server: 8.8.8.8 62 | # backend_listen_port: 53 63 | # - server: 8.8.4.4 64 | # backend_listen_port: 53 65 | # - name: web_app 66 | # frontend_listen_port: 80 67 | # locations: 68 | # - location: / 69 | # options: 70 | # - proxy_buffering off 71 | # - proxy_http_version 1.1 72 | # - "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for" 73 | # - "proxy_set_header Upgrade $http_upgrade" 74 | # - "proxy_set_header Connection $http_connection" 75 | # - access_log off 76 | # - proxy_pass http://127.0.0.1:8080 77 | # method: round_robin 78 | # protocol: http 79 | # server_name: 80 | # - test.vagrant.local 81 | # ssl: false 82 | # upstream: 83 | # - servers: "{{ groups['web_servers'] }}" 84 | # backend_listen_port: 80 85 | # options: 86 | # - "fail_timeout=10s" 87 | # - "max_conns=0" 88 | # - "max_fails=1" 89 | # - "weight=1" 90 | # - server: 192.168.250.11 91 | # backend_listen_port: 80 92 | # options: 93 | # - "fail_timeout=10s" 94 | # - "max_conns=0" 95 | # - "weight=1" 96 | # - server: 192.168.250.12 97 | # backend_listen_port: 80 98 | # options: 99 | # - backup 100 | # - "fail_timeout=10s" 101 | # - "max_conns=0" 102 | # - "weight=1" 103 | 104 | # Provides the configuration file context in which the directives that affect 105 | # connection processing are specified. 106 | nginx_load_balancer_events: 107 | # Sets the maximum number of simultaneous connections that can be opened by a 108 | # worker process. 109 | # The Ubuntu default is 768 110 | - "worker_connections 1024" 111 | 112 | # Includes another file, or files matching the specified mask, into 113 | # configuration. Included files should consist of syntactically correct 114 | # directives and blocks 115 | nginx_load_balancer_includes: 116 | - "/etc/nginx/modules-enabled/*.conf" 117 | 118 | # Defines a file that will store the process ID of the main process 119 | ngninx_load_balancer_pid: /run/nginx.pid 120 | 121 | # Defines if using a highly available setup. i.e. multiple nginx load balancers 122 | nginx_load_balancer_ha: false 123 | 124 | # Defines the prefix path/file for SSL cert(s) when using HA 125 | ## We do this in order to generate the keys on the primary and sync the keys to 126 | ## all other nodes in the HA setup. 127 | nginx_load_balancer_ha_key_file_prefix: "{{ '/etc/ssl/' + nginx_load_balancer_ha_primary }}" 128 | 129 | # Defines the primary host when in HA mode 130 | nginx_load_balancer_ha_primary: node0 131 | 132 | # Defines SSL cert(s) info 133 | nginx_load_balancer_ssl: 134 | {} 135 | # csr_key_file: "/etc/ssl/{{ inventory_hostname }}-csr.pem" 136 | # enabled: false 137 | # generate_keys: false 138 | # private_key_file: "/etc/ssl/private/{{ inventory_hostname }}-key.pem" 139 | # private_key_size: 4096 140 | # private_key_type: RSA 141 | # protocols: 142 | # - TLSv1 143 | # - TLSv1.1 144 | # - TLSv1.2 145 | # public_key_file: "/etc/ssl/public/{{ inventory_hostname }}-cert.pem" 146 | # public_key_valid_days: 1825 147 | # regenerate_keys: false 148 | 149 | # Defines the user which NGINX runs as 150 | nginx_load_balancer_user: www-data 151 | 152 | # Define version to install 153 | # development/stable 154 | nginx_load_balancer_version: stable 155 | 156 | # Defines the number of worker processes. 157 | # The optimal value depends on many factors including (but not limited to) the 158 | # number of CPU cores, the number of hard disk drives that store data, and 159 | # load pattern. When one is in doubt, setting it to the number of available CPU 160 | # cores would be a good start (the value “auto” will try to autodetect it). 161 | # 162 | # The default below will detect the number of cpu cores/threads and multiply by 163 | # 4. You may want to scale this up/down or set to auto. You can also experiment 164 | # by using the Apache benchmark tool to see where the sweet spot is. 165 | # ab -c 40 -n 50000 http://192.168.250.200/ 166 | nginx_load_balancer_worker_processes: "{{ ansible_processor_vcpus * 4 }}" 167 | -------------------------------------------------------------------------------- /files/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrlesmithjr/ansible-nginx-load-balancer/762f50630d4c9ae135cda0e759b9df49d54a8d82/files/.gitkeep -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for ansible-nginx-load-balancer 3 | - name: restart nginx 4 | service: 5 | name: nginx 6 | state: restarted 7 | enabled: true 8 | become: true 9 | -------------------------------------------------------------------------------- /library/openssl_csr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # (c) 2017, Yanis Guenane 5 | # 6 | # Ansible is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # Ansible is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with Ansible. If not, see . 18 | import os 19 | import errno 20 | from ansible.module_utils._text import to_native 21 | from ansible.module_utils.basic import AnsibleModule 22 | 23 | ANSIBLE_METADATA = {'metadata_version': '1.0', 24 | 'status': ['preview'], 25 | 'supported_by': 'community'} 26 | 27 | 28 | DOCUMENTATION = ''' 29 | --- 30 | module: openssl_csr 31 | author: "Yanis Guenane (@Spredzy)" 32 | version_added: "2.4" 33 | short_description: Generate OpenSSL Certificate Signing Request (CSR) 34 | description: 35 | - "This module allows one to (re)generates OpenSSL certificate signing 36 | requests. It uses the pyOpenSSL python library to interact with openssl. 37 | This module support the subjectAltName extension. Note: At least one of 38 | commonName or subjectAltName must be specified." 39 | requirements: 40 | - "python-pyOpenSSL" 41 | options: 42 | state: 43 | required: false 44 | default: "present" 45 | choices: [ present, absent ] 46 | description: 47 | - Whether the certificate signing request should exist or not, 48 | taking action if the state is different from what is stated. 49 | digest: 50 | required: false 51 | default: "sha256" 52 | description: 53 | - Digest used when signing the certificate signing request with the 54 | private key 55 | privatekey_path: 56 | required: true 57 | description: 58 | - Path to the privatekey to use when signing the certificate 59 | signing request 60 | version: 61 | required: false 62 | default: 3 63 | description: 64 | - Version of the certificate signing request 65 | force: 66 | required: false 67 | default: False 68 | choices: [ True, False ] 69 | description: 70 | - Should the certificate signing request be forced regenerated by 71 | this ansible module 72 | path: 73 | required: true 74 | description: 75 | - Name of the folder in which the generated OpenSSL certificate 76 | signing request will be written 77 | subjectAltName: 78 | required: false 79 | description: 80 | - SAN extension to attach to the certificate signing request 81 | countryName: 82 | required: false 83 | aliases: [ 'C' ] 84 | description: 85 | - countryName field of the certificate signing request subject 86 | stateOrProvinceName: 87 | required: false 88 | aliases: [ 'ST' ] 89 | description: 90 | - stateOrProvinceName field of the certificate signing request 91 | subject 92 | localityName: 93 | required: false 94 | aliases: [ 'L' ] 95 | description: 96 | - localityName field of the certificate signing request subject 97 | organizationName: 98 | required: false 99 | aliases: [ 'O' ] 100 | description: 101 | - organizationName field of the certificate signing request subject 102 | organizationUnitName: 103 | required: false 104 | aliases: [ 'OU' ] 105 | description: 106 | - organizationUnitName field of the certificate signing request 107 | subject 108 | commonName: 109 | required: false 110 | aliases: [ 'CN' ] 111 | description: 112 | - commonName field of the certificate signing request subject 113 | emailAddress: 114 | required: false 115 | aliases: [ 'E' ] 116 | description: 117 | - emailAddress field of the certificate signing request subject 118 | ''' 119 | 120 | 121 | EXAMPLES = ''' 122 | # Generate an OpenSSL Certificate Signing Request 123 | - openssl_csr: 124 | path: /etc/ssl/csr/www.ansible.com.csr 125 | privatekey_path: /etc/ssl/private/ansible.com.pem 126 | commonName: www.ansible.com 127 | 128 | # Generate an OpenSSL Certificate Signing Request with Subject information 129 | - openssl_csr: 130 | path: /etc/ssl/csr/www.ansible.com.csr 131 | privatekey_path: /etc/ssl/private/ansible.com.pem 132 | countryName: FR 133 | organizationName: Ansible 134 | emailAddress: jdoe@ansible.com 135 | commonName: www.ansible.com 136 | 137 | # Generate an OpenSSL Certificate Signing Request with subjectAltName extension 138 | - openssl_csr: 139 | path: /etc/ssl/csr/www.ansible.com.csr 140 | privatekey_path: /etc/ssl/private/ansible.com.pem 141 | subjectAltName: 'DNS:www.ansible.com,DNS:m.ansible.com' 142 | 143 | # Force re-generate an OpenSSL Certificate Signing Request 144 | - openssl_csr: 145 | path: /etc/ssl/csr/www.ansible.com.csr 146 | privatekey_path: /etc/ssl/private/ansible.com.pem 147 | force: True 148 | commonName: www.ansible.com 149 | ''' 150 | 151 | 152 | RETURN = ''' 153 | csr: 154 | description: Path to the generated Certificate Signing Request 155 | returned: changed or success 156 | type: string 157 | sample: /etc/ssl/csr/www.ansible.com.csr 158 | subject: 159 | description: A dictionnary of the subject attached to the CSR 160 | returned: changed or success 161 | type: list 162 | sample: {'CN': 'www.ansible.com', 'O': 'Ansible'} 163 | subjectAltName: 164 | description: The alternative names this CSR is valid for 165 | returned: changed or success 166 | type: string 167 | sample: 'DNS:www.ansible.com,DNS:m.ansible.com' 168 | ''' 169 | 170 | 171 | try: 172 | from OpenSSL import crypto 173 | except ImportError: 174 | pyopenssl_found = False 175 | else: 176 | pyopenssl_found = True 177 | 178 | 179 | class CertificateSigningRequestError(Exception): 180 | pass 181 | 182 | 183 | class CertificateSigningRequest(object): 184 | 185 | def __init__(self, module): 186 | self.state = module.params['state'] 187 | self.digest = module.params['digest'] 188 | self.force = module.params['force'] 189 | self.subjectAltName = module.params['subjectAltName'] 190 | self.path = module.params['path'] 191 | self.privatekey_path = module.params['privatekey_path'] 192 | self.version = module.params['version'] 193 | self.changed = True 194 | self.request = None 195 | self.privatekey = None 196 | 197 | self.subject = { 198 | 'C': module.params['countryName'], 199 | 'ST': module.params['stateOrProvinceName'], 200 | 'L': module.params['localityName'], 201 | 'O': module.params['organizationName'], 202 | 'OU': module.params['organizationalUnitName'], 203 | 'CN': module.params['commonName'], 204 | 'emailAddress': module.params['emailAddress'], 205 | } 206 | 207 | if self.subjectAltName is None: 208 | self.subjectAltName = 'DNS:%s' % self.subject['CN'] 209 | 210 | self.subject = dict((k, v) for k, v in self.subject.items() if v) 211 | 212 | def generate(self, module): 213 | '''Generate the certificate signing request.''' 214 | 215 | if not os.path.exists(self.path) or self.force: 216 | req = crypto.X509Req() 217 | req.set_version(self.version) 218 | subject = req.get_subject() 219 | for (key, value) in self.subject.items(): 220 | if value is not None: 221 | setattr(subject, key, value) 222 | 223 | if self.subjectAltName is not None: 224 | req.add_extensions([crypto.X509Extension( 225 | b"subjectAltName", False, 226 | self.subjectAltName.encode('ascii'))]) 227 | 228 | privatekey_content = open(self.privatekey_path).read() 229 | self.privatekey = crypto.load_privatekey( 230 | crypto.FILETYPE_PEM, privatekey_content) 231 | 232 | req.set_pubkey(self.privatekey) 233 | req.sign(self.privatekey, self.digest) 234 | self.request = req 235 | 236 | try: 237 | csr_file = open(self.path, 'wb') 238 | csr_file.write(crypto.dump_certificate_request( 239 | crypto.FILETYPE_PEM, self.request)) 240 | csr_file.close() 241 | except (IOError, OSError) as exc: 242 | raise CertificateSigningRequestError(exc) 243 | else: 244 | self.changed = False 245 | 246 | file_args = module.load_file_common_arguments(module.params) 247 | if module.set_fs_attributes_if_different(file_args, False): 248 | self.changed = True 249 | 250 | def remove(self): 251 | '''Remove the Certificate Signing Request.''' 252 | 253 | try: 254 | os.remove(self.path) 255 | except OSError as exc: 256 | if exc.errno != errno.ENOENT: 257 | raise CertificateSigningRequestError(exc) 258 | else: 259 | self.changed = False 260 | 261 | def dump(self): 262 | '''Serialize the object into a dictionary.''' 263 | 264 | result = { 265 | 'csr': self.path, 266 | 'subject': self.subject, 267 | 'subjectAltName': self.subjectAltName, 268 | 'changed': self.changed 269 | } 270 | 271 | return result 272 | 273 | 274 | def main(): 275 | module = AnsibleModule( 276 | argument_spec=dict( 277 | state=dict(default='present', choices=[ 278 | 'present', 'absent'], type='str'), 279 | digest=dict(default='sha256', type='str'), 280 | privatekey_path=dict(require=True, type='path'), 281 | version=dict(default='3', type='int'), 282 | force=dict(default=False, type='bool'), 283 | subjectAltName=dict(aliases=['subjectAltName'], type='str'), 284 | path=dict(required=True, type='path'), 285 | countryName=dict(aliases=['C'], type='str'), 286 | stateOrProvinceName=dict(aliases=['ST'], type='str'), 287 | localityName=dict(aliases=['L'], type='str'), 288 | organizationName=dict(aliases=['O'], type='str'), 289 | organizationalUnitName=dict(aliases=['OU'], type='str'), 290 | commonName=dict(aliases=['CN'], type='str'), 291 | emailAddress=dict(aliases=['E'], type='str'), 292 | ), 293 | add_file_common_args=True, 294 | supports_check_mode=True, 295 | required_one_of=[['commonName', 'subjectAltName']], 296 | ) 297 | 298 | if not pyopenssl_found: 299 | module.fail_json(msg='the python pyOpenSSL module is required') 300 | 301 | path = module.params['path'] 302 | base_dir = os.path.dirname(module.params['path']) 303 | 304 | if not os.path.isdir(base_dir): 305 | module.fail_json( 306 | name=path, msg='The directory %s does not exist' % path) 307 | 308 | csr = CertificateSigningRequest(module) 309 | 310 | if module.params['state'] == 'present': 311 | 312 | if module.check_mode: 313 | result = csr.dump() 314 | result['changed'] = module.params['force'] or not os.path.exists( 315 | path) 316 | module.exit_json(**result) 317 | 318 | try: 319 | csr.generate(module) 320 | except CertificateSigningRequestError as exc: 321 | module.fail_json(msg=to_native(exc)) 322 | 323 | else: 324 | 325 | if module.check_mode: 326 | result = csr.dump() 327 | result['changed'] = os.path.exists(path) 328 | module.exit_json(**result) 329 | 330 | try: 331 | csr.remove() 332 | except CertificateSigningRequestError as exc: 333 | module.fail_json(msg=to_native(exc)) 334 | 335 | result = csr.dump() 336 | 337 | module.exit_json(**result) 338 | 339 | 340 | if __name__ == "__main__": 341 | main() 342 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: Larry Smith Jr. 4 | description: Ansible role to install/configure an NGINX load balancer for HTTP/HTTPS/TCP/UDP 5 | 6 | license: MIT 7 | 8 | min_ansible_version: 2.5 9 | 10 | platforms: 11 | - name: Ubuntu 12 | versions: 13 | - bionic 14 | - trusty 15 | - xenial 16 | - zesty 17 | 18 | galaxy_tags: 19 | - loadbalancing 20 | 21 | dependencies: [] 22 | -------------------------------------------------------------------------------- /molecule/centos7/INSTALL.rst: -------------------------------------------------------------------------------- 1 | ******* 2 | Docker driver installation guide 3 | ******* 4 | 5 | Requirements 6 | ============ 7 | 8 | * Docker Engine 9 | 10 | Install 11 | ======= 12 | 13 | Please refer to the `Virtual environment`_ documentation for installation best 14 | practices. If not using a virtual environment, please consider passing the 15 | widely recommended `'--user' flag`_ when invoking ``pip``. 16 | 17 | .. _Virtual environment: https://virtualenv.pypa.io/en/latest/ 18 | .. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site 19 | 20 | .. code-block:: bash 21 | 22 | $ pip install 'molecule[docker]' 23 | -------------------------------------------------------------------------------- /molecule/centos7/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | enabled: true 5 | options: 6 | role-file: requirements.yml 7 | driver: 8 | name: docker 9 | lint: | 10 | yamllint . 11 | ansible-lint 12 | flake8 13 | platforms: 14 | - name: centos7 15 | image: jrei/systemd-centos:7 16 | privileged: true 17 | command: /usr/sbin/init 18 | tmpfs: 19 | - /run 20 | - /tmp 21 | volumes: 22 | - /sys/fs/cgroup:/sys/fs/cgroup:ro 23 | provisioner: 24 | name: ansible 25 | playbooks: 26 | converge: ../shared/converge.yml 27 | verifier: 28 | name: ansible 29 | -------------------------------------------------------------------------------- /molecule/centos7/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is an example playbook to execute Ansible tests. 3 | 4 | - name: Verify 5 | hosts: all 6 | tasks: 7 | - name: Example assertion 8 | assert: 9 | that: true 10 | -------------------------------------------------------------------------------- /molecule/centos8/INSTALL.rst: -------------------------------------------------------------------------------- 1 | ******* 2 | Docker driver installation guide 3 | ******* 4 | 5 | Requirements 6 | ============ 7 | 8 | * Docker Engine 9 | 10 | Install 11 | ======= 12 | 13 | Please refer to the `Virtual environment`_ documentation for installation best 14 | practices. If not using a virtual environment, please consider passing the 15 | widely recommended `'--user' flag`_ when invoking ``pip``. 16 | 17 | .. _Virtual environment: https://virtualenv.pypa.io/en/latest/ 18 | .. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site 19 | 20 | .. code-block:: bash 21 | 22 | $ pip install 'molecule[docker]' 23 | -------------------------------------------------------------------------------- /molecule/centos8/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | enabled: true 5 | options: 6 | role-file: requirements.yml 7 | driver: 8 | name: docker 9 | lint: | 10 | yamllint . 11 | ansible-lint 12 | flake8 13 | platforms: 14 | - name: centos8 15 | image: jrei/systemd-centos:8 16 | privileged: true 17 | command: /usr/sbin/init 18 | tmpfs: 19 | - /run 20 | - /tmp 21 | volumes: 22 | - /sys/fs/cgroup:/sys/fs/cgroup:ro 23 | provisioner: 24 | name: ansible 25 | playbooks: 26 | converge: ../shared/converge.yml 27 | verifier: 28 | name: ansible 29 | -------------------------------------------------------------------------------- /molecule/centos8/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is an example playbook to execute Ansible tests. 3 | 4 | - name: Verify 5 | hosts: all 6 | tasks: 7 | - name: Example assertion 8 | assert: 9 | that: true 10 | -------------------------------------------------------------------------------- /molecule/debian10/INSTALL.rst: -------------------------------------------------------------------------------- 1 | ******* 2 | Docker driver installation guide 3 | ******* 4 | 5 | Requirements 6 | ============ 7 | 8 | * Docker Engine 9 | 10 | Install 11 | ======= 12 | 13 | Please refer to the `Virtual environment`_ documentation for installation best 14 | practices. If not using a virtual environment, please consider passing the 15 | widely recommended `'--user' flag`_ when invoking ``pip``. 16 | 17 | .. _Virtual environment: https://virtualenv.pypa.io/en/latest/ 18 | .. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site 19 | 20 | .. code-block:: bash 21 | 22 | $ pip install 'molecule[docker]' 23 | -------------------------------------------------------------------------------- /molecule/debian10/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | enabled: true 5 | options: 6 | role-file: requirements.yml 7 | driver: 8 | name: docker 9 | lint: | 10 | yamllint . 11 | ansible-lint 12 | flake8 13 | platforms: 14 | - name: debian10 15 | image: jrei/systemd-debian:10 16 | privileged: true 17 | command: /lib/systemd/systemd 18 | tmpfs: 19 | - /run 20 | - /tmp 21 | volumes: 22 | - /sys/fs/cgroup:/sys/fs/cgroup:ro 23 | provisioner: 24 | name: ansible 25 | playbooks: 26 | converge: ../shared/converge.yml 27 | verifier: 28 | name: ansible 29 | -------------------------------------------------------------------------------- /molecule/debian10/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is an example playbook to execute Ansible tests. 3 | 4 | - name: Verify 5 | hosts: all 6 | tasks: 7 | - name: Example assertion 8 | assert: 9 | that: true 10 | -------------------------------------------------------------------------------- /molecule/debian8/INSTALL.rst: -------------------------------------------------------------------------------- 1 | ******* 2 | Docker driver installation guide 3 | ******* 4 | 5 | Requirements 6 | ============ 7 | 8 | * Docker Engine 9 | 10 | Install 11 | ======= 12 | 13 | Please refer to the `Virtual environment`_ documentation for installation best 14 | practices. If not using a virtual environment, please consider passing the 15 | widely recommended `'--user' flag`_ when invoking ``pip``. 16 | 17 | .. _Virtual environment: https://virtualenv.pypa.io/en/latest/ 18 | .. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site 19 | 20 | .. code-block:: bash 21 | 22 | $ pip install 'molecule[docker]' 23 | -------------------------------------------------------------------------------- /molecule/debian8/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | enabled: true 5 | options: 6 | role-file: requirements.yml 7 | driver: 8 | name: docker 9 | lint: | 10 | yamllint . 11 | ansible-lint 12 | flake8 13 | platforms: 14 | - name: debian8 15 | image: jrei/systemd-debian:8 16 | privileged: true 17 | command: /lib/systemd/systemd 18 | tmpfs: 19 | - /run 20 | - /tmp 21 | volumes: 22 | - /sys/fs/cgroup:/sys/fs/cgroup:ro 23 | provisioner: 24 | name: ansible 25 | playbooks: 26 | converge: ../shared/converge.yml 27 | verifier: 28 | name: ansible 29 | -------------------------------------------------------------------------------- /molecule/debian8/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is an example playbook to execute Ansible tests. 3 | 4 | - name: Verify 5 | hosts: all 6 | tasks: 7 | - name: Example assertion 8 | assert: 9 | that: true 10 | -------------------------------------------------------------------------------- /molecule/debian9/INSTALL.rst: -------------------------------------------------------------------------------- 1 | ******* 2 | Docker driver installation guide 3 | ******* 4 | 5 | Requirements 6 | ============ 7 | 8 | * Docker Engine 9 | 10 | Install 11 | ======= 12 | 13 | Please refer to the `Virtual environment`_ documentation for installation best 14 | practices. If not using a virtual environment, please consider passing the 15 | widely recommended `'--user' flag`_ when invoking ``pip``. 16 | 17 | .. _Virtual environment: https://virtualenv.pypa.io/en/latest/ 18 | .. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site 19 | 20 | .. code-block:: bash 21 | 22 | $ pip install 'molecule[docker]' 23 | -------------------------------------------------------------------------------- /molecule/debian9/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | enabled: true 5 | options: 6 | role-file: requirements.yml 7 | driver: 8 | name: docker 9 | lint: | 10 | yamllint . 11 | ansible-lint 12 | flake8 13 | platforms: 14 | - name: debian9 15 | image: jrei/systemd-debian:9 16 | privileged: true 17 | command: /lib/systemd/systemd 18 | tmpfs: 19 | - /run 20 | - /tmp 21 | volumes: 22 | - /sys/fs/cgroup:/sys/fs/cgroup:ro 23 | provisioner: 24 | name: ansible 25 | playbooks: 26 | converge: ../shared/converge.yml 27 | verifier: 28 | name: ansible 29 | -------------------------------------------------------------------------------- /molecule/debian9/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is an example playbook to execute Ansible tests. 3 | 4 | - name: Verify 5 | hosts: all 6 | tasks: 7 | - name: Example assertion 8 | assert: 9 | that: true 10 | -------------------------------------------------------------------------------- /molecule/fedora/INSTALL.rst: -------------------------------------------------------------------------------- 1 | ******* 2 | Docker driver installation guide 3 | ******* 4 | 5 | Requirements 6 | ============ 7 | 8 | * Docker Engine 9 | 10 | Install 11 | ======= 12 | 13 | Please refer to the `Virtual environment`_ documentation for installation best 14 | practices. If not using a virtual environment, please consider passing the 15 | widely recommended `'--user' flag`_ when invoking ``pip``. 16 | 17 | .. _Virtual environment: https://virtualenv.pypa.io/en/latest/ 18 | .. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site 19 | 20 | .. code-block:: bash 21 | 22 | $ pip install 'molecule[docker]' 23 | -------------------------------------------------------------------------------- /molecule/fedora/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | enabled: true 5 | options: 6 | role-file: requirements.yml 7 | driver: 8 | name: docker 9 | lint: | 10 | yamllint . 11 | ansible-lint 12 | flake8 13 | platforms: 14 | - name: fedora 15 | image: jrei/systemd-fedora 16 | privileged: true 17 | command: /usr/sbin/init 18 | tmpfs: 19 | - /run 20 | - /tmp 21 | volumes: 22 | - /sys/fs/cgroup:/sys/fs/cgroup:ro 23 | provisioner: 24 | name: ansible 25 | playbooks: 26 | converge: ../shared/converge.yml 27 | verifier: 28 | name: ansible 29 | -------------------------------------------------------------------------------- /molecule/fedora/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is an example playbook to execute Ansible tests. 3 | 4 | - name: Verify 5 | hosts: all 6 | tasks: 7 | - name: Example assertion 8 | assert: 9 | that: true 10 | -------------------------------------------------------------------------------- /molecule/shared/converge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Converge 3 | hosts: all 4 | vars: 5 | nginx_load_balancer_configs: 6 | - name: google_dns 7 | frontend_listen_port: 53 8 | method: round_robin 9 | protocol: udp 10 | upstream: 11 | - server: 8.8.8.8 12 | backend_listen_port: 53 13 | - server: 8.8.4.4 14 | backend_listen_port: 53 15 | - name: web_app 16 | frontend_listen_port: 80 17 | locations: 18 | - location: / 19 | options: [] 20 | method: round_robin 21 | protocol: http 22 | server_name: 23 | - test.vagrant.local 24 | ssl: false 25 | upstream: 26 | - server: 192.168.250.11 27 | backend_listen_port: 80 28 | options: 29 | - "fail_timeout=10s" 30 | - "max_conns=0" 31 | - "weight=1" 32 | - server: 192.168.250.12 33 | backend_listen_port: 80 34 | options: 35 | - backup 36 | - "fail_timeout=10s" 37 | - "max_conns=0" 38 | - "weight=1" 39 | nginx_load_balancer_ssl: 40 | csr_key_file: "/etc/ssl/{{ inventory_hostname }}-csr.pem" 41 | enabled: true 42 | generate_keys: true 43 | private_key_file: "/etc/ssl/private/{{ inventory_hostname }}-key.pem" 44 | private_key_size: 4096 45 | private_key_type: RSA 46 | protocols: 47 | - TLSv1 48 | - TLSv1.1 49 | - TLSv1.2 50 | public_key_file: "/etc/ssl/public/{{ inventory_hostname }}-cert.pem" 51 | public_key_valid_days: 1825 52 | regenerate_keys: false 53 | tasks: 54 | - name: Include ansible-bootstrap-python 55 | include_role: 56 | name: ansible-bootstrap-python 57 | - name: Include ansible-nginx-load-balancer 58 | include_role: 59 | name: ansible-nginx-load-balancer 60 | -------------------------------------------------------------------------------- /molecule/shared/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is an example playbook to execute Ansible tests. 3 | 4 | - name: Verify 5 | hosts: all 6 | tasks: 7 | - name: Example assertion 8 | assert: 9 | that: true 10 | -------------------------------------------------------------------------------- /molecule/ubuntu1604/INSTALL.rst: -------------------------------------------------------------------------------- 1 | ******* 2 | Docker driver installation guide 3 | ******* 4 | 5 | Requirements 6 | ============ 7 | 8 | * Docker Engine 9 | 10 | Install 11 | ======= 12 | 13 | Please refer to the `Virtual environment`_ documentation for installation best 14 | practices. If not using a virtual environment, please consider passing the 15 | widely recommended `'--user' flag`_ when invoking ``pip``. 16 | 17 | .. _Virtual environment: https://virtualenv.pypa.io/en/latest/ 18 | .. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site 19 | 20 | .. code-block:: bash 21 | 22 | $ pip install 'molecule[docker]' 23 | -------------------------------------------------------------------------------- /molecule/ubuntu1604/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | enabled: true 5 | options: 6 | role-file: requirements.yml 7 | driver: 8 | name: docker 9 | lint: | 10 | yamllint . 11 | ansible-lint 12 | flake8 13 | platforms: 14 | - name: ubuntu1604 15 | image: jrei/systemd-ubuntu:16.04 16 | privileged: true 17 | command: /lib/systemd/systemd 18 | tmpfs: 19 | - /run 20 | - /tmp 21 | volumes: 22 | - /sys/fs/cgroup:/sys/fs/cgroup:ro 23 | provisioner: 24 | name: ansible 25 | playbooks: 26 | converge: ../shared/converge.yml 27 | verifier: 28 | name: ansible 29 | -------------------------------------------------------------------------------- /molecule/ubuntu1604/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is an example playbook to execute Ansible tests. 3 | 4 | - name: Verify 5 | hosts: all 6 | tasks: 7 | - name: Example assertion 8 | assert: 9 | that: true 10 | -------------------------------------------------------------------------------- /molecule/ubuntu1804/INSTALL.rst: -------------------------------------------------------------------------------- 1 | ******* 2 | Docker driver installation guide 3 | ******* 4 | 5 | Requirements 6 | ============ 7 | 8 | * Docker Engine 9 | 10 | Install 11 | ======= 12 | 13 | Please refer to the `Virtual environment`_ documentation for installation best 14 | practices. If not using a virtual environment, please consider passing the 15 | widely recommended `'--user' flag`_ when invoking ``pip``. 16 | 17 | .. _Virtual environment: https://virtualenv.pypa.io/en/latest/ 18 | .. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site 19 | 20 | .. code-block:: bash 21 | 22 | $ pip install 'molecule[docker]' 23 | -------------------------------------------------------------------------------- /molecule/ubuntu1804/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | enabled: true 5 | options: 6 | role-file: requirements.yml 7 | driver: 8 | name: docker 9 | lint: | 10 | yamllint . 11 | ansible-lint 12 | flake8 13 | platforms: 14 | - name: ubuntu1804 15 | image: jrei/systemd-ubuntu:18.04 16 | privileged: true 17 | command: /lib/systemd/systemd 18 | tmpfs: 19 | - /run 20 | - /tmp 21 | volumes: 22 | - /sys/fs/cgroup:/sys/fs/cgroup:ro 23 | provisioner: 24 | name: ansible 25 | playbooks: 26 | converge: ../shared/converge.yml 27 | verifier: 28 | name: ansible 29 | -------------------------------------------------------------------------------- /molecule/ubuntu1804/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is an example playbook to execute Ansible tests. 3 | 4 | - name: Verify 5 | hosts: all 6 | tasks: 7 | - name: Example assertion 8 | assert: 9 | that: true 10 | -------------------------------------------------------------------------------- /playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Example Playbook 3 | hosts: all 4 | vars: 5 | etc_hosts_add_all_hosts: true 6 | tasks: 7 | - name: Include ansible-etc-hosts 8 | include_role: 9 | name: ansible-etc-hosts 10 | 11 | - name: Configuring Load Balancers 12 | hosts: load_balancers 13 | vars: 14 | keepalived_config: true 15 | keepalived_router_info: 16 | - name: vrrp_1 17 | check_script: 18 | - name: chk_nginx 19 | script: pidof nginx 20 | interval: 2 21 | weight: 2 22 | master_node: "{{ groups['load_balancers'][0] }}" 23 | router_id: 51 24 | router_pri_backup: 100 25 | router_pri_master: 150 26 | vip_int: enp0s8 27 | vip_addresses: 28 | - 192.168.250.200 29 | nginx_load_balancer_configs: 30 | - name: web_app 31 | frontend_listen_port: 80 32 | location: / 33 | method: round_robin 34 | options: 35 | - proxy_buffering off 36 | - proxy_http_version 1.1 37 | - "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for" 38 | - "proxy_set_header Upgrade $http_upgrade" 39 | - "proxy_set_header Connection $http_connection" 40 | - access_log off 41 | - proxy_pass http://127.0.0.1:8080 42 | protocol: http 43 | server_name: 44 | - test.vagrant.local 45 | # ssl: true 46 | upstream: 47 | - servers: "{{ groups['web_servers'] }}" 48 | backend_listen_port: 80 49 | options: 50 | - fail_timeout=10s 51 | - max_conns=0 52 | - max_fails=1 53 | - weight=1 54 | nginx_load_balancer_headers: 55 | - "Host $host" 56 | - "X-Real-IP $remote_addr" 57 | - "X-Forwarded-For $remote_addr" 58 | - "X-Forwarded-Host $remote_addr" 59 | pri_domain_name: test.vagrant.local 60 | tasks: 61 | - name: Include ansible-bootstrap-python 62 | include_role: 63 | name: ansible-bootstrap-python 64 | - name: Include ansible-keepalived 65 | include_role: 66 | name: ansible-keepalived 67 | - name: Include ansible-nginx-load-balancer 68 | include_role: 69 | name: ansible-nginx-load-balancer 70 | 71 | - name: Configuring Web Servers 72 | hosts: web_servers 73 | vars: 74 | config_nginx: true 75 | nginx_headers: 76 | - "set_real_ip_from 192.168.250.0/24" 77 | - "real_ip_header X-Real-IP" 78 | - "real_ip_recursive on" 79 | pri_domain_name: test.vagrant.local 80 | tasks: 81 | - name: Include ansible-nginx 82 | include_role: 83 | name: ansible-nginx 84 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | # Python requirements for development -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Python requirements for executing 2 | ansible 3 | ansible-lint 4 | docker 5 | flake8 6 | molecule 7 | testinfra -------------------------------------------------------------------------------- /requirements.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - src: https://github.com/mrlesmithjr/ansible-etc-hosts 3 | - src: https://github.com/mrlesmithjr/ansible-keepalived 4 | - src: https://github.com/mrlesmithjr/ansible-bootstrap-python.git 5 | -------------------------------------------------------------------------------- /tasks/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: config | Configuring NGNIX Load Balancer 3 | template: 4 | src: etc/nginx/nginx.conf.j2 5 | dest: /etc/nginx/nginx.conf 6 | owner: root 7 | group: root 8 | mode: u=rw,g=r,o=r 9 | become: true 10 | notify: restart nginx 11 | -------------------------------------------------------------------------------- /tasks/debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: debian | Adding NGINX PPA 3 | apt_repository: 4 | repo: "{{ 'ppa:nginx/' + nginx_load_balancer_version }}" 5 | state: present 6 | become: true 7 | register: result 8 | until: result is successful 9 | 10 | - name: debian | Installing NGINX 11 | apt: 12 | name: nginx 13 | state: present 14 | become: true 15 | register: result 16 | until: result is successful 17 | 18 | - name: debian | Installing Apache2 Modules 19 | apt: 20 | name: 21 | - libapache2-mod-rpaf 22 | state: present 23 | become: true 24 | register: result 25 | until: result is successful 26 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for ansible-nginx-load-balancer 3 | - include: debian.yml 4 | when: ansible_os_family == "Debian" 5 | 6 | - include: ssl.yml 7 | when: 8 | - nginx_load_balancer_ssl is defined 9 | - nginx_load_balancer_ssl != {} 10 | - nginx_load_balancer_ssl['enabled']|bool 11 | 12 | - include: config.yml 13 | -------------------------------------------------------------------------------- /tasks/ssl.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: ssl | Installing Python Modules 3 | pip: 4 | name: 5 | - pyOpenSSL 6 | state: present 7 | become: true 8 | register: result 9 | until: result is successful 10 | 11 | - name: ssl | Ensuring SSL Keys Folders Exist 12 | file: 13 | path: "{{ item|dirname }}" 14 | state: directory 15 | become: true 16 | loop: 17 | - "{{ nginx_load_balancer_ssl['private_key_file'] }}" 18 | - "{{ nginx_load_balancer_ssl['public_key_file'] }}" 19 | when: nginx_load_balancer_ssl['generate_keys']|bool 20 | 21 | - name: ssl | Generating SSL Private Key 22 | openssl_privatekey: 23 | force: "{{ nginx_load_balancer_ssl['regenerate_keys'] }}" 24 | path: "{{ nginx_load_balancer_ssl['private_key_file'] }}" 25 | size: "{{ nginx_load_balancer_ssl['private_key_size'] }}" 26 | state: present 27 | type: "{{ nginx_load_balancer_ssl['private_key_type'] }}" 28 | become: true 29 | register: _nginx_load_balancer_ssl_priv_key 30 | when: > 31 | nginx_load_balancer_ssl['generate_keys']|bool and 32 | (not nginx_load_balancer_ha|bool or 33 | (nginx_load_balancer_ha|bool and 34 | inventory_hostname == nginx_load_balancer_ha_primary )) 35 | 36 | # This module is included in Ansible 2.4 so for now it is included in library/ 37 | - name: ssl | Generating SSL CSR 38 | openssl_csr: 39 | force: "{{ nginx_load_balancer_ssl['regenerate_keys'] }}" 40 | commonName: "{{ inventory_hostname }}" 41 | path: "{{ nginx_load_balancer_ssl['csr_key_file'] }}" 42 | privatekey_path: "{{ nginx_load_balancer_ssl['private_key_file'] }}" 43 | become: true 44 | register: _nginx_load_balancer_ssl_csr 45 | when: > 46 | nginx_load_balancer_ssl['generate_keys']|bool and 47 | (not nginx_load_balancer_ha|bool or 48 | (nginx_load_balancer_ha|bool and 49 | inventory_hostname == nginx_load_balancer_ha_primary )) 50 | 51 | # The below module does not work as expected 52 | # - name: ssl | Generating SSL Public Key 53 | # openssl_publickey: 54 | # force: "{{ nginx_load_balancer_ssl['regenerate_keys'] }}" 55 | # path: "{{ nginx_load_balancer_ssl['public_key_file'] }}" 56 | # privatekey_path: "{{ nginx_load_balancer_ssl['private_key_file'] }}" 57 | # state: "present" 58 | # become: true 59 | # when: nginx_load_balancer_ssl['generate_keys'] 60 | 61 | - name: ssl | Generating SSL Public Key # noqa 503 62 | command: > 63 | openssl req 64 | -x509 65 | -days {{ nginx_load_balancer_ssl['public_key_valid_days'] }} 66 | -key {{ nginx_load_balancer_ssl['private_key_file'] }} 67 | -in {{ nginx_load_balancer_ssl['csr_key_file'] }} 68 | -out {{ nginx_load_balancer_ssl['public_key_file'] }} 69 | become: true 70 | when: > 71 | nginx_load_balancer_ssl['generate_keys']|bool and 72 | (not nginx_load_balancer_ha|bool or 73 | (nginx_load_balancer_ha|bool and 74 | inventory_hostname == nginx_load_balancer_ha_primary )) and 75 | (_nginx_load_balancer_ssl_priv_key['changed'] or 76 | _nginx_load_balancer_ssl_csr['changed']) 77 | 78 | # We capture the ha primary private key in order to sync to all other load 79 | # balancers. This will ensure that all load balancers use the same key for SSL. 80 | - name: ssl | Capturing Private SSL Key On Primary 81 | slurp: 82 | src: "{{ nginx_load_balancer_ssl['private_key_file'] }}" 83 | become: true 84 | register: _nginx_load_balancer_ssl_priv_key_ 85 | when: 86 | - nginx_load_balancer_ssl['generate_keys']|bool 87 | - nginx_load_balancer_ha|bool 88 | - inventory_hostname == nginx_load_balancer_ha_primary 89 | 90 | # We capture the ha primary public key in order to sync to all other load 91 | # balancers. This will ensure that all load balancers use the same key for SSL. 92 | - name: ssl | Capturing Public SSL Key On Primary 93 | slurp: 94 | src: "{{ nginx_load_balancer_ssl['public_key_file'] }}" 95 | become: true 96 | register: _nginx_load_balancer_ssl_pub_key_ 97 | when: 98 | - nginx_load_balancer_ssl['generate_keys']|bool 99 | - nginx_load_balancer_ha|bool 100 | - inventory_hostname == nginx_load_balancer_ha_primary 101 | 102 | # We now sync the ha primary private key to all load balancers. This will ensure 103 | # that all load balancers are configured to use the same key for SSL. 104 | - name: ssl | Syncing Primary SSL Private Key 105 | template: 106 | src: key.j2 107 | dest: "{{ nginx_load_balancer_ha_key_file_prefix + '-key.pem' }}" 108 | become: true 109 | when: 110 | - nginx_load_balancer_ssl['generate_keys']|bool 111 | - nginx_load_balancer_ha|bool 112 | 113 | # We now sync the ha primary public key to all load balancers. This will ensure 114 | # that all load balancers are configured to use the same key for SSL. 115 | - name: ssl | Syncing Primary SSL Public Key 116 | template: 117 | src: cert.j2 118 | dest: "{{ nginx_load_balancer_ha_key_file_prefix + '-cert.pem' }}" 119 | become: true 120 | when: 121 | - nginx_load_balancer_ssl['generate_keys']|bool 122 | - nginx_load_balancer_ha|bool 123 | -------------------------------------------------------------------------------- /templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrlesmithjr/ansible-nginx-load-balancer/762f50630d4c9ae135cda0e759b9df49d54a8d82/templates/.gitkeep -------------------------------------------------------------------------------- /templates/cert.j2: -------------------------------------------------------------------------------- 1 | {{ hostvars[nginx_load_balancer_ha_primary]['_nginx_load_balancer_ssl_pub_key_']['content']|b64decode }} 2 | -------------------------------------------------------------------------------- /templates/etc/nginx/nginx.conf.j2: -------------------------------------------------------------------------------- 1 | {{ ansible_managed|comment }} 2 | 3 | pid {{ ngninx_load_balancer_pid }}; 4 | user {{ nginx_load_balancer_user }}; 5 | worker_processes {{ nginx_load_balancer_worker_processes }}; 6 | {% if nginx_load_balancer_includes is defined %} 7 | {% for item in nginx_load_balancer_includes %} 8 | include {{ item }}; 9 | {% endfor %} 10 | {% endif %} 11 | {% if nginx_load_balancer_events is defined %} 12 | events { 13 | {% for item in nginx_load_balancer_events %} 14 | {{ item }}; 15 | {% endfor %} 16 | } 17 | {% endif %} 18 | {% if nginx_load_balancer_configs is defined %} 19 | http { 20 | {% for item1 in nginx_load_balancer_configs %} 21 | {% if item1['protocol']|lower == 'http' or item1['protocol']|lower == 'https' %} 22 | {% if item1['upstream'] is defined and item1['upstream'] != [] %} 23 | upstream {{ item1['name'] }} { 24 | {% if item1['method'] != 'round_robin' %} 25 | {{ item1['method'] }}; 26 | {% endif %} 27 | {% for item2 in item1['upstream'] %} 28 | {% set blp = item2['backend_listen_port'] %} 29 | {% if item2['server'] is defined %} 30 | server {{ item2['server'] }}:{{ blp }}{% if item2['options'] is defined %} {{ item2['options']|join(' ') }}{% endif %}; 31 | {% elif item2['servers'] is defined %} 32 | {% for item3 in item2['servers'] %} 33 | server {{ item3 }}:{{ blp }}{% if item2['options'] is defined %} {{ item2['options']|join(' ') }}{% endif %}; 34 | {% endfor %} 35 | {% endif %} 36 | {% endfor %} 37 | } 38 | {% endif %} 39 | server { 40 | listen {{ item1['frontend_listen_port'] }}{% if item1['ssl']|default(false) %} ssl{% endif %}; 41 | server_name {{ item1['server_name']|join(' ') }}; 42 | {% for location in item1['locations'] %} 43 | location {{ location['location'] }} { 44 | {% if location['options'] is defined and location['options'] != [] %} 45 | {% for option in location['options'] %} 46 | {{ option }}; 47 | {% endfor %} 48 | {% endif %} 49 | } 50 | {% endfor %} 51 | {% if item1['ssl']|default(false) %} 52 | {% if not nginx_load_balancer_ha %} 53 | ssl_certificate {{ nginx_load_balancer_ssl['public_key_file'] }}; 54 | ssl_certificate_key {{ nginx_load_balancer_ssl['private_key_file'] }}; 55 | {% elif nginx_load_balancer_ha %} 56 | ssl_certificate {{ nginx_load_balancer_ha_key_file_prefix }}-cert.pem; 57 | ssl_certificate_key {{ nginx_load_balancer_ha_key_file_prefix }}-key.pem; 58 | {% endif %} 59 | {% endif %} 60 | } 61 | {% endif %} 62 | {% endfor %} 63 | } 64 | stream { 65 | {% for item1 in nginx_load_balancer_configs %} 66 | {% if item1['protocol']|lower == 'tcp' or item1['protocol']|lower == 'udp' %} 67 | upstream {{ item1['name'] }} { 68 | {% if item1['method'] != 'round_robin' %} 69 | {{ item1['method'] }}; 70 | {% endif %} 71 | {% if item1['upstream'] is defined %} 72 | {% for item2 in item1['upstream'] %} 73 | {% set blp = item2['backend_listen_port'] %} 74 | {% if item2['server'] is defined %} 75 | server {{ item2['server'] }}:{{ blp }}{% if item2['options'] is defined %} {{ item2['options']|join(' ') }}{% endif %}; 76 | {% elif item2['servers'] is defined %} 77 | {% for item3 in item2['servers'] %} 78 | server {{ item3 }}:{{ blp }}{% if item2['options'] is defined %} {{ item2['options']|join(' ') }}{% endif %}; 79 | {% endfor %} 80 | {% endif %} 81 | {% endfor %} 82 | {% endif %} 83 | } 84 | server { 85 | listen {{ item1['frontend_listen_port'] }} {% if item1['protocol'] != "tcp" %}{{ item1['protocol'] }}{% endif %}; 86 | proxy_pass {{ item1['name'] }}; 87 | } 88 | {% endif %} 89 | {% endfor %} 90 | } 91 | {% endif %} 92 | -------------------------------------------------------------------------------- /templates/key.j2: -------------------------------------------------------------------------------- 1 | {{ hostvars[nginx_load_balancer_ha_primary]['_nginx_load_balancer_ssl_priv_key_']['content']|b64decode }} 2 | -------------------------------------------------------------------------------- /vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for ansible-nginx-load-balancer 3 | --------------------------------------------------------------------------------