├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── README.md ├── build-oss-image.md ├── build-plus-image.md ├── configuration.md ├── nginx-oss-router-install.md └── nginx-plus-router-install.md ├── examples ├── cafe-app │ ├── README.md │ ├── cafe-app.yaml │ ├── coffee-route.yaml │ ├── dashboard.png │ └── tea-route.yaml └── tcp-udp │ ├── README.md │ ├── dns-tcp-route.yaml │ ├── dns-udp-route.yaml │ └── dns.yaml └── src ├── nginx-plus ├── Dockerfile ├── conf │ ├── error-page-503.html │ └── nginx-config.template └── reload-nginx └── nginx ├── Dockerfile ├── conf ├── error-page-503.html └── nginx-config.template ├── nginx.repo └── reload-nginx /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Deploy using 'some_command' 13 | 2. View logs '....' 14 | 3. See error 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Your environment** 20 | * NGINX Router version 21 | * Openshift version 22 | * NGINX or NGINX Plus version 23 | 24 | **Additional context** 25 | Add any other context about the problem here. Any log files you want to share. 26 | 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context about the feature request here. 18 | 19 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Proposed changes 2 | Describe the use case and detail of the change. If this PR addresses an issue on GitHub, make sure to include a link to that issue here in this description (not in the title of the PR). 3 | 4 | ### Checklist 5 | Before creating a PR, run through this checklist and mark each as complete. 6 | 7 | - [ ] I have read the [CONTRIBUTING](https://github.com/nginxinc/nginx-openshift-router/blob/master/CONTRIBUTING.md) guide 8 | - [ ] I have proven my fix is effective or that my feature works 9 | - [ ] I have updated necessary documentation 10 | - [ ] I have rebased my branch onto master 11 | - [ ] I will ensure my PR is targeting the master branch and pulling from my branch on my own fork 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # NGINX Plus license files 2 | *.crt 3 | *.key 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Release 0.2 4 | 5 | **FEATURES**: 6 | * [5](https://github.com/nginxinc/nginx-openshift-router/pull/5): *Support for Prometheus*. NGINX Plus Router can optionally expose metrics ready to be collected by Prometheus. 7 | * [1](https://github.com/nginxinc/nginx-openshift-router/pull/1): *Support for TCP/UDP load balancing*. NGINX Plus Router brings support for load balancing TCP/UDP applications, including supporting edge TLS termination and re-encryption for TCP, via a TCP/UDP load balancing extension. 8 | 9 | ## Release 0.1 10 | * Initial release. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | The following is a set of guidelines for contributing to the NGINX OpenShift Router. We really appreciate that you are considering contributing! 4 | 5 | #### Table Of Contents 6 | 7 | [Ask a Question](#ask-a-question) 8 | 9 | [Getting Started](#getting-started) 10 | 11 | [Contributing](#contributing) 12 | 13 | [Git Style Guide](#git-style-guide) 14 | 15 | [Code of Conduct](#code-of-conduct) 16 | 17 | ## Ask a Question 18 | 19 | We will have a public forum soon where you can come and ask questions and have a discussion. For now please open an Issue on GitHub with the label `question`. 20 | 21 | ## Getting Started 22 | 23 | Follow our [NGINX](docs/nginx-oss-router-install.md) or [NGINX Plus](docs/nginx-plus-router-install.md) Installation Guides to get the NGINX Router up and running. 24 | 25 | Read the [documentation](docs) and [configuration](examples) examples. 26 | 27 | ## Contributing 28 | 29 | ### Report a Bug 30 | 31 | To report a bug, open an issue on GitHub with the label `bug` using the available bug report issue template. Please ensure the issue has not already been reported. 32 | 33 | ### Suggest an Enhancement 34 | 35 | To suggest an enhancement, please create an issue on GitHub with the label `enhancement` using the available feature issue template. 36 | 37 | ### Open a Pull Request 38 | 39 | * Fork the repo, create a branch, submit a PR when your changes are tested and ready for review 40 | * Fill in [our pull request template](https://github.com/nginxinc/nginx-openshift-router/blob/master/.github/PULL_REQUEST_TEMPLATE.md) 41 | 42 | Note: if you’d like to implement a new feature, please consider creating a feature request issue first to start a discussion about the feature. 43 | 44 | ## Git Style Guide 45 | 46 | * Keep a clean, concise and meaningful git commit history on your branch, rebasing locally and squashing before submitting a PR 47 | * Follow the guidelines of writing a good commit message as described here https://chris.beams.io/posts/git-commit/ and summarised in the next few points 48 | * In the subject line, use the present tense ("Add feature" not "Added feature") 49 | * In the subject line, use the imperative mood ("Move cursor to..." not "Moves cursor to...") 50 | * Limit the subject line to 72 characters or less 51 | * Reference issues and pull requests liberally after the subject line 52 | * Add more detailed description in the body of the git message (`git commit -a` to give you more space and time in your text editor to write a good message instead of `git commit -am`) 53 | 54 | ## Code of Conduct 55 | 56 | This project and everyone participating in it is governed by this code. 57 | 58 | ### Our Pledge 59 | 60 | In the interest of fostering an open and welcoming environment, we as 61 | contributors and maintainers pledge to making participation in our project and 62 | our community a harassment-free experience for everyone, regardless of age, body 63 | size, disability, ethnicity, sex characteristics, gender identity and expression, 64 | level of experience, education, socio-economic status, nationality, personal 65 | appearance, race, religion, or sexual identity and orientation. 66 | 67 | ### Our Standards 68 | 69 | Examples of behavior that contributes to creating a positive environment 70 | include: 71 | 72 | * Using welcoming and inclusive language 73 | * Being respectful of differing viewpoints and experiences 74 | * Gracefully accepting constructive criticism 75 | * Focusing on what is best for the community 76 | * Showing empathy towards other community members 77 | 78 | Examples of unacceptable behavior by participants include: 79 | 80 | * The use of sexualized language or imagery and unwelcome sexual attention or 81 | advances 82 | * Trolling, insulting/derogatory comments, and personal or political attacks 83 | * Public or private harassment 84 | * Publishing others' private information, such as a physical or electronic 85 | address, without explicit permission 86 | * Other conduct which could reasonably be considered inappropriate in a 87 | professional setting 88 | 89 | ### Our Responsibilities 90 | 91 | Project maintainers are responsible for clarifying the standards of acceptable 92 | behavior and are expected to take appropriate and fair corrective action in 93 | response to any instances of unacceptable behavior. 94 | 95 | Project maintainers have the right and responsibility to remove, edit, or 96 | reject comments, commits, code, wiki edits, issues, and other contributions 97 | that are not aligned to this Code of Conduct, or to ban temporarily or 98 | permanently any contributor for other behaviors that they deem inappropriate, 99 | threatening, offensive, or harmful. 100 | 101 | ### Scope 102 | 103 | This Code of Conduct applies both within project spaces and in public spaces 104 | when an individual is representing the project or its community. Examples of 105 | representing a project or community include using an official project e-mail 106 | address, posting via an official social media account, or acting as an appointed 107 | representative at an online or offline event. Representation of a project may be 108 | further defined and clarified by project maintainers. 109 | 110 | ### Enforcement 111 | 112 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 113 | reported by contacting the project team at [mailto:nginx@nginx.org]. All 114 | complaints will be reviewed and investigated and will result in a response that 115 | is deemed necessary and appropriate to the circumstances. The project team is 116 | obligated to maintain confidentiality with regard to the reporter of an incident. 117 | Further details of specific enforcement policies may be posted separately. 118 | 119 | Project maintainers who do not follow or enforce the Code of Conduct in good 120 | faith may face temporary or permanent repercussions as determined by other 121 | members of the project's leadership. 122 | 123 | ### Attribution 124 | 125 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 126 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2018 Nginx, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | This project includes source files with or without modification 204 | from OpenShift Origin (https://github.com/openshift/origin), distributed 205 | under the following license: 206 | 207 | 208 | Apache License 209 | Version 2.0, January 2004 210 | http://www.apache.org/licenses/ 211 | 212 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 213 | 214 | 1. Definitions. 215 | 216 | "License" shall mean the terms and conditions for use, reproduction, 217 | and distribution as defined by Sections 1 through 9 of this document. 218 | 219 | "Licensor" shall mean the copyright owner or entity authorized by 220 | the copyright owner that is granting the License. 221 | 222 | "Legal Entity" shall mean the union of the acting entity and all 223 | other entities that control, are controlled by, or are under common 224 | control with that entity. For the purposes of this definition, 225 | "control" means (i) the power, direct or indirect, to cause the 226 | direction or management of such entity, whether by contract or 227 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 228 | outstanding shares, or (iii) beneficial ownership of such entity. 229 | 230 | "You" (or "Your") shall mean an individual or Legal Entity 231 | exercising permissions granted by this License. 232 | 233 | "Source" form shall mean the preferred form for making modifications, 234 | including but not limited to software source code, documentation 235 | source, and configuration files. 236 | 237 | "Object" form shall mean any form resulting from mechanical 238 | transformation or translation of a Source form, including but 239 | not limited to compiled object code, generated documentation, 240 | and conversions to other media types. 241 | 242 | "Work" shall mean the work of authorship, whether in Source or 243 | Object form, made available under the License, as indicated by a 244 | copyright notice that is included in or attached to the work 245 | (an example is provided in the Appendix below). 246 | 247 | "Derivative Works" shall mean any work, whether in Source or Object 248 | form, that is based on (or derived from) the Work and for which the 249 | editorial revisions, annotations, elaborations, or other modifications 250 | represent, as a whole, an original work of authorship. For the purposes 251 | of this License, Derivative Works shall not include works that remain 252 | separable from, or merely link (or bind by name) to the interfaces of, 253 | the Work and Derivative Works thereof. 254 | 255 | "Contribution" shall mean any work of authorship, including 256 | the original version of the Work and any modifications or additions 257 | to that Work or Derivative Works thereof, that is intentionally 258 | submitted to Licensor for inclusion in the Work by the copyright owner 259 | or by an individual or Legal Entity authorized to submit on behalf of 260 | the copyright owner. For the purposes of this definition, "submitted" 261 | means any form of electronic, verbal, or written communication sent 262 | to the Licensor or its representatives, including but not limited to 263 | communication on electronic mailing lists, source code control systems, 264 | and issue tracking systems that are managed by, or on behalf of, the 265 | Licensor for the purpose of discussing and improving the Work, but 266 | excluding communication that is conspicuously marked or otherwise 267 | designated in writing by the copyright owner as "Not a Contribution." 268 | 269 | "Contributor" shall mean Licensor and any individual or Legal Entity 270 | on behalf of whom a Contribution has been received by Licensor and 271 | subsequently incorporated within the Work. 272 | 273 | 2. Grant of Copyright License. Subject to the terms and conditions of 274 | this License, each Contributor hereby grants to You a perpetual, 275 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 276 | copyright license to reproduce, prepare Derivative Works of, 277 | publicly display, publicly perform, sublicense, and distribute the 278 | Work and such Derivative Works in Source or Object form. 279 | 280 | 3. Grant of Patent License. Subject to the terms and conditions of 281 | this License, each Contributor hereby grants to You a perpetual, 282 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 283 | (except as stated in this section) patent license to make, have made, 284 | use, offer to sell, sell, import, and otherwise transfer the Work, 285 | where such license applies only to those patent claims licensable 286 | by such Contributor that are necessarily infringed by their 287 | Contribution(s) alone or by combination of their Contribution(s) 288 | with the Work to which such Contribution(s) was submitted. If You 289 | institute patent litigation against any entity (including a 290 | cross-claim or counterclaim in a lawsuit) alleging that the Work 291 | or a Contribution incorporated within the Work constitutes direct 292 | or contributory patent infringement, then any patent licenses 293 | granted to You under this License for that Work shall terminate 294 | as of the date such litigation is filed. 295 | 296 | 4. Redistribution. You may reproduce and distribute copies of the 297 | Work or Derivative Works thereof in any medium, with or without 298 | modifications, and in Source or Object form, provided that You 299 | meet the following conditions: 300 | 301 | (a) You must give any other recipients of the Work or 302 | Derivative Works a copy of this License; and 303 | 304 | (b) You must cause any modified files to carry prominent notices 305 | stating that You changed the files; and 306 | 307 | (c) You must retain, in the Source form of any Derivative Works 308 | that You distribute, all copyright, patent, trademark, and 309 | attribution notices from the Source form of the Work, 310 | excluding those notices that do not pertain to any part of 311 | the Derivative Works; and 312 | 313 | (d) If the Work includes a "NOTICE" text file as part of its 314 | distribution, then any Derivative Works that You distribute must 315 | include a readable copy of the attribution notices contained 316 | within such NOTICE file, excluding those notices that do not 317 | pertain to any part of the Derivative Works, in at least one 318 | of the following places: within a NOTICE text file distributed 319 | as part of the Derivative Works; within the Source form or 320 | documentation, if provided along with the Derivative Works; or, 321 | within a display generated by the Derivative Works, if and 322 | wherever such third-party notices normally appear. The contents 323 | of the NOTICE file are for informational purposes only and 324 | do not modify the License. You may add Your own attribution 325 | notices within Derivative Works that You distribute, alongside 326 | or as an addendum to the NOTICE text from the Work, provided 327 | that such additional attribution notices cannot be construed 328 | as modifying the License. 329 | 330 | You may add Your own copyright statement to Your modifications and 331 | may provide additional or different license terms and conditions 332 | for use, reproduction, or distribution of Your modifications, or 333 | for any such Derivative Works as a whole, provided Your use, 334 | reproduction, and distribution of the Work otherwise complies with 335 | the conditions stated in this License. 336 | 337 | 5. Submission of Contributions. Unless You explicitly state otherwise, 338 | any Contribution intentionally submitted for inclusion in the Work 339 | by You to the Licensor shall be under the terms and conditions of 340 | this License, without any additional terms or conditions. 341 | Notwithstanding the above, nothing herein shall supersede or modify 342 | the terms of any separate license agreement you may have executed 343 | with Licensor regarding such Contributions. 344 | 345 | 6. Trademarks. This License does not grant permission to use the trade 346 | names, trademarks, service marks, or product names of the Licensor, 347 | except as required for reasonable and customary use in describing the 348 | origin of the Work and reproducing the content of the NOTICE file. 349 | 350 | 7. Disclaimer of Warranty. Unless required by applicable law or 351 | agreed to in writing, Licensor provides the Work (and each 352 | Contributor provides its Contributions) on an "AS IS" BASIS, 353 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 354 | implied, including, without limitation, any warranties or conditions 355 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 356 | PARTICULAR PURPOSE. You are solely responsible for determining the 357 | appropriateness of using or redistributing the Work and assume any 358 | risks associated with Your exercise of permissions under this License. 359 | 360 | 8. Limitation of Liability. In no event and under no legal theory, 361 | whether in tort (including negligence), contract, or otherwise, 362 | unless required by applicable law (such as deliberate and grossly 363 | negligent acts) or agreed to in writing, shall any Contributor be 364 | liable to You for damages, including any direct, indirect, special, 365 | incidental, or consequential damages of any character arising as a 366 | result of this License or out of the use or inability to use the 367 | Work (including but not limited to damages for loss of goodwill, 368 | work stoppage, computer failure or malfunction, or any and all 369 | other commercial damages or losses), even if such Contributor 370 | has been advised of the possibility of such damages. 371 | 372 | 9. Accepting Warranty or Additional Liability. While redistributing 373 | the Work or Derivative Works thereof, You may choose to offer, 374 | and charge a fee for, acceptance of support, warranty, indemnity, 375 | or other liability obligations and/or rights consistent with this 376 | License. However, in accepting such obligations, You may act only 377 | on Your own behalf and on Your sole responsibility, not on behalf 378 | of any other Contributor, and only if You agree to indemnify, 379 | defend, and hold each Contributor harmless for any liability 380 | incurred by, or claims asserted against, such Contributor by reason 381 | of your accepting any such warranty or additional liability. 382 | 383 | END OF TERMS AND CONDITIONS 384 | 385 | Copyright 2014 Red Hat, Inc. 386 | 387 | Licensed under the Apache License, Version 2.0 (the "License"); 388 | you may not use this file except in compliance with the License. 389 | You may obtain a copy of the License at 390 | 391 | http://www.apache.org/licenses/LICENSE-2.0 392 | 393 | Unless required by applicable law or agreed to in writing, software 394 | distributed under the License is distributed on an "AS IS" BASIS, 395 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 396 | See the License for the specific language governing permissions and 397 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Project Status: Abandoned – Initial development has started, but there has not yet been a stable, usable release; the project has been abandoned and the author(s) do not intend on continuing development.](https://www.repostatus.org/badges/latest/abandoned.svg)](https://www.repostatus.org/#abandoned) 2 | 3 | # NGINX OpenShift Router 4 | 5 | # This repository has been archived. There will likely be no further development on the project and security vulnerabilities may be unaddressed. 6 | 7 | 8 | This repo includes an implementation of an OpenShift Router based on [NGINX](https://nginx.org) and [NGINX Plus](https://www.nginx.com/products/). 9 | 10 | ## What is the Router? 11 | 12 | The [Router](https://docs.okd.io/latest/install_config/router/index.html) provides edge load balancing for applications on OpenShift, acting as an entry point for all external requests coming to applications running on OpenShift. The Router’s job is to identify which application a particular request is sent to and then route it to an instance (pod) of that application. OpenShift includes a special resource named [Route](https://docs.okd.io/latest/architecture/networking/routes.html) for configuring the Router. 13 | 14 | ## NGINX OpenShift Router 15 | 16 | NGINX Router is built on top of OpenShift Template Router. Below are the key features of NGINX Router: 17 | * **Full support of the Route specification.** NGINX Router fully supports the features defined by the Route resource. 18 | * **Customization options.** Various customization options and extra features are available through environment variables and Route annotations – a common approach in other Router implementations. 19 | * **Familiar operational experience.** NGINX Router is integrated in OpenShift through the Template Router software, the same software that underpins the default Router implementation. As a result, you get the familiar operational experience, which makes it easier to migrate from the default Router implementation. 20 | * **NGINX performance and stability.** With NGINX Router you get the performance and reliability of NGINX software. 21 | * **Latest NGINX features.** We are also excited to bring our new features, such as native support for gRPC load balancing, into the OpenShift Router. As new features are made available in NGINX and NGINX Plus, they can be incorporated into the Router’s capabilities. 22 | * **Support for TCP/UDP load balancing.** NGINX Router brings support for load balancing TCP/UDP applications, including supporting edge TLS termination and re-encryption for TCP, via a TCP/UDP load balancing [extension](docs/configuration.md/#tcpudp-load-balancing-extension). 23 | * **Support for Prometheus**. NGINX Router can optionally expose metrics ready to be collected by [Prometheus](https://prometheus.io/). 24 | * **Advanced features of NGINX Plus.** When NGINX Router is used with NGINX Plus, you get the additional benefits of NGINX Plus, such as its monitoring API, dashboard, extended number of metrics for Prometheus and more [fine-tuned](docs/configuration.md#fine-tuning-load-balancing-methods-with-nginx-plus) control over load balancing methods. 25 | 26 | ## How To Get Started 27 | 28 | * Read the installation guide for [NGINX](docs/nginx-oss-router-install.md) or [NGINX Plus](docs/nginx-plus-router-install.md) installation instructions. 29 | * See how to use NGINX Router for edge load balancing of an example HTTP application in our [Cafe Application example](examples/cafe-app). 30 | * See how to use NGINX Router for edge load balancing of a TCP/UDP application in our [TCP/UDP example](examples/tcp-udp). 31 | 32 | ## Contacts 33 | 34 | We’d like to hear your feedback! If you have any questions or suggestions for NGINX Router, please create an issue on GitHub. 35 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ## Documentation 2 | 3 | ### NGINX Router 4 | 5 | * [Installation](nginx-oss-router-install.md) 6 | * [Building NGINX Router Image](build-oss-image.md) 7 | * [Configuration](configuration.md) 8 | 9 | ### NGINX Router with NGINX Plus (NGINX Plus Router) 10 | 11 | * [Installation](nginx-plus-router-install.md) 12 | * [Building NGINX Router Image with NGINX Plus](build-plus-image.md) 13 | * [Configuration](configuration.md) 14 | 15 | ## Examples 16 | 17 | * [Cafe App](../examples/cafe-app/README.md) 18 | * [TCP/UDP Load Balancing](../examples/tcp-udp/README.md) -------------------------------------------------------------------------------- /docs/build-oss-image.md: -------------------------------------------------------------------------------- 1 | # How to Build the NGINX Router Image 2 | 3 | In this guide we will build the NGINX Router image and upload it to the OpenShift private registry. 4 | 5 | ## Prerequisites 6 | 7 | Before you can build the image, make sure that the following software is installed on your machine: 8 | * [Docker](https://www.docker.com/products/docker) 9 | * [git](https://git-scm.com/) 10 | 11 | **Note**: the instructions assume that you run docker commands on one of the nodes of your OpenShift cluster. To be able to push the image to the `openshift` project, your user account must have admin access to the OpenShift cluster. 12 | 13 | ## Build the Image 14 | 15 | 1. Clone the NGINX Router repo and change your directory to `src/nginx`: 16 | ``` 17 | $ git clone https://github.com/nginxinc/nginx-openshift-router 18 | $ cd nginx-openshift-router/src/nginx 19 | ``` 20 | 21 | 1. Build the image: 22 | ``` 23 | $ docker build -t nginx-openshift-router:0.2 . 24 | ``` 25 | 26 | ## Upload the Image to the OpenShift Private Registry 27 | 28 | 1. To upload the image to your private repository, you need to get login credentials for the private repository. Get those by logging into the registry portal, along with the correct URL syntax for the tag and push commands. Then, log in: 29 | ``` 30 | $ sudo docker login -p -e unused -u unused docker-registry-default.router.default.svc.cluster.local 31 | ``` 32 | 33 | 1. Tag the image: 34 | ``` 35 | $ docker tag nginx-openshift-router:0.2 docker-registry-default.router.default.svc.cluster.local/openshift/nginx-openshift-router:0.2 36 | ``` 37 | 38 | 1. Push the image to the registry: 39 | ``` 40 | $ docker push docker-registry-default.router.default.svc.cluster.local/openshift/nginx-openshift-router:0.2 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/build-plus-image.md: -------------------------------------------------------------------------------- 1 | # How to Build the NGINX Plus Router Image 2 | 3 | In this guide we will build the NGINX Plus Router image and upload it to the OpenShift private registry. 4 | 5 | ## Prerequisites 6 | 7 | Before you can build the image, make sure that the following software is installed on your machine: 8 | * [Docker](https://www.docker.com/products/docker) 9 | * [git](https://git-scm.com/) 10 | * NGINX Plus license -- the certificate (`nginx-repo.crt`) and the key (`nginx-repo.key`). If you don't have one, you can sign up for a [free 30-day trial](https://www.nginx.com/free-trial-request/). 11 | 12 | **Note**: the instructions assume that you run docker commands on one of the nodes of your OpenShift cluster. To be able to push the image to the `openshift` project, your user account must have admin access to the OpenShift cluster. 13 | 14 | ## Build the Image 15 | 16 | 1. Clone the NGINX Router repo and change your directory to `src/nginx-plus`: 17 | ``` 18 | $ git clone https://github.com/nginxinc/nginx-openshift-router 19 | $ cd nginx-openshift-router/src/nginx-plus 20 | ``` 21 | 22 | 1. Make sure that the certificate (`nginx-repo.crt`) and the key (`nginx-repo.key`) of your license are located in the `nginx-plus` directory: 23 | ``` 24 | $ ls nginx-repo.* 25 | nginx-repo.crt nginx-repo.key 26 | ``` 27 | 28 | 1. Build the image: 29 | ``` 30 | $ docker build -t nginx-plus-openshift-router:0.2 . 31 | ``` 32 | 33 | ## Upload the Image to the OpenShift Private Registry 34 | 35 | 1. To upload the image to your private repository, you need to get login credentials for the private repository. Get those by logging into the registry portal, along with the correct URL syntax for the tag and push commands. Then, log in: 36 | ``` 37 | $ sudo docker login -p -e unused -u unused docker-registry-default.router.default.svc.cluster.local 38 | ``` 39 | 40 | 1. Tag the image: 41 | ``` 42 | $ docker tag nginx-plus-openshift-router:0.2 docker-registry-default.router.default.svc.cluster.local/openshift/nginx-plus-openshift-router:0.2 43 | ``` 44 | 45 | 1. Push the image to the registry: 46 | ``` 47 | $ docker push docker-registry-default.router.default.svc.cluster.local/openshift/nginx-plus-openshift-router:0.2 48 | ``` 49 | -------------------------------------------------------------------------------- /docs/configuration.md: -------------------------------------------------------------------------------- 1 | # The NGINX Router Configuration 2 | 3 | The NGINX Router can be customized using environment variables or annotations. 4 | 5 | ## Environment Variables 6 | 7 | The NGINX Router supports the majority of the standard Router environment variables, described in [this document](https://docs.okd.io/latest/architecture/networking/routes.html#router-environment-variables). 8 | 9 | The NGINX Router supports the following standard Router environment variables: 10 | * `DEFAULT_CERTIFICATE` 11 | * `EXTENDED_VALIDATION` 12 | * `NAMESPACE_LABELS` 13 | * `RELOAD_SCRIPT` 14 | * `ROUTER_ALLOWED_DOMAINS` 15 | * `ROUTER_DEFAULT_CLIENT_TIMEOUT` 16 | * `ROUTER_DEFAULT_CONNECT_TIMEOUT` 17 | * `ROUTER_DEFAULT_SERVER_TIMEOUT` 18 | * `ROUTER_DEFAULT_TUNNEL_TIMEOUT` 19 | * `ROUTER_DENIED_DOMAINS` 20 | * `ROUTER_ENABLE_INGRESS` 21 | * `ROUTER_LISTEN_ADDR` 22 | * `ROUTER_LOG_LEVEL` 23 | * `ROUTER_MAX_CONNECTIONS` 24 | * `ROUTER_OVERRIDE_HOSTNAME` 25 | * `ROUTER_SERVICE_HTTPS_PORT` 26 | * `ROUTER_SERVICE_HTTP_PORT` 27 | * `ROUTER_SERVICE_NAME` 28 | * `ROUTER_CANONICAL_HOSTNAME` 29 | * `ROUTER_SERVICE_NAMESPACE` 30 | * `ROUTER_SERVICE_SNI_PORT` 31 | * `ROUTER_SLOWLORIS_HTTP_KEEPALIVE` 32 | * `ROUTER_SUBDOMAIN` 33 | * `ROUTER_SYSLOG_ADDRESS` 34 | * `ROUTE_LABELS` 35 | * `RELOAD_INTERVAL` 36 | * `ROUTER_USE_PROXY_PROTOCOL` 37 | * `ROUTER_ALLOW_WILDCARD_ROUTES` 38 | * `ROUTER_DISABLE_NAMESPACE_OWNERSHIP_CHECK` 39 | 40 | The following standard environment variables are supported, but have some differences comparing with the default Router: 41 | * `DEFAULT_CERTIFICATE_DIR`. The default value is `/etc/pki/tls/private`. 42 | * `ROUTER_TCP_BALANCE_SCHEME`. Specifies the load balancing algorithm for TCP/UDP and passthrough upstreams. Supported values are `round_robin`, `random`, `random_two`, `least_conn`, `ip_hash` and `least_time` (NGINX Plus). The default is `random_two`. 43 | * `ROUTER_LOAD_BALANCE_ALGORITHM`. Specifies the load balancing algorithm for HTTP upstreams. Supported values are `round_robin`, `random`, `random_two`, `least_conn`, `ip_hash` and `least_time` (NGINX Plus). The default is `random_two`. 44 | * `ROUTER_METRICS_TYPE`. The value must be empty. 45 | * `ROUTER_SYSLOG_FORMAT`. Specifies the log format for a server that routes HTTP(s) traffic. 46 | * `TEMPLATE_FILE`. The default value is `/var/lib/nginx/conf/nginx-config.template`. 47 | 48 | 49 | The following standard environment variables are not available: 50 | * `DEFAULT_CERTIFICATE_PATH` 51 | * `DROP_SYN_DURING_RESTART` 52 | * `ROUTER_BACKEND_CHECK_INTERVAL` 53 | * `ROUTER_BACKEND_PROCESS_ENDPOINTS` 54 | * `ROUTER_CLIENT_FIN_TIMEOUT` 55 | * `ROUTER_COOKIE_NAME` 56 | * `ROUTER_COMPRESSION_MIME` 57 | * `ROUTER_DEFAULT_SERVER_FIN_TIMEOUT` 58 | * `ROUTER_ENABLE_COMPRESSION` 59 | * `ROUTER_SERVICE_NO_SNI_PORT` 60 | * `ROUTER_SLOWLORIS_TIMEOUT` 61 | * `STATS_PASSWORD` 62 | * `STATS_USERNAME` 63 | * `ROUTER_STRICT_SNI` 64 | 65 | 66 | The NGINX Router includes the following additional environment variables: 67 | * `ROUTER_SERVICE_UNREACHABLE_PORT`. For Routes with zero endpoints, the Router sends passthrough connections to `127.0.0.1:`. The Router assumes that nothing is running on that port. The default is `10446`. 68 | * `ROUTER_PROXY_PROTOCOL_TRUSTED_SOURCE`. Configures trusted sources of client connections when PROXY PROTOCOL is enabled (using `ROUTER_USE_PROXY_PROTOCOL` variable). The default is `0.0.0.0/0`, which means any source is trusted. Configure this variable with the value of the IP address or the subnet of outgoing connections of your external load balancer that uses PROXY PROTOCOL. When the load balancer is not trusted, the client IP address is not extracted using the PROXY PROTOCOL and the IP address of the load balancer is used as the client IP. 69 | * `ROUTER_SERVICE_INTERNAL_PASSTHROUGH_PORT`. Specifies the port of the helper server that routes passthrough connections. The default is `10447`. 70 | * `ROUTER_SYSLOG_FORMAT_FOR_PASSTHROUGH`. Specifies the log format for the passthrough server -- the server, which handles both HTTPS and passthrough connections, before forwarding them to the Router internal helper servers. 71 | * `ROUTER_SYSLOG_FORMAT_FOR_INTERNAL_PASSTHROUGH`. Specifies the log format for the internal server that routes passthrough connections. 72 | * `ROUTER_SERVICE_503_SERVER_PORT`. Specifies the port of the helper server, which serves 503 error pages. 73 | * `ROUTER_SERVICE_PASSTHROUGH_PORT`. Specifies the port of the passthrough server -- the server, which handles both HTTPS and passthrough connections, before forwarding them to the Router internal helper servers. The default is `443` and equal to `ROUTER_SERVICE_HTTPS_PORT`. However, `ROUTER_SERVICE_PASSTHROUGH_PORT` and `ROUTER_SERVICE_HTTPS_PORT` can be different. In that case the server on the passthrough port will only handle passthrough connections and the server on the HTTPS port will only handle HTTPS connections. 74 | * `KEEPALIVE_REQUESTS`. Specifies the maximum number of requests NGINX can serve through a single keep-alive connection. The default value is `100`. 75 | * `WORKER_PROCESSES`. Specifies the number of worker processes, and is used to help tune NGINX performance. To see the list of factors that influences the optimal value, see [our documentation](http://nginx.org/en/docs/ngx_core_module.html#worker_processes). It is considered a good start to set this value to the number of CPU cores of the node in which the router is running. Leaving this value to default will allow NGINX to try and autodetect it. 76 | * `WORKER_CPU_AFFINITY`. Tied closely with `WORKER_PROCESSES`, this value binds worker processes to the sets of CPUs. Each CPU set is represented by a bitmask of allowed CPUs. See the [documentation](http://nginx.org/en/docs/ngx_core_module.html#worker_cpu_affinity) for examples of how to use it. 77 | * `WORKER_RLIMIT_NOFILE`. Specifies the maximum number of open files for worker processes. The default value is `8192`, but it can be useful to increase this number when NGINX is handling a large number of connections. 78 | * `ROUTER_ENABLE_UNSAFE_ANNOTATIONS` Enables the unsafe annotations. The unsafe annotations are not validated by the Router and could lead to invalid NGINX configuration. The default is `false`. 79 | 80 | The NGINX Router with NGINX Plus offers the additional following environment variables: 81 | 82 | * `ROUTER_HTTP_BALANCE_PARAMETERS`. Modifies the `ROUTER_LOAD_BALANCE_ALGORITHM` default environment variable and the `nginx.router.openshift.io/balance` annotation to specify load balancing functionality. 83 | * `ROUTER_TCP_BALANCE_PARAMETERS`. Modifies the `ROUTER_TCP_BALANCE_SCHEME` default environment variable and the `nginx.router.openshift.io/balance` annotation to specify load balancing functionality. 84 | 85 | For more information on specifying load balancing with `ROUTER_HTTP_BALANCE_PARAMETERS` and `ROUTER_TCP_BALANCE_PARAMETERS`, see the [Fine-Tuning Load Balancing with NGINX Plus](#fine-tuning-load-balancing-methods-with-nginx-plus) section. 86 | 87 | ## Annotations 88 | 89 | The NGINX Router supports the following annotations: 90 | * `nginx.router.openshift.io/balance`. Configures a load balancing method. The supported values are `round_robin`, `least_conn`, `random`, `random_two`, `ip_hash` and `least_time` (NGINX Plus). The default value is configured using `ROUTER_LOAD_BALANCE_ALGORITHM` or `ROUTER_TCP_BALANCE_SCHEME` environment variables. `random_two` defaults to `random two least_conn` in the NGINX configuration. 91 | * `nginx.router.openshift.io/balance-parameters`. Specific to NGINX Plus. Modifies the load balancing algorithm to specify more precise functionality. See [Fine-Tuning Load Balancing with NGINX Plus](#fine-tuning-load-balancing-methods-with-nginx-plus) for more information on tuning NGINX load balancing. 92 | * `nginx.router.openshift.io/keepalive`. Activates the cache for connections between NGINX and upstream servers. The default is `0`, which means the cache is not activated. Not applicable for passthrough routes. See http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive for more details. 93 | * `nginx.router.openshift.io/websocket`. Enables Websocket. The default is `false`. 94 | * `nginx.router.openshift.io/grpc`. Enables gRPC. The default is `false`. 95 | * `nginx.router.openshift.io/proxy_ssl_name`. Specifies the server name for verifying the proxied server certificate. Only used when re-encryption is enabled. The default value is the host of the route. 96 | 97 | The NGINX Router supports the following unsafe annotations: 98 | 99 | * `unsafe.nginx.router.openshift.io/server-snippets`. Sets custom snippets in the server context of the generated NGINX config. If multiple routes are created for the same host and all have this annotation present, the annotation of the primary route will be used. The primary route is a route which name is the alphabetically last among all routes. If some routes have TLS termination enabled, the primary route is a route which name is the alphabetically last among all TLS-enabled routes. Not available for passthrough routes. 100 | * `unsafe.nginx.router.openshift.io/location-snippets`. Sets custom snippets in the location context of the generated NGINX config. Not available for passthrough and TCP/UDP routes. 101 | 102 | **Notes**: 103 | * The Router doesn't validate the unsafe annotations, which might lead to invalid NGINX configuration. Check the Router logs to makes sure that the annotations have been successfully applied. 104 | * Requires the `ROUTER_ENABLE_UNSAFE_ANNOTATIONS` environment variable set to `true`. 105 | 106 | 107 | Additional annotations are available in the [TCP/UDP Load Balancing Extension](#tcpudp-load-balancing-extension). 108 | 109 | ## Configuring Edge Termination 110 | 111 | If edge termination is enabled for a host in one route, it will be enabled in all other routes that reference that host as well. Thus, you only need to configure edge termination in one route. This behavior is different from the default Router behavior, where you would have to enable edge termination in every route. 112 | 113 | If you still want to configure edge termination in every route that reference a particular host, please note that for all those routes the Router will use edge termination settings, such as termination policy and the certificate, from a route with a name that is alphabetically last among those routes. 114 | 115 | ## TCP/UDP Load Balancing Extension 116 | 117 | This section describes the configuration, features, and limitations of the TCP/UDP load balancing extension. The extension is specific to the NGINX Router and not supported by other routers. For a demonstration, see the [TCP/UDP Load Balancing](../examples/tcp-udp) example. 118 | 119 | ### Configuration 120 | 121 | The NGINX Router supports TCP/UDP load balancing through the following annotations: 122 | * `nginx.router.openshift.io/protocol`. Enables TCP or UDP load balancing. The accepted values are `tcp` or `udp`. 123 | * `nginx.router.openshift.io/port`. Specifies the port for TCP and UDP load balancing for NGINX to listen on. Notes: 124 | * The specified port is not checked against the ports specified in other routes. As a result, port conflicts between routes may occur. Make sure to use unique ports per route. 125 | * You can use the same port in two routes, but only if one of them is a TCP route and the other one is a UDP route. 126 | * Make sure to open the specified port in the firewall for the protocol specified in the nginx.router.openshift.io/protocol annotation on every node where the Router is running. You can use iptables or firewall-cmd. For example, to open port 5353 for TCP traffic, run: 127 | ``` 128 | $ sudo iptables -I OS_FIREWALL_ALLOW -p tcp --dport 5353 -j ACCEPT 129 | ``` 130 | * `nginx.router.openshift.io/proxy_ssl_name`. Specifies the server name for verifying the proxied server certificate. Only used when re-encryption is enabled. The default value is the host of the route. 131 | * `nginx.router.openshift.io/responses`. Specifies the number of datagrams expected by the proxied server in response to a client datagram. Only used in UDP load balancing. 132 | 133 | For TCP/UDP load balancing, the host and path of the route are ignored. However, keep in mind that the router allows only a single hostname/path combination across all routes. This means that if two or more routes have the same hostname/path combination, the oldest route will “win” and the other ones will be ignored. To avoid such collisions for TCP/UDP load balancing, we suggest providing each route with a host following a specific format: 134 | 135 | ``` 136 | host: ..nginx.router.openshift.io 137 | ``` 138 | For example, `9003.tcp.nginx.router.openshift.io`. This will prevent hostname/path collisions as well as help to avoid port conflicts among routes. 139 | 140 | Here is an example route for TCP load balancing from the [TCP/UDP Load Balancing](../examples/tcp-udp) example: 141 | ``` 142 | apiVersion: v1 143 | kind: Route 144 | metadata: 145 | name: tcp-route 146 | annotations: 147 | nginx.router.openshift.io/protocol: tcp 148 | nginx.router.openshift.io/port: "5353" 149 | spec: 150 | host: 5353.tcp.nginx.router.openshift.io 151 | to: 152 | kind: Service 153 | name: coredns 154 | port: 155 | targetPort: 53 156 | ``` 157 | 158 | ### Edge Termination and Re-encryption 159 | 160 | Load balancing of secure TCP connections can be configured using the tls configuration option similar to HTTP routes: 161 | * `edge`. Terminates SSL at the router and establishes an unencrypted TCP connection to the backend. 162 | * `reencrypt`. Terminates SSL at the router and establishes a new encrypted TCP connection to the backend. 163 | 164 | Here is an example route using the `reencrypt` SSL termination policy: 165 | ``` 166 | apiVersion: v1 167 | kind: Route 168 | metadata: 169 | name: tcp-reencrypt-route 170 | annotations: 171 | nginx.router.openshift.io/protocol: "tcp" 172 | nginx.router.openshift.io/port: "9003" 173 | nginx.router.openshift.io/proxy_ssl_name: "app.example.com" 174 | spec: 175 | host: 9003.tcp.nginx.router.openshift.io 176 | to: 177 | kind: Service 178 | name: secure-app 179 | port: 180 | targetPort: 9003 181 | tls: 182 | termination: reencrypt 183 | key: |- 184 | -----BEGIN PRIVATE KEY----- 185 | [...] 186 | -----END PRIVATE KEY----- 187 | certificate: |- 188 | -----BEGIN CERTIFICATE----- 189 | [...] 190 | -----END CERTIFICATE----- 191 | destinationCACertificate: |- 192 | -----BEGIN CERTIFICATE----- 193 | [...] 194 | -----END CERTIFICATE----- 195 | ``` 196 | 197 | 198 | ### Limitations 199 | 200 | The NGINX Router doesn't allow load balancing TCP/UDP on standard HTTP ports, or any ports used for internal routing. The table below shows these ports along with the environment variables that could override them: 201 | 202 | | Default Value | Environment Variable | 203 | | ------------- | ------------- | 204 | | 443 | ROUTER_SERVICE_HTTPS_PORT | 205 | | 443 | ROUTER_SERVICE_PASSTHROUGH_PORT | 206 | | 80 | ROUTER_SERVICE_HTTP_PORT | 207 | | 10444 | ROUTER_SERVICE_SNI_PORT | 208 | | 10445 | ROUTER_SERVICE_503_SERVER_PORT | 209 | | 10446 | ROUTER_SERVICE_UNREACHABLE_PORT | 210 | | 10447 | ROUTER_SERVICE_INTERNAL_PASSTHROUGH_PORT | 211 | | 1936 | STATS_PORT | 212 | 213 | ## Fine-Tuning Load Balancing Methods with NGINX Plus 214 | 215 | This section describes the allowed values for the HTTP, TCP/UDP, and passthrough upstream load balancing algorithms. These values are specific to the NGINX Plus Router and not supported by other routers. 216 | 217 | When specifying the load balancing algorithm `least_time`, for example, the router will default to `least_time header` within the NGINX configuration. It is sometimes necessary, however, to specify exactly how an algorithm will act, perhaps with `least_time first_byte`. This section describes how that mechanism is configured within the NGINX Router with NGINX Plus. 218 | 219 | ### HTTP 220 | 221 | HTTP load balancing is configured with the `nginx.router.openshift.io/balance` annotation but defaults to the `ROUTER_LOAD_BALANCE_ALGORITHM` environment variable. This algorithm can be adjusted to support more fine-tuned load balancing algorithms using the `nginx.router.openshift.io/balance-parameters`, which defaults to the `ROUTER_HTTP_BALANCE_PARAMETERS` environment variable. 222 | 223 | * `random_two`: Supported values are `least_conn`, `least_time=header` and `least_time=last_byte`. Default value is `random two least_conn`. 224 | * `least_time`: Supported values are `header`, `last_byte`, `header infight` and `last_byte inflight`. Default value is `least_time header`. 225 | 226 | ### TCP/UDP and Passthrough 227 | 228 | TCP/UDP as well as passthrough load balancing is configured with the `nginx.router.openshift.io/balance` annotation but defaults to the `ROUTER_TCP_BALANCE_SCHEME` environment variable. This algorithm can be adjusted to support more fine-tuned load balancing algorithms using the `nginx.router.openshift.io/balance-parameters`, which defaults to the `ROUTER_TCP_BALANCE_PARAMETERS` environment variable. 229 | 230 | * `random_two`: Supported values are `least_conn`, `least_time=connect`, `least_time=first_byte` and `least_time=last_byte`. Default value is `random two least_conn`. 231 | * `least_time`: Supported values are `connect`, `first_byte`, `last_byte`, `connect inflight`, `first_byte inflight` and `last_byte inflight`. Default value is `least_time connect`. 232 | -------------------------------------------------------------------------------- /docs/nginx-oss-router-install.md: -------------------------------------------------------------------------------- 1 | # Installing the NGINX Router 2 | 3 | ## Prerequisites 4 | 5 | * Build the Router image and upload it to your private registry. Please see the instructions [here](build-oss-image.md). 6 | * It is important to upload the image to the private registry *before* deleting the default Router, as it will render the registry unavailable. 7 | 8 | ## 1. Log into the OpenShift Cluster 9 | 10 | 1. Log in as admin: 11 | ``` 12 | $ oc login -u system:admin 13 | ``` 14 | 15 | 1. Select the `default` project: 16 | ``` 17 | $ oc project default 18 | ``` 19 | 20 | ## 2. Delete the Default Router 21 | 22 | 1. Back up the default Router config, in case it needs to be recreated: 23 | ``` 24 | $ oc get -o yaml service/router dc/router clusterrolebinding/router-router-role serviceaccount/router > default-router-backup.yaml 25 | ``` 26 | 27 | 1. Delete the Router: 28 | ``` 29 | $ oc delete -f default-router-backup.yaml 30 | ``` 31 | 32 | ## 3. Deploy the NGINX Router 33 | 34 | 1. Deploy the NGINX Router: 35 | ``` 36 | $ oc adm router router --images=docker-registry.default.svc:5000/openshift/nginx-openshift-router:0.2 --type='' --selector='node-role.kubernetes.io/infra=true' 37 | ``` 38 | **Note**: 39 | * The selector parameter specifies a label selector for nodes where the Router will be deployed: `node-role.kubernetes.io/infra=true`. Use a selector that makes sense for your environment. 40 | 41 | 1. Run the following command to make sure that the Router pods are running: 42 | ``` 43 | $ oc get pods 44 | ``` 45 | You should see a Router pod with the name `router-1-`. 46 | 47 | ## 4. Access the Stub Status Page 48 | 49 | 1. By default, the NGINX stub status page is available via port 1936 of the node where the Router is running (you can change this port with the `STATS_PORT` env variable). To access the page outside of the node, you need to add an entry to the IPtables rules for that node: 50 | ``` 51 | $ sudo iptables -I OS_FIREWALL_ALLOW -p tcp -s -m tcp --dport 1936 -j ACCEPT 52 | ``` 53 | 1. Open your browser at `http://:1936/stub_status` to access the stub status page. 54 | 55 | ## 5. Support for Prometheus Monitoring 56 | 57 | If you are using [Prometheus](https://prometheus.io/), you can deploy the [NGINX Prometheus Exporter](https://github.com/nginxinc/nginx-prometheus-exporter) with the NGINX Router to export the NGINX metrics into Prometheus. To add the exporter to the Router: 58 | 59 | 1. Patch the Router deployment configuration to add the exporter container to the Router pod: 60 | ``` 61 | $ oc patch dc/router -p 'spec: 62 | template: 63 | spec: 64 | containers: 65 | - image: nginx/nginx-prometheus-exporter:0.1.0 66 | name: nginx-prometheus-exporter 67 | ports: 68 | - name: prometheus 69 | containerPort: 9113 70 | args: 71 | - -web.listen-address 72 | - :9113 73 | - -nginx.scrape-uri 74 | - http://127.0.0.1:1936/stub_status' 75 | ``` 76 | The exporter will make the metrics available on port 9113. 77 | 78 | **Note**: 79 | * Change port 1936 in the patch command if the Router was configured to expose the status on a different port other than the default port 1936. 80 | 81 | 1. Annotate the Router service to indicate to Prometheus to automatically scrape the metrics from the Router endpoints through port 9113: 82 | ``` 83 | $ oc annotate service router --overwrite prometheus.io/port=9113 prometheus.io/scrape=true 84 | ``` 85 | 86 | **Note**: 87 | * Your Prometheus must be configured to automatically discover targets through the annotations `prometheus.io/port` and `prometheus.io/scrape` applied to a service. 88 | 89 | ## Uninstall the NGINX Router 90 | 91 | * Delete the NGINX Router: 92 | ``` 93 | $ oc delete service/router dc/router clusterrolebinding/router-router-role serviceaccount/router 94 | ``` 95 | -------------------------------------------------------------------------------- /docs/nginx-plus-router-install.md: -------------------------------------------------------------------------------- 1 | # Installing the NGINX Plus Router 2 | 3 | ## Prerequisites 4 | 5 | * Build the Router image and upload it to your private registry. Please see the instructions [here](build-plus-image.md) 6 | * It is important to upload the image to the private registry *before* deleting the default Router, as it will render the registry unavailable. 7 | 8 | ## 1. Log into the OpenShift Cluster 9 | 10 | 1. Log in as admin: 11 | ``` 12 | $ oc login -u system:admin 13 | ``` 14 | 15 | 1. Select the `default` project: 16 | ``` 17 | $ oc project default 18 | ``` 19 | 20 | ## 2. Delete the Default Router 21 | 22 | 1. Back up the default Router config, in case it needs to be recreated: 23 | ``` 24 | $ oc get -o yaml service/router dc/router clusterrolebinding/router-router-role serviceaccount/router > default-router-backup.yaml 25 | ``` 26 | 27 | 1. Delete the Router: 28 | ``` 29 | $ oc delete -f default-router-backup.yaml 30 | ``` 31 | 32 | ## 3. Deploy the NGINX Plus Router 33 | 34 | 1. Deploy the NGINX Plus Router: 35 | ``` 36 | $ oc adm router router --images=docker-registry.default.svc:5000/openshift/nginx-plus-openshift-router:0.2 --type='' --selector='node-role.kubernetes.io/infra=true' 37 | ``` 38 | 39 | **Note**: 40 | * The NGINX Plus Router image must be stored in the `openshift` directory, with the name `nginx-plus-openshift-router:0.2` 41 | * The selector parameter specifies a label selector for nodes where the Router will be deployed: `node-role.kubernetes.io/infra=true`. Use a selector that makes sense for your environment. 42 | 43 | 1. Run the following command to make sure that the Router pods are running: 44 | ``` 45 | $ oc get pods 46 | ``` 47 | You should see a Router pod with the name `router-1-`. 48 | 49 | ## 4. Access the Live Activity Monitoring Dashboard 50 | 51 | 1. By default, the NGINX Plus status dashboard is available via port 1936 of the node where the Router is running (you can change this port with the `STATS_PORT` env variable). To access the dashboard outside of the node, you need to add an entry to the IPtables rules for that node: 52 | ``` 53 | $ sudo iptables -I OS_FIREWALL_ALLOW -p tcp -s -m tcp --dport 1936 -j ACCEPT 54 | ``` 55 | 1. Open your browser at `http://:1936/dashboard.html` to access the dashboard. 56 | 57 | ## 5. Support for Prometheus Monitoring 58 | 59 | If you are using [Prometheus](https://prometheus.io/), you can deploy the [NGINX Prometheus Exporter](https://github.com/nginxinc/nginx-prometheus-exporter) with the NGINX Plus Router to export the NGINX Plus metrics into Prometheus. To add the exporter to the Router: 60 | 61 | 1. Patch the Router deployment configuration to add the exporter container to the Router pod: 62 | ``` 63 | $ oc patch dc/router -p 'spec: 64 | template: 65 | spec: 66 | containers: 67 | - image: nginx/nginx-prometheus-exporter:0.1.0 68 | name: nginx-prometheus-exporter 69 | ports: 70 | - name: prometheus 71 | containerPort: 9113 72 | args: 73 | - -web.listen-address 74 | - :9113 75 | - -nginx.plus 76 | - -nginx.scrape-uri 77 | - http://127.0.0.1:1936/api' 78 | ``` 79 | The exporter will make the metrics available on port 9113. 80 | 81 | **Note**: 82 | * Change port 1936 in the patch command if the Router was configured to expose the status on a different port other than the default port 1936. 83 | 84 | 1. Annotate the Router service to indicate to Prometheus to automatically scrape the metrics from the Router endpoints through port 9113: 85 | ``` 86 | $ oc annotate service router --overwrite prometheus.io/port=9113 prometheus.io/scrape=true 87 | ``` 88 | 89 | **Note**: 90 | * Your Prometheus must be configured to automatically discover targets through the annotations `prometheus.io/port` and `prometheus.io/scrape` applied to a service. 91 | 92 | 93 | ## Uninstall the NGINX Plus Router 94 | 95 | * Delete the NGINX Plus Router: 96 | ``` 97 | $ oc delete service/router dc/router clusterrolebinding/router-router-role serviceaccount/router 98 | ``` 99 | -------------------------------------------------------------------------------- /examples/cafe-app/README.md: -------------------------------------------------------------------------------- 1 | # Cafe App Example 2 | 3 | In this example we deploy the NGINX OpenShift Router, a simple web application and then expose that application using the Router. 4 | 5 | ## Running the Example 6 | 7 | ## 1. Deploy the NGINX Router 8 | 9 | 1. Follow the installation instructions for [NGINX](../../docs/nginx-oss-router-install.md) or [NGINX Plus](../../docs/nginx-plus-router-install.md). 10 | 11 | 1. Save the public IP address of the node where the Router is running into a shell variable: 12 | ``` 13 | $ export ROUTER_IP=xxx.xxx.xxx.xxx 14 | ``` 15 | ## 2. Deploy the Cafe Application 16 | 17 | 1. The cafe application container runs its application as root user. Before deploying the application, allow containers with root access: 18 | ``` 19 | $ oc adm policy add-scc-to-group anyuid system:authenticated 20 | ``` 21 | 1. Create the deployments and services for the coffee and tea applications 22 | ``` 23 | $ oc create -f cafe.yaml 24 | ``` 25 | 26 | ## 3. Create the Routes 27 | 28 | ``` 29 | $ oc create -f tea-route.yaml 30 | $ oc create -f coffee-route.yaml 31 | ``` 32 | 33 | **A note about edge (TLS) termination**: The coffee-route route configured edge termination for `cafe.example.com` host using a self-signed TLS certificate and key. Note that if edge termination is enabled for a host in one route, it will be enabled in all other routes that reference that host as well. Thus, we only need to configure edge termination in the coffee-route route. This behavior is different from the default Router behavior, where you would have to enable edge termination in every route. 34 | 35 | ## 4. Test the Application 36 | 37 | 1. To access the application, curl the coffee and the tea services. We'll use `curl`'s --insecure option to turn off certificate verification of our self-signed 38 | certificate and the --resolve option to set the Host header of a request with `cafe.example.com`: 39 | 40 | To get coffee: 41 | ``` 42 | $ curl --resolve cafe.example.com:443:$ROUTER_IP https://cafe.example.com/coffee --insecure 43 | Server address: 10.129.0.6:80 44 | Server name: coffee-7586895968-r26zn 45 | ... 46 | ``` 47 | If you would rather prefer tea: 48 | ``` 49 | $ curl --resolve cafe.example.com:443:$ROUTER_IP https://cafe.example.com/tea --insecure 50 | Server address: 10.130.0.5:80 51 | Server name: tea-7cd44fcb4d-xfw2x 52 | ... 53 | ``` 54 | 55 | 1. For the NGINX Plus Router, open the live activity monitoring dashboard: 56 | 1. Follow the [instructions](../../docs/nginx-plus-router-install.md#4-Access-the-Live-Activity-Monitoring-Dashboard) to access the dashboard. 57 | 1. If you go to the Upstream tab, you'll see: ![dashboard](dashboard.png) -------------------------------------------------------------------------------- /examples/cafe-app/cafe-app.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: coffee 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: coffee 10 | template: 11 | metadata: 12 | labels: 13 | app: coffee 14 | spec: 15 | containers: 16 | - name: coffee 17 | image: nginxdemos/hello:0.2 18 | ports: 19 | - containerPort: 80 20 | --- 21 | apiVersion: v1 22 | kind: Service 23 | metadata: 24 | name: coffee-svc 25 | spec: 26 | ports: 27 | - port: 80 28 | targetPort: 80 29 | protocol: TCP 30 | name: http 31 | selector: 32 | app: coffee 33 | --- 34 | apiVersion: extensions/v1beta1 35 | kind: Deployment 36 | metadata: 37 | name: tea 38 | spec: 39 | replicas: 1 40 | selector: 41 | matchLabels: 42 | app: tea 43 | template: 44 | metadata: 45 | labels: 46 | app: tea 47 | spec: 48 | containers: 49 | - name: tea 50 | image: nginxdemos/hello:0.2 51 | ports: 52 | - containerPort: 80 53 | --- 54 | apiVersion: v1 55 | kind: Service 56 | metadata: 57 | name: tea-svc 58 | labels: 59 | spec: 60 | ports: 61 | - port: 80 62 | targetPort: 80 63 | protocol: TCP 64 | name: http 65 | selector: 66 | app: tea -------------------------------------------------------------------------------- /examples/cafe-app/coffee-route.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Route 3 | metadata: 4 | name: coffee-route 5 | spec: 6 | host: cafe.example.com 7 | path: "/coffee" 8 | to: 9 | kind: Service 10 | name: coffee-svc 11 | tls: 12 | termination: edge 13 | insecureEdgeTerminationPolicy: Redirect 14 | key: |- 15 | -----BEGIN RSA PRIVATE KEY----- 16 | MIIEowIBAAKCAQEAo/ln2tuM7Awn0HSNQG2H0aNtpYwuKq8bPIeEr8XmhDMpI/wS 17 | aWs1vrr0gbKvl+OKeWQ8ZAaVq4HyCBJmzosglFICGlGR8pjKfF7uTVdt7S+c0qoW 18 | eUrfXJzsSjGAVFqfbGVRHMtIDy04N2t+yBHHN7c+/YVvvOHj6Cg3c9sbiFZS1rWt 19 | 1H8noso6NLFiIZ6EsRn3HYADrRLsG1aeIt2iTkMd4ARpvfoZpeFaphP4QYMq/XSb 20 | UVDWO3sPH7ItlAlozgUdRIKsQb7NK+MKfmZnbRtrqn5CZntzretgHdtt8yWB5E+M 21 | a0rkU/1XyYJ7/cyf7k7cKRbFZgQq9RKXu5l8ZQIDAQABAoIBAG/qN+H+W054dWwn 22 | QIkquLpyqtGEvbXQUeycKgm2LsEoEfpHf2GIFOSawWsMRCCM4uQ7b6RtghXO2Rx9 23 | QsHR32icGGdSKSTE996vBEKxW4u5JXX7NN+QJKcXS4bQBmCMgab/976JWCNTn7zj 24 | l2KCD9CNN2bdfggSvPSlDkP61e3UtWJFmqU3OILD/8OWcxsM6GOE/fQLWcsFOoi8 25 | qhtS5K2VOU3DWovnyyGm15+p9ZgFioob4t0pQlFT742vOEimKFihf1Nm4fS4b6S6 26 | 1jxiDJx9IhOkI9ubuWz5lbELgmNqL22u5lZVVHVuo/4f+Bpew9rWHEV0l2/Wrr33 27 | Pc/CFvkCgYEA00eZ/4/1QH5UWK+Fbd41xS3On8iRA4I/uH97SOxg1XtIbJwS+xbl 28 | cJbP9pN0R8s9vR0jOpihcyObGUTvZi+6Y4DW0o5G20n31YUf3ByOZAvJDDaKy7k9 29 | gaaMx+zpIBGDa83kzzF+vHRoUA73GBLTF7dc1eZyLNyhVZA2uxczEycCgYEAxq6C 30 | 9PTTih39hLb2akSH5alVnJOv4sVKAcVpeFqA93KxNmqYEWcR9uu7nYUFpasIapfW 31 | I8NXT0DRPyMNYCgwedJoMyCDR7olsjjT8diq9ziP+XXoOdz28tZlUjoS6x22WmaY 32 | 9bfqnDjkfqoYnYmSZfI7hvpsHSoPLfaD3OB4u5MCgYBhRpAyyDck8IUpJ/cI9MxQ 33 | 8pw1mQSbVva7nYZHtv2GjPJ1fw6GKK6OvgEWCCH7hCnyzl2P9wIunvAkHEcVB1iL 34 | w6Ak5XjeMho3ZsmacFNm4L46L0qMLceRz/r1ebCEIUwe8Hcuph0x626znZBKtzAV 35 | tUi6+xUKbrKhUHrCfRX49QKBgDm3LDe4f1MaDzFkbQTFz6x5mnMXu/pmUW9eR5s8 36 | v0YivTQPlwlHJcLTC/dgUxmjK5i7buuIrW5KZ/6tUg9i3WImKzre8QP/IUA6necd 37 | h9y1Q622ALX+aIZ2nYxbbm96fCSatUh8Gt0y8b2R8ACjnDGdQomdaZa3Rx2VBQ0+ 38 | 8BOdAoGBAIiKGQ7TMQJlFN6C6TPNBpGxKc+IxCWQQ/NyzOIpG0skEuERat4/Wa2V 39 | thIqFEwKLj31FIRF/vXbBfpNMGiJ8/jwqdu+maq36k9zm0zd87bd8Klb/AyNRUl/ 40 | JGQl1usEqyN/q5GnMt14aC5GdeHSjVx2O3Yfl+Gf5aHDnfIB8AvE 41 | -----END RSA PRIVATE KEY----- 42 | certificate: |- 43 | -----BEGIN CERTIFICATE----- 44 | MIIEDzCCAvegAwIBAgIJAPZ+V80VswZPMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNV 45 | BAYTAkdCMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX 46 | aWRnaXRzIFB0eSBMdGQxGzAZBgNVBAMTEmNvZmZlZS5leGFtcGxlLmNvbTAeFw0x 47 | ODAyMTExODQ3NTlaFw0xOTAyMTExODQ3NTlaMGIxCzAJBgNVBAYTAkdCMRMwEQYD 48 | VQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBM 49 | dGQxGzAZBgNVBAMTEmNvZmZlZS5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB 50 | BQADggEPADCCAQoCggEBAKP5Z9rbjOwMJ9B0jUBth9GjbaWMLiqvGzyHhK/F5oQz 51 | KSP8EmlrNb669IGyr5fjinlkPGQGlauB8ggSZs6LIJRSAhpRkfKYynxe7k1Xbe0v 52 | nNKqFnlK31yc7EoxgFRan2xlURzLSA8tODdrfsgRxze3Pv2Fb7zh4+goN3PbG4hW 53 | Uta1rdR/J6LKOjSxYiGehLEZ9x2AA60S7BtWniLdok5DHeAEab36GaXhWqYT+EGD 54 | Kv10m1FQ1jt7Dx+yLZQJaM4FHUSCrEG+zSvjCn5mZ20ba6p+QmZ7c63rYB3bbfMl 55 | geRPjGtK5FP9V8mCe/3Mn+5O3CkWxWYEKvUSl7uZfGUCAwEAAaOBxzCBxDAdBgNV 56 | HQ4EFgQU0M65EFHhDuPVV/V3f6arkNmcxZAwgZQGA1UdIwSBjDCBiYAU0M65EFHh 57 | DuPVV/V3f6arkNmcxZChZqRkMGIxCzAJBgNVBAYTAkdCMRMwEQYDVQQIEwpTb21l 58 | LVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxGzAZBgNV 59 | BAMTEmNvZmZlZS5leGFtcGxlLmNvbYIJAPZ+V80VswZPMAwGA1UdEwQFMAMBAf8w 60 | DQYJKoZIhvcNAQEFBQADggEBAGB6xTSX4DiLasEs2qNGlINHvE+yvCJxtbuatl7B 61 | v0cPJb7Icgmnp8NGtUHY8+nvDxXWMzBteMhHrRzNdod+hynyg1xeiNZPkJzMkH3p 62 | leZ+odVWYjG8Kq+cK1VLDylS+pAwnPFfkJ9MJvif4PRIB9lsCwP6WNOK9UswiGrM 63 | rtviB/6vlbzG5iGAyBrCLh8dOCeeQ2w2hHVfJ27j6GAqhVzy9NBM03Y4Tr5d7h1r 64 | 5AbnOmLR4D24ZJr9w7avHm5NYiKjw9gVqL9arHUTJHlqV0ngSZ35e0XUlcMt32xP 65 | 9hkMA8IeqiDTQiv4X961Ey+SVrIYCpuw/RrC/jX9raLWWfg= 66 | -----END CERTIFICATE----- 67 | -------------------------------------------------------------------------------- /examples/cafe-app/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nginxinc/nginx-openshift-router/c1cbb0f4c473dc809a1ac91645fafbe2d31720fd/examples/cafe-app/dashboard.png -------------------------------------------------------------------------------- /examples/cafe-app/tea-route.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Route 3 | metadata: 4 | name: tea-route 5 | spec: 6 | host: cafe.example.com 7 | path: "/tea" 8 | to: 9 | kind: Service 10 | name: tea-svc -------------------------------------------------------------------------------- /examples/tcp-udp/README.md: -------------------------------------------------------------------------------- 1 | # TCP/UDP Load Balancing Example 2 | 3 | In this example we deploy the NGINX OpenShift Router, a DNS server and then configure both TCP and UDP load balancing for the DNS server using routes. 4 | 5 | ## Prerequisites 6 | 7 | * We use `dig` for testing. Make sure it is installed on your machine. 8 | * Make sure to open port 5353 in the firewall for both TCP and UDP traffic on the node where the Router is running: 9 | ``` 10 | $ sudo iptables -I OS_FIREWALL_ALLOW -p tcp --dport 5353 -j ACCEPT 11 | $ sudo iptables -I OS_FIREWALL_ALLOW -p udp --dport 5353 -j ACCEPT 12 | ``` 13 | 14 | ## 1. Deploy the NGINX Router 15 | 16 | 1. Follow the installation instructions for [NGINX](../../docs/nginx-oss-router-install.md) or [NGINX Plus](../../docs/nginx-plus-router-install.md). 17 | 18 | 1. Save the public IP address of the node where the Router is running into a shell variable: 19 | ``` 20 | $ export ROUTER_IP=xxx.xxx.xxx.xxx 21 | ``` 22 | 1. Save port 5353 of the Router into a shell variable: 23 | ``` 24 | $ export ROUTER_5353_PORT=5353 25 | ``` 26 | 27 | ### 2. Deploy the DNS Server 28 | 29 | We deploy two replicas of [CoreDNS](https://coredns.io/), configured to forward DNS queries to `8.8.8.8`. 30 | 31 | Deploy the DNS server: 32 | 33 | ``` 34 | $ kubectl apply -f dns.yaml 35 | ``` 36 | 37 | ## 3. Create the Routes 38 | 39 | ``` 40 | $ oc create -f dns-udp-route.yaml 41 | $ oc create -f dns-tcp-route.yaml 42 | ``` 43 | 44 | ### 3. Test the DNS Server 45 | 46 | To test that the configured TCP/UDP load balancing works, we resolve the name `openshift.io` using our DNS server available through the Router: 47 | 48 | 1. Resolve `openshift.io` through UDP: 49 | ``` 50 | $ dig @$ROUTER_IP -p $ROUTER_5353_PORT openshift.io 51 | 52 | ; <<>> DiG 9.10.6 <<>> @192.168.99.100 -p 5353 openshift.io 53 | ; (1 server found) 54 | ;; global options: +cmd 55 | ;; Got answer: 56 | ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34229 57 | ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 58 | 59 | ;; OPT PSEUDOSECTION: 60 | ; EDNS: version: 0, flags:; udp: 512 61 | ;; QUESTION SECTION: 62 | ;openshift.io. IN A 63 | 64 | ;; ANSWER SECTION: 65 | openshift.io. 6 IN A 52.44.3.11 66 | openshift.io. 6 IN A 52.71.98.175 67 | 68 | ;; Query time: 47 msec 69 | ;; SERVER: 192.168.99.100#5353(192.168.99.100) 70 | ;; WHEN: Fri Aug 17 12:21:42 PDT 2018 71 | ;; MSG SIZE rcvd: 97 72 | ``` 73 | 74 | 1. Resolve `openshift.io` through TCP: 75 | ``` 76 | $ dig @$ROUTER_IP -p $ROUTER_5353_PORT openshift.io +tcp 77 | 78 | ; <<>> DiG 9.10.6 <<>> @192.168.99.100 -p 5353 openshift.io +tcp 79 | ; (1 server found) 80 | ;; global options: +cmd 81 | ;; Got answer: 82 | ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24550 83 | ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 84 | 85 | ;; OPT PSEUDOSECTION: 86 | ; EDNS: version: 0, flags:; udp: 512 87 | ;; QUESTION SECTION: 88 | ;openshift.io. IN A 89 | 90 | ;; ANSWER SECTION: 91 | openshift.io. 7 IN A 52.44.3.11 92 | openshift.io. 7 IN A 52.71.98.175 93 | 94 | ;; Query time: 62 msec 95 | ;; SERVER: 192.168.99.100#5353(192.168.99.100) 96 | ;; WHEN: Fri Aug 17 12:22:12 PDT 2018 97 | ;; MSG SIZE rcvd: 97 98 | ``` 99 | -------------------------------------------------------------------------------- /examples/tcp-udp/dns-tcp-route.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Route 3 | metadata: 4 | name: tcp-route 5 | annotations: 6 | nginx.router.openshift.io/protocol: tcp 7 | nginx.router.openshift.io/port: "5353" 8 | spec: 9 | host: 5353.tcp.nginx.router.openshift.io 10 | to: 11 | kind: Service 12 | name: coredns 13 | port: 14 | targetPort: 5353 -------------------------------------------------------------------------------- /examples/tcp-udp/dns-udp-route.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Route 3 | metadata: 4 | name: udp-route 5 | annotations: 6 | nginx.router.openshift.io/protocol: udp 7 | nginx.router.openshift.io/port: "5353" 8 | spec: 9 | host: 5353.udp.nginx.router.openshift.io 10 | to: 11 | kind: Service 12 | name: coredns 13 | port: 14 | targetPort: 5353 -------------------------------------------------------------------------------- /examples/tcp-udp/dns.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: coredns 5 | data: 6 | Corefile: | 7 | .:5353 { 8 | forward . 8.8.8.8:53 9 | log 10 | } 11 | --- 12 | apiVersion: extensions/v1beta1 13 | kind: Deployment 14 | metadata: 15 | name: coredns 16 | spec: 17 | replicas: 2 18 | selector: 19 | matchLabels: 20 | app: coredns 21 | template: 22 | metadata: 23 | labels: 24 | app: coredns 25 | spec: 26 | containers: 27 | - name: coredns 28 | image: coredns/coredns:1.2.0 29 | args: [ "-conf", "/etc/coredns/Corefile" ] 30 | volumeMounts: 31 | - name: config-volume 32 | mountPath: /etc/coredns 33 | readOnly: true 34 | ports: 35 | - containerPort: 5353 36 | name: dns 37 | protocol: UDP 38 | - containerPort: 5353 39 | name: dns-tcp 40 | protocol: TCP 41 | volumes: 42 | - name: config-volume 43 | configMap: 44 | name: coredns 45 | items: 46 | - key: Corefile 47 | path: Corefile 48 | --- 49 | apiVersion: v1 50 | kind: Service 51 | metadata: 52 | name: coredns 53 | spec: 54 | selector: 55 | app: coredns 56 | ports: 57 | - name: dns 58 | port: 5353 59 | protocol: UDP 60 | - name: dns-tcp 61 | port: 5353 62 | protocol: TCP -------------------------------------------------------------------------------- /src/nginx-plus/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # This is the NGINX Plus router for OpenShift Origin. 3 | # 4 | # The standard name for this image is openshift/origin-nginx-plus-router 5 | # 6 | 7 | FROM openshift/origin-cli:v3.11.0 8 | 9 | # Download certificate and key from the customer portal (https://cs.nginx.com) 10 | # and copy to the build context 11 | RUN mkdir -p /etc/ssl/nginx/ 12 | COPY nginx-repo.crt /etc/ssl/nginx/ 13 | COPY nginx-repo.key /etc/ssl/nginx/ 14 | 15 | # Make sure the certificate and key have correct permissions 16 | RUN chmod 644 /etc/ssl/nginx/* 17 | 18 | # Configure NGINX Plus repo 19 | RUN echo -e "[nginx]\nname=nginx plus repo" >> /etc/yum.repos.d/nginx-plus.repo && \ 20 | echo "baseurl=https://plus-pkgs.nginx.com/centos/7.4/\$basearch/" >> /etc/yum.repos.d/nginx-plus.repo && \ 21 | echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/nginx-plus.repo && \ 22 | echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/nginx-plus.repo && \ 23 | echo -e "gpgcheck=0\nenabled=1" >> /etc/yum.repos.d/nginx-plus.repo 24 | 25 | RUN yum install -y nginx-plus && \ 26 | yum clean all && \ 27 | mkdir -p /var/lib/nginx/router/{certs,cacerts} && \ 28 | mkdir -p /var/lib/nginx/{conf,run,log,cache} && \ 29 | touch /var/lib/nginx/conf/nginx.conf && \ 30 | setcap 'cap_net_bind_service=ep' /usr/sbin/nginx && \ 31 | chown -R :0 /var/lib/nginx && \ 32 | chmod -R g+w /var/lib/nginx && \ 33 | ln -sf /var/lib/nginx/log/error.log /var/log/nginx/error.log && \ 34 | rm /etc/yum.repos.d/nginx-plus.repo && \ 35 | rm -rf /etc/ssl/nginx 36 | 37 | COPY . /var/lib/nginx/ 38 | 39 | LABEL io.k8s.display-name="OpenShift Origin NGINX Plus Router" \ 40 | io.k8s.description="This is a component of OpenShift Origin and contains an NGINX Plus instance that automatically exposes services within the cluster through routes, and offers TLS termination, reencryption, or SNI-passthrough on ports 80 and 443." 41 | USER 1001 42 | EXPOSE 80 443 43 | WORKDIR /var/lib/nginx/conf 44 | ENV TEMPLATE_FILE=/var/lib/nginx/conf/nginx-config.template \ 45 | RELOAD_SCRIPT=/var/lib/nginx/reload-nginx 46 | ENTRYPOINT ["/usr/bin/openshift-router", "--working-dir=/var/lib/nginx/router"] 47 | -------------------------------------------------------------------------------- /src/nginx-plus/conf/error-page-503.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 107 | 108 | 109 |
110 |

Application is not available

111 |

The application is currently not serving requests at this endpoint. It may not have been started or is still starting.

112 | 113 |
114 |

115 | Possible reasons you are seeing this page: 116 |

117 |
    118 |
  • 119 | The host doesn't exist. 120 | Make sure the hostname was typed correctly and that a route matching this hostname exists. 121 |
  • 122 |
  • 123 | The host exists, but doesn't have a matching path. 124 | Check if the URL path was typed correctly and that the route was created using the desired path. 125 |
  • 126 |
  • 127 | Route and path matches, but all pods are down. 128 | Make sure that the resources exposed by this route (pods, services, deployment configs, etc) have at least one pod running. 129 |
  • 130 |
131 |
132 |
133 | 134 | 135 | -------------------------------------------------------------------------------- /src/nginx-plus/conf/nginx-config.template: -------------------------------------------------------------------------------- 1 | {{/* 2 | nginx.conf: contains the main configuration file. 3 | */}} 4 | {{- define "/var/lib/nginx/conf/nginx.conf" -}} 5 | {{- $workingDir := .WorkingDir }} 6 | {{- $defaultDestinationCA := .DefaultDestinationCA }} 7 | {{ $httpAliases := getHTTPAliasesGroupedByHost .State }} 8 | {{ $httpsPort := env "ROUTER_SERVICE_HTTPS_PORT" "443" }} 9 | {{ $passthroughPort := env "ROUTER_SERVICE_PASSTHROUGH_PORT" "443" }} 10 | {{ $logLevel := firstMatch "info|notice|warn|error|crit|alert|emerg" (env "ROUTER_LOG_LEVEL") "warn" }} 11 | worker_processes {{ env "WORKER_PROCESSES" "auto" }}; 12 | {{ with $cpuAffinity := env "WORKER_CPU_AFFINITY" }} 13 | worker_cpu_affinity {{ $cpuAffinity }}; 14 | {{ end }} 15 | {{ with $syslogAddress := env "ROUTER_SYSLOG_ADDRESS" }} 16 | error_log syslog:server={{ $syslogAddress }},facility={{env "ROUTER_LOG_FACILITY" "local1"}} {{ $logLevel }}; 17 | {{ else }} 18 | error_log /var/lib/nginx/log/error.log {{ $logLevel }}; 19 | {{ end }} 20 | pid /var/lib/nginx/run/nginx.pid; 21 | worker_rlimit_nofile {{ env "WORKER_RLIMIT_NOFILE" "8192" }}; 22 | worker_shutdown_timeout {{ env "ROUTER_DEFAULT_TUNNEL_TIMEOUT" "1h" }}; 23 | 24 | events { 25 | worker_connections {{env "ROUTER_MAX_CONNECTIONS" "20000"}}; 26 | } 27 | 28 | http { 29 | default_type application/octet-stream; 30 | 31 | {{ with $format := env "ROUTER_SYSLOG_FORMAT" }} 32 | log_format main '{{ $format }}'; 33 | {{ else }} 34 | log_format main '$remote_addr - $remote_user [$time_local] $status ' 35 | '"$request" $body_bytes_sent "$http_referer" ' 36 | '"$http_user_agent" "$http_x_forwarded_for"'; 37 | {{ end }} 38 | {{ with $syslogAddress := env "ROUTER_SYSLOG_ADDRESS" }} 39 | access_log syslog:server={{ $syslogAddress }},facility={{env "ROUTER_LOG_FACILITY" "local1"}},severity={{ $logLevel }} main; 40 | {{ else }} 41 | access_log /var/lib/nginx/log/access.log main; 42 | {{ end }} 43 | sendfile on; 44 | tcp_nopush on; 45 | server_names_hash_bucket_size 256; 46 | 47 | proxy_temp_path /var/lib/nginx/cache/proxy_temp; 48 | client_body_temp_path /var/lib/nginx/cache/client_temp; 49 | fastcgi_temp_path /var/lib/nginx/cache/fastcgi_temp; 50 | uwsgi_temp_path /var/lib/nginx/cache/uwsgi_temp; 51 | scgi_temp_path /var/lib/nginx/cache/scgi_temp; 52 | 53 | keepalive_requests {{ env "KEEPALIVE_REQUESTS" "100" }}; 54 | keepalive_timeout {{ env "ROUTER_SLOWLORIS_HTTP_KEEPALIVE" "300s" }}; 55 | 56 | client_body_timeout {{ env "ROUTER_DEFAULT_CLIENT_TIMEOUT" "30s" }}; 57 | client_header_timeout {{ env "ROUTER_DEFAULT_CLIENT_TIMEOUT" "30s" }}; 58 | send_timeout {{ env "ROUTER_DEFAULT_CLIENT_TIMEOUT" "30s" }}; 59 | proxy_connect_timeout {{ env "ROUTER_DEFAULT_CONNECT_TIMEOUT" "5s" }}; 60 | grpc_connect_timeout {{ env "ROUTER_DEFAULT_CONNECT_TIMEOUT" "5s" }}; 61 | proxy_read_timeout {{ env "ROUTER_DEFAULT_SERVER_TIMEOUT" "30s" }}; 62 | grpc_read_timeout {{ env "ROUTER_DEFAULT_SERVER_TIMEOUT" "30s" }}; 63 | proxy_send_timeout {{ env "ROUTER_DEFAULT_SERVER_TIMEOUT" "30s" }}; 64 | grpc_send_timeout {{ env "ROUTER_DEFAULT_SERVER_TIMEOUT" "30s" }}; 65 | 66 | # Prevent vulnerability to POODLE attacks (CVE‑2014‑3566) - omit SSLv3 67 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 68 | 69 | # The default cipher suite can be selected from the three sets recommended by https://wiki.mozilla.org/Security/Server_Side_TLS, 70 | # or the user can provide one using the ROUTER_CIPHERS environment variable. 71 | # By default when a cipher set is not provided, intermediate is used. 72 | {{- if eq (env "ROUTER_CIPHERS" "intermediate") "modern" }} 73 | # Modern cipher suite (no legacy browser support) from https://wiki.mozilla.org/Security/Server_Side_TLS 74 | ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256; 75 | {{- else if eq (env "ROUTER_CIPHERS" "intermediate") "intermediate" }} 76 | # Intermediate cipher suite (default) from https://wiki.mozilla.org/Security/Server_Side_TLS 77 | ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS; 78 | {{- else if eq (env "ROUTER_CIPHERS" "intermediate") "old" }} 79 | # Old cipher suite (maximum compatibility but insecure) from https://wiki.mozilla.org/Security/Server_Side_TLS 80 | ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP; 81 | {{- else }} 82 | # user provided list of ciphers (Colon separated list as seen above) 83 | # the env default is not used here since we can't get here with empty ROUTER_CIPHERS 84 | ssl_ciphers {{env "ROUTER_CIPHERS" "ECDHE-ECDSA-CHACHA20-POLY1305"}}; 85 | {{- end }} 86 | 87 | map $http_upgrade $connection_upgrade { 88 | default upgrade; 89 | '' close; 90 | } 91 | 92 | map $https $forwarded_port { 93 | default $server_port; 94 | 'on' {{ $httpsPort }}; 95 | } 96 | 97 | server { 98 | listen {{if (gt .StatsPort 0)}}{{.StatsPort}}{{else}}1936{{end}}; 99 | 100 | status_zone status; 101 | 102 | access_log off; 103 | 104 | default_type text/html; 105 | 106 | location /healthz { 107 | return 200 "healthy\n"; 108 | } 109 | 110 | {{ if gt .StatsPort 0 }} 111 | location /api { 112 | api write=off; 113 | } 114 | 115 | location = /dashboard.html { 116 | root /usr/share/nginx/html; 117 | } 118 | 119 | location /swagger-ui { 120 | root /usr/share/nginx/html; 121 | } 122 | {{ end }} 123 | } 124 | 125 | # default server 126 | server { 127 | listen {{env "ROUTER_SERVICE_HTTP_PORT" "80"}} default_server{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 128 | listen {{env "ROUTER_SERVICE_503_SERVER_PORT" "10445" }}; 129 | {{ if eq $httpsPort $passthroughPort }} 130 | listen 127.0.0.1:{{env "ROUTER_SERVICE_SNI_PORT" "10444"}} default_server ssl{{ if isTrue (env "ROUTER_USE_HTTP2") }} http2{{ end }} proxy_protocol; 131 | set_real_ip_from 127.0.0.1; 132 | {{ else }} 133 | listen {{ $httpsPort }} default_server ssl{{ if isTrue (env "ROUTER_USE_HTTP2") }} http2{{ end }}{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 134 | {{ end }} 135 | 136 | status_zone default_server; 137 | 138 | {{ if or (eq $httpsPort $passthroughPort) (isTrue (env "ROUTER_USE_PROXY_PROTOCOL")) }} 139 | real_ip_header proxy_protocol; 140 | {{ end }} 141 | 142 | {{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} 143 | set_real_ip_from {{ env "ROUTER_PROXY_PROTOCOL_TRUSTED_SOURCE" "0.0.0.0/0" }}; 144 | {{ end }} 145 | 146 | server_name _; 147 | 148 | ssl_certificate {{ printf "%s/tls.crt" (env "DEFAULT_CERTIFICATE_DIR" "/etc/pki/tls/private") }}; 149 | ssl_certificate_key {{ printf "%s/tls.key" (env "DEFAULT_CERTIFICATE_DIR" "/etc/pki/tls/private") }}; 150 | 151 | error_page 503 /error-page-503.html; 152 | 153 | location / { 154 | return 503; 155 | } 156 | 157 | location = /error-page-503.html { 158 | root /var/lib/nginx/conf; 159 | } 160 | } 161 | 162 | # HTTP Upstreams 163 | {{range $cfgHost, $configs := $httpAliases }} 164 | {{- range $cfg := $configs }} 165 | {{- if not (and (firstMatch "tcp|udp" (index $cfg.Annotations "nginx.router.openshift.io/protocol")) (isInteger (index $cfg.Annotations "nginx.router.openshift.io/port"))) }} 166 | upstream be_{{$cfg.Namespace}}_{{$cfg.Name}} { 167 | {{ with $balanceAlgo := firstMatch "round_robin|least_time|random|random_two|least_conn|ip_hash" (index $cfg.Annotations "nginx.router.openshift.io/balance") (env "ROUTER_LOAD_BALANCE_ALGORITHM") "random_two" }} 168 | {{ if eq $balanceAlgo "least_time" }} 169 | {{ with $balanceParameters := firstMatch "header|last_byte|header inflight|last_byte inflight" (index $cfg.Annotations "nginx.router.openshift.io/balance-parameters") (env "ROUTER_HTTP_BALANCE_PARAMETERS") "header" }} 170 | least_time {{ $balanceParameters }}; 171 | {{ else }} 172 | least_time header; 173 | {{ end}} 174 | {{ else if eq $balanceAlgo "random_two" }} 175 | {{ with $balanceParameters := firstMatch "least_conn|least_time=header|least_time=last_byte" (index $cfg.Annotations "nginx.router.openshift.io/balance-parameters") (env "ROUTER_HTTP_BALANCE_PARAMETERS") "least_conn" }} 176 | random two {{ $balanceParameters }}; 177 | {{ else }} 178 | random two least_conn; 179 | {{ end }} 180 | {{ else if ne $balanceAlgo "round_robin" }} 181 | {{ $balanceAlgo }}; 182 | {{ end }} 183 | {{ else }} 184 | random two least_conn; 185 | {{ end }} 186 | zone {{$cfg.Namespace}}_{{$cfg.Name}} 64k; 187 | {{ if gt $cfg.ActiveEndpoints 0 }} 188 | {{- range $serviceUnitName, $weight := $cfg.ServiceUnitNames }} 189 | # endpoints of {{$serviceUnitName}} 190 | {{- with $serviceUnit := index $.ServiceUnits $serviceUnitName }} 191 | {{- range $idx, $endpoint := endpointsForAlias $cfg $serviceUnit }} 192 | server {{$endpoint.IP}}:{{$endpoint.Port}} {{ if eq $weight 0 }}down{{ else }}weight={{ $weight }}{{ end }}; 193 | {{ end -}} 194 | {{ end }} 195 | {{ end -}} 196 | {{ else }} 197 | server 127.0.0.1:{{env "ROUTER_SERVICE_503_SERVER_PORT" "10445"}}; 198 | {{ end }} 199 | {{ with $keepalive := (index $cfg.Annotations "nginx.router.openshift.io/keepalive") }} 200 | {{ if and (isInteger $keepalive) (ne $keepalive "0") }} 201 | keepalive {{ $keepalive }}; 202 | {{ end }} 203 | {{ end }} 204 | } 205 | {{ end }} 206 | {{ end }} 207 | 208 | {{ $primaryCfgIdx := getPrimaryAliasKey $configs }} 209 | {{ $primaryCfg := index $configs $primaryCfgIdx }} 210 | {{- if not (and (firstMatch "tcp|udp" (index $primaryCfg.Annotations "nginx.router.openshift.io/protocol")) (isInteger (index $primaryCfg.Annotations "nginx.router.openshift.io/port"))) }} 211 | 212 | # the primary route is {{ $primaryCfgIdx }} 213 | server { 214 | {{ if or (eq $primaryCfg.TLSTermination "") (or (eq $primaryCfg.InsecureEdgeTerminationPolicy "Allow") (eq $primaryCfg.InsecureEdgeTerminationPolicy "Redirect")) }} 215 | listen {{env "ROUTER_SERVICE_HTTP_PORT" "80"}}{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 216 | {{ end }} 217 | 218 | server_name {{genCertificateHostName $cfgHost $primaryCfg.IsWildcard }}; 219 | 220 | status_zone {{$cfgHost}}; 221 | 222 | {{ if or (eq $httpsPort $passthroughPort) (isTrue (env "ROUTER_USE_PROXY_PROTOCOL")) }} 223 | real_ip_header proxy_protocol; 224 | {{ end }} 225 | 226 | {{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} 227 | set_real_ip_from {{ env "ROUTER_PROXY_PROTOCOL_TRUSTED_SOURCE" "0.0.0.0/0" }}; 228 | {{ end }} 229 | 230 | {{ if eq $primaryCfg.InsecureEdgeTerminationPolicy "Redirect" }} 231 | if ($scheme = http) { 232 | return 301 https://$host$request_uri; 233 | } 234 | {{ end }} 235 | 236 | {{- if (or (eq $primaryCfg.TLSTermination "edge") (eq $primaryCfg.TLSTermination "reencrypt")) -}} 237 | {{ $cert := index $primaryCfg.Certificates $cfgHost -}} 238 | {{ if ne $cert.Contents "" }} 239 | ssl_certificate {{$workingDir}}/certs/{{$primaryCfgIdx}}.pem; 240 | ssl_certificate_key {{$workingDir}}/certs/{{$primaryCfgIdx}}.pem; 241 | {{ else }} 242 | ssl_certificate {{ printf "%s/tls.crt" (env "DEFAULT_CERTIFICATE_DIR" "/etc/pki/tls/private") }}; 243 | ssl_certificate_key {{ printf "%s/tls.key" (env "DEFAULT_CERTIFICATE_DIR" "/etc/pki/tls/private") }}; 244 | {{ end }} 245 | {{ if eq $httpsPort $passthroughPort }} 246 | listen 127.0.0.1:{{env "ROUTER_SERVICE_SNI_PORT" "10444"}} ssl{{ if isTrue (env "ROUTER_USE_HTTP2") }} http2{{ end }} proxy_protocol; 247 | set_real_ip_from 127.0.0.1; 248 | {{ else }} 249 | listen {{ $httpsPort }} ssl{{ if isTrue (env "ROUTER_USE_HTTP2") }} http2{{ end }}{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 250 | {{ end }} 251 | {{ end }} 252 | 253 | {{ if isTrue (env "ROUTER_ENABLE_UNSAFE_ANNOTATIONS") }} 254 | {{ with $value := index $primaryCfg.Annotations "unsafe.nginx.router.openshift.io/server-snippets" }} 255 | {{ $value }} 256 | {{ end }} 257 | {{ end }} 258 | 259 | {{ range $cfgIdx, $cfg := $configs }} 260 | # this path belongs to the {{ $cfgIdx }} route 261 | location {{ if eq $cfg.Path ""}}/{{ else }}{{$cfg.Path}}{{ end }} { 262 | {{ if isTrue (index $cfg.Annotations "nginx.router.openshift.io/grpc") }} 263 | grpc_set_header X-Real-IP $remote_addr; 264 | grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 265 | grpc_set_header X-Forwarded-Host $host; 266 | grpc_set_header X-Forwarded-Port $forwarded_port; 267 | grpc_set_header X-Forwarded-Proto $scheme; 268 | 269 | {{ if eq $cfg.TLSTermination "reencrypt" }} 270 | {{ with $ssl_name := index $cfg.Annotations "nginx.router.openshift.io/proxy_ssl_name" }} 271 | grpc_ssl_name {{ $ssl_name }}; 272 | {{ else }} 273 | grpc_ssl_name {{ $cfg.Host }}; 274 | {{ end }} 275 | {{- if gt (len (index $cfg.Certificates (printf "%s_pod" $cfg.Host)).Contents) 0 }} 276 | grpc_ssl_trusted_certificate {{ $workingDir }}/cacerts/{{$cfgIdx}}.pem; 277 | grpc_ssl_verify on; 278 | {{ else }} 279 | {{ if gt (len $defaultDestinationCA) 0 }} 280 | grpc_ssl_trusted_certificate {{ $defaultDestinationCA }}; 281 | grpc_ssl_verify on; 282 | {{ else }} 283 | grpc_ssl_verify off; 284 | {{ end }} 285 | {{ end }} 286 | grpc_pass grpcs://be_{{$cfg.Namespace}}_{{$cfg.Name}}; 287 | {{ else }} 288 | grpc_pass grpc://be_{{$cfg.Namespace}}_{{$cfg.Name}}; 289 | {{ end }} 290 | {{ else }} 291 | proxy_http_version 1.1; 292 | {{ if isTrue (index $cfg.Annotations "nginx.router.openshift.io/websocket") }} 293 | proxy_set_header Upgrade $http_upgrade; 294 | proxy_set_header Connection $connection_upgrade; 295 | {{ else }} 296 | {{ with $keepalive := (index $cfg.Annotations "nginx.router.openshift.io/keepalive") }} 297 | {{ if and (isInteger $keepalive) (ne $keepalive "0") }} 298 | proxy_set_header Connection ""; 299 | {{ end }} 300 | {{ end }} 301 | {{ end }} 302 | 303 | proxy_set_header Host $host; 304 | proxy_set_header X-Real-IP $remote_addr; 305 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 306 | proxy_set_header X-Forwarded-Host $host; 307 | proxy_set_header X-Forwarded-Port $forwarded_port; 308 | proxy_set_header X-Forwarded-Proto $scheme; 309 | 310 | {{ if eq $cfg.TLSTermination "reencrypt" }} 311 | {{ with $ssl_name := index $cfg.Annotations "nginx.router.openshift.io/proxy_ssl_name" }} 312 | proxy_ssl_name {{ $ssl_name }}; 313 | {{ else }} 314 | proxy_ssl_name {{ $cfg.Host }}; 315 | {{ end }} 316 | {{- if gt (len (index $cfg.Certificates (printf "%s_pod" $cfg.Host)).Contents) 0 }} 317 | proxy_ssl_trusted_certificate {{ $workingDir }}/cacerts/{{$cfgIdx}}.pem; 318 | proxy_ssl_verify on; 319 | {{ else }} 320 | {{ if gt (len $defaultDestinationCA) 0 }} 321 | proxy_ssl_trusted_certificate {{ $defaultDestinationCA }}; 322 | proxy_ssl_verify on; 323 | {{ else }} 324 | proxy_ssl_verify off; 325 | {{ end }} 326 | {{ end }} 327 | proxy_pass https://be_{{$cfg.Namespace}}_{{$cfg.Name}}; 328 | {{ else }} 329 | proxy_pass http://be_{{$cfg.Namespace}}_{{$cfg.Name}}; 330 | {{ end }} 331 | #health_check uri={{ if eq $cfg.Path ""}}/{{ else }}{{$cfg.Path}}{{ end }} fails=1 passes=1 mandatory; 332 | {{ end }} 333 | 334 | {{ if isTrue (env "ROUTER_ENABLE_UNSAFE_ANNOTATIONS") }} 335 | {{ with $value := index $cfg.Annotations "unsafe.nginx.router.openshift.io/location-snippets" }} 336 | {{ $value }} 337 | {{ end }} 338 | {{ end }} 339 | } 340 | {{ end }} 341 | } 342 | {{ end -}} 343 | {{ end -}} 344 | } 345 | 346 | stream { 347 | {{ with $format := env "ROUTER_SYSLOG_FORMAT_FOR_PASSTHROUGH" }} 348 | log_format passthrough '{{ $format }}'; 349 | {{ else }} 350 | log_format passthrough '$remote_addr [$time_local] ' 351 | '$protocol $status $bytes_sent $bytes_received ' 352 | '$session_time "$ssl_preread_server_name" "$dest_passthrough"'; 353 | {{ end }} 354 | {{ with $format := env "ROUTER_SYSLOG_FORMAT_FOR_INTERNAL_PASSTHROUGH" }} 355 | log_format internal_passthrough '{{ $format }}'; 356 | {{ else }} 357 | log_format internal_passthrough '$remote_addr [$time_local] ' 358 | '$protocol $status $bytes_sent $bytes_received ' 359 | '$session_time "$ssl_preread_server_name" $dest_internal_passthrough"'; 360 | {{ end }} 361 | {{ with $format := env "ROUTER_SYSLOG_FORMAT_FOR_TCP_UDP" }} 362 | log_format stream '{{ $format }}'; 363 | {{ else }} 364 | log_format stream '$remote_addr [$time_local] ' 365 | '$protocol $status $bytes_sent $bytes_received ' 366 | '$session_time "$upstream_addr"'; 367 | {{ end }} 368 | 369 | proxy_timeout {{ env "ROUTER_DEFAULT_CLIENT_TIMEOUT" "30s" }}; 370 | proxy_connect_timeout {{ env "ROUTER_DEFAULT_CONNECT_TIMEOUT" "5s" }}; 371 | map_hash_bucket_size 256; 372 | 373 | # Prevent vulnerability to POODLE attacks (CVE‑2014‑3566) - omit SSLv3 374 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 375 | 376 | # The default cipher suite can be selected from the three sets recommended by https://wiki.mozilla.org/Security/Server_Side_TLS, 377 | # or the user can provide one using the ROUTER_CIPHERS environment variable. 378 | # By default when a cipher set is not provided, intermediate is used. 379 | {{- if eq (env "ROUTER_CIPHERS" "intermediate") "modern" }} 380 | # Modern cipher suite (no legacy browser support) from https://wiki.mozilla.org/Security/Server_Side_TLS 381 | ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256; 382 | {{- else if eq (env "ROUTER_CIPHERS" "intermediate") "intermediate" }} 383 | # Intermediate cipher suite (default) from https://wiki.mozilla.org/Security/Server_Side_TLS 384 | ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS; 385 | {{- else if eq (env "ROUTER_CIPHERS" "intermediate") "old" }} 386 | # Old cipher suite (maximum compatibility but insecure) from https://wiki.mozilla.org/Security/Server_Side_TLS 387 | ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP; 388 | {{- else }} 389 | # user provided list of ciphers (Colon separated list as seen above) 390 | # the env default is not used here since we can't get here with empty ROUTER_CIPHERS 391 | ssl_ciphers {{env "ROUTER_CIPHERS" "ECDHE-ECDSA-CHACHA20-POLY1305"}}; 392 | {{- end }} 393 | 394 | 395 | upstream https-route { 396 | server 127.0.0.1:{{env "ROUTER_SERVICE_SNI_PORT" "10444"}}; 397 | } 398 | 399 | map $ssl_preread_server_name $dest_passthrough { 400 | {{- range $cfgIdx, $cfg := .State }} 401 | {{ if eq $cfg.TLSTermination "passthrough" }} 402 | {{ $cfg.Host }} 127.0.0.1:{{ env "ROUTER_SERVICE_INTERNAL_PASSTHROUGH_PORT" "10447" }}; 403 | {{ end }} 404 | {{ end }} 405 | default https-route; 406 | } 407 | 408 | # passthrough routes 409 | server { 410 | listen {{ $passthroughPort }}{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 411 | {{ with $syslogAddress := env "ROUTER_SYSLOG_ADDRESS" }} 412 | access_log syslog:server={{ $syslogAddress }},facility={{env "ROUTER_LOG_FACILITY" "local1"}},severity={{ $logLevel }} passthrough; 413 | {{ else }} 414 | access_log /var/lib/nginx/log/passthrough_access.log passthrough; 415 | {{ end }} 416 | status_zone passthrough; 417 | proxy_pass $dest_passthrough; 418 | ssl_preread on; 419 | proxy_protocol on; 420 | {{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} 421 | set_real_ip_from {{ env "ROUTER_PROXY_PROTOCOL_TRUSTED_SOURCE" "0.0.0.0/0" }}; 422 | {{ end }} 423 | } 424 | 425 | # passthrough upstreams 426 | {{- range $cfgIdx, $cfg := .State }} 427 | {{ if eq $cfg.TLSTermination "passthrough" }} 428 | upstream be_passthrough_{{$cfg.Namespace}}_{{$cfg.Name}} { 429 | {{ with $balanceAlgo := firstMatch "round_robin|least_time|random|random_two|least_conn|ip_hash" (index $cfg.Annotations "nginx.router.openshift.io/balance") (env "ROUTER_TCP_BALANCE_SCHEME") "random_two" }} 430 | {{ if eq $balanceAlgo "ip_hash" }} 431 | hash $remote_addr consistent; 432 | {{ else if eq $balanceAlgo "least_time" }} 433 | {{ with $balanceParameters := firstMatch "connect|first_byte|last_byte|connect inflight|first_byte inflight|last_byte inflight" (index $cfg.Annotations "nginx.router.openshift.io/balance-parameters") (env "ROUTER_TCP_BALANCE_PARAMETERS") "connect" }} 434 | least_time {{ $balanceParameters }}; 435 | {{ else }} 436 | least_time connect; 437 | {{ end}} 438 | {{ else if eq $balanceAlgo "random_two" }} 439 | {{ with $balanceParameters := firstMatch "least_conn|least_time=connect|least_time=first_byte|least_time=last_byte" (index $cfg.Annotations "nginx.router.openshift.io/balance-parameters") (env "ROUTER_TCP_BALANCE_PARAMETERS") "least_conn" }} 440 | random two {{ $balanceParameters }}; 441 | {{ else }} 442 | random two least_conn; 443 | {{ end }} 444 | {{ else if ne $balanceAlgo "round_robin" }} 445 | {{ $balanceAlgo }}; 446 | {{ end }} 447 | {{ else }} 448 | random two least_conn; 449 | {{ end }} 450 | zone {{$cfg.Namespace}}_{{$cfg.Name}} 64k; 451 | {{ if gt $cfg.ActiveEndpoints 0 }} 452 | {{- range $serviceUnitName, $weight := $cfg.ServiceUnitNames }} 453 | {{- with $serviceUnit := index $.ServiceUnits $serviceUnitName }} 454 | {{- range $idx, $endpoint := endpointsForAlias $cfg $serviceUnit }} 455 | server {{$endpoint.IP}}:{{$endpoint.Port}} {{ if eq $weight 0 }}down{{ else }}weight={{ $weight }}{{ end }}; 456 | {{ end -}} 457 | {{ end -}} 458 | {{ end -}} 459 | {{ else }} 460 | server 127.0.0.1:{{env "ROUTER_SERVICE_UNREACHABLE_PORT" "10446"}}; 461 | {{ end }} 462 | } 463 | {{ end }} 464 | {{ end }} 465 | 466 | map $ssl_preread_server_name $dest_internal_passthrough { 467 | {{- range $cfgIdx, $cfg := .State }} 468 | {{ if eq $cfg.TLSTermination "passthrough" }} 469 | {{ $cfg.Host }} be_passthrough_{{$cfg.Namespace}}_{{$cfg.Name}}; 470 | {{ end }} 471 | {{ end }} 472 | default 127.0.0.1:{{env "ROUTER_SERVICE_UNREACHABLE_PORT" "10446"}}; 473 | } 474 | 475 | server { 476 | listen {{ env "ROUTER_SERVICE_INTERNAL_PASSTHROUGH_PORT" "10447" }} proxy_protocol; 477 | 478 | {{ with $syslogAddress := env "ROUTER_SYSLOG_ADDRESS" }} 479 | access_log syslog:server={{ $syslogAddress }},facility={{env "ROUTER_LOG_FACILITY" "local1"}},severity={{ $logLevel }} internal_passthrough; 480 | {{ else }} 481 | access_log /var/lib/nginx/log/internal_passthrough_access.log internal_passthrough; 482 | {{ end }} 483 | 484 | ssl_preread on; 485 | set_real_ip_from 127.0.0.1; 486 | status_zone internal_passthrough; 487 | proxy_pass $dest_internal_passthrough; 488 | } 489 | 490 | # TCP/UDP upstreams 491 | {{- range $cfgIdx, $cfg := .State }} 492 | {{- with $streamProtocol := firstMatch "tcp|udp" (index $cfg.Annotations "nginx.router.openshift.io/protocol") }} 493 | {{- with $streamPort := index $cfg.Annotations "nginx.router.openshift.io/port" }} 494 | {{- if isInteger $streamPort }} 495 | {{ if not (firstMatch (index $cfg.Annotations "nginx.router.openshift.io/port") (env "ROUTER_SERVICE_HTTPS_PORT" "443") (env "ROUTER_SERVICE_PASSTHROUGH_PORT" "443") (env "ROUTER_SERVICE_HTTP_PORT" "80") (env "ROUTER_SERVICE_SNI_PORT" "10444") (env "ROUTER_SERVICE_503_SERVER_PORT" "10445") (env "ROUTER_SERVICE_UNREACHABLE_PORT" "10446") (env "ROUTER_SERVICE_INTERNAL_PASSTHROUGH_PORT" "10447") "1936") }} 496 | upstream be_stream_{{$cfg.Namespace}}_{{$cfg.Name}} { 497 | {{ with $balanceAlgo := firstMatch "round_robin|least_time|random|random_two|least_conn|ip_hash" (index $cfg.Annotations "nginx.router.openshift.io/balance") (env "ROUTER_TCP_BALANCE_SCHEME") "random_two" }} 498 | {{ if eq $balanceAlgo "ip_hash" }} 499 | hash $remote_addr consistent; 500 | {{ else if eq $balanceAlgo "least_time" }} 501 | {{ with $balanceParameters := firstMatch "connect|first_byte|last_byte|connect inflight|first_byte inflight|last_byte inflight" (index $cfg.Annotations "nginx.router.openshift.io/balance-parameters") (env "ROUTER_TCP_BALANCE_PARAMETERS") "connect" }} 502 | least_time {{ $balanceParameters }}; 503 | {{ else }} 504 | least_time connect; 505 | {{ end}} 506 | {{ else if eq $balanceAlgo "random_two" }} 507 | {{ with $balanceParameters := firstMatch "least_conn|least_time=connect|least_time=first_byte|least_time=last_byte" (index $cfg.Annotations "nginx.router.openshift.io/balance-parameters") (env "ROUTER_TCP_BALANCE_PARAMETERS") "least_conn" }} 508 | random two {{ $balanceParameters }}; 509 | {{ else }} 510 | random two least_conn; 511 | {{ end }} 512 | {{ else if ne $balanceAlgo "round_robin" }} 513 | {{ $balanceAlgo }}; 514 | {{ end }} 515 | {{ else }} 516 | random two least_conn; 517 | {{ end }} 518 | zone stream_{{$cfg.Namespace}}_{{$cfg.Name}} 64k; 519 | {{ if gt $cfg.ActiveEndpoints 0 }} 520 | {{- range $serviceUnitName, $weight := $cfg.ServiceUnitNames }} 521 | {{- with $serviceUnit := index $.ServiceUnits $serviceUnitName }} 522 | {{- range $idx, $endpoint := endpointsForAlias $cfg $serviceUnit }} 523 | server {{$endpoint.IP}}:{{$endpoint.Port}} {{ if eq $weight 0 }}down{{ else }}weight={{ $weight }}{{ end }}; 524 | {{ end -}} 525 | {{ end -}} 526 | {{ end -}} 527 | {{ end }} 528 | } 529 | 530 | # tcp/udp server 531 | server { 532 | {{- if eq $streamProtocol "tcp" }} 533 | {{- if (or (eq $cfg.TLSTermination "edge") (eq $cfg.TLSTermination "reencrypt")) }} 534 | {{ $cert := index $cfg.Certificates $cfg.Host -}} 535 | {{ if ne $cert.Contents "" }} 536 | ssl_certificate {{$workingDir}}/certs/{{$cfgIdx}}.pem; 537 | ssl_certificate_key {{$workingDir}}/certs/{{$cfgIdx}}.pem; 538 | {{ else }} 539 | ssl_certificate {{ printf "%s/tls.crt" (env "DEFAULT_CERTIFICATE_DIR" "/etc/pki/tls/private") }}; 540 | ssl_certificate_key {{ printf "%s/tls.key" (env "DEFAULT_CERTIFICATE_DIR" "/etc/pki/tls/private") }}; 541 | {{ end }} 542 | listen {{ $streamPort }} ssl{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 543 | {{ else }} 544 | listen {{ $streamPort }}{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 545 | {{ end }} 546 | 547 | {{ if eq $cfg.TLSTermination "reencrypt" }} 548 | proxy_ssl on; 549 | {{ with $ssl_name := index $cfg.Annotations "nginx.router.openshift.io/proxy_ssl_name" }} 550 | proxy_ssl_name {{ $ssl_name }}; 551 | {{ else }} 552 | proxy_ssl_name {{ $cfg.Host }}; 553 | {{ end }} 554 | {{- if gt (len (index $cfg.Certificates (printf "%s_pod" $cfg.Host)).Contents) 0 }} 555 | proxy_ssl_trusted_certificate {{ $workingDir }}/cacerts/{{$cfgIdx}}.pem; 556 | proxy_ssl_verify on; 557 | {{ else if gt (len $defaultDestinationCA) 0 }} 558 | proxy_ssl_trusted_certificate {{ $defaultDestinationCA }}; 559 | proxy_ssl_verify on; 560 | {{ else }} 561 | proxy_ssl_verify off; 562 | {{ end }} 563 | {{ end }} 564 | {{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} 565 | set_real_ip_from {{ env "ROUTER_PROXY_PROTOCOL_TRUSTED_SOURCE" "0.0.0.0/0" }}; 566 | {{ end }} 567 | {{ else }} 568 | listen {{ $streamPort }} udp; 569 | 570 | {{- with $proxyResponses := index $cfg.Annotations "nginx.router.openshift.io/responses" }} 571 | {{- if isInteger $proxyResponses }} 572 | proxy_responses {{ $proxyResponses}}; 573 | {{ end -}} 574 | {{ end -}} 575 | {{ end -}} 576 | {{ with $syslogAddress := env "ROUTER_SYSLOG_ADDRESS" }} 577 | access_log syslog:server={{ $syslogAddress }},facility={{env "ROUTER_LOG_FACILITY" "local1"}},severity={{ $logLevel }} stream; 578 | {{ else }} 579 | access_log /var/lib/nginx/log/stream_access.log stream; 580 | {{ end }} 581 | status_zone {{$streamPort}}_{{$streamProtocol}}_{{$cfg.Name}}; 582 | proxy_pass be_stream_{{$cfg.Namespace}}_{{$cfg.Name}}; 583 | 584 | {{ if isTrue (env "ROUTER_ENABLE_UNSAFE_ANNOTATIONS") }} 585 | {{ with $value := index $cfg.Annotations "unsafe.nginx.router.openshift.io/server-snippets" }} 586 | {{ $value }} 587 | {{ end }} 588 | {{ end }} 589 | } 590 | {{ end -}} 591 | {{ end -}} 592 | {{ end -}} 593 | {{ end -}} 594 | {{ end }} 595 | } 596 | {{ end -}}{{/* end config file */}} 597 | -------------------------------------------------------------------------------- /src/nginx-plus/reload-nginx: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o nounset 4 | 5 | config_file=/var/lib/nginx/conf/nginx.conf 6 | pid_file=/var/lib/nginx/run/nginx.pid 7 | 8 | if [ -f $pid_file ]; then 9 | # NGINX is running. Reloading NGINX with the new configuration. 10 | /usr/sbin/nginx -c $config_file -s reload 11 | status=$? 12 | operation=reload 13 | else 14 | # NGINX is not running. Starting NGINX with the initial configuration. 15 | /usr/sbin/nginx -c $config_file 16 | status=$? 17 | operation=start 18 | fi 19 | 20 | if [[ $status -ne 0 ]]; then 21 | >&2 echo "Failed to $operation NGINX." 22 | else 23 | echo "Router was successfully ${operation}ed." 24 | fi 25 | 26 | exit $status 27 | -------------------------------------------------------------------------------- /src/nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # This is the NGINX router for OpenShift Origin. 3 | # 4 | # The standard name for this image is openshift/origin-nginx-router 5 | # 6 | FROM openshift/origin-cli:v3.11.0 7 | 8 | ENV NGINX_VERSION 1.15.6-1.el7_4.ngx 9 | 10 | COPY nginx.repo /etc/yum.repos.d/ 11 | 12 | RUN yum install -y nginx-${NGINX_VERSION} && \ 13 | yum clean all && \ 14 | mkdir -p /var/lib/nginx/router/{certs,cacerts} && \ 15 | mkdir -p /var/lib/nginx/{conf,run,log,cache} && \ 16 | touch /var/lib/nginx/conf/nginx.conf && \ 17 | setcap 'cap_net_bind_service=ep' /usr/sbin/nginx && \ 18 | chown -R :0 /var/lib/nginx && \ 19 | chmod -R g+w /var/lib/nginx && \ 20 | ln -sf /var/lib/nginx/log/error.log /var/log/nginx/error.log && \ 21 | rm /etc/yum.repos.d/nginx.repo 22 | 23 | COPY . /var/lib/nginx/ 24 | 25 | LABEL io.k8s.display-name="OpenShift Origin NGINX Router" \ 26 | io.k8s.description="This is a component of OpenShift Origin and contains an NGINX instance that automatically exposes services within the cluster through routes, and offers TLS termination, reencryption, or SNI-passthrough on ports 80 and 443." 27 | USER 1001 28 | EXPOSE 80 443 29 | WORKDIR /var/lib/nginx/conf 30 | ENV TEMPLATE_FILE=/var/lib/nginx/conf/nginx-config.template \ 31 | RELOAD_SCRIPT=/var/lib/nginx/reload-nginx 32 | ENTRYPOINT ["/usr/bin/openshift-router", "--working-dir=/var/lib/nginx/router"] 33 | -------------------------------------------------------------------------------- /src/nginx/conf/error-page-503.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 107 | 108 | 109 |
110 |

Application is not available

111 |

The application is currently not serving requests at this endpoint. It may not have been started or is still starting.

112 | 113 |
114 |

115 | Possible reasons you are seeing this page: 116 |

117 |
    118 |
  • 119 | The host doesn't exist. 120 | Make sure the hostname was typed correctly and that a route matching this hostname exists. 121 |
  • 122 |
  • 123 | The host exists, but doesn't have a matching path. 124 | Check if the URL path was typed correctly and that the route was created using the desired path. 125 |
  • 126 |
  • 127 | Route and path matches, but all pods are down. 128 | Make sure that the resources exposed by this route (pods, services, deployment configs, etc) have at least one pod running. 129 |
  • 130 |
131 |
132 |
133 | 134 | 135 | -------------------------------------------------------------------------------- /src/nginx/conf/nginx-config.template: -------------------------------------------------------------------------------- 1 | {{/* 2 | nginx.conf: contains the main configuration file. 3 | */}} 4 | {{- define "/var/lib/nginx/conf/nginx.conf" -}} 5 | {{- $workingDir := .WorkingDir }} 6 | {{- $defaultDestinationCA := .DefaultDestinationCA }} 7 | {{ $httpAliases := getHTTPAliasesGroupedByHost .State }} 8 | {{ $httpsPort := env "ROUTER_SERVICE_HTTPS_PORT" "443" }} 9 | {{ $passthroughPort := env "ROUTER_SERVICE_PASSTHROUGH_PORT" "443" }} 10 | {{ $logLevel := firstMatch "info|notice|warn|error|crit|alert|emerg" (env "ROUTER_LOG_LEVEL") "warn" }} 11 | worker_processes {{ env "WORKER_PROCESSES" "auto" }}; 12 | {{ with $cpuAffinity := env "WORKER_CPU_AFFINITY" }} 13 | worker_cpu_affinity {{ $cpuAffinity }}; 14 | {{ end }} 15 | {{ with $syslogAddress := env "ROUTER_SYSLOG_ADDRESS" }} 16 | error_log syslog:server={{ $syslogAddress }},facility={{env "ROUTER_LOG_FACILITY" "local1"}} {{ $logLevel }}; 17 | {{ else }} 18 | error_log /var/lib/nginx/log/error.log {{ $logLevel }}; 19 | {{ end }} 20 | pid /var/lib/nginx/run/nginx.pid; 21 | worker_rlimit_nofile {{ env "WORKER_RLIMIT_NOFILE" "8192" }}; 22 | worker_shutdown_timeout {{ env "ROUTER_DEFAULT_TUNNEL_TIMEOUT" "1h" }}; 23 | 24 | events { 25 | worker_connections {{env "ROUTER_MAX_CONNECTIONS" "20000"}}; 26 | } 27 | 28 | http { 29 | default_type application/octet-stream; 30 | 31 | {{ with $format := env "ROUTER_SYSLOG_FORMAT" }} 32 | log_format main '{{ $format }}'; 33 | {{ else }} 34 | log_format main '$remote_addr - $remote_user [$time_local] $status ' 35 | '"$request" $body_bytes_sent "$http_referer" ' 36 | '"$http_user_agent" "$http_x_forwarded_for"'; 37 | {{ end }} 38 | {{ with $syslogAddress := env "ROUTER_SYSLOG_ADDRESS" }} 39 | access_log syslog:server={{ $syslogAddress }},facility={{env "ROUTER_LOG_FACILITY" "local1"}},severity={{ $logLevel }} main; 40 | {{ else }} 41 | access_log /var/lib/nginx/log/access.log main; 42 | {{ end }} 43 | sendfile on; 44 | tcp_nopush on; 45 | server_names_hash_bucket_size 256; 46 | 47 | proxy_temp_path /var/lib/nginx/cache/proxy_temp; 48 | client_body_temp_path /var/lib/nginx/cache/client_temp; 49 | fastcgi_temp_path /var/lib/nginx/cache/fastcgi_temp; 50 | uwsgi_temp_path /var/lib/nginx/cache/uwsgi_temp; 51 | scgi_temp_path /var/lib/nginx/cache/scgi_temp; 52 | 53 | keepalive_requests {{ env "KEEPALIVE_REQUESTS" "100" }}; 54 | keepalive_timeout {{ env "ROUTER_SLOWLORIS_HTTP_KEEPALIVE" "300s" }}; 55 | 56 | client_body_timeout {{ env "ROUTER_DEFAULT_CLIENT_TIMEOUT" "30s" }}; 57 | client_header_timeout {{ env "ROUTER_DEFAULT_CLIENT_TIMEOUT" "30s" }}; 58 | send_timeout {{ env "ROUTER_DEFAULT_CLIENT_TIMEOUT" "30s" }}; 59 | proxy_connect_timeout {{ env "ROUTER_DEFAULT_CONNECT_TIMEOUT" "5s" }}; 60 | grpc_connect_timeout {{ env "ROUTER_DEFAULT_CONNECT_TIMEOUT" "5s" }}; 61 | proxy_read_timeout {{ env "ROUTER_DEFAULT_SERVER_TIMEOUT" "30s" }}; 62 | grpc_read_timeout {{ env "ROUTER_DEFAULT_SERVER_TIMEOUT" "30s" }}; 63 | proxy_send_timeout {{ env "ROUTER_DEFAULT_SERVER_TIMEOUT" "30s" }}; 64 | grpc_send_timeout {{ env "ROUTER_DEFAULT_SERVER_TIMEOUT" "30s" }}; 65 | 66 | # Prevent vulnerability to POODLE attacks (CVE‑2014‑3566) - omit SSLv3 67 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 68 | 69 | # The default cipher suite can be selected from the three sets recommended by https://wiki.mozilla.org/Security/Server_Side_TLS, 70 | # or the user can provide one using the ROUTER_CIPHERS environment variable. 71 | # By default when a cipher set is not provided, intermediate is used. 72 | {{- if eq (env "ROUTER_CIPHERS" "intermediate") "modern" }} 73 | # Modern cipher suite (no legacy browser support) from https://wiki.mozilla.org/Security/Server_Side_TLS 74 | ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256; 75 | {{- else if eq (env "ROUTER_CIPHERS" "intermediate") "intermediate" }} 76 | # Intermediate cipher suite (default) from https://wiki.mozilla.org/Security/Server_Side_TLS 77 | ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS; 78 | {{- else if eq (env "ROUTER_CIPHERS" "intermediate") "old" }} 79 | # Old cipher suite (maximum compatibility but insecure) from https://wiki.mozilla.org/Security/Server_Side_TLS 80 | ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP; 81 | {{- else }} 82 | # user provided list of ciphers (Colon separated list as seen above) 83 | # the env default is not used here since we can't get here with empty ROUTER_CIPHERS 84 | ssl_ciphers {{env "ROUTER_CIPHERS" "ECDHE-ECDSA-CHACHA20-POLY1305"}}; 85 | {{- end }} 86 | 87 | map $http_upgrade $connection_upgrade { 88 | default upgrade; 89 | '' close; 90 | } 91 | 92 | map $https $forwarded_port { 93 | default $server_port; 94 | 'on' {{ $httpsPort }}; 95 | } 96 | 97 | server { 98 | listen {{if (gt .StatsPort 0)}}{{.StatsPort}}{{else}}1936{{end}}; 99 | 100 | access_log off; 101 | 102 | default_type text/html; 103 | 104 | location /healthz { 105 | return 200 "healthy\n"; 106 | } 107 | 108 | {{ if gt .StatsPort 0 }} 109 | location = / { 110 | return 302 /stub_status; 111 | } 112 | 113 | location /stub_status { 114 | stub_status; 115 | } 116 | {{ end }} 117 | } 118 | 119 | # default server 120 | server { 121 | listen {{env "ROUTER_SERVICE_HTTP_PORT" "80"}} default_server{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 122 | listen {{env "ROUTER_SERVICE_503_SERVER_PORT" "10445" }}; 123 | {{ if eq $httpsPort $passthroughPort }} 124 | listen 127.0.0.1:{{env "ROUTER_SERVICE_SNI_PORT" "10444"}} default_server ssl{{ if isTrue (env "ROUTER_USE_HTTP2") }} http2{{ end }} proxy_protocol; 125 | set_real_ip_from 127.0.0.1; 126 | {{ else }} 127 | listen {{ $httpsPort }} default_server ssl{{ if isTrue (env "ROUTER_USE_HTTP2") }} http2{{ end }}{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 128 | {{ end }} 129 | 130 | {{ if or (eq $httpsPort $passthroughPort) (isTrue (env "ROUTER_USE_PROXY_PROTOCOL")) }} 131 | real_ip_header proxy_protocol; 132 | {{ end }} 133 | 134 | {{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} 135 | set_real_ip_from {{ env "ROUTER_PROXY_PROTOCOL_TRUSTED_SOURCE" "0.0.0.0/0" }}; 136 | {{ end }} 137 | 138 | server_name _; 139 | 140 | ssl_certificate {{ printf "%s/tls.crt" (env "DEFAULT_CERTIFICATE_DIR" "/etc/pki/tls/private") }}; 141 | ssl_certificate_key {{ printf "%s/tls.key" (env "DEFAULT_CERTIFICATE_DIR" "/etc/pki/tls/private") }}; 142 | 143 | error_page 503 /error-page-503.html; 144 | 145 | location / { 146 | return 503; 147 | } 148 | 149 | location = /error-page-503.html { 150 | root /var/lib/nginx/conf; 151 | } 152 | } 153 | 154 | # HTTP Upstreams 155 | {{range $cfgHost, $configs := $httpAliases }} 156 | {{- range $cfg := $configs }} 157 | {{- if not (and (firstMatch "tcp|udp" (index $cfg.Annotations "nginx.router.openshift.io/protocol")) (isInteger (index $cfg.Annotations "nginx.router.openshift.io/port"))) }} 158 | upstream be_{{$cfg.Namespace}}_{{$cfg.Name}} { 159 | {{ with $balanceAlgo := firstMatch "round_robin|random|random_two|least_conn|ip_hash" (index $cfg.Annotations "nginx.router.openshift.io/balance") (env "ROUTER_LOAD_BALANCE_ALGORITHM") "random_two" }} 160 | {{ if eq $balanceAlgo "random_two" }} 161 | random two least_conn; 162 | {{ else if ne $balanceAlgo "round_robin" }} 163 | {{ $balanceAlgo }}; 164 | {{ end }} 165 | {{ else }} 166 | random two least_conn; 167 | {{ end }} 168 | {{ if gt $cfg.ActiveEndpoints 0 }} 169 | {{- range $serviceUnitName, $weight := $cfg.ServiceUnitNames }} 170 | # endpoints of {{$serviceUnitName}} 171 | {{- with $serviceUnit := index $.ServiceUnits $serviceUnitName }} 172 | {{- range $idx, $endpoint := endpointsForAlias $cfg $serviceUnit }} 173 | server {{$endpoint.IP}}:{{$endpoint.Port}} {{ if eq $weight 0 }}down{{ else }}weight={{ $weight }}{{ end }}; 174 | {{ end -}} 175 | {{ end }} 176 | {{ end -}} 177 | {{ else }} 178 | server 127.0.0.1:{{env "ROUTER_SERVICE_503_SERVER_PORT" "10445"}}; 179 | {{ end }} 180 | {{ with $keepalive := (index $cfg.Annotations "nginx.router.openshift.io/keepalive") }} 181 | {{ if and (isInteger $keepalive) (ne $keepalive "0") }} 182 | keepalive {{ $keepalive }}; 183 | {{ end }} 184 | {{ end }} 185 | } 186 | {{ end }} 187 | {{ end }} 188 | 189 | {{ $primaryCfgIdx := getPrimaryAliasKey $configs }} 190 | {{ $primaryCfg := index $configs $primaryCfgIdx }} 191 | {{- if not (and (firstMatch "tcp|udp" (index $primaryCfg.Annotations "nginx.router.openshift.io/protocol")) (isInteger (index $primaryCfg.Annotations "nginx.router.openshift.io/port"))) }} 192 | 193 | # the primary route is {{ $primaryCfgIdx }} 194 | server { 195 | {{ if or (eq $primaryCfg.TLSTermination "") (or (eq $primaryCfg.InsecureEdgeTerminationPolicy "Allow") (eq $primaryCfg.InsecureEdgeTerminationPolicy "Redirect")) }} 196 | listen {{env "ROUTER_SERVICE_HTTP_PORT" "80"}}{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 197 | {{ end }} 198 | 199 | server_name {{genCertificateHostName $cfgHost $primaryCfg.IsWildcard }}; 200 | 201 | {{ if or (eq $httpsPort $passthroughPort) (isTrue (env "ROUTER_USE_PROXY_PROTOCOL")) }} 202 | real_ip_header proxy_protocol; 203 | {{ end }} 204 | 205 | {{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} 206 | set_real_ip_from {{ env "ROUTER_PROXY_PROTOCOL_TRUSTED_SOURCE" "0.0.0.0/0" }}; 207 | {{ end }} 208 | 209 | {{ if eq $primaryCfg.InsecureEdgeTerminationPolicy "Redirect" }} 210 | if ($scheme = http) { 211 | return 301 https://$host$request_uri; 212 | } 213 | {{ end }} 214 | 215 | {{- if (or (eq $primaryCfg.TLSTermination "edge") (eq $primaryCfg.TLSTermination "reencrypt")) -}} 216 | {{ $cert := index $primaryCfg.Certificates $cfgHost -}} 217 | {{ if ne $cert.Contents "" }} 218 | ssl_certificate {{$workingDir}}/certs/{{$primaryCfgIdx}}.pem; 219 | ssl_certificate_key {{$workingDir}}/certs/{{$primaryCfgIdx}}.pem; 220 | {{ else }} 221 | ssl_certificate {{ printf "%s/tls.crt" (env "DEFAULT_CERTIFICATE_DIR" "/etc/pki/tls/private") }}; 222 | ssl_certificate_key {{ printf "%s/tls.key" (env "DEFAULT_CERTIFICATE_DIR" "/etc/pki/tls/private") }}; 223 | {{ end }} 224 | {{ if eq $httpsPort $passthroughPort }} 225 | listen 127.0.0.1:{{env "ROUTER_SERVICE_SNI_PORT" "10444"}} ssl{{ if isTrue (env "ROUTER_USE_HTTP2") }} http2{{ end }} proxy_protocol; 226 | set_real_ip_from 127.0.0.1; 227 | {{ else }} 228 | listen {{ $httpsPort }} ssl{{ if isTrue (env "ROUTER_USE_HTTP2") }} http2{{ end }}{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 229 | {{ end }} 230 | {{ end }} 231 | 232 | {{ if isTrue (env "ROUTER_ENABLE_UNSAFE_ANNOTATIONS") }} 233 | {{ with $value := index $primaryCfg.Annotations "unsafe.nginx.router.openshift.io/server-snippets" }} 234 | {{ $value }} 235 | {{ end }} 236 | {{ end }} 237 | 238 | {{ range $cfgIdx, $cfg := $configs }} 239 | # this path belongs to the {{ $cfgIdx }} route 240 | location {{ if eq $cfg.Path ""}}/{{ else }}{{$cfg.Path}}{{ end }} { 241 | {{ if isTrue (index $cfg.Annotations "nginx.router.openshift.io/grpc") }} 242 | grpc_set_header X-Real-IP $remote_addr; 243 | grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 244 | grpc_set_header X-Forwarded-Host $host; 245 | grpc_set_header X-Forwarded-Port $forwarded_port; 246 | grpc_set_header X-Forwarded-Proto $scheme; 247 | 248 | {{ if eq $cfg.TLSTermination "reencrypt" }} 249 | {{ with $ssl_name := index $cfg.Annotations "nginx.router.openshift.io/proxy_ssl_name" }} 250 | grpc_ssl_name {{ $ssl_name }}; 251 | {{ else }} 252 | grpc_ssl_name {{ $cfg.Host }}; 253 | {{ end }} 254 | {{- if gt (len (index $cfg.Certificates (printf "%s_pod" $cfg.Host)).Contents) 0 }} 255 | grpc_ssl_trusted_certificate {{ $workingDir }}/cacerts/{{$cfgIdx}}.pem; 256 | grpc_ssl_verify on; 257 | {{ else }} 258 | {{ if gt (len $defaultDestinationCA) 0 }} 259 | grpc_ssl_trusted_certificate {{ $defaultDestinationCA }}; 260 | grpc_ssl_verify on; 261 | {{ else }} 262 | grpc_ssl_verify off; 263 | {{ end }} 264 | {{ end }} 265 | grpc_pass grpcs://be_{{$cfg.Namespace}}_{{$cfg.Name}}; 266 | {{ else }} 267 | grpc_pass grpc://be_{{$cfg.Namespace}}_{{$cfg.Name}}; 268 | {{ end }} 269 | {{ else }} 270 | proxy_http_version 1.1; 271 | {{ if isTrue (index $cfg.Annotations "nginx.router.openshift.io/websocket") }} 272 | proxy_set_header Upgrade $http_upgrade; 273 | proxy_set_header Connection $connection_upgrade; 274 | {{ else }} 275 | {{ with $keepalive := (index $cfg.Annotations "nginx.router.openshift.io/keepalive") }} 276 | {{ if and (isInteger $keepalive) (ne $keepalive "0") }} 277 | proxy_set_header Connection ""; 278 | {{ end }} 279 | {{ end }} 280 | {{ end }} 281 | 282 | proxy_set_header Host $host; 283 | proxy_set_header X-Real-IP $remote_addr; 284 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 285 | proxy_set_header X-Forwarded-Host $host; 286 | proxy_set_header X-Forwarded-Port $forwarded_port; 287 | proxy_set_header X-Forwarded-Proto $scheme; 288 | 289 | {{ if eq $cfg.TLSTermination "reencrypt" }} 290 | {{ with $ssl_name := index $cfg.Annotations "nginx.router.openshift.io/proxy_ssl_name" }} 291 | proxy_ssl_name {{ $ssl_name }}; 292 | {{ else }} 293 | proxy_ssl_name {{ $cfg.Host }}; 294 | {{ end }} 295 | {{- if gt (len (index $cfg.Certificates (printf "%s_pod" $cfg.Host)).Contents) 0 }} 296 | proxy_ssl_trusted_certificate {{ $workingDir }}/cacerts/{{$cfgIdx}}.pem; 297 | proxy_ssl_verify on; 298 | {{ else }} 299 | {{ if gt (len $defaultDestinationCA) 0 }} 300 | proxy_ssl_trusted_certificate {{ $defaultDestinationCA }}; 301 | proxy_ssl_verify on; 302 | {{ else }} 303 | proxy_ssl_verify off; 304 | {{ end }} 305 | {{ end }} 306 | proxy_pass https://be_{{$cfg.Namespace}}_{{$cfg.Name}}; 307 | {{ else }} 308 | proxy_pass http://be_{{$cfg.Namespace}}_{{$cfg.Name}}; 309 | {{ end }} 310 | {{ end }} 311 | 312 | {{ if isTrue (env "ROUTER_ENABLE_UNSAFE_ANNOTATIONS") }} 313 | {{ with $value := index $cfg.Annotations "unsafe.nginx.router.openshift.io/location-snippets" }} 314 | {{ $value }} 315 | {{ end }} 316 | {{ end }} 317 | } 318 | {{ end }} 319 | } 320 | {{ end -}} 321 | {{ end -}} 322 | } 323 | 324 | stream { 325 | {{ with $format := env "ROUTER_SYSLOG_FORMAT_FOR_PASSTHROUGH" }} 326 | log_format passthrough '{{ $format }}'; 327 | {{ else }} 328 | log_format passthrough '$remote_addr [$time_local] ' 329 | '$protocol $status $bytes_sent $bytes_received ' 330 | '$session_time "$ssl_preread_server_name" "$dest_passthrough"'; 331 | {{ end }} 332 | {{ with $format := env "ROUTER_SYSLOG_FORMAT_FOR_INTERNAL_PASSTHROUGH" }} 333 | log_format internal_passthrough '{{ $format }}'; 334 | {{ else }} 335 | log_format internal_passthrough '$remote_addr [$time_local] ' 336 | '$protocol $status $bytes_sent $bytes_received ' 337 | '$session_time "$ssl_preread_server_name" $dest_internal_passthrough"'; 338 | {{ end }} 339 | {{ with $format := env "ROUTER_SYSLOG_FORMAT_FOR_TCP_UDP" }} 340 | log_format stream '{{ $format }}'; 341 | {{ else }} 342 | log_format stream '$remote_addr [$time_local] ' 343 | '$protocol $status $bytes_sent $bytes_received ' 344 | '$session_time "$upstream_addr"'; 345 | {{ end }} 346 | 347 | proxy_timeout {{ env "ROUTER_DEFAULT_CLIENT_TIMEOUT" "30s" }}; 348 | proxy_connect_timeout {{ env "ROUTER_DEFAULT_CONNECT_TIMEOUT" "5s" }}; 349 | map_hash_bucket_size 256; 350 | 351 | # Prevent vulnerability to POODLE attacks (CVE‑2014‑3566) - omit SSLv3 352 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 353 | 354 | # The default cipher suite can be selected from the three sets recommended by https://wiki.mozilla.org/Security/Server_Side_TLS, 355 | # or the user can provide one using the ROUTER_CIPHERS environment variable. 356 | # By default when a cipher set is not provided, intermediate is used. 357 | {{- if eq (env "ROUTER_CIPHERS" "intermediate") "modern" }} 358 | # Modern cipher suite (no legacy browser support) from https://wiki.mozilla.org/Security/Server_Side_TLS 359 | ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256; 360 | {{- else if eq (env "ROUTER_CIPHERS" "intermediate") "intermediate" }} 361 | # Intermediate cipher suite (default) from https://wiki.mozilla.org/Security/Server_Side_TLS 362 | ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS; 363 | {{- else if eq (env "ROUTER_CIPHERS" "intermediate") "old" }} 364 | # Old cipher suite (maximum compatibility but insecure) from https://wiki.mozilla.org/Security/Server_Side_TLS 365 | ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP; 366 | {{- else }} 367 | # user provided list of ciphers (Colon separated list as seen above) 368 | # the env default is not used here since we can't get here with empty ROUTER_CIPHERS 369 | ssl_ciphers {{env "ROUTER_CIPHERS" "ECDHE-ECDSA-CHACHA20-POLY1305"}}; 370 | {{- end }} 371 | 372 | 373 | upstream https-route { 374 | server 127.0.0.1:{{env "ROUTER_SERVICE_SNI_PORT" "10444"}}; 375 | } 376 | 377 | map $ssl_preread_server_name $dest_passthrough { 378 | {{- range $cfgIdx, $cfg := .State }} 379 | {{ if eq $cfg.TLSTermination "passthrough" }} 380 | {{ $cfg.Host }} 127.0.0.1:{{ env "ROUTER_SERVICE_INTERNAL_PASSTHROUGH_PORT" "10447" }}; 381 | {{ end }} 382 | {{ end }} 383 | default https-route; 384 | } 385 | 386 | # passthrough routes 387 | server { 388 | listen {{ $passthroughPort }}{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 389 | {{ with $syslogAddress := env "ROUTER_SYSLOG_ADDRESS" }} 390 | access_log syslog:server={{ $syslogAddress }},facility={{env "ROUTER_LOG_FACILITY" "local1"}},severity={{ $logLevel }} passthrough; 391 | {{ else }} 392 | access_log /var/lib/nginx/log/passthrough_access.log passthrough; 393 | {{ end }} 394 | proxy_pass $dest_passthrough; 395 | ssl_preread on; 396 | proxy_protocol on; 397 | {{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} 398 | set_real_ip_from {{ env "ROUTER_PROXY_PROTOCOL_TRUSTED_SOURCE" "0.0.0.0/0" }}; 399 | {{ end }} 400 | } 401 | 402 | # passthrough upstreams 403 | {{- range $cfgIdx, $cfg := .State }} 404 | {{ if eq $cfg.TLSTermination "passthrough" }} 405 | upstream be_passthrough_{{$cfg.Namespace}}_{{$cfg.Name}} { 406 | {{ with $balanceAlgo := firstMatch "round_robin|random|random_two|least_conn|ip_hash" (index $cfg.Annotations "nginx.router.openshift.io/balance") (env "ROUTER_TCP_BALANCE_SCHEME") "random_two" }} 407 | {{ if eq $balanceAlgo "ip_hash" }} 408 | hash $remote_addr consistent; 409 | {{ else if eq $balanceAlgo "random_two" }} 410 | random two least_conn; 411 | {{ else if ne $balanceAlgo "round_robin" }} 412 | {{ $balanceAlgo }}; 413 | {{ end }} 414 | {{ else }} 415 | random two least_conn; 416 | {{ end }} 417 | {{ if gt $cfg.ActiveEndpoints 0 }} 418 | {{- range $serviceUnitName, $weight := $cfg.ServiceUnitNames }} 419 | {{- with $serviceUnit := index $.ServiceUnits $serviceUnitName }} 420 | {{- range $idx, $endpoint := endpointsForAlias $cfg $serviceUnit }} 421 | server {{$endpoint.IP}}:{{$endpoint.Port}} {{ if eq $weight 0 }}down{{ else }}weight={{ $weight }}{{ end }}; 422 | {{ end -}} 423 | {{ end -}} 424 | {{ end -}} 425 | {{ else }} 426 | server 127.0.0.1:{{env "ROUTER_SERVICE_UNREACHABLE_PORT" "10446"}}; 427 | {{ end }} 428 | } 429 | {{ end }} 430 | {{ end }} 431 | 432 | map $ssl_preread_server_name $dest_internal_passthrough { 433 | {{- range $cfgIdx, $cfg := .State }} 434 | {{ if eq $cfg.TLSTermination "passthrough" }} 435 | {{ $cfg.Host }} be_passthrough_{{$cfg.Namespace}}_{{$cfg.Name}}; 436 | {{ end }} 437 | {{ end }} 438 | default 127.0.0.1:{{env "ROUTER_SERVICE_UNREACHABLE_PORT" "10446"}}; 439 | } 440 | 441 | server { 442 | listen {{ env "ROUTER_SERVICE_INTERNAL_PASSTHROUGH_PORT" "10447" }} proxy_protocol; 443 | 444 | {{ with $syslogAddress := env "ROUTER_SYSLOG_ADDRESS" }} 445 | access_log syslog:server={{ $syslogAddress }},facility={{env "ROUTER_LOG_FACILITY" "local1"}},severity={{ $logLevel }} internal_passthrough; 446 | {{ else }} 447 | access_log /var/lib/nginx/log/internal_passthrough_access.log internal_passthrough; 448 | {{ end }} 449 | 450 | ssl_preread on; 451 | set_real_ip_from 127.0.0.1; 452 | 453 | proxy_pass $dest_internal_passthrough; 454 | } 455 | 456 | # TCP/UDP upstreams 457 | {{- range $cfgIdx, $cfg := .State }} 458 | {{- with $streamProtocol := firstMatch "tcp|udp" (index $cfg.Annotations "nginx.router.openshift.io/protocol") }} 459 | {{- with $streamPort := index $cfg.Annotations "nginx.router.openshift.io/port" }} 460 | {{- if isInteger $streamPort }} 461 | {{ if not (firstMatch (index $cfg.Annotations "nginx.router.openshift.io/port") (env "ROUTER_SERVICE_HTTPS_PORT" "443") (env "ROUTER_SERVICE_PASSTHROUGH_PORT" "443") (env "ROUTER_SERVICE_HTTP_PORT" "80") (env "ROUTER_SERVICE_SNI_PORT" "10444") (env "ROUTER_SERVICE_503_SERVER_PORT" "10445") (env "ROUTER_SERVICE_UNREACHABLE_PORT" "10446") (env "ROUTER_SERVICE_INTERNAL_PASSTHROUGH_PORT" "10447") "1936") }} 462 | upstream be_stream_{{$cfg.Namespace}}_{{$cfg.Name}} { 463 | {{ with $balanceAlgo := firstMatch "round_robin|random|random_two|least_conn|ip_hash" (index $cfg.Annotations "nginx.router.openshift.io/balance") (env "ROUTER_TCP_BALANCE_SCHEME") "random_two" }} 464 | {{ if eq $balanceAlgo "ip_hash" }} 465 | hash $remote_addr consistent; 466 | {{ else if eq $balanceAlgo "random_two" }} 467 | random two least_conn; 468 | {{ else if ne $balanceAlgo "round_robin" }} 469 | {{ $balanceAlgo }}; 470 | {{ end }} 471 | {{ else }} 472 | random two least_conn; 473 | {{ end }} 474 | {{ if gt $cfg.ActiveEndpoints 0 }} 475 | {{- range $serviceUnitName, $weight := $cfg.ServiceUnitNames }} 476 | {{- with $serviceUnit := index $.ServiceUnits $serviceUnitName }} 477 | {{- range $idx, $endpoint := endpointsForAlias $cfg $serviceUnit }} 478 | server {{$endpoint.IP}}:{{$endpoint.Port}} {{ if eq $weight 0 }}down{{ else }}weight={{ $weight }}{{ end }}; 479 | {{ end -}} 480 | {{ end -}} 481 | {{ end -}} 482 | {{ end }} 483 | } 484 | 485 | # tcp/udp server 486 | server { 487 | {{- if eq $streamProtocol "tcp" }} 488 | {{- if (or (eq $cfg.TLSTermination "edge") (eq $cfg.TLSTermination "reencrypt")) }} 489 | {{ $cert := index $cfg.Certificates $cfg.Host -}} 490 | {{ if ne $cert.Contents "" }} 491 | ssl_certificate {{$workingDir}}/certs/{{$cfgIdx}}.pem; 492 | ssl_certificate_key {{$workingDir}}/certs/{{$cfgIdx}}.pem; 493 | {{ else }} 494 | ssl_certificate {{ printf "%s/tls.crt" (env "DEFAULT_CERTIFICATE_DIR" "/etc/pki/tls/private") }}; 495 | ssl_certificate_key {{ printf "%s/tls.key" (env "DEFAULT_CERTIFICATE_DIR" "/etc/pki/tls/private") }}; 496 | {{ end }} 497 | listen {{ $streamPort }} ssl{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 498 | {{ else }} 499 | listen {{ $streamPort }}{{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} proxy_protocol{{ end }}; 500 | {{ end }} 501 | 502 | {{ if eq $cfg.TLSTermination "reencrypt" }} 503 | proxy_ssl on; 504 | {{ with $ssl_name := index $cfg.Annotations "nginx.router.openshift.io/proxy_ssl_name" }} 505 | proxy_ssl_name {{ $ssl_name }}; 506 | {{ else }} 507 | proxy_ssl_name {{ $cfg.Host }}; 508 | {{ end }} 509 | {{- if gt (len (index $cfg.Certificates (printf "%s_pod" $cfg.Host)).Contents) 0 }} 510 | proxy_ssl_trusted_certificate {{ $workingDir }}/cacerts/{{$cfgIdx}}.pem; 511 | proxy_ssl_verify on; 512 | {{ else if gt (len $defaultDestinationCA) 0 }} 513 | proxy_ssl_trusted_certificate {{ $defaultDestinationCA }}; 514 | proxy_ssl_verify on; 515 | {{ else }} 516 | proxy_ssl_verify off; 517 | {{ end }} 518 | {{ end }} 519 | {{ if isTrue (env "ROUTER_USE_PROXY_PROTOCOL") }} 520 | set_real_ip_from {{ env "ROUTER_PROXY_PROTOCOL_TRUSTED_SOURCE" "0.0.0.0/0" }}; 521 | {{ end }} 522 | {{ else }} 523 | listen {{ $streamPort }} udp; 524 | 525 | {{- with $proxyResponses := index $cfg.Annotations "nginx.router.openshift.io/responses" }} 526 | {{- if isInteger $proxyResponses }} 527 | proxy_responses {{ $proxyResponses}}; 528 | {{ end -}} 529 | {{ end -}} 530 | {{ end -}} 531 | {{ with $syslogAddress := env "ROUTER_SYSLOG_ADDRESS" }} 532 | access_log syslog:server={{ $syslogAddress }},facility={{env "ROUTER_LOG_FACILITY" "local1"}},severity={{ $logLevel }} stream; 533 | {{ else }} 534 | access_log /var/lib/nginx/log/stream_access.log stream; 535 | {{ end }} 536 | proxy_pass be_stream_{{$cfg.Namespace}}_{{$cfg.Name}}; 537 | 538 | {{ if isTrue (env "ROUTER_ENABLE_UNSAFE_ANNOTATIONS") }} 539 | {{ with $value := index $cfg.Annotations "unsafe.nginx.router.openshift.io/server-snippets" }} 540 | {{ $value }} 541 | {{ end }} 542 | {{ end }} 543 | } 544 | {{ end -}} 545 | {{ end -}} 546 | {{ end -}} 547 | {{ end -}} 548 | {{ end }} 549 | } 550 | {{ end -}}{{/* end config file */}} 551 | -------------------------------------------------------------------------------- /src/nginx/nginx.repo: -------------------------------------------------------------------------------- 1 | [nginx] 2 | name=nginx repo 3 | baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/ 4 | gpgcheck=0 5 | enabled=1 6 | -------------------------------------------------------------------------------- /src/nginx/reload-nginx: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o nounset 4 | 5 | config_file=/var/lib/nginx/conf/nginx.conf 6 | pid_file=/var/lib/nginx/run/nginx.pid 7 | 8 | if [ -f $pid_file ]; then 9 | # NGINX is running. Reloading NGINX with the new configuration. 10 | /usr/sbin/nginx -c $config_file -s reload 11 | status=$? 12 | operation=reload 13 | else 14 | # NGINX is not running. Starting NGINX with the initial configuration. 15 | /usr/sbin/nginx -c $config_file 16 | status=$? 17 | operation=start 18 | fi 19 | 20 | if [[ $status -ne 0 ]]; then 21 | >&2 echo "Failed to $operation NGINX." 22 | else 23 | echo "Router was successfully ${operation}ed." 24 | fi 25 | 26 | exit $status 27 | --------------------------------------------------------------------------------