diff --git a/.empty b/.empty deleted file mode 100644 index e69de29bb..000000000 diff --git a/404.html b/404.html new file mode 100644 index 000000000..c2b250595 --- /dev/null +++ b/404.html @@ -0,0 +1,1026 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + + +
+
+ +

404 - Not found

+ + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 000000000..76d17f57a Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/images/icons/bitbucket.4ebea66e.svg b/assets/images/icons/bitbucket.4ebea66e.svg new file mode 100644 index 000000000..ffc79b1ec --- /dev/null +++ b/assets/images/icons/bitbucket.4ebea66e.svg @@ -0,0 +1,20 @@ + + + diff --git a/assets/images/icons/github.a4034fb1.svg b/assets/images/icons/github.a4034fb1.svg new file mode 100644 index 000000000..f8944b015 --- /dev/null +++ b/assets/images/icons/github.a4034fb1.svg @@ -0,0 +1,18 @@ + + + diff --git a/assets/images/icons/gitlab.348cdb3a.svg b/assets/images/icons/gitlab.348cdb3a.svg new file mode 100644 index 000000000..f4df57c66 --- /dev/null +++ b/assets/images/icons/gitlab.348cdb3a.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/javascripts/application.b438e6c5.js b/assets/javascripts/application.b438e6c5.js new file mode 100644 index 000000000..62700fa21 --- /dev/null +++ b/assets/javascripts/application.b438e6c5.js @@ -0,0 +1 @@ +!function(e,t){for(var n in t)e[n]=t[n]}(window,function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=6)}([function(e,t,n){"use strict";t.__esModule=!0,t.default={createElement:function(e,t){var n=document.createElement(e);t&&Array.prototype.forEach.call(Object.keys(t),function(e){n.setAttribute(e,t[e])});for(var r=arguments.length,i=Array(r>2?r-2:0),o=2;o pre, pre > code");Array.prototype.forEach.call(n,function(t,n){var r="__code_"+n,i=e.createElement("button",{class:"md-clipboard",title:h("clipboard.copy"),"data-clipboard-target":"#"+r+" pre, #"+r+" code"},e.createElement("span",{class:"md-clipboard__message"})),o=t.parentNode;o.id=r,o.insertBefore(i,t)});new c.default(".md-clipboard").on("success",function(e){var t=e.trigger.querySelector(".md-clipboard__message");if(!(t instanceof HTMLElement))throw new ReferenceError;e.clearSelection(),t.dataset.mdTimer&&clearTimeout(parseInt(t.dataset.mdTimer,10)),t.classList.add("md-clipboard__message--active"),t.innerHTML=h("clipboard.copied"),t.dataset.mdTimer=setTimeout(function(){t.classList.remove("md-clipboard__message--active"),t.dataset.mdTimer=""},2e3).toString()})}if(!Modernizr.details){var r=document.querySelectorAll("details > summary");Array.prototype.forEach.call(r,function(e){e.addEventListener("click",function(e){var t=e.target.parentNode;t.hasAttribute("open")?t.removeAttribute("open"):t.setAttribute("open","")})})}var i=function(){if(document.location.hash){var e=document.getElementById(document.location.hash.substring(1));if(!e)return;for(var t=e.parentNode;t&&!(t instanceof HTMLDetailsElement);)t=t.parentNode;if(t&&!t.open){t.open=!0;var n=location.hash;location.hash=" ",location.hash=n}}};if(window.addEventListener("hashchange",i),i(),Modernizr.ios){var o=document.querySelectorAll("[data-md-scrollfix]");Array.prototype.forEach.call(o,function(e){e.addEventListener("touchstart",function(){var t=e.scrollTop;0===t?e.scrollTop=1:t+e.offsetHeight===e.scrollHeight&&(e.scrollTop=t-1)})})}}).listen(),new f.default.Event.Listener(window,["scroll","resize","orientationchange"],new f.default.Header.Shadow("[data-md-component=container]","[data-md-component=header]")).listen(),new f.default.Event.Listener(window,["scroll","resize","orientationchange"],new f.default.Header.Title("[data-md-component=title]",".md-typeset h1")).listen(),document.querySelector("[data-md-component=hero]")&&new f.default.Event.Listener(window,["scroll","resize","orientationchange"],new f.default.Tabs.Toggle("[data-md-component=hero]")).listen(),document.querySelector("[data-md-component=tabs]")&&new f.default.Event.Listener(window,["scroll","resize","orientationchange"],new f.default.Tabs.Toggle("[data-md-component=tabs]")).listen(),new f.default.Event.MatchMedia("(min-width: 1220px)",new f.default.Event.Listener(window,["scroll","resize","orientationchange"],new f.default.Sidebar.Position("[data-md-component=navigation]","[data-md-component=header]"))),document.querySelector("[data-md-component=toc]")&&new f.default.Event.MatchMedia("(min-width: 960px)",new f.default.Event.Listener(window,["scroll","resize","orientationchange"],new f.default.Sidebar.Position("[data-md-component=toc]","[data-md-component=header]"))),new f.default.Event.MatchMedia("(min-width: 960px)",new f.default.Event.Listener(window,"scroll",new f.default.Nav.Blur("[data-md-component=toc] [href]")));var n=document.querySelectorAll("[data-md-component=collapsible]");Array.prototype.forEach.call(n,function(e){new f.default.Event.MatchMedia("(min-width: 1220px)",new f.default.Event.Listener(e.previousElementSibling,"click",new f.default.Nav.Collapse(e)))}),new f.default.Event.MatchMedia("(max-width: 1219px)",new f.default.Event.Listener("[data-md-component=navigation] [data-md-toggle]","change",new f.default.Nav.Scrolling("[data-md-component=navigation] nav"))),document.querySelector("[data-md-component=search]")&&(new f.default.Event.MatchMedia("(max-width: 959px)",new f.default.Event.Listener("[data-md-toggle=search]","change",new f.default.Search.Lock("[data-md-toggle=search]"))),new f.default.Event.Listener("[data-md-component=query]",["focus","keyup","change"],new f.default.Search.Result("[data-md-component=result]",function(){return fetch(t.url.base+"/"+(t.version<"0.17"?"mkdocs":"search")+"/search_index.json",{credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){return e.docs.map(function(e){return e.location=t.url.base+e.location,e})})})).listen(),new f.default.Event.Listener("[data-md-component=reset]","click",function(){setTimeout(function(){var e=document.querySelector("[data-md-component=query]");if(!(e instanceof HTMLInputElement))throw new ReferenceError;e.focus()},10)}).listen(),new f.default.Event.Listener("[data-md-toggle=search]","change",function(e){setTimeout(function(e){if(!(e instanceof HTMLInputElement))throw new ReferenceError;if(e.checked){var t=document.querySelector("[data-md-component=query]");if(!(t instanceof HTMLInputElement))throw new ReferenceError;t.focus()}},400,e.target)}).listen(),new f.default.Event.MatchMedia("(min-width: 960px)",new f.default.Event.Listener("[data-md-component=query]","focus",function(){var e=document.querySelector("[data-md-toggle=search]");if(!(e instanceof HTMLInputElement))throw new ReferenceError;e.checked||(e.checked=!0,e.dispatchEvent(new CustomEvent("change")))})),new f.default.Event.Listener(window,"keydown",function(e){var t=document.querySelector("[data-md-toggle=search]");if(!(t instanceof HTMLInputElement))throw new ReferenceError;var n=document.querySelector("[data-md-component=query]");if(!(n instanceof HTMLInputElement))throw new ReferenceError;if(!e.metaKey&&!e.ctrlKey)if(t.checked){if(13===e.keyCode){if(n===document.activeElement){e.preventDefault();var r=document.querySelector("[data-md-component=search] [href][data-md-state=active]");r instanceof HTMLLinkElement&&(window.location=r.getAttribute("href"),t.checked=!1,t.dispatchEvent(new CustomEvent("change")),n.blur())}}else if(9===e.keyCode||27===e.keyCode)t.checked=!1,t.dispatchEvent(new CustomEvent("change")),n.blur();else if(-1!==[8,37,39].indexOf(e.keyCode))n!==document.activeElement&&n.focus();else if(-1!==[38,40].indexOf(e.keyCode)){var i=e.keyCode,o=Array.prototype.slice.call(document.querySelectorAll("[data-md-component=query], [data-md-component=search] [href]")),a=o.find(function(e){if(!(e instanceof HTMLElement))throw new ReferenceError;return"active"===e.dataset.mdState});a&&(a.dataset.mdState="");var s=Math.max(0,(o.indexOf(a)+o.length+(38===i?-1:1))%o.length);return o[s]&&(o[s].dataset.mdState="active",o[s].focus()),e.preventDefault(),e.stopPropagation(),!1}}else document.activeElement&&!document.activeElement.form&&(70!==e.keyCode&&83!==e.keyCode||(n.focus(),e.preventDefault()))}).listen(),new f.default.Event.Listener(window,"keypress",function(){var e=document.querySelector("[data-md-toggle=search]");if(!(e instanceof HTMLInputElement))throw new ReferenceError;if(e.checked){var t=document.querySelector("[data-md-component=query]");if(!(t instanceof HTMLInputElement))throw new ReferenceError;t!==document.activeElement&&t.focus()}}).listen()),new f.default.Event.Listener(document.body,"keydown",function(e){if(9===e.keyCode){var t=document.querySelectorAll("[data-md-component=navigation] .md-nav__link[for]:not([tabindex])");Array.prototype.forEach.call(t,function(e){e.offsetHeight&&(e.tabIndex=0)})}}).listen(),new f.default.Event.Listener(document.body,"mousedown",function(){var e=document.querySelectorAll("[data-md-component=navigation] .md-nav__link[tabindex]");Array.prototype.forEach.call(e,function(e){e.removeAttribute("tabIndex")})}).listen(),document.body.addEventListener("click",function(){"tabbing"===document.body.dataset.mdState&&(document.body.dataset.mdState="")}),new f.default.Event.MatchMedia("(max-width: 959px)",new f.default.Event.Listener("[data-md-component=navigation] [href^='#']","click",function(){var e=document.querySelector("[data-md-toggle=drawer]");if(!(e instanceof HTMLInputElement))throw new ReferenceError;e.checked&&(e.checked=!1,e.dispatchEvent(new CustomEvent("change")))})),function(){var e=document.querySelector("[data-md-source]");if(!e)return a.default.resolve([]);if(!(e instanceof HTMLAnchorElement))throw new ReferenceError;switch(e.dataset.mdSource){case"github":return new f.default.Source.Adapter.GitHub(e).fetch();default:return a.default.resolve([])}}().then(function(e){var t=document.querySelectorAll("[data-md-source]");Array.prototype.forEach.call(t,function(t){new f.default.Source.Repository(t).initialize(e)})})}t.__esModule=!0,t.app=void 0,n(7),n(8),n(9),n(10),n(11),n(12),n(13);var o=n(14),a=r(o),s=n(18),c=r(s),u=n(19),l=r(u),d=n(20),f=r(d);window.Promise=window.Promise||a.default;var h=function(e){var t=document.getElementsByName("lang:"+e)[0];if(!(t instanceof HTMLMetaElement))throw new ReferenceError;return t.content},p={initialize:i};t.app=p}).call(t,n(0))},function(e,t,n){e.exports=n.p+"assets/images/icons/bitbucket.4ebea66e.svg"},function(e,t,n){e.exports=n.p+"assets/images/icons/github.a4034fb1.svg"},function(e,t,n){e.exports=n.p+"assets/images/icons/gitlab.348cdb3a.svg"},function(e,t){},function(e,t){},function(e,t){try{var n=new window.CustomEvent("test");if(n.preventDefault(),!0!==n.defaultPrevented)throw new Error("Could not prevent default")}catch(e){var r=function(e,t){var n,r;return t=t||{bubbles:!1,cancelable:!1,detail:void 0},n=document.createEvent("CustomEvent"),n.initCustomEvent(e,t.bubbles,t.cancelable,t.detail),r=n.preventDefault,n.preventDefault=function(){r.call(this);try{Object.defineProperty(this,"defaultPrevented",{get:function(){return!0}})}catch(e){this.defaultPrevented=!0}},n};r.prototype=window.Event.prototype,window.CustomEvent=r}},function(e,t,n){window.fetch||(window.fetch=n(2).default||n(2))},function(e,t,n){"use strict";(function(t){function n(){}function r(e,t){return function(){e.apply(t,arguments)}}function i(e){if(!(this instanceof i))throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],l(e,this)}function o(e,t){for(;3===e._state;)e=e._value;if(0===e._state)return void e._deferreds.push(t);e._handled=!0,i._immediateFn(function(){var n=1===e._state?t.onFulfilled:t.onRejected;if(null===n)return void(1===e._state?a:s)(t.promise,e._value);var r;try{r=n(e._value)}catch(e){return void s(t.promise,e)}a(t.promise,r)})}function a(e,t){try{if(t===e)throw new TypeError("A promise cannot be resolved with itself.");if(t&&("object"==typeof t||"function"==typeof t)){var n=t.then;if(t instanceof i)return e._state=3,e._value=t,void c(e);if("function"==typeof n)return void l(r(n,t),e)}e._state=1,e._value=t,c(e)}catch(t){s(e,t)}}function s(e,t){e._state=2,e._value=t,c(e)}function c(e){2===e._state&&0===e._deferreds.length&&i._immediateFn(function(){e._handled||i._unhandledRejectionFn(e._value)});for(var t=0,n=e._deferreds.length;t=0&&(e._idleTimeoutId=setTimeout(function(){e._onTimeout&&e._onTimeout()},t))},n(16),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(t,n(1))},function(e,t,n){(function(e,t){!function(e,n){"use strict";function r(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),n=0;n1)for(var n=1;n0&&void 0!==arguments[0]?arguments[0]:{};this.action=e.action,this.container=e.container,this.emitter=e.emitter,this.target=e.target,this.text=e.text,this.trigger=e.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var e=this,t="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return e.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[t?"right":"left"]="-9999px";var n=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=n+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=(0,r.default)(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=(0,r.default)(this.target),this.copyText()}},{key:"copyText",value:function(){var e=void 0;try{e=document.execCommand(this.action)}catch(t){e=!1}this.handleResult(e)}},{key:"handleResult",value:function(e){this.emitter.emit(e?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=e,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(e){if(void 0!==e){if(!e||"object"!==(void 0===e?"undefined":i(e))||1!==e.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(e.hasAttribute("readonly")||e.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=e}},get:function(){return this._target}}]),e}();e.exports=a})},function(e,t,n){function r(e,t,n){if(!e&&!t&&!n)throw new Error("Missing required arguments");if(!s.string(t))throw new TypeError("Second argument must be a String");if(!s.fn(n))throw new TypeError("Third argument must be a Function");if(s.node(e))return i(e,t,n);if(s.nodeList(e))return o(e,t,n);if(s.string(e))return a(e,t,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function i(e,t,n){return e.addEventListener(t,n),{destroy:function(){e.removeEventListener(t,n)}}}function o(e,t,n){return Array.prototype.forEach.call(e,function(e){e.addEventListener(t,n)}),{destroy:function(){Array.prototype.forEach.call(e,function(e){e.removeEventListener(t,n)})}}}function a(e,t,n){return c(document.body,e,t,n)}var s=n(6),c=n(5);e.exports=r},function(e,t){function n(){}n.prototype={on:function(e,t,n){var r=this.e||(this.e={});return(r[e]||(r[e]=[])).push({fn:t,ctx:n}),this},once:function(e,t,n){function r(){i.off(e,r),t.apply(n,arguments)}var i=this;return r._=t,this.on(e,r,n)},emit:function(e){var t=[].slice.call(arguments,1),n=((this.e||(this.e={}))[e]||[]).slice(),r=0,i=n.length;for(r;r0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof e.action?e.action:this.defaultAction,this.target="function"==typeof e.target?e.target:this.defaultTarget,this.text="function"==typeof e.text?e.text:this.defaultText,this.container="object"===f(e.container)?e.container:document.body}},{key:"listenClick",value:function(e){var t=this;this.listener=(0,d.default)(e,"click",function(e){return t.onClick(e)})}},{key:"onClick",value:function(e){var t=e.delegateTarget||e.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new u.default({action:this.action(t),target:this.target(t),text:this.text(t),container:this.container,trigger:t,emitter:this})}},{key:"defaultAction",value:function(e){return c("action",e)}},{key:"defaultTarget",value:function(e){var t=c("target",e);if(t)return document.querySelector(t)}},{key:"defaultText",value:function(e){return c("text",e)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["copy","cut"],t="string"==typeof e?[e]:e,n=!!document.queryCommandSupported;return t.forEach(function(e){n=n&&!!document.queryCommandSupported(e)}),n}}]),t}(l.default);e.exports=p})},function(e,t){function n(e,t){for(;e&&e.nodeType!==r;){if("function"==typeof e.matches&&e.matches(t))return e;e=e.parentNode}}var r=9;if("undefined"!=typeof Element&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}e.exports=n},function(e,t,n){function r(e,t,n,r,i){var a=o.apply(this,arguments);return e.addEventListener(n,a,i),{destroy:function(){e.removeEventListener(n,a,i)}}}function i(e,t,n,i,o){return"function"==typeof e.addEventListener?r.apply(null,arguments):"function"==typeof n?r.bind(null,document).apply(null,arguments):("string"==typeof e&&(e=document.querySelectorAll(e)),Array.prototype.map.call(e,function(e){return r(e,t,n,i,o)}))}function o(e,t,n,r){return function(n){n.delegateTarget=a(n.target,t),n.delegateTarget&&r.call(e,n)}}var a=n(4);e.exports=i},function(e,t){t.node=function(e){return void 0!==e&&e instanceof HTMLElement&&1===e.nodeType},t.nodeList=function(e){var n=Object.prototype.toString.call(e);return void 0!==e&&("[object NodeList]"===n||"[object HTMLCollection]"===n)&&"length"in e&&(0===e.length||t.node(e[0]))},t.string=function(e){return"string"==typeof e||e instanceof String},t.fn=function(e){return"[object Function]"===Object.prototype.toString.call(e)}},function(e,t){function n(e){var t;if("SELECT"===e.nodeName)e.focus(),t=e.value;else if("INPUT"===e.nodeName||"TEXTAREA"===e.nodeName){var n=e.hasAttribute("readonly");n||e.setAttribute("readonly",""),e.select(),e.setSelectionRange(0,e.value.length),n||e.removeAttribute("readonly"),t=e.value}else{e.hasAttribute("contenteditable")&&e.focus();var r=window.getSelection(),i=document.createRange();i.selectNodeContents(e),r.removeAllRanges(),r.addRange(i),t=r.toString()}return t}e.exports=n}])})},function(e,t,n){var r;!function(){"use strict";function i(e,t){var n;if(t=t||{},this.trackingClick=!1,this.trackingClickStart=0,this.targetElement=null,this.touchStartX=0,this.touchStartY=0,this.lastTouchIdentifier=0,this.touchBoundary=t.touchBoundary||10,this.layer=e,this.tapDelay=t.tapDelay||200,this.tapTimeout=t.tapTimeout||700,!i.notNeeded(e)){for(var r=["onMouse","onClick","onTouchStart","onTouchMove","onTouchEnd","onTouchCancel"],o=this,s=0,c=r.length;s=0,a=navigator.userAgent.indexOf("Android")>0&&!o,s=/iP(ad|hone|od)/.test(navigator.userAgent)&&!o,c=s&&/OS 4_\d(_\d)?/.test(navigator.userAgent),u=s&&/OS [6-7]_\d/.test(navigator.userAgent),l=navigator.userAgent.indexOf("BB10")>0;i.prototype.needsClick=function(e){switch(e.nodeName.toLowerCase()){case"button":case"select":case"textarea":if(e.disabled)return!0;break;case"input":if(s&&"file"===e.type||e.disabled)return!0;break;case"label":case"iframe":case"video":return!0}return/\bneedsclick\b/.test(e.className)},i.prototype.needsFocus=function(e){switch(e.nodeName.toLowerCase()){case"textarea":return!0;case"select":return!a;case"input":switch(e.type){case"button":case"checkbox":case"file":case"image":case"radio":case"submit":return!1}return!e.disabled&&!e.readOnly;default:return/\bneedsfocus\b/.test(e.className)}},i.prototype.sendClick=function(e,t){var n,r;document.activeElement&&document.activeElement!==e&&document.activeElement.blur(),r=t.changedTouches[0],n=document.createEvent("MouseEvents"),n.initMouseEvent(this.determineEventType(e),!0,!0,window,1,r.screenX,r.screenY,r.clientX,r.clientY,!1,!1,!1,!1,0,null),n.forwardedTouchEvent=!0,e.dispatchEvent(n)},i.prototype.determineEventType=function(e){return a&&"select"===e.tagName.toLowerCase()?"mousedown":"click"},i.prototype.focus=function(e){var t;s&&e.setSelectionRange&&0!==e.type.indexOf("date")&&"time"!==e.type&&"month"!==e.type?(t=e.value.length,e.setSelectionRange(t,t)):e.focus()},i.prototype.updateScrollParent=function(e){var t,n;if(!(t=e.fastClickScrollParent)||!t.contains(e)){n=e;do{if(n.scrollHeight>n.offsetHeight){t=n,e.fastClickScrollParent=n;break}n=n.parentElement}while(n)}t&&(t.fastClickLastScrollTop=t.scrollTop)},i.prototype.getTargetElementFromEventTarget=function(e){return e.nodeType===Node.TEXT_NODE?e.parentNode:e},i.prototype.onTouchStart=function(e){var t,n,r;if(e.targetTouches.length>1)return!0;if(t=this.getTargetElementFromEventTarget(e.target),n=e.targetTouches[0],s){if(r=window.getSelection(),r.rangeCount&&!r.isCollapsed)return!0;if(!c){if(n.identifier&&n.identifier===this.lastTouchIdentifier)return e.preventDefault(),!1;this.lastTouchIdentifier=n.identifier,this.updateScrollParent(t)}}return this.trackingClick=!0,this.trackingClickStart=e.timeStamp,this.targetElement=t,this.touchStartX=n.pageX,this.touchStartY=n.pageY,e.timeStamp-this.lastClickTimen||Math.abs(t.pageY-this.touchStartY)>n},i.prototype.onTouchMove=function(e){return!this.trackingClick||((this.targetElement!==this.getTargetElementFromEventTarget(e.target)||this.touchHasMoved(e))&&(this.trackingClick=!1,this.targetElement=null),!0)},i.prototype.findControl=function(e){return void 0!==e.control?e.control:e.htmlFor?document.getElementById(e.htmlFor):e.querySelector("button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea")},i.prototype.onTouchEnd=function(e){var t,n,r,i,o,l=this.targetElement;if(!this.trackingClick)return!0;if(e.timeStamp-this.lastClickTimethis.tapTimeout)return!0;if(this.cancelNextClick=!1,this.lastClickTime=e.timeStamp,n=this.trackingClickStart,this.trackingClick=!1,this.trackingClickStart=0,u&&(o=e.changedTouches[0],l=document.elementFromPoint(o.pageX-window.pageXOffset,o.pageY-window.pageYOffset)||l,l.fastClickScrollParent=this.targetElement.fastClickScrollParent),"label"===(r=l.tagName.toLowerCase())){if(t=this.findControl(l)){if(this.focus(l),a)return!1;l=t}}else if(this.needsFocus(l))return e.timeStamp-n>100||s&&window.top!==window&&"input"===r?(this.targetElement=null,!1):(this.focus(l),this.sendClick(l,e),s&&"select"===r||(this.targetElement=null,e.preventDefault()),!1);return!(!s||c||!(i=l.fastClickScrollParent)||i.fastClickLastScrollTop===i.scrollTop)||(this.needsClick(l)||(e.preventDefault(),this.sendClick(l,e)),!1)},i.prototype.onTouchCancel=function(){this.trackingClick=!1,this.targetElement=null},i.prototype.onMouse=function(e){return!this.targetElement||(!!e.forwardedTouchEvent||(!e.cancelable||(!(!this.needsClick(this.targetElement)||this.cancelNextClick)||(e.stopImmediatePropagation?e.stopImmediatePropagation():e.propagationStopped=!0,e.stopPropagation(),e.preventDefault(),!1))))},i.prototype.onClick=function(e){var t;return this.trackingClick?(this.targetElement=null,this.trackingClick=!1,!0):"submit"===e.target.type&&0===e.detail||(t=this.onMouse(e),t||(this.targetElement=null),t)},i.prototype.destroy=function(){var e=this.layer;a&&(e.removeEventListener("mouseover",this.onMouse,!0),e.removeEventListener("mousedown",this.onMouse,!0),e.removeEventListener("mouseup",this.onMouse,!0)),e.removeEventListener("click",this.onClick,!0),e.removeEventListener("touchstart",this.onTouchStart,!1),e.removeEventListener("touchmove",this.onTouchMove,!1),e.removeEventListener("touchend",this.onTouchEnd,!1),e.removeEventListener("touchcancel",this.onTouchCancel,!1)},i.notNeeded=function(e){var t,n,r;if(void 0===window.ontouchstart)return!0;if(n=+(/Chrome\/([0-9]+)/.exec(navigator.userAgent)||[,0])[1]){if(!a)return!0;if(t=document.querySelector("meta[name=viewport]")){if(-1!==t.content.indexOf("user-scalable=no"))return!0;if(n>31&&document.documentElement.scrollWidth<=window.outerWidth)return!0}}if(l&&(r=navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/),r[1]>=10&&r[2]>=3&&(t=document.querySelector("meta[name=viewport]")))){if(-1!==t.content.indexOf("user-scalable=no"))return!0;if(document.documentElement.scrollWidth<=window.outerWidth)return!0}return"none"===e.style.msTouchAction||"manipulation"===e.style.touchAction||(!!(+(/Firefox\/([0-9]+)/.exec(navigator.userAgent)||[,0])[1]>=27&&(t=document.querySelector("meta[name=viewport]"))&&(-1!==t.content.indexOf("user-scalable=no")||document.documentElement.scrollWidth<=window.outerWidth))||("none"===e.style.touchAction||"manipulation"===e.style.touchAction))},i.attach=function(e,t){return new i(e,t)},void 0!==(r=function(){return i}.call(t,n,t,e))&&(e.exports=r)}()},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(21),o=r(i),a=n(23),s=r(a),c=n(26),u=r(c),l=n(30),d=r(l),f=n(36),h=r(f),p=n(38),m=r(p),v=n(44),y=r(v);t.default={Event:o.default,Header:s.default,Nav:u.default,Search:d.default,Sidebar:h.default,Source:m.default,Tabs:y.default}},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(3),o=r(i),a=n(22),s=r(a);t.default={Listener:o.default,MatchMedia:s.default}},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var i=n(3),o=(function(e){e&&e.__esModule}(i),function e(t,n){r(this,e),this.handler_=function(e){e.matches?n.listen():n.unlisten()};var i=window.matchMedia(t);i.addListener(this.handler_),this.handler_(i)});t.default=o},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(24),o=r(i),a=n(25),s=r(a);t.default={Shadow:o.default,Title:s.default}},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var i=function(){function e(t,n){r(this,e);var i="string"==typeof t?document.querySelector(t):t;if(!(i instanceof HTMLElement&&i.parentNode instanceof HTMLElement))throw new ReferenceError;if(this.el_=i.parentNode,!((i="string"==typeof n?document.querySelector(n):n)instanceof HTMLElement))throw new ReferenceError;this.header_=i,this.height_=0,this.active_=!1}return e.prototype.setup=function(){for(var e=this.el_;e=e.previousElementSibling;){if(!(e instanceof HTMLElement))throw new ReferenceError;this.height_+=e.offsetHeight}this.update()},e.prototype.update=function(e){if(!e||"resize"!==e.type&&"orientationchange"!==e.type){var t=window.pageYOffset>=this.height_;t!==this.active_&&(this.header_.dataset.mdState=(this.active_=t)?"shadow":"")}else this.height_=0,this.setup()},e.prototype.reset=function(){this.header_.dataset.mdState="",this.height_=0,this.active_=!1},e}();t.default=i},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var i=function(){function e(t,n){r(this,e);var i="string"==typeof t?document.querySelector(t):t;if(!(i instanceof HTMLElement))throw new ReferenceError;if(this.el_=i,!((i="string"==typeof n?document.querySelector(n):n)instanceof HTMLHeadingElement))throw new ReferenceError;this.header_=i,this.active_=!1}return e.prototype.setup=function(){var e=this;Array.prototype.forEach.call(this.el_.children,function(t){t.style.width=e.el_.offsetWidth-20+"px"})},e.prototype.update=function(e){var t=this,n=window.pageYOffset>=this.header_.offsetTop;n!==this.active_&&(this.el_.dataset.mdState=(this.active_=n)?"active":""),"resize"!==e.type&&"orientationchange"!==e.type||Array.prototype.forEach.call(this.el_.children,function(e){e.style.width=t.el_.offsetWidth-20+"px"})},e.prototype.reset=function(){this.el_.dataset.mdState="",this.el_.style.width="",this.active_=!1},e}();t.default=i},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(27),o=r(i),a=n(28),s=r(a),c=n(29),u=r(c);t.default={Blur:o.default,Collapse:s.default,Scrolling:u.default}},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var i=function(){function e(t){r(this,e),this.els_="string"==typeof t?document.querySelectorAll(t):t,this.index_=0,this.offset_=window.pageYOffset,this.dir_=!1,this.anchors_=[].reduce.call(this.els_,function(e,t){return e.concat(document.getElementById(t.hash.substring(1))||[])},[])}return e.prototype.setup=function(){this.update()},e.prototype.update=function(){var e=window.pageYOffset,t=this.offset_-e<0;if(this.dir_!==t&&(this.index_=this.index_=t?0:this.els_.length-1),0!==this.anchors_.length){if(this.offset_<=e)for(var n=this.index_+1;n0&&(this.els_[n-1].dataset.mdState="blur"),this.index_=n;else for(var r=this.index_;r>=0;r--){if(!(this.anchors_[r].offsetTop-80>e)){this.index_=r;break}r>0&&(this.els_[r-1].dataset.mdState="")}this.offset_=e,this.dir_=t}},e.prototype.reset=function(){Array.prototype.forEach.call(this.els_,function(e){e.dataset.mdState=""}),this.index_=0,this.offset_=window.pageYOffset},e}();t.default=i},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var i=function(){function e(t){r(this,e);var n="string"==typeof t?document.querySelector(t):t;if(!(n instanceof HTMLElement))throw new ReferenceError;this.el_=n}return e.prototype.setup=function(){var e=this.el_.getBoundingClientRect().height;this.el_.style.display=e?"block":"none",this.el_.style.overflow=e?"visible":"hidden"},e.prototype.update=function(){var e=this,t=this.el_.getBoundingClientRect().height;if(this.el_.style.display="block",this.el_.style.overflow="",t)this.el_.style.maxHeight=t+"px",requestAnimationFrame(function(){e.el_.setAttribute("data-md-state","animate"),e.el_.style.maxHeight="0px"});else{this.el_.setAttribute("data-md-state","expand"),this.el_.style.maxHeight="";var n=this.el_.getBoundingClientRect().height;this.el_.removeAttribute("data-md-state"),this.el_.style.maxHeight="0px",requestAnimationFrame(function(){e.el_.setAttribute("data-md-state","animate"),e.el_.style.maxHeight=n+"px"})}var r=function e(n){var r=n.target;if(!(r instanceof HTMLElement))throw new ReferenceError;r.removeAttribute("data-md-state"),r.style.maxHeight="",r.style.display=t?"none":"block",r.style.overflow=t?"hidden":"visible",r.removeEventListener("transitionend",e)};this.el_.addEventListener("transitionend",r,!1)},e.prototype.reset=function(){this.el_.dataset.mdState="",this.el_.style.maxHeight="",this.el_.style.display="",this.el_.style.overflow=""},e}();t.default=i},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var i=function(){function e(t){r(this,e);var n="string"==typeof t?document.querySelector(t):t;if(!(n instanceof HTMLElement))throw new ReferenceError;this.el_=n}return e.prototype.setup=function(){this.el_.children[this.el_.children.length-1].style.webkitOverflowScrolling="touch";var e=this.el_.querySelectorAll("[data-md-toggle]");Array.prototype.forEach.call(e,function(e){if(!(e instanceof HTMLInputElement))throw new ReferenceError;if(e.checked){var t=e.nextElementSibling;if(!(t instanceof HTMLElement))throw new ReferenceError;for(;"NAV"!==t.tagName&&t.nextElementSibling;)t=t.nextElementSibling;if(!(e.parentNode instanceof HTMLElement&&e.parentNode.parentNode instanceof HTMLElement))throw new ReferenceError;var n=e.parentNode.parentNode,r=t.children[t.children.length-1];n.style.webkitOverflowScrolling="",r.style.webkitOverflowScrolling="touch"}})},e.prototype.update=function(e){var t=e.target;if(!(t instanceof HTMLElement))throw new ReferenceError;var n=t.nextElementSibling;if(!(n instanceof HTMLElement))throw new ReferenceError;for(;"NAV"!==n.tagName&&n.nextElementSibling;)n=n.nextElementSibling;if(!(t.parentNode instanceof HTMLElement&&t.parentNode.parentNode instanceof HTMLElement))throw new ReferenceError;var r=t.parentNode.parentNode,i=n.children[n.children.length-1];if(r.style.webkitOverflowScrolling="",i.style.webkitOverflowScrolling="",!t.checked){var o=function e(){n instanceof HTMLElement&&(r.style.webkitOverflowScrolling="touch",n.removeEventListener("transitionend",e))};n.addEventListener("transitionend",o,!1)}if(t.checked){var a=function e(){n instanceof HTMLElement&&(i.style.webkitOverflowScrolling="touch",n.removeEventListener("transitionend",e))};n.addEventListener("transitionend",a,!1)}},e.prototype.reset=function(){this.el_.children[1].style.webkitOverflowScrolling="";var e=this.el_.querySelectorAll("[data-md-toggle]");Array.prototype.forEach.call(e,function(e){if(!(e instanceof HTMLInputElement))throw new ReferenceError;if(e.checked){var t=e.nextElementSibling;if(!(t instanceof HTMLElement))throw new ReferenceError;for(;"NAV"!==t.tagName&&t.nextElementSibling;)t=t.nextElementSibling;if(!(e.parentNode instanceof HTMLElement&&e.parentNode.parentNode instanceof HTMLElement))throw new ReferenceError;var n=e.parentNode.parentNode,r=t.children[t.children.length-1];n.style.webkitOverflowScrolling="",r.style.webkitOverflowScrolling=""}})},e}();t.default=i},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(31),o=r(i),a=n(32),s=r(a);t.default={Lock:o.default,Result:s.default}},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var i=function(){function e(t){r(this,e);var n="string"==typeof t?document.querySelector(t):t;if(!(n instanceof HTMLInputElement))throw new ReferenceError;if(this.el_=n,!document.body)throw new ReferenceError;this.lock_=document.body}return e.prototype.setup=function(){this.update()},e.prototype.update=function(){var e=this;this.el_.checked?(this.offset_=window.pageYOffset,setTimeout(function(){window.scrollTo(0,0),e.el_.checked&&(e.lock_.dataset.mdState="lock")},400)):(this.lock_.dataset.mdState="",setTimeout(function(){void 0!==e.offset_&&window.scrollTo(0,e.offset_)},100))},e.prototype.reset=function(){"lock"===this.lock_.dataset.mdState&&window.scrollTo(0,this.offset_),this.lock_.dataset.mdState=""},e}();t.default=i},function(e,t,n){"use strict";(function(e){function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var o=n(33),a=r(o),s=n(34),c=r(s),u=function(e,t){var n=t;if(e.length>n){for(;" "!==e[n]&&--n>0;);return e.substring(0,n)+"..."}return e},l=function(e){var t=document.getElementsByName("lang:"+e)[0];if(!(t instanceof HTMLMetaElement))throw new ReferenceError;return t.content},d=function(){function t(e,n){i(this,t);var r="string"==typeof e?document.querySelector(e):e;if(!(r instanceof HTMLElement))throw new ReferenceError;this.el_=r;var o=Array.prototype.slice.call(this.el_.children),a=o[0],s=o[1];this.data_=n,this.meta_=a,this.list_=s,this.message_={placeholder:this.meta_.textContent,none:l("search.result.none"),one:l("search.result.one"),other:l("search.result.other")};var u=l("search.tokenizer");u.length&&(c.default.tokenizer.separator=u),this.lang_=l("search.language").split(",").filter(Boolean).map(function(e){return e.trim()})}return t.prototype.update=function(t){var n=this;if("focus"!==t.type||this.index_){if("focus"===t.type||"keyup"===t.type){var r=t.target;if(!(r instanceof HTMLInputElement))throw new ReferenceError;if(!this.index_||r.value===this.value_)return;for(;this.list_.firstChild;)this.list_.removeChild(this.list_.firstChild);if(this.value_=r.value,0===this.value_.length)return void(this.meta_.textContent=this.message_.placeholder);var i=this.index_.query(function(e){n.value_.toLowerCase().split(" ").filter(Boolean).forEach(function(t){e.term(t,{wildcard:c.default.Query.wildcard.TRAILING})})}).reduce(function(e,t){var r=n.docs_.get(t.ref);if(r.parent){var i=r.parent.location;e.set(i,(e.get(i)||[]).concat(t))}else{var o=r.location;e.set(o,e.get(o)||[])}return e},new Map),o=(0,a.default)(this.value_.trim()).replace(new RegExp(c.default.tokenizer.separator,"img"),"|"),s=new RegExp("(^|"+c.default.tokenizer.separator+")("+o+")","img"),d=function(e,t,n){return t+""+n+""};this.stack_=[],i.forEach(function(t,r){var i,o=n.docs_.get(r),a=e.createElement("li",{class:"md-search-result__item"},e.createElement("a",{href:o.location,title:o.title,class:"md-search-result__link",tabindex:"-1"},e.createElement("article",{class:"md-search-result__article md-search-result__article--document"},e.createElement("h1",{class:"md-search-result__title"},{__html:o.title.replace(s,d)}),o.text.length?e.createElement("p",{class:"md-search-result__teaser"},{__html:o.text.replace(s,d)}):{}))),c=t.map(function(t){return function(){var r=n.docs_.get(t.ref);a.appendChild(e.createElement("a",{href:r.location,title:r.title,class:"md-search-result__link","data-md-rel":"anchor",tabindex:"-1"},e.createElement("article",{class:"md-search-result__article"},e.createElement("h1",{class:"md-search-result__title"},{__html:r.title.replace(s,d)}),r.text.length?e.createElement("p",{class:"md-search-result__teaser"},{__html:u(r.text.replace(s,d),400)}):{})))}});(i=n.stack_).push.apply(i,[function(){return n.list_.appendChild(a)}].concat(c))});var f=this.el_.parentNode;if(!(f instanceof HTMLElement))throw new ReferenceError;for(;this.stack_.length&&f.offsetHeight>=f.scrollHeight-16;)this.stack_.shift()();var h=this.list_.querySelectorAll("[data-md-rel=anchor]");switch(Array.prototype.forEach.call(h,function(e){["click","keydown"].forEach(function(t){e.addEventListener(t,function(n){if("keydown"!==t||13===n.keyCode){var r=document.querySelector("[data-md-toggle=search]");if(!(r instanceof HTMLInputElement))throw new ReferenceError;r.checked&&(r.checked=!1,r.dispatchEvent(new CustomEvent("change"))),n.preventDefault(),setTimeout(function(){document.location.href=e.href},100)}})})}),i.size){case 0:this.meta_.textContent=this.message_.none;break;case 1:this.meta_.textContent=this.message_.one;break;default:this.meta_.textContent=this.message_.other.replace("#",i.size)}}}else{var p=function(e){n.docs_=e.reduce(function(e,t){var n=t.location.split("#"),r=n[0];return n[1]&&(t.parent=e.get(r),t.parent&&!t.parent.done&&(t.parent.title=t.title,t.parent.text=t.text,t.parent.done=!0)),t.text=t.text.replace(/\n/g," ").replace(/\s+/g," ").replace(/\s+([,.:;!?])/g,function(e,t){return t}),t.parent&&t.parent.title===t.title||e.set(t.location,t),e},new Map);var t=n.docs_,r=n.lang_;n.stack_=[],n.index_=(0,c.default)(function(){var e,n=this,i={"search.pipeline.trimmer":c.default.trimmer,"search.pipeline.stopwords":c.default.stopWordFilter},o=Object.keys(i).reduce(function(e,t){return l(t).match(/^false$/i)||e.push(i[t]),e},[]);this.pipeline.reset(),o&&(e=this.pipeline).add.apply(e,o),1===r.length&&"en"!==r[0]&&c.default[r[0]]?this.use(c.default[r[0]]):r.length>1&&this.use(c.default.multiLanguage.apply(c.default,r)),this.field("title",{boost:10}),this.field("text"),this.ref("location"),t.forEach(function(e){return n.add(e)})});var i=n.el_.parentNode;if(!(i instanceof HTMLElement))throw new ReferenceError;i.addEventListener("scroll",function(){for(;n.stack_.length&&i.scrollTop+i.offsetHeight>=i.scrollHeight-16;)n.stack_.splice(0,10).forEach(function(e){return e()})})};setTimeout(function(){return"function"==typeof n.data_?n.data_().then(p):p(n.data_)},250)}},t}();t.default=d}).call(t,n(0))},function(e,t,n){"use strict";var r=/[|\\{}()[\]^$+*?.]/g;e.exports=function(e){if("string"!=typeof e)throw new TypeError("Expected a string");return e.replace(r,"\\$&")}},function(e,t,n){(function(t){e.exports=t.lunr=n(35)}).call(t,n(1))},function(e,t,n){var r,i;!function(){var o=function(e){var t=new o.Builder;return t.pipeline.add(o.trimmer,o.stopWordFilter,o.stemmer),t.searchPipeline.add(o.stemmer),e.call(t,t),t.build()};o.version="2.1.5",o.utils={},o.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),o.utils.asString=function(e){return void 0===e||null===e?"":e.toString()},o.FieldRef=function(e,t,n){this.docRef=e,this.fieldName=t,this._stringValue=n},o.FieldRef.joiner="/",o.FieldRef.fromString=function(e){var t=e.indexOf(o.FieldRef.joiner);if(-1===t)throw"malformed field ref string";var n=e.slice(0,t),r=e.slice(t+1);return new o.FieldRef(r,n,e)},o.FieldRef.prototype.toString=function(){return void 0==this._stringValue&&(this._stringValue=this.fieldName+o.FieldRef.joiner+this.docRef),this._stringValue},o.idf=function(e,t){var n=0;for(var r in e)"_index"!=r&&(n+=Object.keys(e[r]).length);var i=(t-n+.5)/(n+.5);return Math.log(1+Math.abs(i))},o.Token=function(e,t){this.str=e||"",this.metadata=t||{}},o.Token.prototype.toString=function(){return this.str},o.Token.prototype.update=function(e){return this.str=e(this.str,this.metadata),this},o.Token.prototype.clone=function(e){return e=e||function(e){return e},new o.Token(e(this.str,this.metadata),this.metadata)},o.tokenizer=function(e){if(null==e||void 0==e)return[];if(Array.isArray(e))return e.map(function(e){return new o.Token(o.utils.asString(e).toLowerCase())});for(var t=e.toString().trim().toLowerCase(),n=t.length,r=[],i=0,a=0;i<=n;i++){var s=t.charAt(i),c=i-a;(s.match(o.tokenizer.separator)||i==n)&&(c>0&&r.push(new o.Token(t.slice(a,i),{position:[a,c],index:r.length})),a=i+1)}return r},o.tokenizer.separator=/[\s\-]+/,o.Pipeline=function(){this._stack=[]},o.Pipeline.registeredFunctions=Object.create(null),o.Pipeline.registerFunction=function(e,t){t in this.registeredFunctions&&o.utils.warn("Overwriting existing registered function: "+t),e.label=t,o.Pipeline.registeredFunctions[e.label]=e},o.Pipeline.warnIfFunctionNotRegistered=function(e){e.label&&e.label in this.registeredFunctions||o.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},o.Pipeline.load=function(e){var t=new o.Pipeline;return e.forEach(function(e){var n=o.Pipeline.registeredFunctions[e];if(!n)throw new Error("Cannot load unregistered function: "+e);t.add(n)}),t},o.Pipeline.prototype.add=function(){Array.prototype.slice.call(arguments).forEach(function(e){o.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)},this)},o.Pipeline.prototype.after=function(e,t){o.Pipeline.warnIfFunctionNotRegistered(t);var n=this._stack.indexOf(e);if(-1==n)throw new Error("Cannot find existingFn");n+=1,this._stack.splice(n,0,t)},o.Pipeline.prototype.before=function(e,t){o.Pipeline.warnIfFunctionNotRegistered(t);var n=this._stack.indexOf(e);if(-1==n)throw new Error("Cannot find existingFn");this._stack.splice(n,0,t)},o.Pipeline.prototype.remove=function(e){var t=this._stack.indexOf(e);-1!=t&&this._stack.splice(t,1)},o.Pipeline.prototype.run=function(e){for(var t=this._stack.length,n=0;n1&&(oe&&(n=i),o!=e);)r=n-t,i=t+Math.floor(r/2),o=this.elements[2*i];return o==e?2*i:o>e?2*i:os?u+=2:a==s&&(t+=n[c+1]*r[u+1],c+=2,u+=2);return t},o.Vector.prototype.similarity=function(e){return this.dot(e)/(this.magnitude()*e.magnitude())},o.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),t=1,n=0;t0){var a,s=i.str.charAt(0);s in i.node.edges?a=i.node.edges[s]:(a=new o.TokenSet,i.node.edges[s]=a),1==i.str.length?a.final=!0:r.push({node:a,editsRemaining:i.editsRemaining,str:i.str.slice(1)})}if(i.editsRemaining>0&&i.str.length>1){var c,s=i.str.charAt(1);s in i.node.edges?c=i.node.edges[s]:(c=new o.TokenSet,i.node.edges[s]=c),i.str.length<=2?c.final=!0:r.push({node:c,editsRemaining:i.editsRemaining-1,str:i.str.slice(2)})}if(i.editsRemaining>0&&1==i.str.length&&(i.node.final=!0),i.editsRemaining>0&&i.str.length>=1){if("*"in i.node.edges)var u=i.node.edges["*"];else{var u=new o.TokenSet;i.node.edges["*"]=u}1==i.str.length?u.final=!0:r.push({node:u,editsRemaining:i.editsRemaining-1,str:i.str.slice(1)})}if(i.editsRemaining>0){if("*"in i.node.edges)var l=i.node.edges["*"];else{var l=new o.TokenSet;i.node.edges["*"]=l}0==i.str.length?l.final=!0:r.push({node:l,editsRemaining:i.editsRemaining-1,str:i.str})}if(i.editsRemaining>0&&i.str.length>1){var d,f=i.str.charAt(0),h=i.str.charAt(1);h in i.node.edges?d=i.node.edges[h]:(d=new o.TokenSet,i.node.edges[h]=d),1==i.str.length?d.final=!0:r.push({node:d,editsRemaining:i.editsRemaining-1,str:f+i.str.slice(2)})}}return n},o.TokenSet.fromString=function(e){for(var t=new o.TokenSet,n=t,r=!1,i=0,a=e.length;i=e;t--){var n=this.uncheckedNodes[t],r=n.child.toString();r in this.minimizedNodes?n.parent.edges[n.char]=this.minimizedNodes[r]:(n.child._str=r,this.minimizedNodes[r]=n.child),this.uncheckedNodes.pop()}},o.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},o.Index.prototype.search=function(e){return this.query(function(t){new o.QueryParser(e,t).parse()})},o.Index.prototype.query=function(e){var t=new o.Query(this.fields),n=Object.create(null),r=Object.create(null),i=Object.create(null);e.call(t,t);for(var a=0;a1?1:e},o.Builder.prototype.k1=function(e){this._k1=e},o.Builder.prototype.add=function(e){var t=e[this._ref];this.documentCount+=1;for(var n=0;n=this.length)return o.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},o.QueryLexer.prototype.width=function(){return this.pos-this.start},o.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},o.QueryLexer.prototype.backup=function(){this.pos-=1},o.QueryLexer.prototype.acceptDigitRun=function(){var e,t;do{e=this.next(),t=e.charCodeAt(0)}while(t>47&&t<58);e!=o.QueryLexer.EOS&&this.backup()},o.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(o.QueryLexer.TERM)),e.ignore(),e.more())return o.QueryLexer.lexText},o.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(o.QueryLexer.EDIT_DISTANCE),o.QueryLexer.lexText},o.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(o.QueryLexer.BOOST),o.QueryLexer.lexText},o.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(o.QueryLexer.TERM)},o.QueryLexer.termSeparator=o.tokenizer.separator,o.QueryLexer.lexText=function(e){for(;;){var t=e.next();if(t==o.QueryLexer.EOS)return o.QueryLexer.lexEOS;if(92!=t.charCodeAt(0)){if(":"==t)return o.QueryLexer.lexField;if("~"==t)return e.backup(),e.width()>0&&e.emit(o.QueryLexer.TERM),o.QueryLexer.lexEditDistance;if("^"==t)return e.backup(),e.width()>0&&e.emit(o.QueryLexer.TERM),o.QueryLexer.lexBoost;if(t.match(o.QueryLexer.termSeparator))return o.QueryLexer.lexTerm}else e.escapeCharacter()}},o.QueryParser=function(e,t){this.lexer=new o.QueryLexer(e),this.query=t,this.currentClause={},this.lexemeIdx=0},o.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=o.QueryParser.parseFieldOrTerm;e;)e=e(this);return this.query},o.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},o.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},o.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},o.QueryParser.parseFieldOrTerm=function(e){var t=e.peekLexeme();if(void 0!=t)switch(t.type){case o.QueryLexer.FIELD:return o.QueryParser.parseField;case o.QueryLexer.TERM:return o.QueryParser.parseTerm;default:var n="expected either a field or a term, found "+t.type;throw t.str.length>=1&&(n+=" with value '"+t.str+"'"),new o.QueryParseError(n,t.start,t.end)}},o.QueryParser.parseField=function(e){var t=e.consumeLexeme();if(void 0!=t){if(-1==e.query.allFields.indexOf(t.str)){var n=e.query.allFields.map(function(e){return"'"+e+"'"}).join(", "),r="unrecognised field '"+t.str+"', possible fields: "+n;throw new o.QueryParseError(r,t.start,t.end)}e.currentClause.fields=[t.str];var i=e.peekLexeme();if(void 0==i){var r="expecting term, found nothing";throw new o.QueryParseError(r,t.start,t.end)}switch(i.type){case o.QueryLexer.TERM:return o.QueryParser.parseTerm;default:var r="expecting term, found '"+i.type+"'";throw new o.QueryParseError(r,i.start,i.end)}}},o.QueryParser.parseTerm=function(e){var t=e.consumeLexeme();if(void 0!=t){e.currentClause.term=t.str.toLowerCase(),-1!=t.str.indexOf("*")&&(e.currentClause.usePipeline=!1);var n=e.peekLexeme();if(void 0==n)return void e.nextClause();switch(n.type){case o.QueryLexer.TERM:return e.nextClause(),o.QueryParser.parseTerm;case o.QueryLexer.FIELD:return e.nextClause(),o.QueryParser.parseField;case o.QueryLexer.EDIT_DISTANCE:return o.QueryParser.parseEditDistance;case o.QueryLexer.BOOST:return o.QueryParser.parseBoost;default:var r="Unexpected lexeme type '"+n.type+"'";throw new o.QueryParseError(r,n.start,n.end)}}},o.QueryParser.parseEditDistance=function(e){var t=e.consumeLexeme();if(void 0!=t){var n=parseInt(t.str,10);if(isNaN(n)){var r="edit distance must be numeric";throw new o.QueryParseError(r,t.start,t.end)}e.currentClause.editDistance=n;var i=e.peekLexeme();if(void 0==i)return void e.nextClause();switch(i.type){case o.QueryLexer.TERM:return e.nextClause(),o.QueryParser.parseTerm;case o.QueryLexer.FIELD:return e.nextClause(),o.QueryParser.parseField;case o.QueryLexer.EDIT_DISTANCE:return o.QueryParser.parseEditDistance;case o.QueryLexer.BOOST:return o.QueryParser.parseBoost;default:var r="Unexpected lexeme type '"+i.type+"'";throw new o.QueryParseError(r,i.start,i.end)}}},o.QueryParser.parseBoost=function(e){var t=e.consumeLexeme();if(void 0!=t){var n=parseInt(t.str,10);if(isNaN(n)){var r="boost must be numeric";throw new o.QueryParseError(r,t.start,t.end)}e.currentClause.boost=n;var i=e.peekLexeme();if(void 0==i)return void e.nextClause();switch(i.type){case o.QueryLexer.TERM:return e.nextClause(),o.QueryParser.parseTerm;case o.QueryLexer.FIELD:return e.nextClause(),o.QueryParser.parseField;case o.QueryLexer.EDIT_DISTANCE:return o.QueryParser.parseEditDistance;case o.QueryLexer.BOOST:return o.QueryParser.parseBoost;default:var r="Unexpected lexeme type '"+i.type+"'";throw new o.QueryParseError(r,i.start,i.end)}}},function(o,a){r=a,void 0!==(i="function"==typeof r?r.call(t,n,t,e):r)&&(e.exports=i)}(0,function(){return o})}()},function(e,t,n){"use strict";t.__esModule=!0;var r=n(37),i=function(e){return e&&e.__esModule?e:{default:e}}(r);t.default={Position:i.default}},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var i=function(){function e(t,n){r(this,e);var i="string"==typeof t?document.querySelector(t):t;if(!(i instanceof HTMLElement&&i.parentNode instanceof HTMLElement))throw new ReferenceError;if(this.el_=i,this.parent_=i.parentNode,!((i="string"==typeof n?document.querySelector(n):n)instanceof HTMLElement))throw new ReferenceError;this.header_=i,this.height_=0,this.pad_="fixed"===window.getComputedStyle(this.header_).position}return e.prototype.setup=function(){var e=Array.prototype.reduce.call(this.parent_.children,function(e,t){return Math.max(e,t.offsetTop)},0);this.offset_=e-(this.pad_?this.header_.offsetHeight:0),this.update()},e.prototype.update=function(e){var t=window.pageYOffset,n=window.innerHeight;e&&"resize"===e.type&&this.setup();var r={top:this.pad_?this.header_.offsetHeight:0,bottom:this.parent_.offsetTop+this.parent_.offsetHeight},i=n-r.top-Math.max(0,this.offset_-t)-Math.max(0,t+n-r.bottom);i!==this.height_&&(this.el_.style.height=(this.height_=i)+"px"),t>=this.offset_?"lock"!==this.el_.dataset.mdState&&(this.el_.dataset.mdState="lock"):"lock"===this.el_.dataset.mdState&&(this.el_.dataset.mdState="")},e.prototype.reset=function(){this.el_.dataset.mdState="",this.el_.style.height="",this.height_=0},e}();t.default=i},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(39),o=r(i),a=n(43),s=r(a);t.default={Adapter:o.default,Repository:s.default}},function(e,t,n){"use strict";t.__esModule=!0;var r=n(40),i=function(e){return e&&e.__esModule?e:{default:e}}(r);t.default={GitHub:i.default}},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function o(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0;var a=n(41),s=function(e){return e&&e.__esModule?e:{default:e}}(a),c=function(e){function t(n){r(this,t);var o=i(this,e.call(this,n)),a=/^.+github\.com\/([^\/]+)\/?([^\/]+)?.*$/.exec(o.base_);if(a&&3===a.length){var s=a[1],c=a[2];o.base_="https://api.github.com/users/"+s+"/repos",o.name_=c}return o}return o(t,e),t.prototype.fetch_=function(){var e=this;return function t(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;return fetch(e.base_+"?per_page=30&page="+n).then(function(e){return e.json()}).then(function(r){if(!(r instanceof Array))throw new TypeError;if(e.name_){var i=r.find(function(t){return t.name===e.name_});return i||30!==r.length?i?[e.format_(i.stargazers_count)+" Stars",e.format_(i.forks_count)+" Forks"]:[]:t(n+1)}return[r.length+" Repositories"]})}()},t}(s.default);t.default=c},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var i=n(42),o=function(e){return e&&e.__esModule?e:{default:e}}(i),a=function(){function e(t){r(this,e);var n="string"==typeof t?document.querySelector(t):t;if(!(n instanceof HTMLAnchorElement))throw new ReferenceError;this.el_=n,this.base_=this.el_.href,this.salt_=this.hash_(this.base_)}return e.prototype.fetch=function(){var e=this;return new Promise(function(t){var n=o.default.getJSON(e.salt_+".cache-source");void 0!==n?t(n):e.fetch_().then(function(n){o.default.set(e.salt_+".cache-source",n,{expires:1/96}),t(n)})})},e.prototype.fetch_=function(){throw new Error("fetch_(): Not implemented")},e.prototype.format_=function(e){return e>1e4?(e/1e3).toFixed(0)+"k":e>1e3?(e/1e3).toFixed(1)+"k":""+e},e.prototype.hash_=function(e){var t=0;if(0===e.length)return t;for(var n=0,r=e.length;n1){if(o=e({path:"/"},r.defaults,o),"number"==typeof o.expires){var s=new Date;s.setMilliseconds(s.getMilliseconds()+864e5*o.expires),o.expires=s}o.expires=o.expires?o.expires.toUTCString():"";try{a=JSON.stringify(i),/^[\{\[]/.test(a)&&(i=a)}catch(e){}i=n.write?n.write(i,t):encodeURIComponent(String(i)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),t=encodeURIComponent(String(t)),t=t.replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent),t=t.replace(/[\(\)]/g,escape);var c="";for(var u in o)o[u]&&(c+="; "+u,!0!==o[u]&&(c+="="+o[u]));return document.cookie=t+"="+i+c}t||(a={});for(var l=document.cookie?document.cookie.split("; "):[],d=/(%[0-9A-Z]{2})+/g,f=0;f=this.el_.children[0].offsetTop+-43;e!==this.active_&&(this.el_.dataset.mdState=(this.active_=e)?"hidden":"")},e.prototype.reset=function(){this.el_.dataset.mdState="",this.active_=!1},e}();t.default=i}])); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.da.js b/assets/javascripts/lunr/lunr.da.js new file mode 100644 index 000000000..3b07b2c19 --- /dev/null +++ b/assets/javascripts/lunr/lunr.da.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,i,n;e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=(r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){var e,n,t,s=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],o=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],a=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],u=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],c=new i;function l(){var e,r=c.limit-c.cursor;c.cursor>=n&&(e=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,c.find_among_b(o,4)?(c.bra=c.cursor,c.limit_backward=e,c.cursor=c.limit-r,c.cursor>c.limit_backward&&(c.cursor--,c.bra=c.cursor,c.slice_del())):c.limit_backward=e)}this.setCurrent=function(e){c.setCurrent(e)},this.getCurrent=function(){return c.getCurrent()},this.stem=function(){var r,i=c.cursor;return function(){var r,i=c.cursor+3;if(n=c.limit,0<=i&&i<=c.limit){for(e=i;;){if(r=c.cursor,c.in_grouping(d,97,248)){c.cursor=r;break}if(c.cursor=r,r>=c.limit)return;c.cursor++}for(;!c.out_grouping(d,97,248);){if(c.cursor>=c.limit)return;c.cursor++}(n=c.cursor)=n&&(r=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,e=c.find_among_b(s,32),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del();break;case 2:c.in_grouping_b(u,97,229)&&c.slice_del()}}(),c.cursor=c.limit,l(),c.cursor=c.limit,function(){var e,r,i,t=c.limit-c.cursor;if(c.ket=c.cursor,c.eq_s_b(2,"st")&&(c.bra=c.cursor,c.eq_s_b(2,"ig")&&c.slice_del()),c.cursor=c.limit-t,c.cursor>=n&&(r=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,e=c.find_among_b(a,5),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del(),i=c.limit-c.cursor,l(),c.cursor=c.limit-i;break;case 2:c.slice_from("løs")}}(),c.cursor=c.limit,c.cursor>=n&&(r=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,c.out_grouping_b(d,97,248)?(c.bra=c.cursor,t=c.slice_to(t),c.limit_backward=r,c.eq_v_b(t)&&c.slice_del()):c.limit_backward=r),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.de.js b/assets/javascripts/lunr/lunr.de.js new file mode 100644 index 000000000..ebd78f281 --- /dev/null +++ b/assets/javascripts/lunr/lunr.de.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,n,i;e.de=function(){this.pipeline.reset(),this.pipeline.add(e.de.trimmer,e.de.stopWordFilter,e.de.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.de.stemmer))},e.de.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.de.trimmer=e.trimmerSupport.generateTrimmer(e.de.wordCharacters),e.Pipeline.registerFunction(e.de.trimmer,"trimmer-de"),e.de.stemmer=(r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){var e,i,s,t=[new r("",-1,6),new r("U",0,2),new r("Y",0,1),new r("ä",0,3),new r("ö",0,4),new r("ü",0,5)],o=[new r("e",-1,2),new r("em",-1,1),new r("en",-1,2),new r("ern",-1,1),new r("er",-1,1),new r("s",-1,3),new r("es",5,2)],c=[new r("en",-1,1),new r("er",-1,1),new r("st",-1,2),new r("est",2,1)],u=[new r("ig",-1,1),new r("lich",-1,1)],a=[new r("end",-1,1),new r("ig",-1,2),new r("ung",-1,1),new r("lich",-1,3),new r("isch",-1,2),new r("ik",-1,2),new r("heit",-1,3),new r("keit",-1,4)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32,8],l=[117,30,5],m=[117,30,4],h=new n;function w(e,r,n){return!(!h.eq_s(1,e)||(h.ket=h.cursor,!h.in_grouping(d,97,252)))&&(h.slice_from(r),h.cursor=n,!0)}function f(){for(;!h.in_grouping(d,97,252);){if(h.cursor>=h.limit)return!0;h.cursor++}for(;!h.out_grouping(d,97,252);){if(h.cursor>=h.limit)return!0;h.cursor++}return!1}function b(){return s<=h.cursor}function _(){return i<=h.cursor}this.setCurrent=function(e){h.setCurrent(e)},this.getCurrent=function(){return h.getCurrent()},this.stem=function(){var r=h.cursor;return function(){for(var e,r,n,i,s=h.cursor;;)if(e=h.cursor,h.bra=e,h.eq_s(1,"ß"))h.ket=h.cursor,h.slice_from("ss");else{if(e>=h.limit)break;h.cursor=e+1}for(h.cursor=s;;)for(r=h.cursor;;){if(n=h.cursor,h.in_grouping(d,97,252)){if(i=h.cursor,h.bra=i,w("u","U",n))break;if(h.cursor=i,w("y","Y",n))break}if(n>=h.limit)return void(h.cursor=r);h.cursor=n+1}}(),h.cursor=r,function(){s=h.limit,i=s;var r=h.cursor+3;0<=r&&r<=h.limit&&(e=r,f()||((s=h.cursor)=h.limit)return;h.cursor++}}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}),e.Pipeline.registerFunction(e.de.stemmer,"stemmer-de"),e.de.stopWordFilter=e.generateStopWordFilter("aber alle allem allen aller alles als also am an ander andere anderem anderen anderer anderes anderm andern anderr anders auch auf aus bei bin bis bist da damit dann das dasselbe dazu daß dein deine deinem deinen deiner deines dem demselben den denn denselben der derer derselbe derselben des desselben dessen dich die dies diese dieselbe dieselben diesem diesen dieser dieses dir doch dort du durch ein eine einem einen einer eines einig einige einigem einigen einiger einiges einmal er es etwas euch euer eure eurem euren eurer eures für gegen gewesen hab habe haben hat hatte hatten hier hin hinter ich ihm ihn ihnen ihr ihre ihrem ihren ihrer ihres im in indem ins ist jede jedem jeden jeder jedes jene jenem jenen jener jenes jetzt kann kein keine keinem keinen keiner keines können könnte machen man manche manchem manchen mancher manches mein meine meinem meinen meiner meines mich mir mit muss musste nach nicht nichts noch nun nur ob oder ohne sehr sein seine seinem seinen seiner seines selbst sich sie sind so solche solchem solchen solcher solches soll sollte sondern sonst um und uns unse unsem unsen unser unses unter viel vom von vor war waren warst was weg weil weiter welche welchem welchen welcher welches wenn werde werden wie wieder will wir wird wirst wo wollen wollte während würde würden zu zum zur zwar zwischen über".split(" ")),e.Pipeline.registerFunction(e.de.stopWordFilter,"stopWordFilter-de")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.du.js b/assets/javascripts/lunr/lunr.du.js new file mode 100644 index 000000000..375c0e763 --- /dev/null +++ b/assets/javascripts/lunr/lunr.du.js @@ -0,0 +1 @@ +!function(r,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():e()(r.lunr)}(this,function(){return function(r){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var e,i,n;r.du=function(){this.pipeline.reset(),this.pipeline.add(r.du.trimmer,r.du.stopWordFilter,r.du.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(r.du.stemmer))},r.du.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",r.du.trimmer=r.trimmerSupport.generateTrimmer(r.du.wordCharacters),r.Pipeline.registerFunction(r.du.trimmer,"trimmer-du"),r.du.stemmer=(e=r.stemmerSupport.Among,i=r.stemmerSupport.SnowballProgram,n=new function(){var r,n,o,t=[new e("",-1,6),new e("á",0,1),new e("ä",0,1),new e("é",0,2),new e("ë",0,2),new e("í",0,3),new e("ï",0,3),new e("ó",0,4),new e("ö",0,4),new e("ú",0,5),new e("ü",0,5)],s=[new e("",-1,3),new e("I",0,2),new e("Y",0,1)],u=[new e("dd",-1,-1),new e("kk",-1,-1),new e("tt",-1,-1)],c=[new e("ene",-1,2),new e("se",-1,3),new e("en",-1,2),new e("heden",2,1),new e("s",-1,3)],a=[new e("end",-1,1),new e("ig",-1,2),new e("ing",-1,1),new e("lijk",-1,3),new e("baar",-1,4),new e("bar",-1,5)],l=[new e("aa",-1,-1),new e("ee",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1)],m=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],d=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],f=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],_=new i;function w(r){return _.cursor=r,r>=_.limit||(_.cursor++,!1)}function b(){for(;!_.in_grouping(m,97,232);){if(_.cursor>=_.limit)return!0;_.cursor++}for(;!_.out_grouping(m,97,232);){if(_.cursor>=_.limit)return!0;_.cursor++}return!1}function p(){return n<=_.cursor}function g(){return r<=_.cursor}function h(){var r=_.limit-_.cursor;_.find_among_b(u,3)&&(_.cursor=_.limit-r,_.ket=_.cursor,_.cursor>_.limit_backward&&(_.cursor--,_.bra=_.cursor,_.slice_del()))}function k(){var r;o=!1,_.ket=_.cursor,_.eq_s_b(1,"e")&&(_.bra=_.cursor,p()&&(r=_.limit-_.cursor,_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-r,_.slice_del(),o=!0,h())))}function v(){var r;p()&&(r=_.limit-_.cursor,_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-r,_.eq_s_b(3,"gem")||(_.cursor=_.limit-r,_.slice_del(),h())))}this.setCurrent=function(r){_.setCurrent(r)},this.getCurrent=function(){return _.getCurrent()},this.stem=function(){var e=_.cursor;return function(){for(var r,e,i,n=_.cursor;;){if(_.bra=_.cursor,r=_.find_among(t,11))switch(_.ket=_.cursor,r){case 1:_.slice_from("a");continue;case 2:_.slice_from("e");continue;case 3:_.slice_from("i");continue;case 4:_.slice_from("o");continue;case 5:_.slice_from("u");continue;case 6:if(_.cursor>=_.limit)break;_.cursor++;continue}break}for(_.cursor=n,_.bra=n,_.eq_s(1,"y")?(_.ket=_.cursor,_.slice_from("Y")):_.cursor=n;;)if(e=_.cursor,_.in_grouping(m,97,232)){if(i=_.cursor,_.bra=i,_.eq_s(1,"i"))_.ket=_.cursor,_.in_grouping(m,97,232)&&(_.slice_from("I"),_.cursor=e);else if(_.cursor=i,_.eq_s(1,"y"))_.ket=_.cursor,_.slice_from("Y"),_.cursor=e;else if(w(e))break}else if(w(e))break}(),_.cursor=e,n=_.limit,r=n,b()||((n=_.cursor)<3&&(n=3),b()||(r=_.cursor)),_.limit_backward=e,_.cursor=_.limit,function(){var r,e,i,n,t,s,u=_.limit-_.cursor;if(_.ket=_.cursor,r=_.find_among_b(c,5))switch(_.bra=_.cursor,r){case 1:p()&&_.slice_from("heid");break;case 2:v();break;case 3:p()&&_.out_grouping_b(f,97,232)&&_.slice_del()}if(_.cursor=_.limit-u,k(),_.cursor=_.limit-u,_.ket=_.cursor,_.eq_s_b(4,"heid")&&(_.bra=_.cursor,g()&&(e=_.limit-_.cursor,_.eq_s_b(1,"c")||(_.cursor=_.limit-e,_.slice_del(),_.ket=_.cursor,_.eq_s_b(2,"en")&&(_.bra=_.cursor,v())))),_.cursor=_.limit-u,_.ket=_.cursor,r=_.find_among_b(a,6))switch(_.bra=_.cursor,r){case 1:if(g()){if(_.slice_del(),i=_.limit-_.cursor,_.ket=_.cursor,_.eq_s_b(2,"ig")&&(_.bra=_.cursor,g()&&(n=_.limit-_.cursor,!_.eq_s_b(1,"e")))){_.cursor=_.limit-n,_.slice_del();break}_.cursor=_.limit-i,h()}break;case 2:g()&&(t=_.limit-_.cursor,_.eq_s_b(1,"e")||(_.cursor=_.limit-t,_.slice_del()));break;case 3:g()&&(_.slice_del(),k());break;case 4:g()&&_.slice_del();break;case 5:g()&&o&&_.slice_del()}_.cursor=_.limit-u,_.out_grouping_b(d,73,232)&&(s=_.limit-_.cursor,_.find_among_b(l,4)&&_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-s,_.ket=_.cursor,_.cursor>_.limit_backward&&(_.cursor--,_.bra=_.cursor,_.slice_del())))}(),_.cursor=_.limit_backward,function(){for(var r;;)if(_.bra=_.cursor,r=_.find_among(s,3))switch(_.ket=_.cursor,r){case 1:_.slice_from("y");break;case 2:_.slice_from("i");break;case 3:if(_.cursor>=_.limit)return;_.cursor++}}(),!0}},function(r){return"function"==typeof r.update?r.update(function(r){return n.setCurrent(r),n.stem(),n.getCurrent()}):(n.setCurrent(r),n.stem(),n.getCurrent())}),r.Pipeline.registerFunction(r.du.stemmer,"stemmer-du"),r.du.stopWordFilter=r.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),r.Pipeline.registerFunction(r.du.stopWordFilter,"stopWordFilter-du")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.es.js b/assets/javascripts/lunr/lunr.es.js new file mode 100644 index 000000000..4cb634f0a --- /dev/null +++ b/assets/javascripts/lunr/lunr.es.js @@ -0,0 +1 @@ +!function(e,s){"function"==typeof define&&define.amd?define(s):"object"==typeof exports?module.exports=s():s()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var s,r,n;e.es=function(){this.pipeline.reset(),this.pipeline.add(e.es.trimmer,e.es.stopWordFilter,e.es.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.es.stemmer))},e.es.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.es.trimmer=e.trimmerSupport.generateTrimmer(e.es.wordCharacters),e.Pipeline.registerFunction(e.es.trimmer,"trimmer-es"),e.es.stemmer=(s=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,n=new function(){var e,n,i,a=[new s("",-1,6),new s("á",0,1),new s("é",0,2),new s("í",0,3),new s("ó",0,4),new s("ú",0,5)],t=[new s("la",-1,-1),new s("sela",0,-1),new s("le",-1,-1),new s("me",-1,-1),new s("se",-1,-1),new s("lo",-1,-1),new s("selo",5,-1),new s("las",-1,-1),new s("selas",7,-1),new s("les",-1,-1),new s("los",-1,-1),new s("selos",10,-1),new s("nos",-1,-1)],o=[new s("ando",-1,6),new s("iendo",-1,6),new s("yendo",-1,7),new s("ándo",-1,2),new s("iéndo",-1,1),new s("ar",-1,6),new s("er",-1,6),new s("ir",-1,6),new s("ár",-1,3),new s("ér",-1,4),new s("ír",-1,5)],u=[new s("ic",-1,-1),new s("ad",-1,-1),new s("os",-1,-1),new s("iv",-1,1)],w=[new s("able",-1,1),new s("ible",-1,1),new s("ante",-1,1)],c=[new s("ic",-1,1),new s("abil",-1,1),new s("iv",-1,1)],m=[new s("ica",-1,1),new s("ancia",-1,2),new s("encia",-1,5),new s("adora",-1,2),new s("osa",-1,1),new s("ista",-1,1),new s("iva",-1,9),new s("anza",-1,1),new s("logía",-1,3),new s("idad",-1,8),new s("able",-1,1),new s("ible",-1,1),new s("ante",-1,2),new s("mente",-1,7),new s("amente",13,6),new s("ación",-1,2),new s("ución",-1,4),new s("ico",-1,1),new s("ismo",-1,1),new s("oso",-1,1),new s("amiento",-1,1),new s("imiento",-1,1),new s("ivo",-1,9),new s("ador",-1,2),new s("icas",-1,1),new s("ancias",-1,2),new s("encias",-1,5),new s("adoras",-1,2),new s("osas",-1,1),new s("istas",-1,1),new s("ivas",-1,9),new s("anzas",-1,1),new s("logías",-1,3),new s("idades",-1,8),new s("ables",-1,1),new s("ibles",-1,1),new s("aciones",-1,2),new s("uciones",-1,4),new s("adores",-1,2),new s("antes",-1,2),new s("icos",-1,1),new s("ismos",-1,1),new s("osos",-1,1),new s("amientos",-1,1),new s("imientos",-1,1),new s("ivos",-1,9)],l=[new s("ya",-1,1),new s("ye",-1,1),new s("yan",-1,1),new s("yen",-1,1),new s("yeron",-1,1),new s("yendo",-1,1),new s("yo",-1,1),new s("yas",-1,1),new s("yes",-1,1),new s("yais",-1,1),new s("yamos",-1,1),new s("yó",-1,1)],d=[new s("aba",-1,2),new s("ada",-1,2),new s("ida",-1,2),new s("ara",-1,2),new s("iera",-1,2),new s("ía",-1,2),new s("aría",5,2),new s("ería",5,2),new s("iría",5,2),new s("ad",-1,2),new s("ed",-1,2),new s("id",-1,2),new s("ase",-1,2),new s("iese",-1,2),new s("aste",-1,2),new s("iste",-1,2),new s("an",-1,2),new s("aban",16,2),new s("aran",16,2),new s("ieran",16,2),new s("ían",16,2),new s("arían",20,2),new s("erían",20,2),new s("irían",20,2),new s("en",-1,1),new s("asen",24,2),new s("iesen",24,2),new s("aron",-1,2),new s("ieron",-1,2),new s("arán",-1,2),new s("erán",-1,2),new s("irán",-1,2),new s("ado",-1,2),new s("ido",-1,2),new s("ando",-1,2),new s("iendo",-1,2),new s("ar",-1,2),new s("er",-1,2),new s("ir",-1,2),new s("as",-1,2),new s("abas",39,2),new s("adas",39,2),new s("idas",39,2),new s("aras",39,2),new s("ieras",39,2),new s("ías",39,2),new s("arías",45,2),new s("erías",45,2),new s("irías",45,2),new s("es",-1,1),new s("ases",49,2),new s("ieses",49,2),new s("abais",-1,2),new s("arais",-1,2),new s("ierais",-1,2),new s("íais",-1,2),new s("aríais",55,2),new s("eríais",55,2),new s("iríais",55,2),new s("aseis",-1,2),new s("ieseis",-1,2),new s("asteis",-1,2),new s("isteis",-1,2),new s("áis",-1,2),new s("éis",-1,1),new s("aréis",64,2),new s("eréis",64,2),new s("iréis",64,2),new s("ados",-1,2),new s("idos",-1,2),new s("amos",-1,2),new s("ábamos",70,2),new s("áramos",70,2),new s("iéramos",70,2),new s("íamos",70,2),new s("aríamos",74,2),new s("eríamos",74,2),new s("iríamos",74,2),new s("emos",-1,1),new s("aremos",78,2),new s("eremos",78,2),new s("iremos",78,2),new s("ásemos",78,2),new s("iésemos",78,2),new s("imos",-1,2),new s("arás",-1,2),new s("erás",-1,2),new s("irás",-1,2),new s("ís",-1,2),new s("ará",-1,2),new s("erá",-1,2),new s("irá",-1,2),new s("aré",-1,2),new s("eré",-1,2),new s("iré",-1,2),new s("ió",-1,2)],b=[new s("a",-1,1),new s("e",-1,2),new s("o",-1,1),new s("os",-1,1),new s("á",-1,1),new s("é",-1,2),new s("í",-1,1),new s("ó",-1,1)],f=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,4,10],_=new r;function h(){if(_.out_grouping(f,97,252)){for(;!_.in_grouping(f,97,252);){if(_.cursor>=_.limit)return!0;_.cursor++}return!1}return!0}function v(){var e,s=_.cursor;if(function(){if(_.in_grouping(f,97,252)){var e=_.cursor;if(h()){if(_.cursor=e,!_.in_grouping(f,97,252))return!0;for(;!_.out_grouping(f,97,252);){if(_.cursor>=_.limit)return!0;_.cursor++}}return!1}return!0}()){if(_.cursor=s,!_.out_grouping(f,97,252))return;if(e=_.cursor,h()){if(_.cursor=e,!_.in_grouping(f,97,252)||_.cursor>=_.limit)return;_.cursor++}}i=_.cursor}function p(){for(;!_.in_grouping(f,97,252);){if(_.cursor>=_.limit)return!1;_.cursor++}for(;!_.out_grouping(f,97,252);){if(_.cursor>=_.limit)return!1;_.cursor++}return!0}function g(){return i<=_.cursor}function k(){return e<=_.cursor}function y(e,s){if(!k())return!0;_.slice_del(),_.ket=_.cursor;var r=_.find_among_b(e,s);return r&&(_.bra=_.cursor,1==r&&k()&&_.slice_del()),!1}function q(e){return!k()||(_.slice_del(),_.ket=_.cursor,_.eq_s_b(2,e)&&(_.bra=_.cursor,k()&&_.slice_del()),!1)}function C(){var e;if(_.ket=_.cursor,e=_.find_among_b(m,46)){switch(_.bra=_.cursor,e){case 1:if(!k())return!1;_.slice_del();break;case 2:if(q("ic"))return!1;break;case 3:if(!k())return!1;_.slice_from("log");break;case 4:if(!k())return!1;_.slice_from("u");break;case 5:if(!k())return!1;_.slice_from("ente");break;case 6:if(!(n<=_.cursor))return!1;_.slice_del(),_.ket=_.cursor,(e=_.find_among_b(u,4))&&(_.bra=_.cursor,k()&&(_.slice_del(),1==e&&(_.ket=_.cursor,_.eq_s_b(2,"at")&&(_.bra=_.cursor,k()&&_.slice_del()))));break;case 7:if(y(w,3))return!1;break;case 8:if(y(c,3))return!1;break;case 9:if(q("at"))return!1}return!0}return!1}this.setCurrent=function(e){_.setCurrent(e)},this.getCurrent=function(){return _.getCurrent()},this.stem=function(){var s,r=_.cursor;return s=_.cursor,i=_.limit,n=i,e=i,v(),_.cursor=s,p()&&(n=_.cursor,p()&&(e=_.cursor)),_.limit_backward=r,_.cursor=_.limit,function(){var e;if(_.ket=_.cursor,_.find_among_b(t,13)&&(_.bra=_.cursor,(e=_.find_among_b(o,11))&&g()))switch(e){case 1:_.bra=_.cursor,_.slice_from("iendo");break;case 2:_.bra=_.cursor,_.slice_from("ando");break;case 3:_.bra=_.cursor,_.slice_from("ar");break;case 4:_.bra=_.cursor,_.slice_from("er");break;case 5:_.bra=_.cursor,_.slice_from("ir");break;case 6:_.slice_del();break;case 7:_.eq_s_b(1,"u")&&_.slice_del()}}(),_.cursor=_.limit,C()||(_.cursor=_.limit,function(){var e,s;if(_.cursor>=i&&(s=_.limit_backward,_.limit_backward=i,_.ket=_.cursor,e=_.find_among_b(l,12),_.limit_backward=s,e)){if(_.bra=_.cursor,1==e){if(!_.eq_s_b(1,"u"))return!1;_.slice_del()}return!0}return!1}()||(_.cursor=_.limit,function(){var e,s,r,n;if(_.cursor>=i&&(s=_.limit_backward,_.limit_backward=i,_.ket=_.cursor,e=_.find_among_b(d,96),_.limit_backward=s,e))switch(_.bra=_.cursor,e){case 1:r=_.limit-_.cursor,_.eq_s_b(1,"u")?(n=_.limit-_.cursor,_.eq_s_b(1,"g")?_.cursor=_.limit-n:_.cursor=_.limit-r):_.cursor=_.limit-r,_.bra=_.cursor;case 2:_.slice_del()}}())),_.cursor=_.limit,function(){var e,s;if(_.ket=_.cursor,e=_.find_among_b(b,8))switch(_.bra=_.cursor,e){case 1:g()&&_.slice_del();break;case 2:g()&&(_.slice_del(),_.ket=_.cursor,_.eq_s_b(1,"u")&&(_.bra=_.cursor,s=_.limit-_.cursor,_.eq_s_b(1,"g")&&(_.cursor=_.limit-s,g()&&_.slice_del())))}}(),_.cursor=_.limit_backward,function(){for(var e;;){if(_.bra=_.cursor,e=_.find_among(a,6))switch(_.ket=_.cursor,e){case 1:_.slice_from("a");continue;case 2:_.slice_from("e");continue;case 3:_.slice_from("i");continue;case 4:_.slice_from("o");continue;case 5:_.slice_from("u");continue;case 6:if(_.cursor>=_.limit)break;_.cursor++;continue}break}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}),e.Pipeline.registerFunction(e.es.stemmer,"stemmer-es"),e.es.stopWordFilter=e.generateStopWordFilter("a al algo algunas algunos ante antes como con contra cual cuando de del desde donde durante e el ella ellas ellos en entre era erais eran eras eres es esa esas ese eso esos esta estaba estabais estaban estabas estad estada estadas estado estados estamos estando estar estaremos estará estarán estarás estaré estaréis estaría estaríais estaríamos estarían estarías estas este estemos esto estos estoy estuve estuviera estuvierais estuvieran estuvieras estuvieron estuviese estuvieseis estuviesen estuvieses estuvimos estuviste estuvisteis estuviéramos estuviésemos estuvo está estábamos estáis están estás esté estéis estén estés fue fuera fuerais fueran fueras fueron fuese fueseis fuesen fueses fui fuimos fuiste fuisteis fuéramos fuésemos ha habida habidas habido habidos habiendo habremos habrá habrán habrás habré habréis habría habríais habríamos habrían habrías habéis había habíais habíamos habían habías han has hasta hay haya hayamos hayan hayas hayáis he hemos hube hubiera hubierais hubieran hubieras hubieron hubiese hubieseis hubiesen hubieses hubimos hubiste hubisteis hubiéramos hubiésemos hubo la las le les lo los me mi mis mucho muchos muy más mí mía mías mío míos nada ni no nos nosotras nosotros nuestra nuestras nuestro nuestros o os otra otras otro otros para pero poco por porque que quien quienes qué se sea seamos sean seas seremos será serán serás seré seréis sería seríais seríamos serían serías seáis sido siendo sin sobre sois somos son soy su sus suya suyas suyo suyos sí también tanto te tendremos tendrá tendrán tendrás tendré tendréis tendría tendríais tendríamos tendrían tendrías tened tenemos tenga tengamos tengan tengas tengo tengáis tenida tenidas tenido tenidos teniendo tenéis tenía teníais teníamos tenían tenías ti tiene tienen tienes todo todos tu tus tuve tuviera tuvierais tuvieran tuvieras tuvieron tuviese tuvieseis tuviesen tuvieses tuvimos tuviste tuvisteis tuviéramos tuviésemos tuvo tuya tuyas tuyo tuyos tú un una uno unos vosotras vosotros vuestra vuestras vuestro vuestros y ya yo él éramos".split(" ")),e.Pipeline.registerFunction(e.es.stopWordFilter,"stopWordFilter-es")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.fi.js b/assets/javascripts/lunr/lunr.fi.js new file mode 100644 index 000000000..0200b1fcb --- /dev/null +++ b/assets/javascripts/lunr/lunr.fi.js @@ -0,0 +1 @@ +!function(i,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():e()(i.lunr)}(this,function(){return function(i){if(void 0===i)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===i.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var e,r,n;i.fi=function(){this.pipeline.reset(),this.pipeline.add(i.fi.trimmer,i.fi.stopWordFilter,i.fi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(i.fi.stemmer))},i.fi.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",i.fi.trimmer=i.trimmerSupport.generateTrimmer(i.fi.wordCharacters),i.Pipeline.registerFunction(i.fi.trimmer,"trimmer-fi"),i.fi.stemmer=(e=i.stemmerSupport.Among,r=i.stemmerSupport.SnowballProgram,n=new function(){var i,n,t,s,l=[new e("pa",-1,1),new e("sti",-1,2),new e("kaan",-1,1),new e("han",-1,1),new e("kin",-1,1),new e("hän",-1,1),new e("kään",-1,1),new e("ko",-1,1),new e("pä",-1,1),new e("kö",-1,1)],o=[new e("lla",-1,-1),new e("na",-1,-1),new e("ssa",-1,-1),new e("ta",-1,-1),new e("lta",3,-1),new e("sta",3,-1)],a=[new e("llä",-1,-1),new e("nä",-1,-1),new e("ssä",-1,-1),new e("tä",-1,-1),new e("ltä",3,-1),new e("stä",3,-1)],u=[new e("lle",-1,-1),new e("ine",-1,-1)],c=[new e("nsa",-1,3),new e("mme",-1,3),new e("nne",-1,3),new e("ni",-1,2),new e("si",-1,1),new e("an",-1,4),new e("en",-1,6),new e("än",-1,5),new e("nsä",-1,3)],m=[new e("aa",-1,-1),new e("ee",-1,-1),new e("ii",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1),new e("ää",-1,-1),new e("öö",-1,-1)],w=[new e("a",-1,8),new e("lla",0,-1),new e("na",0,-1),new e("ssa",0,-1),new e("ta",0,-1),new e("lta",4,-1),new e("sta",4,-1),new e("tta",4,9),new e("lle",-1,-1),new e("ine",-1,-1),new e("ksi",-1,-1),new e("n",-1,7),new e("han",11,1),new e("den",11,-1,C),new e("seen",11,-1,v),new e("hen",11,2),new e("tten",11,-1,C),new e("hin",11,3),new e("siin",11,-1,C),new e("hon",11,4),new e("hän",11,5),new e("hön",11,6),new e("ä",-1,8),new e("llä",22,-1),new e("nä",22,-1),new e("ssä",22,-1),new e("tä",22,-1),new e("ltä",26,-1),new e("stä",26,-1),new e("ttä",26,9)],_=[new e("eja",-1,-1),new e("mma",-1,1),new e("imma",1,-1),new e("mpa",-1,1),new e("impa",3,-1),new e("mmi",-1,1),new e("immi",5,-1),new e("mpi",-1,1),new e("impi",7,-1),new e("ejä",-1,-1),new e("mmä",-1,1),new e("immä",10,-1),new e("mpä",-1,1),new e("impä",12,-1)],k=[new e("i",-1,-1),new e("j",-1,-1)],b=[new e("mma",-1,1),new e("imma",0,-1)],d=[17,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8],f=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],h=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],p=[17,97,24,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],g=new r;function j(){for(var i;i=g.cursor,!g.in_grouping(f,97,246);){if(g.cursor=i,i>=g.limit)return!0;g.cursor++}for(g.cursor=i;!g.out_grouping(f,97,246);){if(g.cursor>=g.limit)return!0;g.cursor++}return!1}function q(){var i,e;if(g.cursor>=s)if(e=g.limit_backward,g.limit_backward=s,g.ket=g.cursor,i=g.find_among_b(l,10)){switch(g.bra=g.cursor,g.limit_backward=e,i){case 1:if(!g.in_grouping_b(p,97,246))return;break;case 2:if(!(t<=g.cursor))return}g.slice_del()}else g.limit_backward=e}function v(){return g.find_among_b(m,7)}function C(){return g.eq_s_b(1,"i")&&g.in_grouping_b(h,97,246)}this.setCurrent=function(i){g.setCurrent(i)},this.getCurrent=function(){return g.getCurrent()},this.stem=function(){var e,r=g.cursor;return s=g.limit,t=s,j()||(s=g.cursor,j()||(t=g.cursor)),i=!1,g.limit_backward=r,g.cursor=g.limit,q(),g.cursor=g.limit,function(){var i,e,r;if(g.cursor>=s)if(e=g.limit_backward,g.limit_backward=s,g.ket=g.cursor,i=g.find_among_b(c,9))switch(g.bra=g.cursor,g.limit_backward=e,i){case 1:r=g.limit-g.cursor,g.eq_s_b(1,"k")||(g.cursor=g.limit-r,g.slice_del());break;case 2:g.slice_del(),g.ket=g.cursor,g.eq_s_b(3,"kse")&&(g.bra=g.cursor,g.slice_from("ksi"));break;case 3:g.slice_del();break;case 4:g.find_among_b(o,6)&&g.slice_del();break;case 5:g.find_among_b(a,6)&&g.slice_del();break;case 6:g.find_among_b(u,2)&&g.slice_del()}else g.limit_backward=e}(),g.cursor=g.limit,function(){var e,r,n;if(g.cursor>=s)if(r=g.limit_backward,g.limit_backward=s,g.ket=g.cursor,e=g.find_among_b(w,30)){switch(g.bra=g.cursor,g.limit_backward=r,e){case 1:if(!g.eq_s_b(1,"a"))return;break;case 2:case 9:if(!g.eq_s_b(1,"e"))return;break;case 3:if(!g.eq_s_b(1,"i"))return;break;case 4:if(!g.eq_s_b(1,"o"))return;break;case 5:if(!g.eq_s_b(1,"ä"))return;break;case 6:if(!g.eq_s_b(1,"ö"))return;break;case 7:if(n=g.limit-g.cursor,!v()&&(g.cursor=g.limit-n,!g.eq_s_b(2,"ie"))){g.cursor=g.limit-n;break}if(g.cursor=g.limit-n,g.cursor<=g.limit_backward){g.cursor=g.limit-n;break}g.cursor--,g.bra=g.cursor;break;case 8:if(!g.in_grouping_b(f,97,246)||!g.out_grouping_b(f,97,246))return}g.slice_del(),i=!0}else g.limit_backward=r}(),g.cursor=g.limit,function(){var i,e,r;if(g.cursor>=t)if(e=g.limit_backward,g.limit_backward=t,g.ket=g.cursor,i=g.find_among_b(_,14)){if(g.bra=g.cursor,g.limit_backward=e,1==i){if(r=g.limit-g.cursor,g.eq_s_b(2,"po"))return;g.cursor=g.limit-r}g.slice_del()}else g.limit_backward=e}(),g.cursor=g.limit,i?(g.cursor>=s&&(e=g.limit_backward,g.limit_backward=s,g.ket=g.cursor,g.find_among_b(k,2)?(g.bra=g.cursor,g.limit_backward=e,g.slice_del()):g.limit_backward=e),g.cursor=g.limit):(g.cursor=g.limit,function(){var i,e,r,n,l,o;if(g.cursor>=s){if(e=g.limit_backward,g.limit_backward=s,g.ket=g.cursor,g.eq_s_b(1,"t")&&(g.bra=g.cursor,r=g.limit-g.cursor,g.in_grouping_b(f,97,246)&&(g.cursor=g.limit-r,g.slice_del(),g.limit_backward=e,n=g.limit-g.cursor,g.cursor>=t&&(g.cursor=t,l=g.limit_backward,g.limit_backward=g.cursor,g.cursor=g.limit-n,g.ket=g.cursor,i=g.find_among_b(b,2))))){if(g.bra=g.cursor,g.limit_backward=l,1==i){if(o=g.limit-g.cursor,g.eq_s_b(2,"po"))return;g.cursor=g.limit-o}return void g.slice_del()}g.limit_backward=e}}(),g.cursor=g.limit),function(){var i,e,r,t;if(g.cursor>=s){for(i=g.limit_backward,g.limit_backward=s,e=g.limit-g.cursor,v()&&(g.cursor=g.limit-e,g.ket=g.cursor,g.cursor>g.limit_backward&&(g.cursor--,g.bra=g.cursor,g.slice_del())),g.cursor=g.limit-e,g.ket=g.cursor,g.in_grouping_b(d,97,228)&&(g.bra=g.cursor,g.out_grouping_b(f,97,246)&&g.slice_del()),g.cursor=g.limit-e,g.ket=g.cursor,g.eq_s_b(1,"j")&&(g.bra=g.cursor,r=g.limit-g.cursor,g.eq_s_b(1,"o")?g.slice_del():(g.cursor=g.limit-r,g.eq_s_b(1,"u")&&g.slice_del())),g.cursor=g.limit-e,g.ket=g.cursor,g.eq_s_b(1,"o")&&(g.bra=g.cursor,g.eq_s_b(1,"j")&&g.slice_del()),g.cursor=g.limit-e,g.limit_backward=i;;){if(t=g.limit-g.cursor,g.out_grouping_b(f,97,246)){g.cursor=g.limit-t;break}if(g.cursor=g.limit-t,g.cursor<=g.limit_backward)return;g.cursor--}g.ket=g.cursor,g.cursor>g.limit_backward&&(g.cursor--,g.bra=g.cursor,n=g.slice_to(),g.eq_v_b(n)&&g.slice_del())}}(),!0}},function(i){return"function"==typeof i.update?i.update(function(i){return n.setCurrent(i),n.stem(),n.getCurrent()}):(n.setCurrent(i),n.stem(),n.getCurrent())}),i.Pipeline.registerFunction(i.fi.stemmer,"stemmer-fi"),i.fi.stopWordFilter=i.generateStopWordFilter("ei eivät emme en et ette että he heidän heidät heihin heille heillä heiltä heissä heistä heitä hän häneen hänelle hänellä häneltä hänen hänessä hänestä hänet häntä itse ja johon joiden joihin joiksi joilla joille joilta joina joissa joista joita joka joksi jolla jolle jolta jona jonka jos jossa josta jota jotka kanssa keiden keihin keiksi keille keillä keiltä keinä keissä keistä keitä keneen keneksi kenelle kenellä keneltä kenen kenenä kenessä kenestä kenet ketkä ketkä ketä koska kuin kuka kun me meidän meidät meihin meille meillä meiltä meissä meistä meitä mihin miksi mikä mille millä miltä minkä minkä minua minulla minulle minulta minun minussa minusta minut minuun minä minä missä mistä mitkä mitä mukaan mutta ne niiden niihin niiksi niille niillä niiltä niin niin niinä niissä niistä niitä noiden noihin noiksi noilla noille noilta noin noina noissa noista noita nuo nyt näiden näihin näiksi näille näillä näiltä näinä näissä näistä näitä nämä ole olemme olen olet olette oli olimme olin olisi olisimme olisin olisit olisitte olisivat olit olitte olivat olla olleet ollut on ovat poikki se sekä sen siihen siinä siitä siksi sille sillä sillä siltä sinua sinulla sinulle sinulta sinun sinussa sinusta sinut sinuun sinä sinä sitä tai te teidän teidät teihin teille teillä teiltä teissä teistä teitä tuo tuohon tuoksi tuolla tuolle tuolta tuon tuona tuossa tuosta tuota tähän täksi tälle tällä tältä tämä tämän tänä tässä tästä tätä vaan vai vaikka yli".split(" ")),i.Pipeline.registerFunction(i.fi.stopWordFilter,"stopWordFilter-fi")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.fr.js b/assets/javascripts/lunr/lunr.fr.js new file mode 100644 index 000000000..3a9b9b177 --- /dev/null +++ b/assets/javascripts/lunr/lunr.fr.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,s,i;e.fr=function(){this.pipeline.reset(),this.pipeline.add(e.fr.trimmer,e.fr.stopWordFilter,e.fr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.fr.stemmer))},e.fr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.fr.trimmer=e.trimmerSupport.generateTrimmer(e.fr.wordCharacters),e.Pipeline.registerFunction(e.fr.trimmer,"trimmer-fr"),e.fr.stemmer=(r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,i=new function(){var e,i,n,t=[new r("col",-1,-1),new r("par",-1,-1),new r("tap",-1,-1)],u=[new r("",-1,4),new r("I",0,1),new r("U",0,2),new r("Y",0,3)],o=[new r("iqU",-1,3),new r("abl",-1,3),new r("Ièr",-1,4),new r("ièr",-1,4),new r("eus",-1,2),new r("iv",-1,1)],c=[new r("ic",-1,2),new r("abil",-1,1),new r("iv",-1,3)],a=[new r("iqUe",-1,1),new r("atrice",-1,2),new r("ance",-1,1),new r("ence",-1,5),new r("logie",-1,3),new r("able",-1,1),new r("isme",-1,1),new r("euse",-1,11),new r("iste",-1,1),new r("ive",-1,8),new r("if",-1,8),new r("usion",-1,4),new r("ation",-1,2),new r("ution",-1,4),new r("ateur",-1,2),new r("iqUes",-1,1),new r("atrices",-1,2),new r("ances",-1,1),new r("ences",-1,5),new r("logies",-1,3),new r("ables",-1,1),new r("ismes",-1,1),new r("euses",-1,11),new r("istes",-1,1),new r("ives",-1,8),new r("ifs",-1,8),new r("usions",-1,4),new r("ations",-1,2),new r("utions",-1,4),new r("ateurs",-1,2),new r("ments",-1,15),new r("ements",30,6),new r("issements",31,12),new r("ités",-1,7),new r("ment",-1,15),new r("ement",34,6),new r("issement",35,12),new r("amment",34,13),new r("emment",34,14),new r("aux",-1,10),new r("eaux",39,9),new r("eux",-1,1),new r("ité",-1,7)],l=[new r("ira",-1,1),new r("ie",-1,1),new r("isse",-1,1),new r("issante",-1,1),new r("i",-1,1),new r("irai",4,1),new r("ir",-1,1),new r("iras",-1,1),new r("ies",-1,1),new r("îmes",-1,1),new r("isses",-1,1),new r("issantes",-1,1),new r("îtes",-1,1),new r("is",-1,1),new r("irais",13,1),new r("issais",13,1),new r("irions",-1,1),new r("issions",-1,1),new r("irons",-1,1),new r("issons",-1,1),new r("issants",-1,1),new r("it",-1,1),new r("irait",21,1),new r("issait",21,1),new r("issant",-1,1),new r("iraIent",-1,1),new r("issaIent",-1,1),new r("irent",-1,1),new r("issent",-1,1),new r("iront",-1,1),new r("ît",-1,1),new r("iriez",-1,1),new r("issiez",-1,1),new r("irez",-1,1),new r("issez",-1,1)],w=[new r("a",-1,3),new r("era",0,2),new r("asse",-1,3),new r("ante",-1,3),new r("ée",-1,2),new r("ai",-1,3),new r("erai",5,2),new r("er",-1,2),new r("as",-1,3),new r("eras",8,2),new r("âmes",-1,3),new r("asses",-1,3),new r("antes",-1,3),new r("âtes",-1,3),new r("ées",-1,2),new r("ais",-1,3),new r("erais",15,2),new r("ions",-1,1),new r("erions",17,2),new r("assions",17,3),new r("erons",-1,2),new r("ants",-1,3),new r("és",-1,2),new r("ait",-1,3),new r("erait",23,2),new r("ant",-1,3),new r("aIent",-1,3),new r("eraIent",26,2),new r("èrent",-1,2),new r("assent",-1,3),new r("eront",-1,2),new r("ât",-1,3),new r("ez",-1,2),new r("iez",32,2),new r("eriez",33,2),new r("assiez",33,3),new r("erez",32,2),new r("é",-1,2)],f=[new r("e",-1,3),new r("Ière",0,2),new r("ière",0,2),new r("ion",-1,1),new r("Ier",-1,2),new r("ier",-1,2),new r("ë",-1,4)],m=[new r("ell",-1,-1),new r("eill",-1,-1),new r("enn",-1,-1),new r("onn",-1,-1),new r("ett",-1,-1)],_=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,128,130,103,8,5],b=[1,65,20,0,0,0,0,0,0,0,0,0,0,0,0,0,128],d=new s;function k(e,r,s){return!(!d.eq_s(1,e)||(d.ket=d.cursor,!d.in_grouping(_,97,251)))&&(d.slice_from(r),d.cursor=s,!0)}function p(e,r,s){return!!d.eq_s(1,e)&&(d.ket=d.cursor,d.slice_from(r),d.cursor=s,!0)}function g(){for(;!d.in_grouping(_,97,251);){if(d.cursor>=d.limit)return!0;d.cursor++}for(;!d.out_grouping(_,97,251);){if(d.cursor>=d.limit)return!0;d.cursor++}return!1}function q(){return n<=d.cursor}function v(){return i<=d.cursor}function h(){return e<=d.cursor}function z(){if(!function(){var e,r;if(d.ket=d.cursor,e=d.find_among_b(a,43)){switch(d.bra=d.cursor,e){case 1:if(!h())return!1;d.slice_del();break;case 2:if(!h())return!1;d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"ic")&&(d.bra=d.cursor,h()?d.slice_del():d.slice_from("iqU"));break;case 3:if(!h())return!1;d.slice_from("log");break;case 4:if(!h())return!1;d.slice_from("u");break;case 5:if(!h())return!1;d.slice_from("ent");break;case 6:if(!q())return!1;if(d.slice_del(),d.ket=d.cursor,e=d.find_among_b(o,6))switch(d.bra=d.cursor,e){case 1:h()&&(d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"at")&&(d.bra=d.cursor,h()&&d.slice_del()));break;case 2:h()?d.slice_del():v()&&d.slice_from("eux");break;case 3:h()&&d.slice_del();break;case 4:q()&&d.slice_from("i")}break;case 7:if(!h())return!1;if(d.slice_del(),d.ket=d.cursor,e=d.find_among_b(c,3))switch(d.bra=d.cursor,e){case 1:h()?d.slice_del():d.slice_from("abl");break;case 2:h()?d.slice_del():d.slice_from("iqU");break;case 3:h()&&d.slice_del()}break;case 8:if(!h())return!1;if(d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"at")&&(d.bra=d.cursor,h()&&(d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"ic")))){d.bra=d.cursor,h()?d.slice_del():d.slice_from("iqU");break}break;case 9:d.slice_from("eau");break;case 10:if(!v())return!1;d.slice_from("al");break;case 11:if(h())d.slice_del();else{if(!v())return!1;d.slice_from("eux")}break;case 12:if(!v()||!d.out_grouping_b(_,97,251))return!1;d.slice_del();break;case 13:return q()&&d.slice_from("ant"),!1;case 14:return q()&&d.slice_from("ent"),!1;case 15:return r=d.limit-d.cursor,d.in_grouping_b(_,97,251)&&q()&&(d.cursor=d.limit-r,d.slice_del()),!1}return!0}return!1}()&&(d.cursor=d.limit,!function(){var e,r;if(d.cursor=n){if(s=d.limit_backward,d.limit_backward=n,d.ket=d.cursor,e=d.find_among_b(f,7))switch(d.bra=d.cursor,e){case 1:if(h()){if(i=d.limit-d.cursor,!d.eq_s_b(1,"s")&&(d.cursor=d.limit-i,!d.eq_s_b(1,"t")))break;d.slice_del()}break;case 2:d.slice_from("i");break;case 3:d.slice_del();break;case 4:d.eq_s_b(2,"gu")&&d.slice_del()}d.limit_backward=s}}();d.cursor=d.limit,d.ket=d.cursor,d.eq_s_b(1,"Y")?(d.bra=d.cursor,d.slice_from("i")):(d.cursor=d.limit,d.eq_s_b(1,"ç")&&(d.bra=d.cursor,d.slice_from("c")))}this.setCurrent=function(e){d.setCurrent(e)},this.getCurrent=function(){return d.getCurrent()},this.stem=function(){var r,s=d.cursor;return function(){for(var e,r;;){if(e=d.cursor,d.in_grouping(_,97,251)){if(d.bra=d.cursor,r=d.cursor,k("u","U",e))continue;if(d.cursor=r,k("i","I",e))continue;if(d.cursor=r,p("y","Y",e))continue}if(d.cursor=e,d.bra=e,!k("y","Y",e)){if(d.cursor=e,d.eq_s(1,"q")&&(d.bra=d.cursor,p("u","U",e)))continue;if(d.cursor=e,e>=d.limit)return;d.cursor++}}}(),d.cursor=s,function(){var r=d.cursor;if(n=d.limit,i=n,e=n,d.in_grouping(_,97,251)&&d.in_grouping(_,97,251)&&d.cursor=d.limit){d.cursor=n;break}d.cursor++}while(!d.in_grouping(_,97,251))}n=d.cursor,d.cursor=r,g()||(i=d.cursor,g()||(e=d.cursor))}(),d.limit_backward=s,d.cursor=d.limit,z(),d.cursor=d.limit,r=d.limit-d.cursor,d.find_among_b(m,5)&&(d.cursor=d.limit-r,d.ket=d.cursor,d.cursor>d.limit_backward&&(d.cursor--,d.bra=d.cursor,d.slice_del())),d.cursor=d.limit,function(){for(var e,r=1;d.out_grouping_b(_,97,251);)r--;if(r<=0){if(d.ket=d.cursor,e=d.limit-d.cursor,!d.eq_s_b(1,"é")&&(d.cursor=d.limit-e,!d.eq_s_b(1,"è")))return;d.bra=d.cursor,d.slice_from("e")}}(),d.cursor=d.limit_backward,function(){for(var e,r;r=d.cursor,d.bra=r,e=d.find_among(u,4);)switch(d.ket=d.cursor,e){case 1:d.slice_from("i");break;case 2:d.slice_from("u");break;case 3:d.slice_from("y");break;case 4:if(d.cursor>=d.limit)return;d.cursor++}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}),e.Pipeline.registerFunction(e.fr.stemmer,"stemmer-fr"),e.fr.stopWordFilter=e.generateStopWordFilter("ai aie aient aies ait as au aura aurai auraient aurais aurait auras aurez auriez aurions aurons auront aux avaient avais avait avec avez aviez avions avons ayant ayez ayons c ce ceci celà ces cet cette d dans de des du elle en es est et eu eue eues eurent eus eusse eussent eusses eussiez eussions eut eux eûmes eût eûtes furent fus fusse fussent fusses fussiez fussions fut fûmes fût fûtes ici il ils j je l la le les leur leurs lui m ma mais me mes moi mon même n ne nos notre nous on ont ou par pas pour qu que quel quelle quelles quels qui s sa sans se sera serai seraient serais serait seras serez seriez serions serons seront ses soi soient sois soit sommes son sont soyez soyons suis sur t ta te tes toi ton tu un une vos votre vous y à étaient étais était étant étiez étions été étée étées étés êtes".split(" ")),e.Pipeline.registerFunction(e.fr.stopWordFilter,"stopWordFilter-fr")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.hu.js b/assets/javascripts/lunr/lunr.hu.js new file mode 100644 index 000000000..fa704a69c --- /dev/null +++ b/assets/javascripts/lunr/lunr.hu.js @@ -0,0 +1 @@ +!function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var n,r,i;e.hu=function(){this.pipeline.reset(),this.pipeline.add(e.hu.trimmer,e.hu.stopWordFilter,e.hu.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hu.stemmer))},e.hu.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.hu.trimmer=e.trimmerSupport.generateTrimmer(e.hu.wordCharacters),e.Pipeline.registerFunction(e.hu.trimmer,"trimmer-hu"),e.hu.stemmer=(n=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,i=new function(){var e,i=[new n("cs",-1,-1),new n("dzs",-1,-1),new n("gy",-1,-1),new n("ly",-1,-1),new n("ny",-1,-1),new n("sz",-1,-1),new n("ty",-1,-1),new n("zs",-1,-1)],a=[new n("á",-1,1),new n("é",-1,2)],t=[new n("bb",-1,-1),new n("cc",-1,-1),new n("dd",-1,-1),new n("ff",-1,-1),new n("gg",-1,-1),new n("jj",-1,-1),new n("kk",-1,-1),new n("ll",-1,-1),new n("mm",-1,-1),new n("nn",-1,-1),new n("pp",-1,-1),new n("rr",-1,-1),new n("ccs",-1,-1),new n("ss",-1,-1),new n("zzs",-1,-1),new n("tt",-1,-1),new n("vv",-1,-1),new n("ggy",-1,-1),new n("lly",-1,-1),new n("nny",-1,-1),new n("tty",-1,-1),new n("ssz",-1,-1),new n("zz",-1,-1)],s=[new n("al",-1,1),new n("el",-1,2)],c=[new n("ba",-1,-1),new n("ra",-1,-1),new n("be",-1,-1),new n("re",-1,-1),new n("ig",-1,-1),new n("nak",-1,-1),new n("nek",-1,-1),new n("val",-1,-1),new n("vel",-1,-1),new n("ul",-1,-1),new n("nál",-1,-1),new n("nél",-1,-1),new n("ból",-1,-1),new n("ról",-1,-1),new n("tól",-1,-1),new n("bõl",-1,-1),new n("rõl",-1,-1),new n("tõl",-1,-1),new n("ül",-1,-1),new n("n",-1,-1),new n("an",19,-1),new n("ban",20,-1),new n("en",19,-1),new n("ben",22,-1),new n("képpen",22,-1),new n("on",19,-1),new n("ön",19,-1),new n("képp",-1,-1),new n("kor",-1,-1),new n("t",-1,-1),new n("at",29,-1),new n("et",29,-1),new n("ként",29,-1),new n("anként",32,-1),new n("enként",32,-1),new n("onként",32,-1),new n("ot",29,-1),new n("ért",29,-1),new n("öt",29,-1),new n("hez",-1,-1),new n("hoz",-1,-1),new n("höz",-1,-1),new n("vá",-1,-1),new n("vé",-1,-1)],w=[new n("án",-1,2),new n("én",-1,1),new n("ánként",-1,3)],o=[new n("stul",-1,2),new n("astul",0,1),new n("ástul",0,3),new n("stül",-1,2),new n("estül",3,1),new n("éstül",3,4)],l=[new n("á",-1,1),new n("é",-1,2)],u=[new n("k",-1,7),new n("ak",0,4),new n("ek",0,6),new n("ok",0,5),new n("ák",0,1),new n("ék",0,2),new n("ök",0,3)],m=[new n("éi",-1,7),new n("áéi",0,6),new n("ééi",0,5),new n("é",-1,9),new n("ké",3,4),new n("aké",4,1),new n("eké",4,1),new n("oké",4,1),new n("áké",4,3),new n("éké",4,2),new n("öké",4,1),new n("éé",3,8)],k=[new n("a",-1,18),new n("ja",0,17),new n("d",-1,16),new n("ad",2,13),new n("ed",2,13),new n("od",2,13),new n("ád",2,14),new n("éd",2,15),new n("öd",2,13),new n("e",-1,18),new n("je",9,17),new n("nk",-1,4),new n("unk",11,1),new n("ánk",11,2),new n("énk",11,3),new n("ünk",11,1),new n("uk",-1,8),new n("juk",16,7),new n("ájuk",17,5),new n("ük",-1,8),new n("jük",19,7),new n("éjük",20,6),new n("m",-1,12),new n("am",22,9),new n("em",22,9),new n("om",22,9),new n("ám",22,10),new n("ém",22,11),new n("o",-1,18),new n("á",-1,19),new n("é",-1,20)],f=[new n("id",-1,10),new n("aid",0,9),new n("jaid",1,6),new n("eid",0,9),new n("jeid",3,6),new n("áid",0,7),new n("éid",0,8),new n("i",-1,15),new n("ai",7,14),new n("jai",8,11),new n("ei",7,14),new n("jei",10,11),new n("ái",7,12),new n("éi",7,13),new n("itek",-1,24),new n("eitek",14,21),new n("jeitek",15,20),new n("éitek",14,23),new n("ik",-1,29),new n("aik",18,26),new n("jaik",19,25),new n("eik",18,26),new n("jeik",21,25),new n("áik",18,27),new n("éik",18,28),new n("ink",-1,20),new n("aink",25,17),new n("jaink",26,16),new n("eink",25,17),new n("jeink",28,16),new n("áink",25,18),new n("éink",25,19),new n("aitok",-1,21),new n("jaitok",32,20),new n("áitok",-1,22),new n("im",-1,5),new n("aim",35,4),new n("jaim",36,1),new n("eim",35,4),new n("jeim",38,1),new n("áim",35,2),new n("éim",35,3)],b=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,52,14],d=new r;function g(){return e<=d.cursor}function h(){var e=d.limit-d.cursor;return!!d.find_among_b(t,23)&&(d.cursor=d.limit-e,!0)}function p(){if(d.cursor>d.limit_backward){d.cursor--,d.ket=d.cursor;var e=d.cursor-1;d.limit_backward<=e&&e<=d.limit&&(d.cursor=e,d.bra=e,d.slice_del())}}function _(){d.ket=d.cursor,d.find_among_b(c,44)&&(d.bra=d.cursor,g()&&(d.slice_del(),function(){var e;if(d.ket=d.cursor,(e=d.find_among_b(a,2))&&(d.bra=d.cursor,g()))switch(e){case 1:d.slice_from("a");break;case 2:d.slice_from("e")}}()))}this.setCurrent=function(e){d.setCurrent(e)},this.getCurrent=function(){return d.getCurrent()},this.stem=function(){var n=d.cursor;return function(){var n,r=d.cursor;if(e=d.limit,d.in_grouping(b,97,252))for(;;){if(n=d.cursor,d.out_grouping(b,97,252))return d.cursor=n,d.find_among(i,8)||(d.cursor=n,n=d.limit)return void(e=n);d.cursor++}if(d.cursor=r,d.out_grouping(b,97,252)){for(;!d.in_grouping(b,97,252);){if(d.cursor>=d.limit)return;d.cursor++}e=d.cursor}}(),d.limit_backward=n,d.cursor=d.limit,function(){var e;if(d.ket=d.cursor,(e=d.find_among_b(s,2))&&(d.bra=d.cursor,g())){if((1==e||2==e)&&!h())return;d.slice_del(),p()}}(),d.cursor=d.limit,_(),d.cursor=d.limit,function(){var e;if(d.ket=d.cursor,(e=d.find_among_b(w,3))&&(d.bra=d.cursor,g()))switch(e){case 1:d.slice_from("e");break;case 2:case 3:d.slice_from("a")}}(),d.cursor=d.limit,function(){var e;if(d.ket=d.cursor,(e=d.find_among_b(o,6))&&(d.bra=d.cursor,g()))switch(e){case 1:case 2:d.slice_del();break;case 3:d.slice_from("a");break;case 4:d.slice_from("e")}}(),d.cursor=d.limit,function(){var e;if(d.ket=d.cursor,(e=d.find_among_b(l,2))&&(d.bra=d.cursor,g())){if((1==e||2==e)&&!h())return;d.slice_del(),p()}}(),d.cursor=d.limit,function(){var e;if(d.ket=d.cursor,(e=d.find_among_b(m,12))&&(d.bra=d.cursor,g()))switch(e){case 1:case 4:case 7:case 9:d.slice_del();break;case 2:case 5:case 8:d.slice_from("e");break;case 3:case 6:d.slice_from("a")}}(),d.cursor=d.limit,function(){var e;if(d.ket=d.cursor,(e=d.find_among_b(k,31))&&(d.bra=d.cursor,g()))switch(e){case 1:case 4:case 7:case 8:case 9:case 12:case 13:case 16:case 17:case 18:d.slice_del();break;case 2:case 5:case 10:case 14:case 19:d.slice_from("a");break;case 3:case 6:case 11:case 15:case 20:d.slice_from("e")}}(),d.cursor=d.limit,function(){var e;if(d.ket=d.cursor,(e=d.find_among_b(f,42))&&(d.bra=d.cursor,g()))switch(e){case 1:case 4:case 5:case 6:case 9:case 10:case 11:case 14:case 15:case 16:case 17:case 20:case 21:case 24:case 25:case 26:case 29:d.slice_del();break;case 2:case 7:case 12:case 18:case 22:case 27:d.slice_from("a");break;case 3:case 8:case 13:case 19:case 23:case 28:d.slice_from("e")}}(),d.cursor=d.limit,function(){var e;if(d.ket=d.cursor,(e=d.find_among_b(u,7))&&(d.bra=d.cursor,g()))switch(e){case 1:d.slice_from("a");break;case 2:d.slice_from("e");break;case 3:case 4:case 5:case 6:case 7:d.slice_del()}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}),e.Pipeline.registerFunction(e.hu.stemmer,"stemmer-hu"),e.hu.stopWordFilter=e.generateStopWordFilter("a abban ahhoz ahogy ahol aki akik akkor alatt amely amelyek amelyekben amelyeket amelyet amelynek ami amikor amit amolyan amíg annak arra arról az azok azon azonban azt aztán azután azzal azért be belül benne bár cikk cikkek cikkeket csak de e ebben eddig egy egyes egyetlen egyik egyre egyéb egész ehhez ekkor el ellen elsõ elég elõ elõször elõtt emilyen ennek erre ez ezek ezen ezt ezzel ezért fel felé hanem hiszen hogy hogyan igen ill ill. illetve ilyen ilyenkor ismét ison itt jobban jó jól kell kellett keressünk keresztül ki kívül között közül legalább legyen lehet lehetett lenne lenni lesz lett maga magát majd majd meg mellett mely melyek mert mi mikor milyen minden mindenki mindent mindig mint mintha mit mivel miért most már más másik még míg nagy nagyobb nagyon ne nekem neki nem nincs néha néhány nélkül olyan ott pedig persze rá s saját sem semmi sok sokat sokkal szemben szerint szinte számára talán tehát teljes tovább továbbá több ugyanis utolsó után utána vagy vagyis vagyok valaki valami valamint való van vannak vele vissza viszont volna volt voltak voltam voltunk által általában át én éppen és így õ õk õket össze úgy új újabb újra".split(" ")),e.Pipeline.registerFunction(e.hu.stopWordFilter,"stopWordFilter-hu")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.it.js b/assets/javascripts/lunr/lunr.it.js new file mode 100644 index 000000000..293073389 --- /dev/null +++ b/assets/javascripts/lunr/lunr.it.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,i,n;e.it=function(){this.pipeline.reset(),this.pipeline.add(e.it.trimmer,e.it.stopWordFilter,e.it.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.it.stemmer))},e.it.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.it.trimmer=e.trimmerSupport.generateTrimmer(e.it.wordCharacters),e.Pipeline.registerFunction(e.it.trimmer,"trimmer-it"),e.it.stemmer=(r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){var e,n,o,t=[new r("",-1,7),new r("qu",0,6),new r("á",0,1),new r("é",0,2),new r("í",0,3),new r("ó",0,4),new r("ú",0,5)],s=[new r("",-1,3),new r("I",0,1),new r("U",0,2)],a=[new r("la",-1,-1),new r("cela",0,-1),new r("gliela",0,-1),new r("mela",0,-1),new r("tela",0,-1),new r("vela",0,-1),new r("le",-1,-1),new r("cele",6,-1),new r("gliele",6,-1),new r("mele",6,-1),new r("tele",6,-1),new r("vele",6,-1),new r("ne",-1,-1),new r("cene",12,-1),new r("gliene",12,-1),new r("mene",12,-1),new r("sene",12,-1),new r("tene",12,-1),new r("vene",12,-1),new r("ci",-1,-1),new r("li",-1,-1),new r("celi",20,-1),new r("glieli",20,-1),new r("meli",20,-1),new r("teli",20,-1),new r("veli",20,-1),new r("gli",20,-1),new r("mi",-1,-1),new r("si",-1,-1),new r("ti",-1,-1),new r("vi",-1,-1),new r("lo",-1,-1),new r("celo",31,-1),new r("glielo",31,-1),new r("melo",31,-1),new r("telo",31,-1),new r("velo",31,-1)],u=[new r("ando",-1,1),new r("endo",-1,1),new r("ar",-1,2),new r("er",-1,2),new r("ir",-1,2)],c=[new r("ic",-1,-1),new r("abil",-1,-1),new r("os",-1,-1),new r("iv",-1,1)],w=[new r("ic",-1,1),new r("abil",-1,1),new r("iv",-1,1)],l=[new r("ica",-1,1),new r("logia",-1,3),new r("osa",-1,1),new r("ista",-1,1),new r("iva",-1,9),new r("anza",-1,1),new r("enza",-1,5),new r("ice",-1,1),new r("atrice",7,1),new r("iche",-1,1),new r("logie",-1,3),new r("abile",-1,1),new r("ibile",-1,1),new r("usione",-1,4),new r("azione",-1,2),new r("uzione",-1,4),new r("atore",-1,2),new r("ose",-1,1),new r("ante",-1,1),new r("mente",-1,1),new r("amente",19,7),new r("iste",-1,1),new r("ive",-1,9),new r("anze",-1,1),new r("enze",-1,5),new r("ici",-1,1),new r("atrici",25,1),new r("ichi",-1,1),new r("abili",-1,1),new r("ibili",-1,1),new r("ismi",-1,1),new r("usioni",-1,4),new r("azioni",-1,2),new r("uzioni",-1,4),new r("atori",-1,2),new r("osi",-1,1),new r("anti",-1,1),new r("amenti",-1,6),new r("imenti",-1,6),new r("isti",-1,1),new r("ivi",-1,9),new r("ico",-1,1),new r("ismo",-1,1),new r("oso",-1,1),new r("amento",-1,6),new r("imento",-1,6),new r("ivo",-1,9),new r("ità",-1,8),new r("istà",-1,1),new r("istè",-1,1),new r("istì",-1,1)],m=[new r("isca",-1,1),new r("enda",-1,1),new r("ata",-1,1),new r("ita",-1,1),new r("uta",-1,1),new r("ava",-1,1),new r("eva",-1,1),new r("iva",-1,1),new r("erebbe",-1,1),new r("irebbe",-1,1),new r("isce",-1,1),new r("ende",-1,1),new r("are",-1,1),new r("ere",-1,1),new r("ire",-1,1),new r("asse",-1,1),new r("ate",-1,1),new r("avate",16,1),new r("evate",16,1),new r("ivate",16,1),new r("ete",-1,1),new r("erete",20,1),new r("irete",20,1),new r("ite",-1,1),new r("ereste",-1,1),new r("ireste",-1,1),new r("ute",-1,1),new r("erai",-1,1),new r("irai",-1,1),new r("isci",-1,1),new r("endi",-1,1),new r("erei",-1,1),new r("irei",-1,1),new r("assi",-1,1),new r("ati",-1,1),new r("iti",-1,1),new r("eresti",-1,1),new r("iresti",-1,1),new r("uti",-1,1),new r("avi",-1,1),new r("evi",-1,1),new r("ivi",-1,1),new r("isco",-1,1),new r("ando",-1,1),new r("endo",-1,1),new r("Yamo",-1,1),new r("iamo",-1,1),new r("avamo",-1,1),new r("evamo",-1,1),new r("ivamo",-1,1),new r("eremo",-1,1),new r("iremo",-1,1),new r("assimo",-1,1),new r("ammo",-1,1),new r("emmo",-1,1),new r("eremmo",54,1),new r("iremmo",54,1),new r("immo",-1,1),new r("ano",-1,1),new r("iscano",58,1),new r("avano",58,1),new r("evano",58,1),new r("ivano",58,1),new r("eranno",-1,1),new r("iranno",-1,1),new r("ono",-1,1),new r("iscono",65,1),new r("arono",65,1),new r("erono",65,1),new r("irono",65,1),new r("erebbero",-1,1),new r("irebbero",-1,1),new r("assero",-1,1),new r("essero",-1,1),new r("issero",-1,1),new r("ato",-1,1),new r("ito",-1,1),new r("uto",-1,1),new r("avo",-1,1),new r("evo",-1,1),new r("ivo",-1,1),new r("ar",-1,1),new r("ir",-1,1),new r("erà",-1,1),new r("irà",-1,1),new r("erò",-1,1),new r("irò",-1,1)],f=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,128,128,8,2,1],v=[17,65,0,0,0,0,0,0,0,0,0,0,0,0,0,128,128,8,2],b=[17],d=new i;function _(e,r,i){return!(!d.eq_s(1,e)||(d.ket=d.cursor,!d.in_grouping(f,97,249)))&&(d.slice_from(r),d.cursor=i,!0)}function g(e){if(d.cursor=e,!d.in_grouping(f,97,249))return!1;for(;!d.out_grouping(f,97,249);){if(d.cursor>=d.limit)return!1;d.cursor++}return!0}function p(){var e,r=d.cursor;if(!function(){if(d.in_grouping(f,97,249)){var e=d.cursor;if(d.out_grouping(f,97,249)){for(;!d.in_grouping(f,97,249);){if(d.cursor>=d.limit)return g(e);d.cursor++}return!0}return g(e)}return!1}()){if(d.cursor=r,!d.out_grouping(f,97,249))return;if(e=d.cursor,d.out_grouping(f,97,249)){for(;!d.in_grouping(f,97,249);){if(d.cursor>=d.limit)return d.cursor=e,void(d.in_grouping(f,97,249)&&d.cursor=d.limit)return;d.cursor++}o=d.cursor}function k(){for(;!d.in_grouping(f,97,249);){if(d.cursor>=d.limit)return!1;d.cursor++}for(;!d.out_grouping(f,97,249);){if(d.cursor>=d.limit)return!1;d.cursor++}return!0}function h(){return o<=d.cursor}function q(){return e<=d.cursor}function C(){var e;if(d.ket=d.cursor,!(e=d.find_among_b(l,51)))return!1;switch(d.bra=d.cursor,e){case 1:if(!q())return!1;d.slice_del();break;case 2:if(!q())return!1;d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"ic")&&(d.bra=d.cursor,q()&&d.slice_del());break;case 3:if(!q())return!1;d.slice_from("log");break;case 4:if(!q())return!1;d.slice_from("u");break;case 5:if(!q())return!1;d.slice_from("ente");break;case 6:if(!h())return!1;d.slice_del();break;case 7:if(!(n<=d.cursor))return!1;d.slice_del(),d.ket=d.cursor,(e=d.find_among_b(c,4))&&(d.bra=d.cursor,q()&&(d.slice_del(),1==e&&(d.ket=d.cursor,d.eq_s_b(2,"at")&&(d.bra=d.cursor,q()&&d.slice_del()))));break;case 8:if(!q())return!1;d.slice_del(),d.ket=d.cursor,(e=d.find_among_b(w,3))&&(d.bra=d.cursor,1==e&&q()&&d.slice_del());break;case 9:if(!q())return!1;d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"at")&&(d.bra=d.cursor,q()&&(d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"ic")&&(d.bra=d.cursor,q()&&d.slice_del())))}return!0}function z(){var e;e=d.limit-d.cursor,d.ket=d.cursor,d.in_grouping_b(v,97,242)&&(d.bra=d.cursor,h()&&(d.slice_del(),d.ket=d.cursor,d.eq_s_b(1,"i")&&(d.bra=d.cursor,h())))?d.slice_del():d.cursor=d.limit-e,d.ket=d.cursor,d.eq_s_b(1,"h")&&(d.bra=d.cursor,d.in_grouping_b(b,99,103)&&h()&&d.slice_del())}this.setCurrent=function(e){d.setCurrent(e)},this.getCurrent=function(){return d.getCurrent()},this.stem=function(){var r,i,c,w=d.cursor;return function(){for(var e,r,i,n,o=d.cursor;;){if(d.bra=d.cursor,e=d.find_among(t,7))switch(d.ket=d.cursor,e){case 1:d.slice_from("à");continue;case 2:d.slice_from("è");continue;case 3:d.slice_from("ì");continue;case 4:d.slice_from("ò");continue;case 5:d.slice_from("ù");continue;case 6:d.slice_from("qU");continue;case 7:if(d.cursor>=d.limit)break;d.cursor++;continue}break}for(d.cursor=o;;)for(r=d.cursor;;){if(i=d.cursor,d.in_grouping(f,97,249)){if(d.bra=d.cursor,n=d.cursor,_("u","U",i))break;if(d.cursor=n,_("i","I",i))break}if(d.cursor=i,d.cursor>=d.limit)return void(d.cursor=r);d.cursor++}}(),d.cursor=w,r=d.cursor,o=d.limit,n=o,e=o,p(),d.cursor=r,k()&&(n=d.cursor,k()&&(e=d.cursor)),d.limit_backward=w,d.cursor=d.limit,function(){var e;if(d.ket=d.cursor,d.find_among_b(a,37)&&(d.bra=d.cursor,(e=d.find_among_b(u,5))&&h()))switch(e){case 1:d.slice_del();break;case 2:d.slice_from("e")}}(),d.cursor=d.limit,C()||(d.cursor=d.limit,d.cursor>=o&&(c=d.limit_backward,d.limit_backward=o,d.ket=d.cursor,(i=d.find_among_b(m,87))&&(d.bra=d.cursor,1==i&&d.slice_del()),d.limit_backward=c)),d.cursor=d.limit,z(),d.cursor=d.limit_backward,function(){for(var e;d.bra=d.cursor,e=d.find_among(s,3);)switch(d.ket=d.cursor,e){case 1:d.slice_from("i");break;case 2:d.slice_from("u");break;case 3:if(d.cursor>=d.limit)return;d.cursor++}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}),e.Pipeline.registerFunction(e.it.stemmer,"stemmer-it"),e.it.stopWordFilter=e.generateStopWordFilter("a abbia abbiamo abbiano abbiate ad agl agli ai al all alla alle allo anche avemmo avendo avesse avessero avessi avessimo aveste avesti avete aveva avevamo avevano avevate avevi avevo avrai avranno avrebbe avrebbero avrei avremmo avremo avreste avresti avrete avrà avrò avuta avute avuti avuto c che chi ci coi col come con contro cui da dagl dagli dai dal dall dalla dalle dallo degl degli dei del dell della delle dello di dov dove e ebbe ebbero ebbi ed era erano eravamo eravate eri ero essendo faccia facciamo facciano facciate faccio facemmo facendo facesse facessero facessi facessimo faceste facesti faceva facevamo facevano facevate facevi facevo fai fanno farai faranno farebbe farebbero farei faremmo faremo fareste faresti farete farà farò fece fecero feci fosse fossero fossi fossimo foste fosti fu fui fummo furono gli ha hai hanno ho i il in io l la le lei li lo loro lui ma mi mia mie miei mio ne negl negli nei nel nell nella nelle nello noi non nostra nostre nostri nostro o per perché più quale quanta quante quanti quanto quella quelle quelli quello questa queste questi questo sarai saranno sarebbe sarebbero sarei saremmo saremo sareste saresti sarete sarà sarò se sei si sia siamo siano siate siete sono sta stai stando stanno starai staranno starebbe starebbero starei staremmo staremo stareste staresti starete starà starò stava stavamo stavano stavate stavi stavo stemmo stesse stessero stessi stessimo steste stesti stette stettero stetti stia stiamo stiano stiate sto su sua sue sugl sugli sui sul sull sulla sulle sullo suo suoi ti tra tu tua tue tuo tuoi tutti tutto un una uno vi voi vostra vostre vostri vostro è".split(" ")),e.Pipeline.registerFunction(e.it.stopWordFilter,"stopWordFilter-it")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.jp.js b/assets/javascripts/lunr/lunr.jp.js new file mode 100644 index 000000000..a33c3c71c --- /dev/null +++ b/assets/javascripts/lunr/lunr.jp.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.jp=function(){this.pipeline.reset(),this.pipeline.add(e.jp.stopWordFilter,e.jp.stemmer),r?this.tokenizer=e.jp.tokenizer:(e.tokenizer&&(e.tokenizer=e.jp.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.jp.tokenizer))};var t=new e.TinySegmenter;e.jp.tokenizer=function(n){if(!arguments.length||null==n||null==n)return[];if(Array.isArray(n))return n.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(var i=n.toString().toLowerCase().replace(/^\s+/,""),o=i.length-1;o>=0;o--)if(/\S/.test(i.charAt(o))){i=i.substring(0,o+1);break}return t.segment(i).filter(function(e){return!!e}).map(function(t){return r?new e.Token(t):t})},e.jp.stemmer=function(e){return e},e.Pipeline.registerFunction(e.jp.stemmer,"stemmer-jp"),e.jp.wordCharacters="一二三四五六七八九十百千万億兆一-龠々〆ヵヶぁ-んァ-ヴーア-ン゙a-zA-Za-zA-Z0-90-9",e.jp.stopWordFilter=function(t){if(-1===e.jp.stopWordFilter.stopWords.indexOf(r?t.toString():t))return t},e.jp.stopWordFilter=e.generateStopWordFilter("これ それ あれ この その あの ここ そこ あそこ こちら どこ だれ なに なん 何 私 貴方 貴方方 我々 私達 あの人 あのかた 彼女 彼 です あります おります います は が の に を で え から まで より も どの と し それで しかし".split(" ")),e.Pipeline.registerFunction(e.jp.stopWordFilter,"stopWordFilter-jp")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.multi.js b/assets/javascripts/lunr/lunr.multi.js new file mode 100644 index 000000000..d3dbc860c --- /dev/null +++ b/assets/javascripts/lunr/lunr.multi.js @@ -0,0 +1 @@ +!function(e,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(e.lunr)}(this,function(){return function(e){e.multiLanguage=function(){for(var i=Array.prototype.slice.call(arguments),t=i.join("-"),r="",n=[],s=[],p=0;p=l.limit)return;l.cursor=r+1}for(;!l.out_grouping(a,97,248);){if(l.cursor>=l.limit)return;l.cursor++}(i=l.cursor)=i&&(r=l.limit_backward,l.limit_backward=i,l.ket=l.cursor,e=l.find_among_b(t,29),l.limit_backward=r,e))switch(l.bra=l.cursor,e){case 1:l.slice_del();break;case 2:n=l.limit-l.cursor,l.in_grouping_b(m,98,122)?l.slice_del():(l.cursor=l.limit-n,l.eq_s_b(1,"k")&&l.out_grouping_b(a,97,248)&&l.slice_del());break;case 3:l.slice_from("er")}}(),l.cursor=l.limit,n=l.limit-l.cursor,l.cursor>=i&&(r=l.limit_backward,l.limit_backward=i,l.ket=l.cursor,l.find_among_b(o,2)?(l.bra=l.cursor,l.limit_backward=r,l.cursor=l.limit-n,l.cursor>l.limit_backward&&(l.cursor--,l.bra=l.cursor,l.slice_del())):l.limit_backward=r),l.cursor=l.limit,l.cursor>=i&&(d=l.limit_backward,l.limit_backward=i,l.ket=l.cursor,(u=l.find_among_b(s,11))?(l.bra=l.cursor,l.limit_backward=d,1==u&&l.slice_del()):l.limit_backward=d),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.pt.js b/assets/javascripts/lunr/lunr.pt.js new file mode 100644 index 000000000..51035c969 --- /dev/null +++ b/assets/javascripts/lunr/lunr.pt.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,s,n;e.pt=function(){this.pipeline.reset(),this.pipeline.add(e.pt.trimmer,e.pt.stopWordFilter,e.pt.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.pt.stemmer))},e.pt.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.pt.trimmer=e.trimmerSupport.generateTrimmer(e.pt.wordCharacters),e.Pipeline.registerFunction(e.pt.trimmer,"trimmer-pt"),e.pt.stemmer=(r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,n=new function(){var e,n,i,o=[new r("",-1,3),new r("ã",0,1),new r("õ",0,2)],a=[new r("",-1,3),new r("a~",0,1),new r("o~",0,2)],t=[new r("ic",-1,-1),new r("ad",-1,-1),new r("os",-1,-1),new r("iv",-1,1)],u=[new r("ante",-1,1),new r("avel",-1,1),new r("ível",-1,1)],w=[new r("ic",-1,1),new r("abil",-1,1),new r("iv",-1,1)],m=[new r("ica",-1,1),new r("ância",-1,1),new r("ência",-1,4),new r("ira",-1,9),new r("adora",-1,1),new r("osa",-1,1),new r("ista",-1,1),new r("iva",-1,8),new r("eza",-1,1),new r("logía",-1,2),new r("idade",-1,7),new r("ante",-1,1),new r("mente",-1,6),new r("amente",12,5),new r("ável",-1,1),new r("ível",-1,1),new r("ución",-1,3),new r("ico",-1,1),new r("ismo",-1,1),new r("oso",-1,1),new r("amento",-1,1),new r("imento",-1,1),new r("ivo",-1,8),new r("aça~o",-1,1),new r("ador",-1,1),new r("icas",-1,1),new r("ências",-1,4),new r("iras",-1,9),new r("adoras",-1,1),new r("osas",-1,1),new r("istas",-1,1),new r("ivas",-1,8),new r("ezas",-1,1),new r("logías",-1,2),new r("idades",-1,7),new r("uciones",-1,3),new r("adores",-1,1),new r("antes",-1,1),new r("aço~es",-1,1),new r("icos",-1,1),new r("ismos",-1,1),new r("osos",-1,1),new r("amentos",-1,1),new r("imentos",-1,1),new r("ivos",-1,8)],c=[new r("ada",-1,1),new r("ida",-1,1),new r("ia",-1,1),new r("aria",2,1),new r("eria",2,1),new r("iria",2,1),new r("ara",-1,1),new r("era",-1,1),new r("ira",-1,1),new r("ava",-1,1),new r("asse",-1,1),new r("esse",-1,1),new r("isse",-1,1),new r("aste",-1,1),new r("este",-1,1),new r("iste",-1,1),new r("ei",-1,1),new r("arei",16,1),new r("erei",16,1),new r("irei",16,1),new r("am",-1,1),new r("iam",20,1),new r("ariam",21,1),new r("eriam",21,1),new r("iriam",21,1),new r("aram",20,1),new r("eram",20,1),new r("iram",20,1),new r("avam",20,1),new r("em",-1,1),new r("arem",29,1),new r("erem",29,1),new r("irem",29,1),new r("assem",29,1),new r("essem",29,1),new r("issem",29,1),new r("ado",-1,1),new r("ido",-1,1),new r("ando",-1,1),new r("endo",-1,1),new r("indo",-1,1),new r("ara~o",-1,1),new r("era~o",-1,1),new r("ira~o",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("ir",-1,1),new r("as",-1,1),new r("adas",47,1),new r("idas",47,1),new r("ias",47,1),new r("arias",50,1),new r("erias",50,1),new r("irias",50,1),new r("aras",47,1),new r("eras",47,1),new r("iras",47,1),new r("avas",47,1),new r("es",-1,1),new r("ardes",58,1),new r("erdes",58,1),new r("irdes",58,1),new r("ares",58,1),new r("eres",58,1),new r("ires",58,1),new r("asses",58,1),new r("esses",58,1),new r("isses",58,1),new r("astes",58,1),new r("estes",58,1),new r("istes",58,1),new r("is",-1,1),new r("ais",71,1),new r("eis",71,1),new r("areis",73,1),new r("ereis",73,1),new r("ireis",73,1),new r("áreis",73,1),new r("éreis",73,1),new r("íreis",73,1),new r("ásseis",73,1),new r("ésseis",73,1),new r("ísseis",73,1),new r("áveis",73,1),new r("íeis",73,1),new r("aríeis",84,1),new r("eríeis",84,1),new r("iríeis",84,1),new r("ados",-1,1),new r("idos",-1,1),new r("amos",-1,1),new r("áramos",90,1),new r("éramos",90,1),new r("íramos",90,1),new r("ávamos",90,1),new r("íamos",90,1),new r("aríamos",95,1),new r("eríamos",95,1),new r("iríamos",95,1),new r("emos",-1,1),new r("aremos",99,1),new r("eremos",99,1),new r("iremos",99,1),new r("ássemos",99,1),new r("êssemos",99,1),new r("íssemos",99,1),new r("imos",-1,1),new r("armos",-1,1),new r("ermos",-1,1),new r("irmos",-1,1),new r("ámos",-1,1),new r("arás",-1,1),new r("erás",-1,1),new r("irás",-1,1),new r("eu",-1,1),new r("iu",-1,1),new r("ou",-1,1),new r("ará",-1,1),new r("erá",-1,1),new r("irá",-1,1)],l=[new r("a",-1,1),new r("i",-1,1),new r("o",-1,1),new r("os",-1,1),new r("á",-1,1),new r("í",-1,1),new r("ó",-1,1)],f=[new r("e",-1,1),new r("ç",-1,2),new r("é",-1,1),new r("ê",-1,1)],d=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,3,19,12,2],v=new s;function p(){if(v.out_grouping(d,97,250)){for(;!v.in_grouping(d,97,250);){if(v.cursor>=v.limit)return!0;v.cursor++}return!1}return!0}function _(){var e,r,s=v.cursor;if(v.in_grouping(d,97,250))if(e=v.cursor,p()){if(v.cursor=e,function(){if(v.in_grouping(d,97,250))for(;!v.out_grouping(d,97,250);){if(v.cursor>=v.limit)return!1;v.cursor++}return i=v.cursor,!0}())return}else i=v.cursor;if(v.cursor=s,v.out_grouping(d,97,250)){if(r=v.cursor,p()){if(v.cursor=r,!v.in_grouping(d,97,250)||v.cursor>=v.limit)return;v.cursor++}i=v.cursor}}function h(){for(;!v.in_grouping(d,97,250);){if(v.cursor>=v.limit)return!1;v.cursor++}for(;!v.out_grouping(d,97,250);){if(v.cursor>=v.limit)return!1;v.cursor++}return!0}function b(){return i<=v.cursor}function g(){return e<=v.cursor}function k(){var e;if(v.ket=v.cursor,!(e=v.find_among_b(m,45)))return!1;switch(v.bra=v.cursor,e){case 1:if(!g())return!1;v.slice_del();break;case 2:if(!g())return!1;v.slice_from("log");break;case 3:if(!g())return!1;v.slice_from("u");break;case 4:if(!g())return!1;v.slice_from("ente");break;case 5:if(!(n<=v.cursor))return!1;v.slice_del(),v.ket=v.cursor,(e=v.find_among_b(t,4))&&(v.bra=v.cursor,g()&&(v.slice_del(),1==e&&(v.ket=v.cursor,v.eq_s_b(2,"at")&&(v.bra=v.cursor,g()&&v.slice_del()))));break;case 6:if(!g())return!1;v.slice_del(),v.ket=v.cursor,(e=v.find_among_b(u,3))&&(v.bra=v.cursor,1==e&&g()&&v.slice_del());break;case 7:if(!g())return!1;v.slice_del(),v.ket=v.cursor,(e=v.find_among_b(w,3))&&(v.bra=v.cursor,1==e&&g()&&v.slice_del());break;case 8:if(!g())return!1;v.slice_del(),v.ket=v.cursor,v.eq_s_b(2,"at")&&(v.bra=v.cursor,g()&&v.slice_del());break;case 9:if(!b()||!v.eq_s_b(1,"e"))return!1;v.slice_from("ir")}return!0}function q(e,r){if(v.eq_s_b(1,e)){v.bra=v.cursor;var s=v.limit-v.cursor;if(v.eq_s_b(1,r))return v.cursor=v.limit-s,b()&&v.slice_del(),!1}return!0}function j(){if(!k()&&(v.cursor=v.limit,!function(){var e,r;if(v.cursor>=i){if(r=v.limit_backward,v.limit_backward=i,v.ket=v.cursor,e=v.find_among_b(c,120))return v.bra=v.cursor,1==e&&v.slice_del(),v.limit_backward=r,!0;v.limit_backward=r}return!1}()))return v.cursor=v.limit,v.ket=v.cursor,void((e=v.find_among_b(l,7))&&(v.bra=v.cursor,1==e&&b()&&v.slice_del()));var e;v.cursor=v.limit,v.ket=v.cursor,v.eq_s_b(1,"i")&&(v.bra=v.cursor,v.eq_s_b(1,"c")&&(v.cursor=v.limit,b()&&v.slice_del()))}this.setCurrent=function(e){v.setCurrent(e)},this.getCurrent=function(){return v.getCurrent()},this.stem=function(){var r,s=v.cursor;return function(){for(var e;;){if(v.bra=v.cursor,e=v.find_among(o,3))switch(v.ket=v.cursor,e){case 1:v.slice_from("a~");continue;case 2:v.slice_from("o~");continue;case 3:if(v.cursor>=v.limit)break;v.cursor++;continue}break}}(),v.cursor=s,r=v.cursor,i=v.limit,n=i,e=i,_(),v.cursor=r,h()&&(n=v.cursor,h()&&(e=v.cursor)),v.limit_backward=s,v.cursor=v.limit,j(),v.cursor=v.limit,function(){var e;if(v.ket=v.cursor,e=v.find_among_b(f,4))switch(v.bra=v.cursor,e){case 1:b()&&(v.slice_del(),v.ket=v.cursor,v.limit,v.cursor,q("u","g")&&q("i","c"));break;case 2:v.slice_from("c")}}(),v.cursor=v.limit_backward,function(){for(var e;;){if(v.bra=v.cursor,e=v.find_among(a,3))switch(v.ket=v.cursor,e){case 1:v.slice_from("ã");continue;case 2:v.slice_from("õ");continue;case 3:if(v.cursor>=v.limit)break;v.cursor++;continue}break}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}),e.Pipeline.registerFunction(e.pt.stemmer,"stemmer-pt"),e.pt.stopWordFilter=e.generateStopWordFilter("a ao aos aquela aquelas aquele aqueles aquilo as até com como da das de dela delas dele deles depois do dos e ela elas ele eles em entre era eram essa essas esse esses esta estamos estas estava estavam este esteja estejam estejamos estes esteve estive estivemos estiver estivera estiveram estiverem estivermos estivesse estivessem estivéramos estivéssemos estou está estávamos estão eu foi fomos for fora foram forem formos fosse fossem fui fôramos fôssemos haja hajam hajamos havemos hei houve houvemos houver houvera houveram houverei houverem houveremos houveria houveriam houvermos houverá houverão houveríamos houvesse houvessem houvéramos houvéssemos há hão isso isto já lhe lhes mais mas me mesmo meu meus minha minhas muito na nas nem no nos nossa nossas nosso nossos num numa não nós o os ou para pela pelas pelo pelos por qual quando que quem se seja sejam sejamos sem serei seremos seria seriam será serão seríamos seu seus somos sou sua suas são só também te tem temos tenha tenham tenhamos tenho terei teremos teria teriam terá terão teríamos teu teus teve tinha tinham tive tivemos tiver tivera tiveram tiverem tivermos tivesse tivessem tivéramos tivéssemos tu tua tuas tém tínhamos um uma você vocês vos à às éramos".split(" ")),e.Pipeline.registerFunction(e.pt.stopWordFilter,"stopWordFilter-pt")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.ro.js b/assets/javascripts/lunr/lunr.ro.js new file mode 100644 index 000000000..155cb5621 --- /dev/null +++ b/assets/javascripts/lunr/lunr.ro.js @@ -0,0 +1 @@ +!function(e,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i,r,n;e.ro=function(){this.pipeline.reset(),this.pipeline.add(e.ro.trimmer,e.ro.stopWordFilter,e.ro.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ro.stemmer))},e.ro.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.ro.trimmer=e.trimmerSupport.generateTrimmer(e.ro.wordCharacters),e.Pipeline.registerFunction(e.ro.trimmer,"trimmer-ro"),e.ro.stemmer=(i=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,n=new function(){var e,n,t,a,o=[new i("",-1,3),new i("I",0,1),new i("U",0,2)],s=[new i("ea",-1,3),new i("aţia",-1,7),new i("aua",-1,2),new i("iua",-1,4),new i("aţie",-1,7),new i("ele",-1,3),new i("ile",-1,5),new i("iile",6,4),new i("iei",-1,4),new i("atei",-1,6),new i("ii",-1,4),new i("ului",-1,1),new i("ul",-1,1),new i("elor",-1,3),new i("ilor",-1,4),new i("iilor",14,4)],c=[new i("icala",-1,4),new i("iciva",-1,4),new i("ativa",-1,5),new i("itiva",-1,6),new i("icale",-1,4),new i("aţiune",-1,5),new i("iţiune",-1,6),new i("atoare",-1,5),new i("itoare",-1,6),new i("ătoare",-1,5),new i("icitate",-1,4),new i("abilitate",-1,1),new i("ibilitate",-1,2),new i("ivitate",-1,3),new i("icive",-1,4),new i("ative",-1,5),new i("itive",-1,6),new i("icali",-1,4),new i("atori",-1,5),new i("icatori",18,4),new i("itori",-1,6),new i("ători",-1,5),new i("icitati",-1,4),new i("abilitati",-1,1),new i("ivitati",-1,3),new i("icivi",-1,4),new i("ativi",-1,5),new i("itivi",-1,6),new i("icităi",-1,4),new i("abilităi",-1,1),new i("ivităi",-1,3),new i("icităţi",-1,4),new i("abilităţi",-1,1),new i("ivităţi",-1,3),new i("ical",-1,4),new i("ator",-1,5),new i("icator",35,4),new i("itor",-1,6),new i("ător",-1,5),new i("iciv",-1,4),new i("ativ",-1,5),new i("itiv",-1,6),new i("icală",-1,4),new i("icivă",-1,4),new i("ativă",-1,5),new i("itivă",-1,6)],u=[new i("ica",-1,1),new i("abila",-1,1),new i("ibila",-1,1),new i("oasa",-1,1),new i("ata",-1,1),new i("ita",-1,1),new i("anta",-1,1),new i("ista",-1,3),new i("uta",-1,1),new i("iva",-1,1),new i("ic",-1,1),new i("ice",-1,1),new i("abile",-1,1),new i("ibile",-1,1),new i("isme",-1,3),new i("iune",-1,2),new i("oase",-1,1),new i("ate",-1,1),new i("itate",17,1),new i("ite",-1,1),new i("ante",-1,1),new i("iste",-1,3),new i("ute",-1,1),new i("ive",-1,1),new i("ici",-1,1),new i("abili",-1,1),new i("ibili",-1,1),new i("iuni",-1,2),new i("atori",-1,1),new i("osi",-1,1),new i("ati",-1,1),new i("itati",30,1),new i("iti",-1,1),new i("anti",-1,1),new i("isti",-1,3),new i("uti",-1,1),new i("işti",-1,3),new i("ivi",-1,1),new i("ităi",-1,1),new i("oşi",-1,1),new i("ităţi",-1,1),new i("abil",-1,1),new i("ibil",-1,1),new i("ism",-1,3),new i("ator",-1,1),new i("os",-1,1),new i("at",-1,1),new i("it",-1,1),new i("ant",-1,1),new i("ist",-1,3),new i("ut",-1,1),new i("iv",-1,1),new i("ică",-1,1),new i("abilă",-1,1),new i("ibilă",-1,1),new i("oasă",-1,1),new i("ată",-1,1),new i("ită",-1,1),new i("antă",-1,1),new i("istă",-1,3),new i("ută",-1,1),new i("ivă",-1,1)],w=[new i("ea",-1,1),new i("ia",-1,1),new i("esc",-1,1),new i("ăsc",-1,1),new i("ind",-1,1),new i("ând",-1,1),new i("are",-1,1),new i("ere",-1,1),new i("ire",-1,1),new i("âre",-1,1),new i("se",-1,2),new i("ase",10,1),new i("sese",10,2),new i("ise",10,1),new i("use",10,1),new i("âse",10,1),new i("eşte",-1,1),new i("ăşte",-1,1),new i("eze",-1,1),new i("ai",-1,1),new i("eai",19,1),new i("iai",19,1),new i("sei",-1,2),new i("eşti",-1,1),new i("ăşti",-1,1),new i("ui",-1,1),new i("ezi",-1,1),new i("âi",-1,1),new i("aşi",-1,1),new i("seşi",-1,2),new i("aseşi",29,1),new i("seseşi",29,2),new i("iseşi",29,1),new i("useşi",29,1),new i("âseşi",29,1),new i("işi",-1,1),new i("uşi",-1,1),new i("âşi",-1,1),new i("aţi",-1,2),new i("eaţi",38,1),new i("iaţi",38,1),new i("eţi",-1,2),new i("iţi",-1,2),new i("âţi",-1,2),new i("arăţi",-1,1),new i("serăţi",-1,2),new i("aserăţi",45,1),new i("seserăţi",45,2),new i("iserăţi",45,1),new i("userăţi",45,1),new i("âserăţi",45,1),new i("irăţi",-1,1),new i("urăţi",-1,1),new i("ârăţi",-1,1),new i("am",-1,1),new i("eam",54,1),new i("iam",54,1),new i("em",-1,2),new i("asem",57,1),new i("sesem",57,2),new i("isem",57,1),new i("usem",57,1),new i("âsem",57,1),new i("im",-1,2),new i("âm",-1,2),new i("ăm",-1,2),new i("arăm",65,1),new i("serăm",65,2),new i("aserăm",67,1),new i("seserăm",67,2),new i("iserăm",67,1),new i("userăm",67,1),new i("âserăm",67,1),new i("irăm",65,1),new i("urăm",65,1),new i("ârăm",65,1),new i("au",-1,1),new i("eau",76,1),new i("iau",76,1),new i("indu",-1,1),new i("ându",-1,1),new i("ez",-1,1),new i("ească",-1,1),new i("ară",-1,1),new i("seră",-1,2),new i("aseră",84,1),new i("seseră",84,2),new i("iseră",84,1),new i("useră",84,1),new i("âseră",84,1),new i("iră",-1,1),new i("ură",-1,1),new i("âră",-1,1),new i("ează",-1,1)],m=[new i("a",-1,1),new i("e",-1,1),new i("ie",1,1),new i("i",-1,1),new i("ă",-1,1)],l=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,2,32,0,0,4],f=new r;function p(e,i){f.eq_s(1,e)&&(f.ket=f.cursor,f.in_grouping(l,97,259)&&f.slice_from(i))}function d(){if(f.out_grouping(l,97,259)){for(;!f.in_grouping(l,97,259);){if(f.cursor>=f.limit)return!0;f.cursor++}return!1}return!0}function b(){var e,i,r=f.cursor;if(f.in_grouping(l,97,259)){if(e=f.cursor,!d())return void(a=f.cursor);if(f.cursor=e,!function(){if(f.in_grouping(l,97,259))for(;!f.out_grouping(l,97,259);){if(f.cursor>=f.limit)return!0;f.cursor++}return!1}())return void(a=f.cursor)}f.cursor=r,f.out_grouping(l,97,259)&&(i=f.cursor,d()&&(f.cursor=i,f.in_grouping(l,97,259)&&f.cursor=f.limit)return!1;f.cursor++}for(;!f.out_grouping(l,97,259);){if(f.cursor>=f.limit)return!1;f.cursor++}return!0}function _(){return t<=f.cursor}function g(){var i,r=f.limit-f.cursor;if(f.ket=f.cursor,(i=f.find_among_b(c,46))&&(f.bra=f.cursor,_())){switch(i){case 1:f.slice_from("abil");break;case 2:f.slice_from("ibil");break;case 3:f.slice_from("iv");break;case 4:f.slice_from("ic");break;case 5:f.slice_from("at");break;case 6:f.slice_from("it")}return e=!0,f.cursor=f.limit-r,!0}return!1}function k(){var i,r;for(e=!1;;)if(r=f.limit-f.cursor,!g()){f.cursor=f.limit-r;break}if(f.ket=f.cursor,(i=f.find_among_b(u,62))&&(f.bra=f.cursor,n<=f.cursor)){switch(i){case 1:f.slice_del();break;case 2:f.eq_s_b(1,"ţ")&&(f.bra=f.cursor,f.slice_from("t"));break;case 3:f.slice_from("ist")}e=!0}}function h(){var e;f.ket=f.cursor,(e=f.find_among_b(m,5))&&(f.bra=f.cursor,a<=f.cursor&&1==e&&f.slice_del())}this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var i,r=f.cursor;return function(){for(var e,i;e=f.cursor,f.in_grouping(l,97,259)&&(i=f.cursor,f.bra=i,p("u","U"),f.cursor=i,p("i","I")),f.cursor=e,!(f.cursor>=f.limit);)f.cursor++}(),f.cursor=r,i=f.cursor,a=f.limit,t=a,n=a,b(),f.cursor=i,v()&&(t=f.cursor,v()&&(n=f.cursor)),f.limit_backward=r,f.cursor=f.limit,function(){var e,i;if(f.ket=f.cursor,(e=f.find_among_b(s,16))&&(f.bra=f.cursor,_()))switch(e){case 1:f.slice_del();break;case 2:f.slice_from("a");break;case 3:f.slice_from("e");break;case 4:f.slice_from("i");break;case 5:i=f.limit-f.cursor,f.eq_s_b(2,"ab")||(f.cursor=f.limit-i,f.slice_from("i"));break;case 6:f.slice_from("at");break;case 7:f.slice_from("aţi")}}(),f.cursor=f.limit,k(),f.cursor=f.limit,e||(f.cursor=f.limit,function(){var e,i,r;if(f.cursor>=a){if(i=f.limit_backward,f.limit_backward=a,f.ket=f.cursor,e=f.find_among_b(w,94))switch(f.bra=f.cursor,e){case 1:if(r=f.limit-f.cursor,!f.out_grouping_b(l,97,259)&&(f.cursor=f.limit-r,!f.eq_s_b(1,"u")))break;case 2:f.slice_del()}f.limit_backward=i}}(),f.cursor=f.limit),h(),f.cursor=f.limit_backward,function(){for(var e;;){if(f.bra=f.cursor,e=f.find_among(o,3))switch(f.ket=f.cursor,e){case 1:f.slice_from("i");continue;case 2:f.slice_from("u");continue;case 3:if(f.cursor>=f.limit)break;f.cursor++;continue}break}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}),e.Pipeline.registerFunction(e.ro.stemmer,"stemmer-ro"),e.ro.stopWordFilter=e.generateStopWordFilter("acea aceasta această aceea acei aceia acel acela acele acelea acest acesta aceste acestea aceşti aceştia acolo acord acum ai aia aibă aici al ale alea altceva altcineva am ar are asemenea asta astea astăzi asupra au avea avem aveţi azi aş aşadar aţi bine bucur bună ca care caut ce cel ceva chiar cinci cine cineva contra cu cum cumva curând curînd când cât câte câtva câţi cînd cît cîte cîtva cîţi că căci cărei căror cărui către da dacă dar datorită dată dau de deci deja deoarece departe deşi din dinaintea dintr- dintre doi doilea două drept după dă ea ei el ele eram este eu eşti face fata fi fie fiecare fii fim fiu fiţi frumos fără graţie halbă iar ieri la le li lor lui lângă lîngă mai mea mei mele mereu meu mi mie mine mult multă mulţi mulţumesc mâine mîine mă ne nevoie nici nicăieri nimeni nimeri nimic nişte noastre noastră noi noroc nostru nouă noştri nu opt ori oricare orice oricine oricum oricând oricât oricînd oricît oriunde patra patru patrulea pe pentru peste pic poate pot prea prima primul prin puţin puţina puţină până pînă rog sa sale sau se spate spre sub sunt suntem sunteţi sută sînt sîntem sînteţi să săi său ta tale te timp tine toate toată tot totuşi toţi trei treia treilea tu tăi tău un una unde undeva unei uneia unele uneori unii unor unora unu unui unuia unul vi voastre voastră voi vostru vouă voştri vreme vreo vreun vă zece zero zi zice îi îl îmi împotriva în înainte înaintea încotro încât încît între întrucât întrucît îţi ăla ălea ăsta ăstea ăştia şapte şase şi ştiu ţi ţie".split(" ")),e.Pipeline.registerFunction(e.ro.stopWordFilter,"stopWordFilter-ro")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.ru.js b/assets/javascripts/lunr/lunr.ru.js new file mode 100644 index 000000000..078609ad8 --- /dev/null +++ b/assets/javascripts/lunr/lunr.ru.js @@ -0,0 +1 @@ +!function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var n,r,t;e.ru=function(){this.pipeline.reset(),this.pipeline.add(e.ru.trimmer,e.ru.stopWordFilter,e.ru.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ru.stemmer))},e.ru.wordCharacters="Ѐ-҄҇-ԯᴫᵸⷠ-ⷿꙀ-ꚟ︮︯",e.ru.trimmer=e.trimmerSupport.generateTrimmer(e.ru.wordCharacters),e.Pipeline.registerFunction(e.ru.trimmer,"trimmer-ru"),e.ru.stemmer=(n=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,t=new function(){var e,t,w=[new n("в",-1,1),new n("ив",0,2),new n("ыв",0,2),new n("вши",-1,1),new n("ивши",3,2),new n("ывши",3,2),new n("вшись",-1,1),new n("ившись",6,2),new n("ывшись",6,2)],i=[new n("ее",-1,1),new n("ие",-1,1),new n("ое",-1,1),new n("ые",-1,1),new n("ими",-1,1),new n("ыми",-1,1),new n("ей",-1,1),new n("ий",-1,1),new n("ой",-1,1),new n("ый",-1,1),new n("ем",-1,1),new n("им",-1,1),new n("ом",-1,1),new n("ым",-1,1),new n("его",-1,1),new n("ого",-1,1),new n("ему",-1,1),new n("ому",-1,1),new n("их",-1,1),new n("ых",-1,1),new n("ею",-1,1),new n("ою",-1,1),new n("ую",-1,1),new n("юю",-1,1),new n("ая",-1,1),new n("яя",-1,1)],u=[new n("ем",-1,1),new n("нн",-1,1),new n("вш",-1,1),new n("ивш",2,2),new n("ывш",2,2),new n("щ",-1,1),new n("ющ",5,1),new n("ующ",6,2)],s=[new n("сь",-1,1),new n("ся",-1,1)],o=[new n("ла",-1,1),new n("ила",0,2),new n("ыла",0,2),new n("на",-1,1),new n("ена",3,2),new n("ете",-1,1),new n("ите",-1,2),new n("йте",-1,1),new n("ейте",7,2),new n("уйте",7,2),new n("ли",-1,1),new n("или",10,2),new n("ыли",10,2),new n("й",-1,1),new n("ей",13,2),new n("уй",13,2),new n("л",-1,1),new n("ил",16,2),new n("ыл",16,2),new n("ем",-1,1),new n("им",-1,2),new n("ым",-1,2),new n("н",-1,1),new n("ен",22,2),new n("ло",-1,1),new n("ило",24,2),new n("ыло",24,2),new n("но",-1,1),new n("ено",27,2),new n("нно",27,1),new n("ет",-1,1),new n("ует",30,2),new n("ит",-1,2),new n("ыт",-1,2),new n("ют",-1,1),new n("уют",34,2),new n("ят",-1,2),new n("ны",-1,1),new n("ены",37,2),new n("ть",-1,1),new n("ить",39,2),new n("ыть",39,2),new n("ешь",-1,1),new n("ишь",-1,2),new n("ю",-1,2),new n("ую",44,2)],c=[new n("а",-1,1),new n("ев",-1,1),new n("ов",-1,1),new n("е",-1,1),new n("ие",3,1),new n("ье",3,1),new n("и",-1,1),new n("еи",6,1),new n("ии",6,1),new n("ами",6,1),new n("ями",6,1),new n("иями",10,1),new n("й",-1,1),new n("ей",12,1),new n("ией",13,1),new n("ий",12,1),new n("ой",12,1),new n("ам",-1,1),new n("ем",-1,1),new n("ием",18,1),new n("ом",-1,1),new n("ям",-1,1),new n("иям",21,1),new n("о",-1,1),new n("у",-1,1),new n("ах",-1,1),new n("ях",-1,1),new n("иях",26,1),new n("ы",-1,1),new n("ь",-1,1),new n("ю",-1,1),new n("ию",30,1),new n("ью",30,1),new n("я",-1,1),new n("ия",33,1),new n("ья",33,1)],m=[new n("ост",-1,1),new n("ость",-1,1)],l=[new n("ейше",-1,1),new n("н",-1,2),new n("ейш",-1,1),new n("ь",-1,3)],f=[33,65,8,232],a=new r;function p(){for(;!a.in_grouping(f,1072,1103);){if(a.cursor>=a.limit)return!1;a.cursor++}return!0}function d(){for(;!a.out_grouping(f,1072,1103);){if(a.cursor>=a.limit)return!1;a.cursor++}return!0}function _(e,n){var r,t;if(a.ket=a.cursor,r=a.find_among_b(e,n)){switch(a.bra=a.cursor,r){case 1:if(t=a.limit-a.cursor,!a.eq_s_b(1,"а")&&(a.cursor=a.limit-t,!a.eq_s_b(1,"я")))return!1;case 2:a.slice_del()}return!0}return!1}function b(e,n){var r;return a.ket=a.cursor,!!(r=a.find_among_b(e,n))&&(a.bra=a.cursor,1==r&&a.slice_del(),!0)}function h(){return!!b(i,26)&&(_(u,8),!0)}function g(){var n;a.ket=a.cursor,(n=a.find_among_b(m,2))&&(a.bra=a.cursor,e<=a.cursor&&1==n&&a.slice_del())}this.setCurrent=function(e){a.setCurrent(e)},this.getCurrent=function(){return a.getCurrent()},this.stem=function(){return t=a.limit,e=t,p()&&(t=a.cursor,d()&&p()&&d()&&(e=a.cursor)),a.cursor=a.limit,!(a.cursor=i&&t[(e-=i)>>3]&1<<(7&e))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&t[(e-=i)>>3]&1<<(7&e))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursors||e>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor>1),f=0,l=o0||e==s||c)break;c=!0}}for(;;){if(o>=(_=t[s]).s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o=0;_--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-m.s[_])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var m;if(o>=(m=t[s]).s_size){if(this.cursor=n-m.s_size,!m.method)return m.result;var b=m.method();if(this.cursor=n-m.s_size,b)return m.result}if((s=m.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.sv.js b/assets/javascripts/lunr/lunr.sv.js new file mode 100644 index 000000000..4bb0f9f92 --- /dev/null +++ b/assets/javascripts/lunr/lunr.sv.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,n,t;e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=(r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){var e,t,i=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],s=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],a=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],o=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],u=[119,127,149],m=new n;this.setCurrent=function(e){m.setCurrent(e)},this.getCurrent=function(){return m.getCurrent()},this.stem=function(){var r,n=m.cursor;return function(){var r,n=m.cursor+3;if(t=m.limit,0<=n||n<=m.limit){for(e=n;;){if(r=m.cursor,m.in_grouping(o,97,246)){m.cursor=r;break}if(m.cursor=r,m.cursor>=m.limit)return;m.cursor++}for(;!m.out_grouping(o,97,246);){if(m.cursor>=m.limit)return;m.cursor++}(t=m.cursor)=t&&(m.limit_backward=t,m.cursor=m.limit,m.ket=m.cursor,e=m.find_among_b(i,37),m.limit_backward=r,e))switch(m.bra=m.cursor,e){case 1:m.slice_del();break;case 2:m.in_grouping_b(u,98,121)&&m.slice_del()}}(),m.cursor=m.limit,r=m.limit_backward,m.cursor>=t&&(m.limit_backward=t,m.cursor=m.limit,m.find_among_b(s,7)&&(m.cursor=m.limit,m.ket=m.cursor,m.cursor>m.limit_backward&&(m.bra=--m.cursor,m.slice_del())),m.limit_backward=r),m.cursor=m.limit,function(){var e,r;if(m.cursor>=t){if(r=m.limit_backward,m.limit_backward=t,m.cursor=m.limit,m.ket=m.cursor,e=m.find_among_b(a,5))switch(m.bra=m.cursor,e){case 1:m.slice_del();break;case 2:m.slice_from("lös");break;case 3:m.slice_from("full")}m.limit_backward=r}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/lunr.tr.js b/assets/javascripts/lunr/lunr.tr.js new file mode 100644 index 000000000..c42b349e8 --- /dev/null +++ b/assets/javascripts/lunr/lunr.tr.js @@ -0,0 +1 @@ +!function(r,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(r.lunr)}(this,function(){return function(r){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i,e,n;r.tr=function(){this.pipeline.reset(),this.pipeline.add(r.tr.trimmer,r.tr.stopWordFilter,r.tr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(r.tr.stemmer))},r.tr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",r.tr.trimmer=r.trimmerSupport.generateTrimmer(r.tr.wordCharacters),r.Pipeline.registerFunction(r.tr.trimmer,"trimmer-tr"),r.tr.stemmer=(i=r.stemmerSupport.Among,e=r.stemmerSupport.SnowballProgram,n=new function(){var r,n=[new i("m",-1,-1),new i("n",-1,-1),new i("miz",-1,-1),new i("niz",-1,-1),new i("muz",-1,-1),new i("nuz",-1,-1),new i("müz",-1,-1),new i("nüz",-1,-1),new i("mız",-1,-1),new i("nız",-1,-1)],t=[new i("leri",-1,-1),new i("ları",-1,-1)],u=[new i("ni",-1,-1),new i("nu",-1,-1),new i("nü",-1,-1),new i("nı",-1,-1)],o=[new i("in",-1,-1),new i("un",-1,-1),new i("ün",-1,-1),new i("ın",-1,-1)],s=[new i("a",-1,-1),new i("e",-1,-1)],c=[new i("na",-1,-1),new i("ne",-1,-1)],l=[new i("da",-1,-1),new i("ta",-1,-1),new i("de",-1,-1),new i("te",-1,-1)],a=[new i("nda",-1,-1),new i("nde",-1,-1)],m=[new i("dan",-1,-1),new i("tan",-1,-1),new i("den",-1,-1),new i("ten",-1,-1)],d=[new i("ndan",-1,-1),new i("nden",-1,-1)],f=[new i("la",-1,-1),new i("le",-1,-1)],b=[new i("ca",-1,-1),new i("ce",-1,-1)],w=[new i("im",-1,-1),new i("um",-1,-1),new i("üm",-1,-1),new i("ım",-1,-1)],_=[new i("sin",-1,-1),new i("sun",-1,-1),new i("sün",-1,-1),new i("sın",-1,-1)],k=[new i("iz",-1,-1),new i("uz",-1,-1),new i("üz",-1,-1),new i("ız",-1,-1)],p=[new i("siniz",-1,-1),new i("sunuz",-1,-1),new i("sünüz",-1,-1),new i("sınız",-1,-1)],g=[new i("lar",-1,-1),new i("ler",-1,-1)],y=[new i("niz",-1,-1),new i("nuz",-1,-1),new i("nüz",-1,-1),new i("nız",-1,-1)],z=[new i("dir",-1,-1),new i("tir",-1,-1),new i("dur",-1,-1),new i("tur",-1,-1),new i("dür",-1,-1),new i("tür",-1,-1),new i("dır",-1,-1),new i("tır",-1,-1)],h=[new i("casına",-1,-1),new i("cesine",-1,-1)],v=[new i("di",-1,-1),new i("ti",-1,-1),new i("dik",-1,-1),new i("tik",-1,-1),new i("duk",-1,-1),new i("tuk",-1,-1),new i("dük",-1,-1),new i("tük",-1,-1),new i("dık",-1,-1),new i("tık",-1,-1),new i("dim",-1,-1),new i("tim",-1,-1),new i("dum",-1,-1),new i("tum",-1,-1),new i("düm",-1,-1),new i("tüm",-1,-1),new i("dım",-1,-1),new i("tım",-1,-1),new i("din",-1,-1),new i("tin",-1,-1),new i("dun",-1,-1),new i("tun",-1,-1),new i("dün",-1,-1),new i("tün",-1,-1),new i("dın",-1,-1),new i("tın",-1,-1),new i("du",-1,-1),new i("tu",-1,-1),new i("dü",-1,-1),new i("tü",-1,-1),new i("dı",-1,-1),new i("tı",-1,-1)],q=[new i("sa",-1,-1),new i("se",-1,-1),new i("sak",-1,-1),new i("sek",-1,-1),new i("sam",-1,-1),new i("sem",-1,-1),new i("san",-1,-1),new i("sen",-1,-1)],C=[new i("miş",-1,-1),new i("muş",-1,-1),new i("müş",-1,-1),new i("mış",-1,-1)],P=[new i("b",-1,1),new i("c",-1,2),new i("d",-1,3),new i("ğ",-1,4)],F=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,8,0,0,0,0,0,0,1],S=[1,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,1],W=[65],L=[65],x=[["a",[1,64,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],97,305],["e",[17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130],101,252],["ı",[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],97,305],["i",[17],101,105],["o",W,111,117],["ö",L,246,252],["u",W,111,117]],A=new e;function E(r,i,e){for(;;){var n=A.limit-A.cursor;if(A.in_grouping_b(r,i,e)){A.cursor=A.limit-n;break}if(A.cursor=A.limit-n,A.cursor<=A.limit_backward)return!1;A.cursor--}return!0}function j(){var r,i;r=A.limit-A.cursor,E(F,97,305);for(var e=0;eA.limit_backward&&(A.cursor--,e=A.limit-A.cursor,i()))?(A.cursor=A.limit-e,!0):(A.cursor=A.limit-n,r()?(A.cursor=A.limit-n,!1):(A.cursor=A.limit-n,!(A.cursor<=A.limit_backward)&&(A.cursor--,!!i()&&(A.cursor=A.limit-n,!0))))}function Z(r){return T(r,function(){return A.in_grouping_b(F,97,305)})}function B(){return Z(function(){return A.eq_s_b(1,"n")})}function D(){return Z(function(){return A.eq_s_b(1,"y")})}function G(){return A.find_among_b(n,10)&&T(function(){return A.in_grouping_b(S,105,305)},function(){return A.out_grouping_b(F,97,305)})}function H(){return j()&&A.in_grouping_b(S,105,305)&&Z(function(){return A.eq_s_b(1,"s")})}function I(){return A.find_among_b(t,2)}function J(){return j()&&A.find_among_b(o,4)&&B()}function K(){return j()&&A.find_among_b(l,4)}function M(){return j()&&A.find_among_b(a,2)}function N(){return j()&&A.find_among_b(w,4)&&D()}function O(){return j()&&A.find_among_b(_,4)}function Q(){return j()&&A.find_among_b(k,4)&&D()}function R(){return A.find_among_b(p,4)}function U(){return j()&&A.find_among_b(g,2)}function V(){return j()&&A.find_among_b(z,8)}function X(){return j()&&A.find_among_b(v,32)&&D()}function Y(){return A.find_among_b(q,8)&&D()}function $(){return j()&&A.find_among_b(C,4)&&D()}function rr(){var r=A.limit-A.cursor;return!($()||(A.cursor=A.limit-r,X()||(A.cursor=A.limit-r,Y()||(A.cursor=A.limit-r,A.eq_s_b(3,"ken")&&D()))))}function ir(){if(A.find_among_b(h,2)){var r=A.limit-A.cursor;if(R()||(A.cursor=A.limit-r,U()||(A.cursor=A.limit-r,N()||(A.cursor=A.limit-r,O()||(A.cursor=A.limit-r,Q()||(A.cursor=A.limit-r))))),$())return!1}return!0}function er(){if(!j()||!A.find_among_b(y,4))return!0;var r=A.limit-A.cursor;return!X()&&(A.cursor=A.limit-r,!Y())}function nr(){var i,e,n,t=A.limit-A.cursor;if(A.ket=A.cursor,r=!0,rr()&&(A.cursor=A.limit-t,ir()&&(A.cursor=A.limit-t,function(){if(U()){A.bra=A.cursor,A.slice_del();var i=A.limit-A.cursor;return A.ket=A.cursor,V()||(A.cursor=A.limit-i,X()||(A.cursor=A.limit-i,Y()||(A.cursor=A.limit-i,$()||(A.cursor=A.limit-i)))),r=!1,!1}return!0}()&&(A.cursor=A.limit-t,er()&&(A.cursor=A.limit-t,n=A.limit-A.cursor,!(R()||(A.cursor=A.limit-n,Q()||(A.cursor=A.limit-n,O()||(A.cursor=A.limit-n,N()))))||(A.bra=A.cursor,A.slice_del(),e=A.limit-A.cursor,A.ket=A.cursor,$()||(A.cursor=A.limit-e),0)))))){if(A.cursor=A.limit-t,!V())return;A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,i=A.limit-A.cursor,R()||(A.cursor=A.limit-i,U()||(A.cursor=A.limit-i,N()||(A.cursor=A.limit-i,O()||(A.cursor=A.limit-i,Q()||(A.cursor=A.limit-i))))),$()||(A.cursor=A.limit-i)}A.bra=A.cursor,A.slice_del()}function tr(){var r,i,e,n;if(A.ket=A.cursor,A.eq_s_b(2,"ki")){if(r=A.limit-A.cursor,K())return A.bra=A.cursor,A.slice_del(),i=A.limit-A.cursor,A.ket=A.cursor,U()?(A.bra=A.cursor,A.slice_del(),tr()):(A.cursor=A.limit-i,G()&&(A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,U()&&(A.bra=A.cursor,A.slice_del(),tr()))),!0;if(A.cursor=A.limit-r,J()){if(A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,e=A.limit-A.cursor,I())A.bra=A.cursor,A.slice_del();else{if(A.cursor=A.limit-e,A.ket=A.cursor,!G()&&(A.cursor=A.limit-e,!H()&&(A.cursor=A.limit-e,!tr())))return!0;A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,U()&&(A.bra=A.cursor,A.slice_del(),tr())}return!0}if(A.cursor=A.limit-r,M()){if(n=A.limit-A.cursor,I())A.bra=A.cursor,A.slice_del();else if(A.cursor=A.limit-n,H())A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,U()&&(A.bra=A.cursor,A.slice_del(),tr());else if(A.cursor=A.limit-n,!tr())return!1;return!0}}return!1}function ur(r){if(A.ket=A.cursor,!M()&&(A.cursor=A.limit-r,!j()||!A.find_among_b(c,2)))return!1;var i=A.limit-A.cursor;if(I())A.bra=A.cursor,A.slice_del();else if(A.cursor=A.limit-i,H())A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,U()&&(A.bra=A.cursor,A.slice_del(),tr());else if(A.cursor=A.limit-i,!tr())return!1;return!0}function or(r){if(A.ket=A.cursor,!(j()&&A.find_among_b(d,2)||(A.cursor=A.limit-r,j()&&A.find_among_b(u,4))))return!1;var i=A.limit-A.cursor;return!(!H()&&(A.cursor=A.limit-i,!I()))&&(A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,U()&&(A.bra=A.cursor,A.slice_del(),tr()),!0)}function sr(){var r,i=A.limit-A.cursor;return A.ket=A.cursor,!!(J()||(A.cursor=A.limit-i,j()&&A.find_among_b(f,2)&&D()))&&(A.bra=A.cursor,A.slice_del(),r=A.limit-A.cursor,A.ket=A.cursor,!(!U()||(A.bra=A.cursor,A.slice_del(),!tr()))||(A.cursor=A.limit-r,A.ket=A.cursor,!(G()||(A.cursor=A.limit-r,H()||(A.cursor=A.limit-r,tr())))||(A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,U()&&(A.bra=A.cursor,A.slice_del(),tr()),!0)))}function cr(){var r,i,e=A.limit-A.cursor;if(A.ket=A.cursor,!(K()||(A.cursor=A.limit-e,j()&&A.in_grouping_b(S,105,305)&&D()||(A.cursor=A.limit-e,j()&&A.find_among_b(s,2)&&D()))))return!1;if(A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,r=A.limit-A.cursor,G())A.bra=A.cursor,A.slice_del(),i=A.limit-A.cursor,A.ket=A.cursor,U()||(A.cursor=A.limit-i);else if(A.cursor=A.limit-r,!U())return!0;return A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,tr(),!0}function lr(){var r,i,e=A.limit-A.cursor;if(A.ket=A.cursor,U())return A.bra=A.cursor,A.slice_del(),void tr();if(A.cursor=A.limit-e,A.ket=A.cursor,j()&&A.find_among_b(b,2)&&B())if(A.bra=A.cursor,A.slice_del(),r=A.limit-A.cursor,A.ket=A.cursor,I())A.bra=A.cursor,A.slice_del();else{if(A.cursor=A.limit-r,A.ket=A.cursor,!G()&&(A.cursor=A.limit-r,!H())){if(A.cursor=A.limit-r,A.ket=A.cursor,!U())return;if(A.bra=A.cursor,A.slice_del(),!tr())return}A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,U()&&(A.bra=A.cursor,A.slice_del(),tr())}else if(A.cursor=A.limit-e,!ur(e)&&(A.cursor=A.limit-e,!or(e))){if(A.cursor=A.limit-e,A.ket=A.cursor,j()&&A.find_among_b(m,4))return A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,i=A.limit-A.cursor,void(G()?(A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,U()&&(A.bra=A.cursor,A.slice_del(),tr())):(A.cursor=A.limit-i,U()?(A.bra=A.cursor,A.slice_del(),tr()):(A.cursor=A.limit-i,tr())));if(A.cursor=A.limit-e,!sr()){if(A.cursor=A.limit-e,I())return A.bra=A.cursor,void A.slice_del();A.cursor=A.limit-e,tr()||(A.cursor=A.limit-e,cr()||(A.cursor=A.limit-e,A.ket=A.cursor,(G()||(A.cursor=A.limit-e,H()))&&(A.bra=A.cursor,A.slice_del(),A.ket=A.cursor,U()&&(A.bra=A.cursor,A.slice_del(),tr()))))}}}function ar(r,i,e){if(A.cursor=A.limit-r,function(){for(;;){var r=A.limit-A.cursor;if(A.in_grouping_b(F,97,305)){A.cursor=A.limit-r;break}if(A.cursor=A.limit-r,A.cursor<=A.limit_backward)return!1;A.cursor--}return!0}()){var n=A.limit-A.cursor;if(!A.eq_s_b(1,i)&&(A.cursor=A.limit-n,!A.eq_s_b(1,e)))return!0;A.cursor=A.limit-r;var t=A.cursor;return A.insert(A.cursor,A.cursor,e),A.cursor=t,!1}return!0}function mr(r,i,e){for(;!A.eq_s(i,e);){if(A.cursor>=A.limit)return!0;A.cursor++}return i!=A.limit||(A.cursor=r,!1)}function dr(){var r,i,e=A.cursor;return!(!mr(r=A.cursor,2,"ad")||(A.cursor=r,!mr(r,5,"soyad")))&&(A.limit_backward=e,A.cursor=A.limit,i=A.limit-A.cursor,(A.eq_s_b(1,"d")||(A.cursor=A.limit-i,A.eq_s_b(1,"g")))&&ar(i,"a","ı")&&ar(i,"e","i")&&ar(i,"o","u")&&ar(i,"ö","ü"),A.cursor=A.limit,function(){var r;if(A.ket=A.cursor,r=A.find_among_b(P,4))switch(A.bra=A.cursor,r){case 1:A.slice_from("p");break;case 2:A.slice_from("ç");break;case 3:A.slice_from("t");break;case 4:A.slice_from("k")}}(),!0)}this.setCurrent=function(r){A.setCurrent(r)},this.getCurrent=function(){return A.getCurrent()},this.stem=function(){return!!(function(){for(var r,i=A.cursor,e=2;;){for(r=A.cursor;!A.in_grouping(F,97,305);){if(A.cursor>=A.limit)return A.cursor=r,!(e>0||(A.cursor=i,0));A.cursor++}e--}}()&&(A.limit_backward=A.cursor,A.cursor=A.limit,nr(),A.cursor=A.limit,r&&(lr(),A.cursor=A.limit_backward,dr())))}},function(r){return"function"==typeof r.update?r.update(function(r){return n.setCurrent(r),n.stem(),n.getCurrent()}):(n.setCurrent(r),n.stem(),n.getCurrent())}),r.Pipeline.registerFunction(r.tr.stemmer,"stemmer-tr"),r.tr.stopWordFilter=r.generateStopWordFilter("acaba altmış altı ama ancak arada aslında ayrıca bana bazı belki ben benden beni benim beri beş bile bin bir biri birkaç birkez birçok birşey birşeyi biz bizden bize bizi bizim bu buna bunda bundan bunlar bunları bunların bunu bunun burada böyle böylece da daha dahi de defa değil diye diğer doksan dokuz dolayı dolayısıyla dört edecek eden ederek edilecek ediliyor edilmesi ediyor elli en etmesi etti ettiği ettiğini eğer gibi göre halen hangi hatta hem henüz hep hepsi her herhangi herkesin hiç hiçbir iki ile ilgili ise itibaren itibariyle için işte kadar karşın katrilyon kendi kendilerine kendini kendisi kendisine kendisini kez ki kim kimden kime kimi kimse kırk milyar milyon mu mü mı nasıl ne neden nedenle nerde nerede nereye niye niçin o olan olarak oldu olduklarını olduğu olduğunu olmadı olmadığı olmak olması olmayan olmaz olsa olsun olup olur olursa oluyor on ona ondan onlar onlardan onları onların onu onun otuz oysa pek rağmen sadece sanki sekiz seksen sen senden seni senin siz sizden sizi sizin tarafından trilyon tüm var vardı ve veya ya yani yapacak yapmak yaptı yaptıkları yaptığı yaptığını yapılan yapılması yapıyor yedi yerine yetmiş yine yirmi yoksa yüz zaten çok çünkü öyle üzere üç şey şeyden şeyi şeyler şu şuna şunda şundan şunları şunu şöyle".split(" ")),r.Pipeline.registerFunction(r.tr.stopWordFilter,"stopWordFilter-tr")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/tinyseg.js b/assets/javascripts/lunr/tinyseg.js new file mode 100644 index 000000000..f7ec60326 --- /dev/null +++ b/assets/javascripts/lunr/tinyseg.js @@ -0,0 +1 @@ +!function(_,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(_.lunr)}(this,function(){return function(_){function t(){var _={"[一二三四五六七八九十百千万億兆]":"M","[一-龠々〆ヵヶ]":"H","[ぁ-ん]":"I","[ァ-ヴーア-ン゙ー]":"K","[a-zA-Za-zA-Z]":"A","[0-90-9]":"N"};for(var t in this.chartype_=[],_){var H=new RegExp;H.compile(t),this.chartype_.push([H,_[t]])}return this.BIAS__=-332,this.BC1__={HH:6,II:2461,KH:406,OH:-1378},this.BC2__={AA:-3267,AI:2744,AN:-878,HH:-4070,HM:-1711,HN:4012,HO:3761,IA:1327,IH:-1184,II:-1332,IK:1721,IO:5492,KI:3831,KK:-8741,MH:-3132,MK:3334,OO:-2920},this.BC3__={HH:996,HI:626,HK:-721,HN:-1307,HO:-836,IH:-301,KK:2762,MK:1079,MM:4034,OA:-1652,OH:266},this.BP1__={BB:295,OB:304,OO:-125,UB:352},this.BP2__={BO:60,OO:-1762},this.BQ1__={BHH:1150,BHM:1521,BII:-1158,BIM:886,BMH:1208,BNH:449,BOH:-91,BOO:-2597,OHI:451,OIH:-296,OKA:1851,OKH:-1020,OKK:904,OOO:2965},this.BQ2__={BHH:118,BHI:-1159,BHM:466,BIH:-919,BKK:-1720,BKO:864,OHH:-1139,OHM:-181,OIH:153,UHI:-1146},this.BQ3__={BHH:-792,BHI:2664,BII:-299,BKI:419,BMH:937,BMM:8335,BNN:998,BOH:775,OHH:2174,OHM:439,OII:280,OKH:1798,OKI:-793,OKO:-2242,OMH:-2402,OOO:11699},this.BQ4__={BHH:-3895,BIH:3761,BII:-4654,BIK:1348,BKK:-1806,BMI:-3385,BOO:-12396,OAH:926,OHH:266,OHK:-2036,ONN:-973},this.BW1__={",と":660,",同":727,"B1あ":1404,"B1同":542,"、と":660,"、同":727,"」と":1682,"あっ":1505,"いう":1743,"いっ":-2055,"いる":672,"うし":-4817,"うん":665,"から":3472,"がら":600,"こう":-790,"こと":2083,"こん":-1262,"さら":-4143,"さん":4573,"した":2641,"して":1104,"すで":-3399,"そこ":1977,"それ":-871,"たち":1122,"ため":601,"った":3463,"つい":-802,"てい":805,"てき":1249,"でき":1127,"です":3445,"では":844,"とい":-4915,"とみ":1922,"どこ":3887,"ない":5713,"なっ":3015,"など":7379,"なん":-1113,"にし":2468,"には":1498,"にも":1671,"に対":-912,"の一":-501,"の中":741,"ませ":2448,"まで":1711,"まま":2600,"まる":-2155,"やむ":-1947,"よっ":-2565,"れた":2369,"れで":-913,"をし":1860,"を見":731,"亡く":-1886,"京都":2558,"取り":-2784,"大き":-2604,"大阪":1497,"平方":-2314,"引き":-1336,"日本":-195,"本当":-2423,"毎日":-2113,"目指":-724,"B1あ":1404,"B1同":542,"」と":1682},this.BW2__={"..":-11822,11:-669,"――":-5730,"−−":-13175,"いう":-1609,"うか":2490,"かし":-1350,"かも":-602,"から":-7194,"かれ":4612,"がい":853,"がら":-3198,"きた":1941,"くな":-1597,"こと":-8392,"この":-4193,"させ":4533,"され":13168,"さん":-3977,"しい":-1819,"しか":-545,"した":5078,"して":972,"しな":939,"その":-3744,"たい":-1253,"たた":-662,"ただ":-3857,"たち":-786,"たと":1224,"たは":-939,"った":4589,"って":1647,"っと":-2094,"てい":6144,"てき":3640,"てく":2551,"ては":-3110,"ても":-3065,"でい":2666,"でき":-1528,"でし":-3828,"です":-4761,"でも":-4203,"とい":1890,"とこ":-1746,"とと":-2279,"との":720,"とみ":5168,"とも":-3941,"ない":-2488,"なが":-1313,"など":-6509,"なの":2614,"なん":3099,"にお":-1615,"にし":2748,"にな":2454,"によ":-7236,"に対":-14943,"に従":-4688,"に関":-11388,"のか":2093,"ので":-7059,"のに":-6041,"のの":-6125,"はい":1073,"はが":-1033,"はず":-2532,"ばれ":1813,"まし":-1316,"まで":-6621,"まれ":5409,"めて":-3153,"もい":2230,"もの":-10713,"らか":-944,"らし":-1611,"らに":-1897,"りし":651,"りま":1620,"れた":4270,"れて":849,"れば":4114,"ろう":6067,"われ":7901,"を通":-11877,"んだ":728,"んな":-4115,"一人":602,"一方":-1375,"一日":970,"一部":-1051,"上が":-4479,"会社":-1116,"出て":2163,"分の":-7758,"同党":970,"同日":-913,"大阪":-2471,"委員":-1250,"少な":-1050,"年度":-8669,"年間":-1626,"府県":-2363,"手権":-1982,"新聞":-4066,"日新":-722,"日本":-7068,"日米":3372,"曜日":-601,"朝鮮":-2355,"本人":-2697,"東京":-1543,"然と":-1384,"社会":-1276,"立て":-990,"第に":-1612,"米国":-4268,"11":-669},this.BW3__={"あた":-2194,"あり":719,"ある":3846,"い.":-1185,"い。":-1185,"いい":5308,"いえ":2079,"いく":3029,"いた":2056,"いっ":1883,"いる":5600,"いわ":1527,"うち":1117,"うと":4798,"えと":1454,"か.":2857,"か。":2857,"かけ":-743,"かっ":-4098,"かに":-669,"から":6520,"かり":-2670,"が,":1816,"が、":1816,"がき":-4855,"がけ":-1127,"がっ":-913,"がら":-4977,"がり":-2064,"きた":1645,"けど":1374,"こと":7397,"この":1542,"ころ":-2757,"さい":-714,"さを":976,"し,":1557,"し、":1557,"しい":-3714,"した":3562,"して":1449,"しな":2608,"しま":1200,"す.":-1310,"す。":-1310,"する":6521,"ず,":3426,"ず、":3426,"ずに":841,"そう":428,"た.":8875,"た。":8875,"たい":-594,"たの":812,"たり":-1183,"たる":-853,"だ.":4098,"だ。":4098,"だっ":1004,"った":-4748,"って":300,"てい":6240,"てお":855,"ても":302,"です":1437,"でに":-1482,"では":2295,"とう":-1387,"とし":2266,"との":541,"とも":-3543,"どう":4664,"ない":1796,"なく":-903,"など":2135,"に,":-1021,"に、":-1021,"にし":1771,"にな":1906,"には":2644,"の,":-724,"の、":-724,"の子":-1e3,"は,":1337,"は、":1337,"べき":2181,"まし":1113,"ます":6943,"まっ":-1549,"まで":6154,"まれ":-793,"らし":1479,"られ":6820,"るる":3818,"れ,":854,"れ、":854,"れた":1850,"れて":1375,"れば":-3246,"れる":1091,"われ":-605,"んだ":606,"んで":798,"カ月":990,"会議":860,"入り":1232,"大会":2217,"始め":1681,"市":965,"新聞":-5055,"日,":974,"日、":974,"社会":2024,"カ月":990},this.TC1__={AAA:1093,HHH:1029,HHM:580,HII:998,HOH:-390,HOM:-331,IHI:1169,IOH:-142,IOI:-1015,IOM:467,MMH:187,OOI:-1832},this.TC2__={HHO:2088,HII:-1023,HMM:-1154,IHI:-1965,KKH:703,OII:-2649},this.TC3__={AAA:-294,HHH:346,HHI:-341,HII:-1088,HIK:731,HOH:-1486,IHH:128,IHI:-3041,IHO:-1935,IIH:-825,IIM:-1035,IOI:-542,KHH:-1216,KKA:491,KKH:-1217,KOK:-1009,MHH:-2694,MHM:-457,MHO:123,MMH:-471,NNH:-1689,NNO:662,OHO:-3393},this.TC4__={HHH:-203,HHI:1344,HHK:365,HHM:-122,HHN:182,HHO:669,HIH:804,HII:679,HOH:446,IHH:695,IHO:-2324,IIH:321,III:1497,IIO:656,IOO:54,KAK:4845,KKA:3386,KKK:3065,MHH:-405,MHI:201,MMH:-241,MMM:661,MOM:841},this.TQ1__={BHHH:-227,BHHI:316,BHIH:-132,BIHH:60,BIII:1595,BNHH:-744,BOHH:225,BOOO:-908,OAKK:482,OHHH:281,OHIH:249,OIHI:200,OIIH:-68},this.TQ2__={BIHH:-1401,BIII:-1033,BKAK:-543,BOOO:-5591},this.TQ3__={BHHH:478,BHHM:-1073,BHIH:222,BHII:-504,BIIH:-116,BIII:-105,BMHI:-863,BMHM:-464,BOMH:620,OHHH:346,OHHI:1729,OHII:997,OHMH:481,OIHH:623,OIIH:1344,OKAK:2792,OKHH:587,OKKA:679,OOHH:110,OOII:-685},this.TQ4__={BHHH:-721,BHHM:-3604,BHII:-966,BIIH:-607,BIII:-2181,OAAA:-2763,OAKK:180,OHHH:-294,OHHI:2446,OHHO:480,OHIH:-1573,OIHH:1935,OIHI:-493,OIIH:626,OIII:-4007,OKAK:-8156},this.TW1__={"につい":-4681,"東京都":2026},this.TW2__={"ある程":-2049,"いった":-1256,"ころが":-2434,"しょう":3873,"その後":-4430,"だって":-1049,"ていた":1833,"として":-4657,"ともに":-4517,"もので":1882,"一気に":-792,"初めて":-1512,"同時に":-8097,"大きな":-1255,"対して":-2721,"社会党":-3216},this.TW3__={"いただ":-1734,"してい":1314,"として":-4314,"につい":-5483,"にとっ":-5989,"に当た":-6247,"ので,":-727,"ので、":-727,"のもの":-600,"れから":-3752,"十二月":-2287},this.TW4__={"いう.":8576,"いう。":8576,"からな":-2348,"してい":2958,"たが,":1516,"たが、":1516,"ている":1538,"という":1349,"ました":5543,"ません":1097,"ようと":-4258,"よると":5865},this.UC1__={A:484,K:93,M:645,O:-505},this.UC2__={A:819,H:1059,I:409,M:3987,N:5775,O:646},this.UC3__={A:-1370,I:2311},this.UC4__={A:-2643,H:1809,I:-1032,K:-3450,M:3565,N:3876,O:6646},this.UC5__={H:313,I:-1238,K:-799,M:539,O:-831},this.UC6__={H:-506,I:-253,K:87,M:247,O:-387},this.UP1__={O:-214},this.UP2__={B:69,O:935},this.UP3__={B:189},this.UQ1__={BH:21,BI:-12,BK:-99,BN:142,BO:-56,OH:-95,OI:477,OK:410,OO:-2422},this.UQ2__={BH:216,BI:113,OK:1759},this.UQ3__={BA:-479,BH:42,BI:1913,BK:-7198,BM:3160,BN:6427,BO:14761,OI:-827,ON:-3212},this.UW1__={",":156,"、":156,"「":-463,"あ":-941,"う":-127,"が":-553,"き":121,"こ":505,"で":-201,"と":-547,"ど":-123,"に":-789,"の":-185,"は":-847,"も":-466,"や":-470,"よ":182,"ら":-292,"り":208,"れ":169,"を":-446,"ん":-137,"・":-135,"主":-402,"京":-268,"区":-912,"午":871,"国":-460,"大":561,"委":729,"市":-411,"日":-141,"理":361,"生":-408,"県":-386,"都":-718,"「":-463,"・":-135},this.UW2__={",":-829,"、":-829,"〇":892,"「":-645,"」":3145,"あ":-538,"い":505,"う":134,"お":-502,"か":1454,"が":-856,"く":-412,"こ":1141,"さ":878,"ざ":540,"し":1529,"す":-675,"せ":300,"そ":-1011,"た":188,"だ":1837,"つ":-949,"て":-291,"で":-268,"と":-981,"ど":1273,"な":1063,"に":-1764,"の":130,"は":-409,"ひ":-1273,"べ":1261,"ま":600,"も":-1263,"や":-402,"よ":1639,"り":-579,"る":-694,"れ":571,"を":-2516,"ん":2095,"ア":-587,"カ":306,"キ":568,"ッ":831,"三":-758,"不":-2150,"世":-302,"中":-968,"主":-861,"事":492,"人":-123,"会":978,"保":362,"入":548,"初":-3025,"副":-1566,"北":-3414,"区":-422,"大":-1769,"天":-865,"太":-483,"子":-1519,"学":760,"実":1023,"小":-2009,"市":-813,"年":-1060,"強":1067,"手":-1519,"揺":-1033,"政":1522,"文":-1355,"新":-1682,"日":-1815,"明":-1462,"最":-630,"朝":-1843,"本":-1650,"東":-931,"果":-665,"次":-2378,"民":-180,"気":-1740,"理":752,"発":529,"目":-1584,"相":-242,"県":-1165,"立":-763,"第":810,"米":509,"自":-1353,"行":838,"西":-744,"見":-3874,"調":1010,"議":1198,"込":3041,"開":1758,"間":-1257,"「":-645,"」":3145,"ッ":831,"ア":-587,"カ":306,"キ":568},this.UW3__={",":4889,1:-800,"−":-1723,"、":4889,"々":-2311,"〇":5827,"」":2670,"〓":-3573,"あ":-2696,"い":1006,"う":2342,"え":1983,"お":-4864,"か":-1163,"が":3271,"く":1004,"け":388,"げ":401,"こ":-3552,"ご":-3116,"さ":-1058,"し":-395,"す":584,"せ":3685,"そ":-5228,"た":842,"ち":-521,"っ":-1444,"つ":-1081,"て":6167,"で":2318,"と":1691,"ど":-899,"な":-2788,"に":2745,"の":4056,"は":4555,"ひ":-2171,"ふ":-1798,"へ":1199,"ほ":-5516,"ま":-4384,"み":-120,"め":1205,"も":2323,"や":-788,"よ":-202,"ら":727,"り":649,"る":5905,"れ":2773,"わ":-1207,"を":6620,"ん":-518,"ア":551,"グ":1319,"ス":874,"ッ":-1350,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278,"・":-3794,"一":-1619,"下":-1759,"世":-2087,"両":3815,"中":653,"主":-758,"予":-1193,"二":974,"人":2742,"今":792,"他":1889,"以":-1368,"低":811,"何":4265,"作":-361,"保":-2439,"元":4858,"党":3593,"全":1574,"公":-3030,"六":755,"共":-1880,"円":5807,"再":3095,"分":457,"初":2475,"別":1129,"前":2286,"副":4437,"力":365,"動":-949,"務":-1872,"化":1327,"北":-1038,"区":4646,"千":-2309,"午":-783,"協":-1006,"口":483,"右":1233,"各":3588,"合":-241,"同":3906,"和":-837,"員":4513,"国":642,"型":1389,"場":1219,"外":-241,"妻":2016,"学":-1356,"安":-423,"実":-1008,"家":1078,"小":-513,"少":-3102,"州":1155,"市":3197,"平":-1804,"年":2416,"広":-1030,"府":1605,"度":1452,"建":-2352,"当":-3885,"得":1905,"思":-1291,"性":1822,"戸":-488,"指":-3973,"政":-2013,"教":-1479,"数":3222,"文":-1489,"新":1764,"日":2099,"旧":5792,"昨":-661,"時":-1248,"曜":-951,"最":-937,"月":4125,"期":360,"李":3094,"村":364,"東":-805,"核":5156,"森":2438,"業":484,"氏":2613,"民":-1694,"決":-1073,"法":1868,"海":-495,"無":979,"物":461,"特":-3850,"生":-273,"用":914,"町":1215,"的":7313,"直":-1835,"省":792,"県":6293,"知":-1528,"私":4231,"税":401,"立":-960,"第":1201,"米":7767,"系":3066,"約":3663,"級":1384,"統":-4229,"総":1163,"線":1255,"者":6457,"能":725,"自":-2869,"英":785,"見":1044,"調":-562,"財":-733,"費":1777,"車":1835,"軍":1375,"込":-1504,"通":-1136,"選":-681,"郎":1026,"郡":4404,"部":1200,"金":2163,"長":421,"開":-1432,"間":1302,"関":-1282,"雨":2009,"電":-1045,"非":2066,"駅":1620,"1":-800,"」":2670,"・":-3794,"ッ":-1350,"ア":551,"グ":1319,"ス":874,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278},this.UW4__={",":3930,".":3508,"―":-4841,"、":3930,"。":3508,"〇":4999,"「":1895,"」":3798,"〓":-5156,"あ":4752,"い":-3435,"う":-640,"え":-2514,"お":2405,"か":530,"が":6006,"き":-4482,"ぎ":-3821,"く":-3788,"け":-4376,"げ":-4734,"こ":2255,"ご":1979,"さ":2864,"し":-843,"じ":-2506,"す":-731,"ず":1251,"せ":181,"そ":4091,"た":5034,"だ":5408,"ち":-3654,"っ":-5882,"つ":-1659,"て":3994,"で":7410,"と":4547,"な":5433,"に":6499,"ぬ":1853,"ね":1413,"の":7396,"は":8578,"ば":1940,"ひ":4249,"び":-4134,"ふ":1345,"へ":6665,"べ":-744,"ほ":1464,"ま":1051,"み":-2082,"む":-882,"め":-5046,"も":4169,"ゃ":-2666,"や":2795,"ょ":-1544,"よ":3351,"ら":-2922,"り":-9726,"る":-14896,"れ":-2613,"ろ":-4570,"わ":-1783,"を":13150,"ん":-2352,"カ":2145,"コ":1789,"セ":1287,"ッ":-724,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637,"・":-4371,"ー":-11870,"一":-2069,"中":2210,"予":782,"事":-190,"井":-1768,"人":1036,"以":544,"会":950,"体":-1286,"作":530,"側":4292,"先":601,"党":-2006,"共":-1212,"内":584,"円":788,"初":1347,"前":1623,"副":3879,"力":-302,"動":-740,"務":-2715,"化":776,"区":4517,"協":1013,"参":1555,"合":-1834,"和":-681,"員":-910,"器":-851,"回":1500,"国":-619,"園":-1200,"地":866,"場":-1410,"塁":-2094,"士":-1413,"多":1067,"大":571,"子":-4802,"学":-1397,"定":-1057,"寺":-809,"小":1910,"屋":-1328,"山":-1500,"島":-2056,"川":-2667,"市":2771,"年":374,"庁":-4556,"後":456,"性":553,"感":916,"所":-1566,"支":856,"改":787,"政":2182,"教":704,"文":522,"方":-856,"日":1798,"時":1829,"最":845,"月":-9066,"木":-485,"来":-442,"校":-360,"業":-1043,"氏":5388,"民":-2716,"気":-910,"沢":-939,"済":-543,"物":-735,"率":672,"球":-1267,"生":-1286,"産":-1101,"田":-2900,"町":1826,"的":2586,"目":922,"省":-3485,"県":2997,"空":-867,"立":-2112,"第":788,"米":2937,"系":786,"約":2171,"経":1146,"統":-1169,"総":940,"線":-994,"署":749,"者":2145,"能":-730,"般":-852,"行":-792,"規":792,"警":-1184,"議":-244,"谷":-1e3,"賞":730,"車":-1481,"軍":1158,"輪":-1433,"込":-3370,"近":929,"道":-1291,"選":2596,"郎":-4866,"都":1192,"野":-1100,"銀":-2213,"長":357,"間":-2344,"院":-2297,"際":-2604,"電":-878,"領":-1659,"題":-792,"館":-1984,"首":1749,"高":2120,"「":1895,"」":3798,"・":-4371,"ッ":-724,"ー":-11870,"カ":2145,"コ":1789,"セ":1287,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637},this.UW5__={",":465,".":-299,1:-514,E2:-32768,"]":-2762,"、":465,"。":-299,"「":363,"あ":1655,"い":331,"う":-503,"え":1199,"お":527,"か":647,"が":-421,"き":1624,"ぎ":1971,"く":312,"げ":-983,"さ":-1537,"し":-1371,"す":-852,"だ":-1186,"ち":1093,"っ":52,"つ":921,"て":-18,"で":-850,"と":-127,"ど":1682,"な":-787,"に":-1224,"の":-635,"は":-578,"べ":1001,"み":502,"め":865,"ゃ":3350,"ょ":854,"り":-208,"る":429,"れ":504,"わ":419,"を":-1264,"ん":327,"イ":241,"ル":451,"ン":-343,"中":-871,"京":722,"会":-1153,"党":-654,"務":3519,"区":-901,"告":848,"員":2104,"大":-1296,"学":-548,"定":1785,"嵐":-1304,"市":-2991,"席":921,"年":1763,"思":872,"所":-814,"挙":1618,"新":-1682,"日":218,"月":-4353,"査":932,"格":1356,"機":-1508,"氏":-1347,"田":240,"町":-3912,"的":-3149,"相":1319,"省":-1052,"県":-4003,"研":-997,"社":-278,"空":-813,"統":1955,"者":-2233,"表":663,"語":-1073,"議":1219,"選":-1018,"郎":-368,"長":786,"間":1191,"題":2368,"館":-689,"1":-514,"E2":-32768,"「":363,"イ":241,"ル":451,"ン":-343},this.UW6__={",":227,".":808,1:-270,E1:306,"、":227,"。":808,"あ":-307,"う":189,"か":241,"が":-73,"く":-121,"こ":-200,"じ":1782,"す":383,"た":-428,"っ":573,"て":-1014,"で":101,"と":-105,"な":-253,"に":-149,"の":-417,"は":-236,"も":-206,"り":187,"る":-135,"を":195,"ル":-673,"ン":-496,"一":-277,"中":201,"件":-800,"会":624,"前":302,"区":1792,"員":-1212,"委":798,"学":-960,"市":887,"広":-695,"後":535,"業":-697,"相":753,"社":-507,"福":974,"空":-822,"者":1811,"連":463,"郎":1082,"1":-270,"E1":306,"ル":-673,"ン":-496},this}t.prototype.ctype_=function(_){for(var t in this.chartype_)if(_.match(this.chartype_[t][0]))return this.chartype_[t][1];return"O"},t.prototype.ts_=function(_){return _||0},t.prototype.segment=function(_){if(null==_||null==_||""==_)return[];var t=[],H=["B3","B2","B1"],s=["O","O","O"],h=_.split("");for(K=0;K0&&(t.push(i),i="",N="B"),I=O,O=B,B=N,i+=H[K]}return t.push(i),t},_.TinySegmenter=t}}); \ No newline at end of file diff --git a/assets/javascripts/modernizr.1aa3b519.js b/assets/javascripts/modernizr.1aa3b519.js new file mode 100644 index 000000000..14e111fc3 --- /dev/null +++ b/assets/javascripts/modernizr.1aa3b519.js @@ -0,0 +1 @@ +!function(e,t){for(var n in t)e[n]=t[n]}(window,function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=4)}({4:function(e,t,n){"use strict";n(5)},5:function(e,t){!function(t){!function(e,t,n){function r(e,t){return typeof e===t}function o(e){var t=_.className,n=C._config.classPrefix||"";if(T&&(t=t.baseVal),C._config.enableJSClass){var r=new RegExp("(^|\\s)"+n+"no-js(\\s|$)");t=t.replace(r,"$1"+n+"js$2")}C._config.enableClasses&&(t+=" "+n+e.join(" "+n),T?_.className.baseVal=t:_.className=t)}function i(e,t){if("object"==typeof e)for(var n in e)b(e,n)&&i(n,e[n]);else{e=e.toLowerCase();var r=e.split("."),s=C[r[0]];if(2==r.length&&(s=s[r[1]]),void 0!==s)return C;t="function"==typeof t?t():t,1==r.length?C[r[0]]=t:(!C[r[0]]||C[r[0]]instanceof Boolean||(C[r[0]]=new Boolean(C[r[0]])),C[r[0]][r[1]]=t),o([(t&&0!=t?"":"no-")+r.join("-")]),C._trigger(e,t)}return C}function s(){return"function"!=typeof t.createElement?t.createElement(arguments[0]):T?t.createElementNS.call(t,"http://www.w3.org/2000/svg",arguments[0]):t.createElement.apply(t,arguments)}function a(){var e=t.body;return e||(e=s(T?"svg":"body"),e.fake=!0),e}function u(e,n,r,o){var i,u,l,f,c="modernizr",d=s("div"),p=a();if(parseInt(r,10))for(;r--;)l=s("div"),l.id=o?o[r]:c+(r+1),d.appendChild(l);return i=s("style"),i.type="text/css",i.id="s"+c,(p.fake?p:d).appendChild(i),p.appendChild(d),i.styleSheet?i.styleSheet.cssText=e:i.appendChild(t.createTextNode(e)),d.id=c,p.fake&&(p.style.background="",p.style.overflow="hidden",f=_.style.overflow,_.style.overflow="hidden",_.appendChild(p)),u=n(d,e),p.fake?(p.parentNode.removeChild(p),_.style.overflow=f,_.offsetHeight):d.parentNode.removeChild(d),!!u}function l(e,t){return!!~(""+e).indexOf(t)}function f(e){return e.replace(/([A-Z])/g,function(e,t){return"-"+t.toLowerCase()}).replace(/^ms-/,"-ms-")}function c(t,n,r){var o;if("getComputedStyle"in e){o=getComputedStyle.call(e,t,n);var i=e.console;if(null!==o)r&&(o=o.getPropertyValue(r));else if(i){var s=i.error?"error":"log";i[s].call(i,"getComputedStyle returning null, its possible modernizr test results are inaccurate")}}else o=!n&&t.currentStyle&&t.currentStyle[r];return o}function d(t,r){var o=t.length;if("CSS"in e&&"supports"in e.CSS){for(;o--;)if(e.CSS.supports(f(t[o]),r))return!0;return!1}if("CSSSupportsRule"in e){for(var i=[];o--;)i.push("("+f(t[o])+":"+r+")");return i=i.join(" or "),u("@supports ("+i+") { #modernizr { position: absolute; } }",function(e){return"absolute"==c(e,null,"position")})}return n}function p(e){return e.replace(/([a-z])-([a-z])/g,function(e,t,n){return t+n.toUpperCase()}).replace(/^-/,"")}function h(e,t,o,i){function a(){f&&(delete j.style,delete j.modElem)}if(i=!r(i,"undefined")&&i,!r(o,"undefined")){var u=d(e,o);if(!r(u,"undefined"))return u}for(var f,c,h,m,v,g=["modernizr","tspan","samp"];!j.style&&g.length;)f=!0,j.modElem=s(g.shift()),j.style=j.modElem.style;for(h=e.length,c=0;h>c;c++)if(m=e[c],v=j.style[m],l(m,"-")&&(m=p(m)),j.style[m]!==n){if(i||r(o,"undefined"))return a(),"pfx"!=t||m;try{j.style[m]=o}catch(e){}if(j.style[m]!=v)return a(),"pfx"!=t||m}return a(),!1}function m(e,t){return function(){return e.apply(t,arguments)}}function v(e,t,n){var o;for(var i in e)if(e[i]in t)return!1===n?e[i]:(o=t[e[i]],r(o,"function")?m(o,n||t):o);return!1}function g(e,t,n,o,i){var s=e.charAt(0).toUpperCase()+e.slice(1),a=(e+" "+k.join(s+" ")+s).split(" ");return r(t,"string")||r(t,"undefined")?h(a,t,o,i):(a=(e+" "+A.join(s+" ")+s).split(" "),v(a,t,n))}function y(e,t,r){return g(e,n,n,t,r)}var w=[],S={_version:"3.5.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var n=this;setTimeout(function(){t(n[e])},0)},addTest:function(e,t,n){w.push({name:e,fn:t,options:n})},addAsyncTest:function(e){w.push({name:null,fn:e})}},C=function(){};C.prototype=S,C=new C;var b,x=[],_=t.documentElement,T="svg"===_.nodeName.toLowerCase();!function(){var e={}.hasOwnProperty;b=r(e,"undefined")||r(e.call,"undefined")?function(e,t){return t in e&&r(e.constructor.prototype[t],"undefined")}:function(t,n){return e.call(t,n)}}(),S._l={},S.on=function(e,t){this._l[e]||(this._l[e]=[]),this._l[e].push(t),C.hasOwnProperty(e)&&setTimeout(function(){C._trigger(e,C[e])},0)},S._trigger=function(e,t){if(this._l[e]){var n=this._l[e];setTimeout(function(){var e;for(e=0;e.md-nav__link{color:inherit}button[data-md-color-primary=pink]{background-color:#e91e63}[data-md-color-primary=pink] .md-typeset a{color:#e91e63}[data-md-color-primary=pink] .md-header,[data-md-color-primary=pink] .md-hero{background-color:#e91e63}[data-md-color-primary=pink] .md-nav__link--active,[data-md-color-primary=pink] .md-nav__link:active{color:#e91e63}[data-md-color-primary=pink] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=purple]{background-color:#ab47bc}[data-md-color-primary=purple] .md-typeset a{color:#ab47bc}[data-md-color-primary=purple] .md-header,[data-md-color-primary=purple] .md-hero{background-color:#ab47bc}[data-md-color-primary=purple] .md-nav__link--active,[data-md-color-primary=purple] .md-nav__link:active{color:#ab47bc}[data-md-color-primary=purple] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=deep-purple]{background-color:#7e57c2}[data-md-color-primary=deep-purple] .md-typeset a{color:#7e57c2}[data-md-color-primary=deep-purple] .md-header,[data-md-color-primary=deep-purple] .md-hero{background-color:#7e57c2}[data-md-color-primary=deep-purple] .md-nav__link--active,[data-md-color-primary=deep-purple] .md-nav__link:active{color:#7e57c2}[data-md-color-primary=deep-purple] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=indigo]{background-color:#3f51b5}[data-md-color-primary=indigo] .md-typeset a{color:#3f51b5}[data-md-color-primary=indigo] .md-header,[data-md-color-primary=indigo] .md-hero{background-color:#3f51b5}[data-md-color-primary=indigo] .md-nav__link--active,[data-md-color-primary=indigo] .md-nav__link:active{color:#3f51b5}[data-md-color-primary=indigo] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=blue]{background-color:#2196f3}[data-md-color-primary=blue] .md-typeset a{color:#2196f3}[data-md-color-primary=blue] .md-header,[data-md-color-primary=blue] .md-hero{background-color:#2196f3}[data-md-color-primary=blue] .md-nav__link--active,[data-md-color-primary=blue] .md-nav__link:active{color:#2196f3}[data-md-color-primary=blue] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=light-blue]{background-color:#03a9f4}[data-md-color-primary=light-blue] .md-typeset a{color:#03a9f4}[data-md-color-primary=light-blue] .md-header,[data-md-color-primary=light-blue] .md-hero{background-color:#03a9f4}[data-md-color-primary=light-blue] .md-nav__link--active,[data-md-color-primary=light-blue] .md-nav__link:active{color:#03a9f4}[data-md-color-primary=light-blue] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=cyan]{background-color:#00bcd4}[data-md-color-primary=cyan] .md-typeset a{color:#00bcd4}[data-md-color-primary=cyan] .md-header,[data-md-color-primary=cyan] .md-hero{background-color:#00bcd4}[data-md-color-primary=cyan] .md-nav__link--active,[data-md-color-primary=cyan] .md-nav__link:active{color:#00bcd4}[data-md-color-primary=cyan] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=teal]{background-color:#009688}[data-md-color-primary=teal] .md-typeset a{color:#009688}[data-md-color-primary=teal] .md-header,[data-md-color-primary=teal] .md-hero{background-color:#009688}[data-md-color-primary=teal] .md-nav__link--active,[data-md-color-primary=teal] .md-nav__link:active{color:#009688}[data-md-color-primary=teal] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=green]{background-color:#4caf50}[data-md-color-primary=green] .md-typeset a{color:#4caf50}[data-md-color-primary=green] .md-header,[data-md-color-primary=green] .md-hero{background-color:#4caf50}[data-md-color-primary=green] .md-nav__link--active,[data-md-color-primary=green] .md-nav__link:active{color:#4caf50}[data-md-color-primary=green] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=light-green]{background-color:#7cb342}[data-md-color-primary=light-green] .md-typeset a{color:#7cb342}[data-md-color-primary=light-green] .md-header,[data-md-color-primary=light-green] .md-hero{background-color:#7cb342}[data-md-color-primary=light-green] .md-nav__link--active,[data-md-color-primary=light-green] .md-nav__link:active{color:#7cb342}[data-md-color-primary=light-green] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=lime]{background-color:#c0ca33}[data-md-color-primary=lime] .md-typeset a{color:#c0ca33}[data-md-color-primary=lime] .md-header,[data-md-color-primary=lime] .md-hero{background-color:#c0ca33}[data-md-color-primary=lime] .md-nav__link--active,[data-md-color-primary=lime] .md-nav__link:active{color:#c0ca33}[data-md-color-primary=lime] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=yellow]{background-color:#f9a825}[data-md-color-primary=yellow] .md-typeset a{color:#f9a825}[data-md-color-primary=yellow] .md-header,[data-md-color-primary=yellow] .md-hero{background-color:#f9a825}[data-md-color-primary=yellow] .md-nav__link--active,[data-md-color-primary=yellow] .md-nav__link:active{color:#f9a825}[data-md-color-primary=yellow] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=amber]{background-color:#ffa000}[data-md-color-primary=amber] .md-typeset a{color:#ffa000}[data-md-color-primary=amber] .md-header,[data-md-color-primary=amber] .md-hero{background-color:#ffa000}[data-md-color-primary=amber] .md-nav__link--active,[data-md-color-primary=amber] .md-nav__link:active{color:#ffa000}[data-md-color-primary=amber] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=orange]{background-color:#fb8c00}[data-md-color-primary=orange] .md-typeset a{color:#fb8c00}[data-md-color-primary=orange] .md-header,[data-md-color-primary=orange] .md-hero{background-color:#fb8c00}[data-md-color-primary=orange] .md-nav__link--active,[data-md-color-primary=orange] .md-nav__link:active{color:#fb8c00}[data-md-color-primary=orange] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=deep-orange]{background-color:#ff7043}[data-md-color-primary=deep-orange] .md-typeset a{color:#ff7043}[data-md-color-primary=deep-orange] .md-header,[data-md-color-primary=deep-orange] .md-hero{background-color:#ff7043}[data-md-color-primary=deep-orange] .md-nav__link--active,[data-md-color-primary=deep-orange] .md-nav__link:active{color:#ff7043}[data-md-color-primary=deep-orange] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=brown]{background-color:#795548}[data-md-color-primary=brown] .md-typeset a{color:#795548}[data-md-color-primary=brown] .md-header,[data-md-color-primary=brown] .md-hero{background-color:#795548}[data-md-color-primary=brown] .md-nav__link--active,[data-md-color-primary=brown] .md-nav__link:active{color:#795548}[data-md-color-primary=brown] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=grey]{background-color:#757575}[data-md-color-primary=grey] .md-typeset a{color:#757575}[data-md-color-primary=grey] .md-header,[data-md-color-primary=grey] .md-hero{background-color:#757575}[data-md-color-primary=grey] .md-nav__link--active,[data-md-color-primary=grey] .md-nav__link:active{color:#757575}[data-md-color-primary=grey] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=blue-grey]{background-color:#546e7a}[data-md-color-primary=blue-grey] .md-typeset a{color:#546e7a}[data-md-color-primary=blue-grey] .md-header,[data-md-color-primary=blue-grey] .md-hero{background-color:#546e7a}[data-md-color-primary=blue-grey] .md-nav__link--active,[data-md-color-primary=blue-grey] .md-nav__link:active{color:#546e7a}[data-md-color-primary=blue-grey] .md-nav__item--nested>.md-nav__link{color:inherit}button[data-md-color-primary=white]{box-shadow:inset 0 0 .1rem rgba(0,0,0,.54)}[data-md-color-primary=white] .md-header,[data-md-color-primary=white] .md-hero,button[data-md-color-primary=white]{background-color:#fff;color:rgba(0,0,0,.87)}[data-md-color-primary=white] .md-hero--expand{border-bottom:.1rem solid rgba(0,0,0,.07)}button[data-md-color-accent=red]{background-color:#ff1744}[data-md-color-accent=red] .md-typeset a:active,[data-md-color-accent=red] .md-typeset a:hover{color:#ff1744}[data-md-color-accent=red] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=red] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#ff1744}[data-md-color-accent=red] .md-nav__link:focus,[data-md-color-accent=red] .md-nav__link:hover,[data-md-color-accent=red] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=red] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=red] .md-typeset .md-clipboard:active:before,[data-md-color-accent=red] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=red] .md-typeset [id] .headerlink:focus,[data-md-color-accent=red] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=red] .md-typeset [id]:target .headerlink{color:#ff1744}[data-md-color-accent=red] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#ff1744}[data-md-color-accent=red] .md-search-result__link:hover,[data-md-color-accent=red] .md-search-result__link[data-md-state=active]{background-color:rgba(255,23,68,.1)}[data-md-color-accent=red] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#ff1744}[data-md-color-accent=red] .md-source-file:hover:before{background-color:#ff1744}button[data-md-color-accent=pink]{background-color:#f50057}[data-md-color-accent=pink] .md-typeset a:active,[data-md-color-accent=pink] .md-typeset a:hover{color:#f50057}[data-md-color-accent=pink] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=pink] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#f50057}[data-md-color-accent=pink] .md-nav__link:focus,[data-md-color-accent=pink] .md-nav__link:hover,[data-md-color-accent=pink] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=pink] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=pink] .md-typeset .md-clipboard:active:before,[data-md-color-accent=pink] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=pink] .md-typeset [id] .headerlink:focus,[data-md-color-accent=pink] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=pink] .md-typeset [id]:target .headerlink{color:#f50057}[data-md-color-accent=pink] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#f50057}[data-md-color-accent=pink] .md-search-result__link:hover,[data-md-color-accent=pink] .md-search-result__link[data-md-state=active]{background-color:rgba(245,0,87,.1)}[data-md-color-accent=pink] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#f50057}[data-md-color-accent=pink] .md-source-file:hover:before{background-color:#f50057}button[data-md-color-accent=purple]{background-color:#e040fb}[data-md-color-accent=purple] .md-typeset a:active,[data-md-color-accent=purple] .md-typeset a:hover{color:#e040fb}[data-md-color-accent=purple] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=purple] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#e040fb}[data-md-color-accent=purple] .md-nav__link:focus,[data-md-color-accent=purple] .md-nav__link:hover,[data-md-color-accent=purple] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=purple] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=purple] .md-typeset .md-clipboard:active:before,[data-md-color-accent=purple] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=purple] .md-typeset [id] .headerlink:focus,[data-md-color-accent=purple] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=purple] .md-typeset [id]:target .headerlink{color:#e040fb}[data-md-color-accent=purple] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#e040fb}[data-md-color-accent=purple] .md-search-result__link:hover,[data-md-color-accent=purple] .md-search-result__link[data-md-state=active]{background-color:rgba(224,64,251,.1)}[data-md-color-accent=purple] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#e040fb}[data-md-color-accent=purple] .md-source-file:hover:before{background-color:#e040fb}button[data-md-color-accent=deep-purple]{background-color:#7c4dff}[data-md-color-accent=deep-purple] .md-typeset a:active,[data-md-color-accent=deep-purple] .md-typeset a:hover{color:#7c4dff}[data-md-color-accent=deep-purple] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=deep-purple] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#7c4dff}[data-md-color-accent=deep-purple] .md-nav__link:focus,[data-md-color-accent=deep-purple] .md-nav__link:hover,[data-md-color-accent=deep-purple] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=deep-purple] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=deep-purple] .md-typeset .md-clipboard:active:before,[data-md-color-accent=deep-purple] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=deep-purple] .md-typeset [id] .headerlink:focus,[data-md-color-accent=deep-purple] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=deep-purple] .md-typeset [id]:target .headerlink{color:#7c4dff}[data-md-color-accent=deep-purple] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#7c4dff}[data-md-color-accent=deep-purple] .md-search-result__link:hover,[data-md-color-accent=deep-purple] .md-search-result__link[data-md-state=active]{background-color:rgba(124,77,255,.1)}[data-md-color-accent=deep-purple] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#7c4dff}[data-md-color-accent=deep-purple] .md-source-file:hover:before{background-color:#7c4dff}button[data-md-color-accent=indigo]{background-color:#536dfe}[data-md-color-accent=indigo] .md-typeset a:active,[data-md-color-accent=indigo] .md-typeset a:hover{color:#536dfe}[data-md-color-accent=indigo] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=indigo] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#536dfe}[data-md-color-accent=indigo] .md-nav__link:focus,[data-md-color-accent=indigo] .md-nav__link:hover,[data-md-color-accent=indigo] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=indigo] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=indigo] .md-typeset .md-clipboard:active:before,[data-md-color-accent=indigo] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=indigo] .md-typeset [id] .headerlink:focus,[data-md-color-accent=indigo] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=indigo] .md-typeset [id]:target .headerlink{color:#536dfe}[data-md-color-accent=indigo] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#536dfe}[data-md-color-accent=indigo] .md-search-result__link:hover,[data-md-color-accent=indigo] .md-search-result__link[data-md-state=active]{background-color:rgba(83,109,254,.1)}[data-md-color-accent=indigo] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#536dfe}[data-md-color-accent=indigo] .md-source-file:hover:before{background-color:#536dfe}button[data-md-color-accent=blue]{background-color:#448aff}[data-md-color-accent=blue] .md-typeset a:active,[data-md-color-accent=blue] .md-typeset a:hover{color:#448aff}[data-md-color-accent=blue] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=blue] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#448aff}[data-md-color-accent=blue] .md-nav__link:focus,[data-md-color-accent=blue] .md-nav__link:hover,[data-md-color-accent=blue] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=blue] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=blue] .md-typeset .md-clipboard:active:before,[data-md-color-accent=blue] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=blue] .md-typeset [id] .headerlink:focus,[data-md-color-accent=blue] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=blue] .md-typeset [id]:target .headerlink{color:#448aff}[data-md-color-accent=blue] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#448aff}[data-md-color-accent=blue] .md-search-result__link:hover,[data-md-color-accent=blue] .md-search-result__link[data-md-state=active]{background-color:rgba(68,138,255,.1)}[data-md-color-accent=blue] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#448aff}[data-md-color-accent=blue] .md-source-file:hover:before{background-color:#448aff}button[data-md-color-accent=light-blue]{background-color:#0091ea}[data-md-color-accent=light-blue] .md-typeset a:active,[data-md-color-accent=light-blue] .md-typeset a:hover{color:#0091ea}[data-md-color-accent=light-blue] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=light-blue] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#0091ea}[data-md-color-accent=light-blue] .md-nav__link:focus,[data-md-color-accent=light-blue] .md-nav__link:hover,[data-md-color-accent=light-blue] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=light-blue] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=light-blue] .md-typeset .md-clipboard:active:before,[data-md-color-accent=light-blue] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=light-blue] .md-typeset [id] .headerlink:focus,[data-md-color-accent=light-blue] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=light-blue] .md-typeset [id]:target .headerlink{color:#0091ea}[data-md-color-accent=light-blue] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#0091ea}[data-md-color-accent=light-blue] .md-search-result__link:hover,[data-md-color-accent=light-blue] .md-search-result__link[data-md-state=active]{background-color:rgba(0,145,234,.1)}[data-md-color-accent=light-blue] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#0091ea}[data-md-color-accent=light-blue] .md-source-file:hover:before{background-color:#0091ea}button[data-md-color-accent=cyan]{background-color:#00b8d4}[data-md-color-accent=cyan] .md-typeset a:active,[data-md-color-accent=cyan] .md-typeset a:hover{color:#00b8d4}[data-md-color-accent=cyan] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=cyan] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#00b8d4}[data-md-color-accent=cyan] .md-nav__link:focus,[data-md-color-accent=cyan] .md-nav__link:hover,[data-md-color-accent=cyan] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=cyan] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=cyan] .md-typeset .md-clipboard:active:before,[data-md-color-accent=cyan] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=cyan] .md-typeset [id] .headerlink:focus,[data-md-color-accent=cyan] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=cyan] .md-typeset [id]:target .headerlink{color:#00b8d4}[data-md-color-accent=cyan] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#00b8d4}[data-md-color-accent=cyan] .md-search-result__link:hover,[data-md-color-accent=cyan] .md-search-result__link[data-md-state=active]{background-color:rgba(0,184,212,.1)}[data-md-color-accent=cyan] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#00b8d4}[data-md-color-accent=cyan] .md-source-file:hover:before{background-color:#00b8d4}button[data-md-color-accent=teal]{background-color:#00bfa5}[data-md-color-accent=teal] .md-typeset a:active,[data-md-color-accent=teal] .md-typeset a:hover{color:#00bfa5}[data-md-color-accent=teal] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=teal] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#00bfa5}[data-md-color-accent=teal] .md-nav__link:focus,[data-md-color-accent=teal] .md-nav__link:hover,[data-md-color-accent=teal] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=teal] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=teal] .md-typeset .md-clipboard:active:before,[data-md-color-accent=teal] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=teal] .md-typeset [id] .headerlink:focus,[data-md-color-accent=teal] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=teal] .md-typeset [id]:target .headerlink{color:#00bfa5}[data-md-color-accent=teal] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#00bfa5}[data-md-color-accent=teal] .md-search-result__link:hover,[data-md-color-accent=teal] .md-search-result__link[data-md-state=active]{background-color:rgba(0,191,165,.1)}[data-md-color-accent=teal] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#00bfa5}[data-md-color-accent=teal] .md-source-file:hover:before{background-color:#00bfa5}button[data-md-color-accent=green]{background-color:#00c853}[data-md-color-accent=green] .md-typeset a:active,[data-md-color-accent=green] .md-typeset a:hover{color:#00c853}[data-md-color-accent=green] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=green] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#00c853}[data-md-color-accent=green] .md-nav__link:focus,[data-md-color-accent=green] .md-nav__link:hover,[data-md-color-accent=green] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=green] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=green] .md-typeset .md-clipboard:active:before,[data-md-color-accent=green] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=green] .md-typeset [id] .headerlink:focus,[data-md-color-accent=green] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=green] .md-typeset [id]:target .headerlink{color:#00c853}[data-md-color-accent=green] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#00c853}[data-md-color-accent=green] .md-search-result__link:hover,[data-md-color-accent=green] .md-search-result__link[data-md-state=active]{background-color:rgba(0,200,83,.1)}[data-md-color-accent=green] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#00c853}[data-md-color-accent=green] .md-source-file:hover:before{background-color:#00c853}button[data-md-color-accent=light-green]{background-color:#64dd17}[data-md-color-accent=light-green] .md-typeset a:active,[data-md-color-accent=light-green] .md-typeset a:hover{color:#64dd17}[data-md-color-accent=light-green] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=light-green] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#64dd17}[data-md-color-accent=light-green] .md-nav__link:focus,[data-md-color-accent=light-green] .md-nav__link:hover,[data-md-color-accent=light-green] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=light-green] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=light-green] .md-typeset .md-clipboard:active:before,[data-md-color-accent=light-green] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=light-green] .md-typeset [id] .headerlink:focus,[data-md-color-accent=light-green] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=light-green] .md-typeset [id]:target .headerlink{color:#64dd17}[data-md-color-accent=light-green] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#64dd17}[data-md-color-accent=light-green] .md-search-result__link:hover,[data-md-color-accent=light-green] .md-search-result__link[data-md-state=active]{background-color:rgba(100,221,23,.1)}[data-md-color-accent=light-green] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#64dd17}[data-md-color-accent=light-green] .md-source-file:hover:before{background-color:#64dd17}button[data-md-color-accent=lime]{background-color:#aeea00}[data-md-color-accent=lime] .md-typeset a:active,[data-md-color-accent=lime] .md-typeset a:hover{color:#aeea00}[data-md-color-accent=lime] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=lime] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#aeea00}[data-md-color-accent=lime] .md-nav__link:focus,[data-md-color-accent=lime] .md-nav__link:hover,[data-md-color-accent=lime] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=lime] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=lime] .md-typeset .md-clipboard:active:before,[data-md-color-accent=lime] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=lime] .md-typeset [id] .headerlink:focus,[data-md-color-accent=lime] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=lime] .md-typeset [id]:target .headerlink{color:#aeea00}[data-md-color-accent=lime] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#aeea00}[data-md-color-accent=lime] .md-search-result__link:hover,[data-md-color-accent=lime] .md-search-result__link[data-md-state=active]{background-color:rgba(174,234,0,.1)}[data-md-color-accent=lime] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#aeea00}[data-md-color-accent=lime] .md-source-file:hover:before{background-color:#aeea00}button[data-md-color-accent=yellow]{background-color:#ffd600}[data-md-color-accent=yellow] .md-typeset a:active,[data-md-color-accent=yellow] .md-typeset a:hover{color:#ffd600}[data-md-color-accent=yellow] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=yellow] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#ffd600}[data-md-color-accent=yellow] .md-nav__link:focus,[data-md-color-accent=yellow] .md-nav__link:hover,[data-md-color-accent=yellow] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=yellow] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=yellow] .md-typeset .md-clipboard:active:before,[data-md-color-accent=yellow] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=yellow] .md-typeset [id] .headerlink:focus,[data-md-color-accent=yellow] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=yellow] .md-typeset [id]:target .headerlink{color:#ffd600}[data-md-color-accent=yellow] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#ffd600}[data-md-color-accent=yellow] .md-search-result__link:hover,[data-md-color-accent=yellow] .md-search-result__link[data-md-state=active]{background-color:rgba(255,214,0,.1)}[data-md-color-accent=yellow] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#ffd600}[data-md-color-accent=yellow] .md-source-file:hover:before{background-color:#ffd600}button[data-md-color-accent=amber]{background-color:#ffab00}[data-md-color-accent=amber] .md-typeset a:active,[data-md-color-accent=amber] .md-typeset a:hover{color:#ffab00}[data-md-color-accent=amber] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=amber] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#ffab00}[data-md-color-accent=amber] .md-nav__link:focus,[data-md-color-accent=amber] .md-nav__link:hover,[data-md-color-accent=amber] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=amber] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=amber] .md-typeset .md-clipboard:active:before,[data-md-color-accent=amber] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=amber] .md-typeset [id] .headerlink:focus,[data-md-color-accent=amber] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=amber] .md-typeset [id]:target .headerlink{color:#ffab00}[data-md-color-accent=amber] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#ffab00}[data-md-color-accent=amber] .md-search-result__link:hover,[data-md-color-accent=amber] .md-search-result__link[data-md-state=active]{background-color:rgba(255,171,0,.1)}[data-md-color-accent=amber] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#ffab00}[data-md-color-accent=amber] .md-source-file:hover:before{background-color:#ffab00}button[data-md-color-accent=orange]{background-color:#ff9100}[data-md-color-accent=orange] .md-typeset a:active,[data-md-color-accent=orange] .md-typeset a:hover{color:#ff9100}[data-md-color-accent=orange] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=orange] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#ff9100}[data-md-color-accent=orange] .md-nav__link:focus,[data-md-color-accent=orange] .md-nav__link:hover,[data-md-color-accent=orange] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=orange] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=orange] .md-typeset .md-clipboard:active:before,[data-md-color-accent=orange] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=orange] .md-typeset [id] .headerlink:focus,[data-md-color-accent=orange] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=orange] .md-typeset [id]:target .headerlink{color:#ff9100}[data-md-color-accent=orange] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#ff9100}[data-md-color-accent=orange] .md-search-result__link:hover,[data-md-color-accent=orange] .md-search-result__link[data-md-state=active]{background-color:rgba(255,145,0,.1)}[data-md-color-accent=orange] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#ff9100}[data-md-color-accent=orange] .md-source-file:hover:before{background-color:#ff9100}button[data-md-color-accent=deep-orange]{background-color:#ff6e40}[data-md-color-accent=deep-orange] .md-typeset a:active,[data-md-color-accent=deep-orange] .md-typeset a:hover{color:#ff6e40}[data-md-color-accent=deep-orange] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,[data-md-color-accent=deep-orange] .md-typeset pre code::-webkit-scrollbar-thumb:hover{background-color:#ff6e40}[data-md-color-accent=deep-orange] .md-nav__link:focus,[data-md-color-accent=deep-orange] .md-nav__link:hover,[data-md-color-accent=deep-orange] .md-typeset .footnote li:hover .footnote-backref:hover,[data-md-color-accent=deep-orange] .md-typeset .footnote li:target .footnote-backref,[data-md-color-accent=deep-orange] .md-typeset .md-clipboard:active:before,[data-md-color-accent=deep-orange] .md-typeset .md-clipboard:hover:before,[data-md-color-accent=deep-orange] .md-typeset [id] .headerlink:focus,[data-md-color-accent=deep-orange] .md-typeset [id]:hover .headerlink:hover,[data-md-color-accent=deep-orange] .md-typeset [id]:target .headerlink{color:#ff6e40}[data-md-color-accent=deep-orange] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#ff6e40}[data-md-color-accent=deep-orange] .md-search-result__link:hover,[data-md-color-accent=deep-orange] .md-search-result__link[data-md-state=active]{background-color:rgba(255,110,64,.1)}[data-md-color-accent=deep-orange] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#ff6e40}[data-md-color-accent=deep-orange] .md-source-file:hover:before{background-color:#ff6e40}@media only screen and (max-width:59.9375em){[data-md-color-primary=red] .md-nav__source{background-color:rgba(190,66,64,.9675)}[data-md-color-primary=pink] .md-nav__source{background-color:rgba(185,24,79,.9675)}[data-md-color-primary=purple] .md-nav__source{background-color:rgba(136,57,150,.9675)}[data-md-color-primary=deep-purple] .md-nav__source{background-color:rgba(100,69,154,.9675)}[data-md-color-primary=indigo] .md-nav__source{background-color:rgba(50,64,144,.9675)}[data-md-color-primary=blue] .md-nav__source{background-color:rgba(26,119,193,.9675)}[data-md-color-primary=light-blue] .md-nav__source{background-color:rgba(2,134,194,.9675)}[data-md-color-primary=cyan] .md-nav__source{background-color:rgba(0,150,169,.9675)}[data-md-color-primary=teal] .md-nav__source{background-color:rgba(0,119,108,.9675)}[data-md-color-primary=green] .md-nav__source{background-color:rgba(60,139,64,.9675)}[data-md-color-primary=light-green] .md-nav__source{background-color:rgba(99,142,53,.9675)}[data-md-color-primary=lime] .md-nav__source{background-color:rgba(153,161,41,.9675)}[data-md-color-primary=yellow] .md-nav__source{background-color:rgba(198,134,29,.9675)}[data-md-color-primary=amber] .md-nav__source{background-color:rgba(203,127,0,.9675)}[data-md-color-primary=orange] .md-nav__source{background-color:rgba(200,111,0,.9675)}[data-md-color-primary=deep-orange] .md-nav__source{background-color:rgba(203,89,53,.9675)}[data-md-color-primary=brown] .md-nav__source{background-color:rgba(96,68,57,.9675)}[data-md-color-primary=grey] .md-nav__source{background-color:rgba(93,93,93,.9675)}[data-md-color-primary=blue-grey] .md-nav__source{background-color:rgba(67,88,97,.9675)}[data-md-color-primary=white] .md-nav__source{background-color:rgba(0,0,0,.07);color:rgba(0,0,0,.87)}}@media only screen and (max-width:76.1875em){html [data-md-color-primary=red] .md-nav--primary .md-nav__title--site{background-color:#ef5350}html [data-md-color-primary=pink] .md-nav--primary .md-nav__title--site{background-color:#e91e63}html [data-md-color-primary=purple] .md-nav--primary .md-nav__title--site{background-color:#ab47bc}html [data-md-color-primary=deep-purple] .md-nav--primary .md-nav__title--site{background-color:#7e57c2}html [data-md-color-primary=indigo] .md-nav--primary .md-nav__title--site{background-color:#3f51b5}html [data-md-color-primary=blue] .md-nav--primary .md-nav__title--site{background-color:#2196f3}html [data-md-color-primary=light-blue] .md-nav--primary .md-nav__title--site{background-color:#03a9f4}html [data-md-color-primary=cyan] .md-nav--primary .md-nav__title--site{background-color:#00bcd4}html [data-md-color-primary=teal] .md-nav--primary .md-nav__title--site{background-color:#009688}html [data-md-color-primary=green] .md-nav--primary .md-nav__title--site{background-color:#4caf50}html [data-md-color-primary=light-green] .md-nav--primary .md-nav__title--site{background-color:#7cb342}html [data-md-color-primary=lime] .md-nav--primary .md-nav__title--site{background-color:#c0ca33}html [data-md-color-primary=yellow] .md-nav--primary .md-nav__title--site{background-color:#f9a825}html [data-md-color-primary=amber] .md-nav--primary .md-nav__title--site{background-color:#ffa000}html [data-md-color-primary=orange] .md-nav--primary .md-nav__title--site{background-color:#fb8c00}html [data-md-color-primary=deep-orange] .md-nav--primary .md-nav__title--site{background-color:#ff7043}html [data-md-color-primary=brown] .md-nav--primary .md-nav__title--site{background-color:#795548}html [data-md-color-primary=grey] .md-nav--primary .md-nav__title--site{background-color:#757575}html [data-md-color-primary=blue-grey] .md-nav--primary .md-nav__title--site{background-color:#546e7a}html [data-md-color-primary=white] .md-nav--primary .md-nav__title--site{background-color:#fff;color:rgba(0,0,0,.87)}[data-md-color-primary=white] .md-hero{border-bottom:.1rem solid rgba(0,0,0,.07)}}@media only screen and (min-width:76.25em){[data-md-color-primary=red] .md-tabs{background-color:#ef5350}[data-md-color-primary=pink] .md-tabs{background-color:#e91e63}[data-md-color-primary=purple] .md-tabs{background-color:#ab47bc}[data-md-color-primary=deep-purple] .md-tabs{background-color:#7e57c2}[data-md-color-primary=indigo] .md-tabs{background-color:#3f51b5}[data-md-color-primary=blue] .md-tabs{background-color:#2196f3}[data-md-color-primary=light-blue] .md-tabs{background-color:#03a9f4}[data-md-color-primary=cyan] .md-tabs{background-color:#00bcd4}[data-md-color-primary=teal] .md-tabs{background-color:#009688}[data-md-color-primary=green] .md-tabs{background-color:#4caf50}[data-md-color-primary=light-green] .md-tabs{background-color:#7cb342}[data-md-color-primary=lime] .md-tabs{background-color:#c0ca33}[data-md-color-primary=yellow] .md-tabs{background-color:#f9a825}[data-md-color-primary=amber] .md-tabs{background-color:#ffa000}[data-md-color-primary=orange] .md-tabs{background-color:#fb8c00}[data-md-color-primary=deep-orange] .md-tabs{background-color:#ff7043}[data-md-color-primary=brown] .md-tabs{background-color:#795548}[data-md-color-primary=grey] .md-tabs{background-color:#757575}[data-md-color-primary=blue-grey] .md-tabs{background-color:#546e7a}[data-md-color-primary=white] .md-tabs{border-bottom:.1rem solid rgba(0,0,0,.07);background-color:#fff;color:rgba(0,0,0,.87)}}@media only screen and (min-width:60em){[data-md-color-primary=white] .md-search__input{background-color:rgba(0,0,0,.07)}[data-md-color-primary=white] .md-search__input::-webkit-input-placeholder{color:rgba(0,0,0,.54)}[data-md-color-primary=white] .md-search__input:-ms-input-placeholder,[data-md-color-primary=white] .md-search__input::-ms-input-placeholder{color:rgba(0,0,0,.54)}[data-md-color-primary=white] .md-search__input::placeholder{color:rgba(0,0,0,.54)}} +/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsImZpbGUiOiJhc3NldHMvc3R5bGVzaGVldHMvYXBwbGljYXRpb24tcGFsZXR0ZS42MDc5NDc2Yy5jc3MiLCJzb3VyY2VSb290IjoiIn0=*/ \ No newline at end of file diff --git a/assets/stylesheets/application.8d40d89b.css b/assets/stylesheets/application.8d40d89b.css new file mode 100644 index 000000000..194447e7b --- /dev/null +++ b/assets/stylesheets/application.8d40d89b.css @@ -0,0 +1,2 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none}body{margin:0}hr{overflow:visible;box-sizing:content-box}a{-webkit-text-decoration-skip:objects}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}small,sub,sup{font-size:80%}sub,sup{position:relative;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}table{border-collapse:separate;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{margin:0;padding:0;border:0;outline-style:none;background:transparent;font-size:inherit}input{border:0;outline:0}.md-clipboard:before,.md-icon,.md-nav__button,.md-nav__link:after,.md-nav__title:before,.md-search-result__article--document:before,.md-source-file:before,.md-typeset .admonition>.admonition-title:before,.md-typeset .admonition>summary:before,.md-typeset .critic.comment:before,.md-typeset .footnote-backref,.md-typeset .task-list-control .task-list-indicator:before,.md-typeset details>.admonition-title:before,.md-typeset details>summary:before,.md-typeset summary:after{font-family:Material Icons;font-style:normal;font-variant:normal;font-weight:400;line-height:1;text-transform:none;white-space:nowrap;speak:none;word-wrap:normal;direction:ltr}.md-content__icon,.md-footer-nav__button,.md-header-nav__button,.md-nav__button,.md-nav__title:before,.md-search-result__article--document:before{display:inline-block;margin:.4rem;padding:.8rem;font-size:2.4rem;cursor:pointer}.md-icon--arrow-back:before{content:"\E5C4"}.md-icon--arrow-forward:before{content:"\E5C8"}.md-icon--menu:before{content:"\E5D2"}.md-icon--search:before{content:"\E8B6"}[dir=rtl] .md-icon--arrow-back:before{content:"\E5C8"}[dir=rtl] .md-icon--arrow-forward:before{content:"\E5C4"}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body,input{color:rgba(0,0,0,.87);-webkit-font-feature-settings:"kern","liga";font-feature-settings:"kern","liga";font-family:Helvetica Neue,Helvetica,Arial,sans-serif}code,kbd,pre{color:rgba(0,0,0,.87);-webkit-font-feature-settings:"kern";font-feature-settings:"kern";font-family:Courier New,Courier,monospace}.md-typeset{font-size:1.6rem;line-height:1.6;-webkit-print-color-adjust:exact}.md-typeset blockquote,.md-typeset ol,.md-typeset p,.md-typeset ul{margin:1em 0}.md-typeset h1{margin:0 0 4rem;color:rgba(0,0,0,.54);font-size:3.125rem;line-height:1.3}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{margin:4rem 0 1.6rem;font-size:2.5rem;line-height:1.4}.md-typeset h3{margin:3.2rem 0 1.6rem;font-size:2rem;font-weight:400;letter-spacing:-.01em;line-height:1.5}.md-typeset h2+h3{margin-top:1.6rem}.md-typeset h4{font-size:1.6rem}.md-typeset h4,.md-typeset h5,.md-typeset h6{margin:1.6rem 0;font-weight:700;letter-spacing:-.01em}.md-typeset h5,.md-typeset h6{color:rgba(0,0,0,.54);font-size:1.28rem}.md-typeset h5{text-transform:uppercase}.md-typeset hr{margin:1.5em 0;border-bottom:.1rem dotted rgba(0,0,0,.26)}.md-typeset a{color:#3f51b5;word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color .125s}.md-typeset a:active,.md-typeset a:hover{color:#536dfe}.md-typeset code,.md-typeset pre{background-color:hsla(0,0%,93%,.5);color:#37474f;font-size:85%;direction:ltr}.md-typeset code{margin:0 .29412em;padding:.07353em 0;border-radius:.2rem;box-shadow:.29412em 0 0 hsla(0,0%,93%,.5),-.29412em 0 0 hsla(0,0%,93%,.5);word-break:break-word;-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset h1 code,.md-typeset h2 code,.md-typeset h3 code,.md-typeset h4 code,.md-typeset h5 code,.md-typeset h6 code{margin:0;background-color:transparent;box-shadow:none}.md-typeset a>code{margin:inherit;padding:inherit;border-radius:none;background-color:inherit;color:inherit;box-shadow:none}.md-typeset pre{position:relative;margin:1em 0;border-radius:.2rem;line-height:1.4;-webkit-overflow-scrolling:touch}.md-typeset pre>code{display:block;margin:0;padding:1.05rem 1.2rem;background-color:transparent;font-size:inherit;box-shadow:none;-webkit-box-decoration-break:none;box-decoration-break:none;overflow:auto}.md-typeset pre>code::-webkit-scrollbar{width:.4rem;height:.4rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:#536dfe}.md-typeset kbd{padding:0 .29412em;border:.1rem solid #c9c9c9;border-radius:.3rem;border-bottom-color:#bcbcbc;background-color:#fcfcfc;color:#555;font-size:85%;box-shadow:0 .1rem 0 #b0b0b0;word-break:break-word}.md-typeset mark{margin:0 .25em;padding:.0625em 0;border-radius:.2rem;background-color:rgba(255,235,59,.5);box-shadow:.25em 0 0 rgba(255,235,59,.5),-.25em 0 0 rgba(255,235,59,.5);word-break:break-word;-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset abbr{border-bottom:.1rem dotted rgba(0,0,0,.54);text-decoration:none;cursor:help}.md-typeset small{opacity:.75}.md-typeset sub,.md-typeset sup{margin-left:.07812em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.07812em;margin-left:0}.md-typeset blockquote{padding-left:1.2rem;border-left:.4rem solid rgba(0,0,0,.26);color:rgba(0,0,0,.54)}[dir=rtl] .md-typeset blockquote{padding-right:1.2rem;padding-left:0;border-right:.4rem solid rgba(0,0,0,.26);border-left:initial}.md-typeset ul{list-style-type:disc}.md-typeset ol,.md-typeset ul{margin-left:.625em;padding:0}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em;margin-left:0}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em;margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em;margin-left:0}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin:.5em 0 .5em .625em}[dir=rtl] .md-typeset ol li ol,[dir=rtl] .md-typeset ol li ul,[dir=rtl] .md-typeset ul li ol,[dir=rtl] .md-typeset ul li ul{margin-right:.625em;margin-left:0}.md-typeset dd{margin:1em 0 1em 1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em;margin-left:0}.md-typeset iframe,.md-typeset img,.md-typeset svg{max-width:100%}.md-typeset table:not([class]){box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2);display:inline-block;max-width:100%;border-radius:.2rem;font-size:1.28rem;overflow:auto;-webkit-overflow-scrolling:touch}.md-typeset table:not([class])+*{margin-top:1.5em}.md-typeset table:not([class]) td:not([align]),.md-typeset table:not([class]) th:not([align]){text-align:left}[dir=rtl] .md-typeset table:not([class]) td:not([align]),[dir=rtl] .md-typeset table:not([class]) th:not([align]){text-align:right}.md-typeset table:not([class]) th{min-width:10rem;padding:1.2rem 1.6rem;background-color:rgba(0,0,0,.54);color:#fff;vertical-align:top}.md-typeset table:not([class]) td{padding:1.2rem 1.6rem;border-top:.1rem solid rgba(0,0,0,.07);vertical-align:top}.md-typeset table:not([class]) tr:first-child td{border-top:0}.md-typeset table:not([class]) a{word-break:normal}.md-typeset__scrollwrap{margin:1em -1.6rem;overflow-x:auto;-webkit-overflow-scrolling:touch}.md-typeset .md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 1.6rem}.md-typeset .md-typeset__table table{display:table;width:100%;margin:0;overflow:hidden}html{font-size:62.5%;overflow-x:hidden}body,html{height:100%}body{position:relative}hr{display:block;height:.1rem;padding:0;border:0}.md-svg{display:none}.md-grid{max-width:122rem;margin-right:auto;margin-left:auto}.md-container,.md-main{overflow:auto}.md-container{display:table;width:100%;height:100%;padding-top:4.8rem;table-layout:fixed}.md-main{display:table-row;height:100%}.md-main__inner{height:100%;padding-top:3rem;padding-bottom:.1rem}.md-toggle{display:none}.md-overlay{position:fixed;top:0;width:0;height:0;transition:width 0s .25s,height 0s .25s,opacity .25s;background-color:rgba(0,0,0,.54);opacity:0;z-index:3}.md-flex{display:table}.md-flex__cell{display:table-cell;position:relative;vertical-align:top}.md-flex__cell--shrink{width:0}.md-flex__cell--stretch{display:table;width:100%;table-layout:fixed}.md-flex__ellipsis{display:table-cell;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.md-skip{position:fixed;width:.1rem;height:.1rem;margin:1rem;padding:.6rem 1rem;clip:rect(.1rem);-webkit-transform:translateY(.8rem);transform:translateY(.8rem);border-radius:.2rem;background-color:rgba(0,0,0,.87);color:#fff;font-size:1.28rem;opacity:0;overflow:hidden}.md-skip:focus{width:auto;height:auto;clip:auto;-webkit-transform:translateX(0);transform:translateX(0);transition:opacity .175s 75ms,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .175s 75ms;transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .175s 75ms,-webkit-transform .25s cubic-bezier(.4,0,.2,1);opacity:1;z-index:10}@page{margin:25mm}.md-clipboard{position:absolute;top:.6rem;right:.6rem;width:2.8rem;height:2.8rem;border-radius:.2rem;font-size:1.6rem;cursor:pointer;z-index:1;-webkit-backface-visibility:hidden;backface-visibility:hidden}.md-clipboard:before{transition:color .25s,opacity .25s;color:rgba(0,0,0,.07);content:"\E14D"}.codehilite:hover .md-clipboard:before,.md-typeset .highlight:hover .md-clipboard:before,pre:hover .md-clipboard:before{color:rgba(0,0,0,.54)}.md-clipboard:focus:before,.md-clipboard:hover:before{color:#536dfe}.md-clipboard__message{display:block;position:absolute;top:0;right:3.4rem;padding:.6rem 1rem;-webkit-transform:translateX(.8rem);transform:translateX(.8rem);transition:opacity .175s,-webkit-transform .25s cubic-bezier(.9,.1,.9,0);transition:transform .25s cubic-bezier(.9,.1,.9,0),opacity .175s;transition:transform .25s cubic-bezier(.9,.1,.9,0),opacity .175s,-webkit-transform .25s cubic-bezier(.9,.1,.9,0);border-radius:.2rem;background-color:rgba(0,0,0,.54);color:#fff;font-size:1.28rem;white-space:nowrap;opacity:0;pointer-events:none}.md-clipboard__message--active{-webkit-transform:translateX(0);transform:translateX(0);transition:opacity .175s 75ms,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .175s 75ms;transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .175s 75ms,-webkit-transform .25s cubic-bezier(.4,0,.2,1);opacity:1;pointer-events:auto}.md-clipboard__message:before{content:attr(aria-label)}.md-clipboard__message:after{display:block;position:absolute;top:50%;right:-.4rem;width:0;margin-top:-.4rem;border-width:.4rem 0 .4rem .4rem;border-style:solid;border-color:transparent rgba(0,0,0,.54);content:""}.md-content__inner{margin:0 1.6rem 2.4rem;padding-top:1.2rem}.md-content__inner:before{display:block;height:.8rem;content:""}.md-content__inner>:last-child{margin-bottom:0}.md-content__icon{position:relative;margin:.8rem 0;padding:0;float:right}.md-typeset .md-content__icon{color:rgba(0,0,0,.26)}.md-header{position:fixed;top:0;right:0;left:0;height:4.8rem;transition:background-color .25s,color .25s;background-color:#3f51b5;color:#fff;box-shadow:none;z-index:2;-webkit-backface-visibility:hidden;backface-visibility:hidden}.no-js .md-header{transition:none;box-shadow:none}.md-header[data-md-state=shadow]{transition:background-color .25s,color .25s,box-shadow .25s;box-shadow:0 0 .4rem rgba(0,0,0,.1),0 .4rem .8rem rgba(0,0,0,.2)}.md-header-nav{padding:0 .4rem}.md-header-nav__button{position:relative;transition:opacity .25s;z-index:1}.md-header-nav__button:hover{opacity:.7}.md-header-nav__button.md-logo *{display:block}.no-js .md-header-nav__button.md-icon--search{display:none}.md-header-nav__topic{display:block;position:absolute;transition:opacity .15s,-webkit-transform .4s cubic-bezier(.1,.7,.1,1);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s,-webkit-transform .4s cubic-bezier(.1,.7,.1,1);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.md-header-nav__topic+.md-header-nav__topic{-webkit-transform:translateX(2.5rem);transform:translateX(2.5rem);transition:opacity .15s,-webkit-transform .4s cubic-bezier(1,.7,.1,.1);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s,-webkit-transform .4s cubic-bezier(1,.7,.1,.1);opacity:0;z-index:-1;pointer-events:none}[dir=rtl] .md-header-nav__topic+.md-header-nav__topic{-webkit-transform:translateX(-2.5rem);transform:translateX(-2.5rem)}.no-js .md-header-nav__topic{position:static}.no-js .md-header-nav__topic+.md-header-nav__topic{display:none}.md-header-nav__title{padding:0 2rem;font-size:1.8rem;line-height:4.8rem}.md-header-nav__title[data-md-state=active] .md-header-nav__topic{-webkit-transform:translateX(-2.5rem);transform:translateX(-2.5rem);transition:opacity .15s,-webkit-transform .4s cubic-bezier(1,.7,.1,.1);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s,-webkit-transform .4s cubic-bezier(1,.7,.1,.1);opacity:0;z-index:-1;pointer-events:none}[dir=rtl] .md-header-nav__title[data-md-state=active] .md-header-nav__topic{-webkit-transform:translateX(2.5rem);transform:translateX(2.5rem)}.md-header-nav__title[data-md-state=active] .md-header-nav__topic+.md-header-nav__topic{-webkit-transform:translateX(0);transform:translateX(0);transition:opacity .15s,-webkit-transform .4s cubic-bezier(.1,.7,.1,1);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s,-webkit-transform .4s cubic-bezier(.1,.7,.1,1);opacity:1;z-index:0;pointer-events:auto}.md-header-nav__source{display:none}.md-hero{transition:background .25s;background-color:#3f51b5;color:#fff;font-size:2rem;overflow:hidden}.md-hero__inner{margin-top:2rem;padding:1.6rem 1.6rem .8rem;transition:opacity .25s,-webkit-transform .4s cubic-bezier(.1,.7,.1,1);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s,-webkit-transform .4s cubic-bezier(.1,.7,.1,1);transition-delay:.1s}[data-md-state=hidden] .md-hero__inner{pointer-events:none;-webkit-transform:translateY(1.25rem);transform:translateY(1.25rem);transition:opacity .1s 0s,-webkit-transform 0s .4s;transition:transform 0s .4s,opacity .1s 0s;transition:transform 0s .4s,opacity .1s 0s,-webkit-transform 0s .4s;opacity:0}.md-hero--expand .md-hero__inner{margin-bottom:2.4rem}.md-footer-nav{background-color:rgba(0,0,0,.87);color:#fff}.md-footer-nav__inner{padding:.4rem;overflow:auto}.md-footer-nav__link{padding-top:2.8rem;padding-bottom:.8rem;transition:opacity .25s}.md-footer-nav__link:hover{opacity:.7}.md-footer-nav__link--prev{width:25%;float:left}[dir=rtl] .md-footer-nav__link--prev{float:right}.md-footer-nav__link--next{width:75%;float:right;text-align:right}[dir=rtl] .md-footer-nav__link--next{float:left;text-align:left}.md-footer-nav__button{transition:background .25s}.md-footer-nav__title{position:relative;padding:0 2rem;font-size:1.8rem;line-height:4.8rem}.md-footer-nav__direction{position:absolute;right:0;left:0;margin-top:-2rem;padding:0 2rem;color:hsla(0,0%,100%,.7);font-size:1.5rem}.md-footer-meta{background-color:rgba(0,0,0,.895)}.md-footer-meta__inner{padding:.4rem;overflow:auto}html .md-footer-meta.md-typeset a{color:hsla(0,0%,100%,.7)}html .md-footer-meta.md-typeset a:focus,html .md-footer-meta.md-typeset a:hover{color:#fff}.md-footer-copyright{margin:0 1.2rem;padding:.8rem 0;color:hsla(0,0%,100%,.3);font-size:1.28rem}.md-footer-copyright__highlight{color:hsla(0,0%,100%,.7)}.md-footer-social{margin:0 .8rem;padding:.4rem 0 1.2rem}.md-footer-social__link{display:inline-block;width:3.2rem;height:3.2rem;font-size:1.6rem;text-align:center}.md-footer-social__link:before{line-height:1.9}.md-nav{font-size:1.4rem;line-height:1.3}.md-nav__title{display:block;padding:0 1.2rem;font-weight:700;text-overflow:ellipsis;overflow:hidden}.md-nav__title:before{display:none;content:"\E5C4"}[dir=rtl] .md-nav__title:before{content:"\E5C8"}.md-nav__title .md-nav__button{display:none}.md-nav__list{margin:0;padding:0;list-style:none}.md-nav__item{padding:0 1.2rem}.md-nav__item:last-child{padding-bottom:1.2rem}.md-nav__item .md-nav__item{padding-right:0}[dir=rtl] .md-nav__item .md-nav__item{padding-right:1.2rem;padding-left:0}.md-nav__item .md-nav__item:last-child{padding-bottom:0}.md-nav__button img{width:100%;height:auto}.md-nav__link{display:block;margin-top:.625em;transition:color .125s;text-overflow:ellipsis;cursor:pointer;overflow:hidden}.md-nav__item--nested>.md-nav__link:after{content:"\E313"}html .md-nav__link[for=toc],html .md-nav__link[for=toc]+.md-nav__link:after,html .md-nav__link[for=toc]~.md-nav{display:none}.md-nav__link[data-md-state=blur]{color:rgba(0,0,0,.54)}.md-nav__link--active,.md-nav__link:active{color:#3f51b5}.md-nav__item--nested>.md-nav__link{color:inherit}.md-nav__link:focus,.md-nav__link:hover{color:#536dfe}.md-nav__source,.no-js .md-search{display:none}.md-search__overlay{opacity:0;z-index:1}.md-search__form{position:relative}.md-search__input{position:relative;padding:0 4.4rem 0 7.2rem;text-overflow:ellipsis;z-index:2}[dir=rtl] .md-search__input{padding:0 7.2rem 0 4.4rem}.md-search__input::-webkit-input-placeholder{transition:color .25s cubic-bezier(.1,.7,.1,1)}.md-search__input:-ms-input-placeholder,.md-search__input::-ms-input-placeholder{transition:color .25s cubic-bezier(.1,.7,.1,1)}.md-search__input::placeholder{transition:color .25s cubic-bezier(.1,.7,.1,1)}.md-search__input::-webkit-input-placeholder,.md-search__input~.md-search__icon{color:rgba(0,0,0,.54)}.md-search__input:-ms-input-placeholder,.md-search__input::-ms-input-placeholder,.md-search__input~.md-search__icon{color:rgba(0,0,0,.54)}.md-search__input::placeholder,.md-search__input~.md-search__icon{color:rgba(0,0,0,.54)}.md-search__input::-ms-clear{display:none}.md-search__icon{position:absolute;transition:color .25s cubic-bezier(.1,.7,.1,1),opacity .25s;font-size:2.4rem;cursor:pointer;z-index:2}.md-search__icon:hover{opacity:.7}.md-search__icon[for=search]{top:.6rem;left:1rem}[dir=rtl] .md-search__icon[for=search]{right:1rem;left:auto}.md-search__icon[for=search]:before{content:"\E8B6"}.md-search__icon[type=reset]{top:.6rem;right:1rem;-webkit-transform:scale(.125);transform:scale(.125);transition:opacity .15s,-webkit-transform .15s cubic-bezier(.1,.7,.1,1);transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s;transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s,-webkit-transform .15s cubic-bezier(.1,.7,.1,1);opacity:0}[dir=rtl] .md-search__icon[type=reset]{right:auto;left:1rem}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__icon[type=reset]{-webkit-transform:scale(1);transform:scale(1);opacity:1}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__icon[type=reset]:hover{opacity:.7}.md-search__output{position:absolute;width:100%;border-radius:0 0 .2rem .2rem;overflow:hidden;z-index:1}.md-search__scrollwrap{height:100%;background-color:#fff;box-shadow:inset 0 .1rem 0 rgba(0,0,0,.07);overflow-y:auto;-webkit-overflow-scrolling:touch}.md-search-result{color:rgba(0,0,0,.87);word-break:break-word}.md-search-result__meta{padding:0 1.6rem;background-color:rgba(0,0,0,.07);color:rgba(0,0,0,.54);font-size:1.28rem;line-height:3.6rem}.md-search-result__list{margin:0;padding:0;border-top:.1rem solid rgba(0,0,0,.07);list-style:none}.md-search-result__item{box-shadow:0 -.1rem 0 rgba(0,0,0,.07)}.md-search-result__link{display:block;transition:background .25s;outline:0;overflow:hidden}.md-search-result__link:hover,.md-search-result__link[data-md-state=active]{background-color:rgba(83,109,254,.1)}.md-search-result__link:hover .md-search-result__article:before,.md-search-result__link[data-md-state=active] .md-search-result__article:before{opacity:.7}.md-search-result__link:last-child .md-search-result__teaser{margin-bottom:1.2rem}.md-search-result__article{position:relative;padding:0 1.6rem;overflow:auto}.md-search-result__article--document:before{position:absolute;left:0;margin:.2rem;transition:opacity .25s;color:rgba(0,0,0,.54);content:"\E880"}[dir=rtl] .md-search-result__article--document:before{right:0;left:auto}.md-search-result__article--document .md-search-result__title{margin:1.1rem 0;font-size:1.6rem;font-weight:400;line-height:1.4}.md-search-result__title{margin:.5em 0;font-size:1.28rem;font-weight:700;line-height:1.4}.md-search-result__teaser{display:-webkit-box;max-height:3.3rem;margin:.5em 0;color:rgba(0,0,0,.54);font-size:1.28rem;line-height:1.4;text-overflow:ellipsis;overflow:hidden;-webkit-line-clamp:2}.md-search-result em{font-style:normal;font-weight:700;text-decoration:underline}.md-sidebar{position:absolute;width:24.2rem;padding:2.4rem 0;overflow:hidden}.md-sidebar[data-md-state=lock]{position:fixed;top:4.8rem}.md-sidebar--secondary{display:none}.md-sidebar__scrollwrap{max-height:100%;margin:0 .4rem;overflow-y:auto;-webkit-backface-visibility:hidden;backface-visibility:hidden}.md-sidebar__scrollwrap::-webkit-scrollbar{width:.4rem;height:.4rem}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#536dfe}@-webkit-keyframes md-source__facts--done{0%{height:0}to{height:1.3rem}}@keyframes md-source__facts--done{0%{height:0}to{height:1.3rem}}@-webkit-keyframes md-source__fact--done{0%{-webkit-transform:translateY(100%);transform:translateY(100%);opacity:0}50%{opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes md-source__fact--done{0%{-webkit-transform:translateY(100%);transform:translateY(100%);opacity:0}50%{opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}.md-source{display:block;padding-right:1.2rem;transition:opacity .25s;font-size:1.3rem;line-height:1.2;white-space:nowrap}[dir=rtl] .md-source{padding-right:0;padding-left:1.2rem}.md-source:hover{opacity:.7}.md-source:after,.md-source__icon{display:inline-block;height:4.8rem;content:"";vertical-align:middle}.md-source__icon{width:4.8rem}.md-source__icon svg{width:2.4rem;height:2.4rem;margin-top:1.2rem;margin-left:1.2rem}[dir=rtl] .md-source__icon svg{margin-right:1.2rem;margin-left:0}.md-source__icon+.md-source__repository{margin-left:-4.4rem;padding-left:4rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-4.4rem;margin-left:0;padding-right:4rem;padding-left:0}.md-source__repository{display:inline-block;max-width:100%;margin-left:1.2rem;font-weight:700;text-overflow:ellipsis;overflow:hidden;vertical-align:middle}.md-source__facts{margin:0;padding:0;font-size:1.1rem;font-weight:700;list-style-type:none;opacity:.75;overflow:hidden}[data-md-state=done] .md-source__facts{-webkit-animation:md-source__facts--done .25s ease-in;animation:md-source__facts--done .25s ease-in}.md-source__fact{float:left}[dir=rtl] .md-source__fact{float:right}[data-md-state=done] .md-source__fact{-webkit-animation:md-source__fact--done .4s ease-out;animation:md-source__fact--done .4s ease-out}.md-source__fact:before{margin:0 .2rem;content:"\B7"}.md-source__fact:first-child:before{display:none}.md-source-file{display:inline-block;margin:1em .5em 1em 0;padding-right:.5rem;border-radius:.2rem;background-color:rgba(0,0,0,.07);font-size:1.28rem;list-style-type:none;cursor:pointer;overflow:hidden}.md-source-file:before{display:inline-block;margin-right:.5rem;padding:.5rem;background-color:rgba(0,0,0,.26);color:#fff;font-size:1.6rem;content:"\E86F";vertical-align:middle}html .md-source-file{transition:background .4s,color .4s,box-shadow .4s cubic-bezier(.4,0,.2,1)}html .md-source-file:before{transition:inherit}html body .md-typeset .md-source-file{color:rgba(0,0,0,.54)}.md-source-file:hover{box-shadow:0 0 8px rgba(0,0,0,.18),0 8px 16px rgba(0,0,0,.36)}.md-source-file:hover:before{background-color:#536dfe}.md-tabs{width:100%;transition:background .25s;background-color:#3f51b5;color:#fff;overflow:auto}.md-tabs__list{margin:0;margin-left:.4rem;padding:0;list-style:none;white-space:nowrap}.md-tabs__item{display:inline-block;height:4.8rem;padding-right:1.2rem;padding-left:1.2rem}.md-tabs__link{display:block;margin-top:1.6rem;transition:opacity .25s,-webkit-transform .4s cubic-bezier(.1,.7,.1,1);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s,-webkit-transform .4s cubic-bezier(.1,.7,.1,1);font-size:1.4rem;opacity:.7}.md-tabs__link--active,.md-tabs__link:hover{color:inherit;opacity:1}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:.02s}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:.04s}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:.06s}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:.08s}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[data-md-state=hidden]{pointer-events:none}.md-tabs[data-md-state=hidden] .md-tabs__link{-webkit-transform:translateY(50%);transform:translateY(50%);transition:color .25s,opacity .1s,-webkit-transform 0s .4s;transition:color .25s,transform 0s .4s,opacity .1s;transition:color .25s,transform 0s .4s,opacity .1s,-webkit-transform 0s .4s;opacity:0}.md-typeset .admonition,.md-typeset details{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2);position:relative;margin:1.5625em 0;padding:0 1.2rem;border-left:.4rem solid #448aff;border-radius:.2rem;font-size:1.28rem;overflow:auto}[dir=rtl] .md-typeset .admonition,[dir=rtl] .md-typeset details{border-right:.4rem solid #448aff;border-left:none}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:1.2rem}.md-typeset .admonition .admonition,.md-typeset .admonition details,.md-typeset details .admonition,.md-typeset details details{margin:1em 0}.md-typeset .admonition>.admonition-title,.md-typeset .admonition>summary,.md-typeset details>.admonition-title,.md-typeset details>summary{margin:0 -1.2rem;padding:.8rem 1.2rem .8rem 4rem;border-bottom:.1rem solid rgba(68,138,255,.1);background-color:rgba(68,138,255,.1);font-weight:700}[dir=rtl] .md-typeset .admonition>.admonition-title,[dir=rtl] .md-typeset .admonition>summary,[dir=rtl] .md-typeset details>.admonition-title,[dir=rtl] .md-typeset details>summary{padding:.8rem 4rem .8rem 1.2rem}.md-typeset .admonition>.admonition-title:last-child,.md-typeset .admonition>summary:last-child,.md-typeset details>.admonition-title:last-child,.md-typeset details>summary:last-child{margin-bottom:0}.md-typeset .admonition>.admonition-title:before,.md-typeset .admonition>summary:before,.md-typeset details>.admonition-title:before,.md-typeset details>summary:before{position:absolute;left:1.2rem;color:#448aff;font-size:2rem;content:"\E3C9"}[dir=rtl] .md-typeset .admonition>.admonition-title:before,[dir=rtl] .md-typeset .admonition>summary:before,[dir=rtl] .md-typeset details>.admonition-title:before,[dir=rtl] .md-typeset details>summary:before{right:1.2rem;left:auto}.md-typeset .admonition.abstract,.md-typeset .admonition.summary,.md-typeset .admonition.tldr,.md-typeset details.abstract,.md-typeset details.summary,.md-typeset details.tldr{border-left-color:#00b0ff}[dir=rtl] .md-typeset .admonition.abstract,[dir=rtl] .md-typeset .admonition.summary,[dir=rtl] .md-typeset .admonition.tldr,[dir=rtl] .md-typeset details.abstract,[dir=rtl] .md-typeset details.summary,[dir=rtl] .md-typeset details.tldr{border-right-color:#00b0ff}.md-typeset .admonition.abstract>.admonition-title,.md-typeset .admonition.abstract>summary,.md-typeset .admonition.summary>.admonition-title,.md-typeset .admonition.summary>summary,.md-typeset .admonition.tldr>.admonition-title,.md-typeset .admonition.tldr>summary,.md-typeset details.abstract>.admonition-title,.md-typeset details.abstract>summary,.md-typeset details.summary>.admonition-title,.md-typeset details.summary>summary,.md-typeset details.tldr>.admonition-title,.md-typeset details.tldr>summary{border-bottom-color:.1rem solid rgba(0,176,255,.1);background-color:rgba(0,176,255,.1)}.md-typeset .admonition.abstract>.admonition-title:before,.md-typeset .admonition.abstract>summary:before,.md-typeset .admonition.summary>.admonition-title:before,.md-typeset .admonition.summary>summary:before,.md-typeset .admonition.tldr>.admonition-title:before,.md-typeset .admonition.tldr>summary:before,.md-typeset details.abstract>.admonition-title:before,.md-typeset details.abstract>summary:before,.md-typeset details.summary>.admonition-title:before,.md-typeset details.summary>summary:before,.md-typeset details.tldr>.admonition-title:before,.md-typeset details.tldr>summary:before{color:#00b0ff;content:"\E8D2"}.md-typeset .admonition.info,.md-typeset .admonition.todo,.md-typeset details.info,.md-typeset details.todo{border-left-color:#00b8d4}[dir=rtl] .md-typeset .admonition.info,[dir=rtl] .md-typeset .admonition.todo,[dir=rtl] .md-typeset details.info,[dir=rtl] .md-typeset details.todo{border-right-color:#00b8d4}.md-typeset .admonition.info>.admonition-title,.md-typeset .admonition.info>summary,.md-typeset .admonition.todo>.admonition-title,.md-typeset .admonition.todo>summary,.md-typeset details.info>.admonition-title,.md-typeset details.info>summary,.md-typeset details.todo>.admonition-title,.md-typeset details.todo>summary{border-bottom-color:.1rem solid rgba(0,184,212,.1);background-color:rgba(0,184,212,.1)}.md-typeset .admonition.info>.admonition-title:before,.md-typeset .admonition.info>summary:before,.md-typeset .admonition.todo>.admonition-title:before,.md-typeset .admonition.todo>summary:before,.md-typeset details.info>.admonition-title:before,.md-typeset details.info>summary:before,.md-typeset details.todo>.admonition-title:before,.md-typeset details.todo>summary:before{color:#00b8d4;content:"\E88E"}.md-typeset .admonition.hint,.md-typeset .admonition.important,.md-typeset .admonition.tip,.md-typeset details.hint,.md-typeset details.important,.md-typeset details.tip{border-left-color:#00bfa5}[dir=rtl] .md-typeset .admonition.hint,[dir=rtl] .md-typeset .admonition.important,[dir=rtl] .md-typeset .admonition.tip,[dir=rtl] .md-typeset details.hint,[dir=rtl] .md-typeset details.important,[dir=rtl] .md-typeset details.tip{border-right-color:#00bfa5}.md-typeset .admonition.hint>.admonition-title,.md-typeset .admonition.hint>summary,.md-typeset .admonition.important>.admonition-title,.md-typeset .admonition.important>summary,.md-typeset .admonition.tip>.admonition-title,.md-typeset .admonition.tip>summary,.md-typeset details.hint>.admonition-title,.md-typeset details.hint>summary,.md-typeset details.important>.admonition-title,.md-typeset details.important>summary,.md-typeset details.tip>.admonition-title,.md-typeset details.tip>summary{border-bottom-color:.1rem solid rgba(0,191,165,.1);background-color:rgba(0,191,165,.1)}.md-typeset .admonition.hint>.admonition-title:before,.md-typeset .admonition.hint>summary:before,.md-typeset .admonition.important>.admonition-title:before,.md-typeset .admonition.important>summary:before,.md-typeset .admonition.tip>.admonition-title:before,.md-typeset .admonition.tip>summary:before,.md-typeset details.hint>.admonition-title:before,.md-typeset details.hint>summary:before,.md-typeset details.important>.admonition-title:before,.md-typeset details.important>summary:before,.md-typeset details.tip>.admonition-title:before,.md-typeset details.tip>summary:before{color:#00bfa5;content:"\E80E"}.md-typeset .admonition.check,.md-typeset .admonition.done,.md-typeset .admonition.success,.md-typeset details.check,.md-typeset details.done,.md-typeset details.success{border-left-color:#00c853}[dir=rtl] .md-typeset .admonition.check,[dir=rtl] .md-typeset .admonition.done,[dir=rtl] .md-typeset .admonition.success,[dir=rtl] .md-typeset details.check,[dir=rtl] .md-typeset details.done,[dir=rtl] .md-typeset details.success{border-right-color:#00c853}.md-typeset .admonition.check>.admonition-title,.md-typeset .admonition.check>summary,.md-typeset .admonition.done>.admonition-title,.md-typeset .admonition.done>summary,.md-typeset .admonition.success>.admonition-title,.md-typeset .admonition.success>summary,.md-typeset details.check>.admonition-title,.md-typeset details.check>summary,.md-typeset details.done>.admonition-title,.md-typeset details.done>summary,.md-typeset details.success>.admonition-title,.md-typeset details.success>summary{border-bottom-color:.1rem solid rgba(0,200,83,.1);background-color:rgba(0,200,83,.1)}.md-typeset .admonition.check>.admonition-title:before,.md-typeset .admonition.check>summary:before,.md-typeset .admonition.done>.admonition-title:before,.md-typeset .admonition.done>summary:before,.md-typeset .admonition.success>.admonition-title:before,.md-typeset .admonition.success>summary:before,.md-typeset details.check>.admonition-title:before,.md-typeset details.check>summary:before,.md-typeset details.done>.admonition-title:before,.md-typeset details.done>summary:before,.md-typeset details.success>.admonition-title:before,.md-typeset details.success>summary:before{color:#00c853;content:"\E876"}.md-typeset .admonition.faq,.md-typeset .admonition.help,.md-typeset .admonition.question,.md-typeset details.faq,.md-typeset details.help,.md-typeset details.question{border-left-color:#64dd17}[dir=rtl] .md-typeset .admonition.faq,[dir=rtl] .md-typeset .admonition.help,[dir=rtl] .md-typeset .admonition.question,[dir=rtl] .md-typeset details.faq,[dir=rtl] .md-typeset details.help,[dir=rtl] .md-typeset details.question{border-right-color:#64dd17}.md-typeset .admonition.faq>.admonition-title,.md-typeset .admonition.faq>summary,.md-typeset .admonition.help>.admonition-title,.md-typeset .admonition.help>summary,.md-typeset .admonition.question>.admonition-title,.md-typeset .admonition.question>summary,.md-typeset details.faq>.admonition-title,.md-typeset details.faq>summary,.md-typeset details.help>.admonition-title,.md-typeset details.help>summary,.md-typeset details.question>.admonition-title,.md-typeset details.question>summary{border-bottom-color:.1rem solid rgba(100,221,23,.1);background-color:rgba(100,221,23,.1)}.md-typeset .admonition.faq>.admonition-title:before,.md-typeset .admonition.faq>summary:before,.md-typeset .admonition.help>.admonition-title:before,.md-typeset .admonition.help>summary:before,.md-typeset .admonition.question>.admonition-title:before,.md-typeset .admonition.question>summary:before,.md-typeset details.faq>.admonition-title:before,.md-typeset details.faq>summary:before,.md-typeset details.help>.admonition-title:before,.md-typeset details.help>summary:before,.md-typeset details.question>.admonition-title:before,.md-typeset details.question>summary:before{color:#64dd17;content:"\E887"}.md-typeset .admonition.attention,.md-typeset .admonition.caution,.md-typeset .admonition.warning,.md-typeset details.attention,.md-typeset details.caution,.md-typeset details.warning{border-left-color:#ff9100}[dir=rtl] .md-typeset .admonition.attention,[dir=rtl] .md-typeset .admonition.caution,[dir=rtl] .md-typeset .admonition.warning,[dir=rtl] .md-typeset details.attention,[dir=rtl] .md-typeset details.caution,[dir=rtl] .md-typeset details.warning{border-right-color:#ff9100}.md-typeset .admonition.attention>.admonition-title,.md-typeset .admonition.attention>summary,.md-typeset .admonition.caution>.admonition-title,.md-typeset .admonition.caution>summary,.md-typeset .admonition.warning>.admonition-title,.md-typeset .admonition.warning>summary,.md-typeset details.attention>.admonition-title,.md-typeset details.attention>summary,.md-typeset details.caution>.admonition-title,.md-typeset details.caution>summary,.md-typeset details.warning>.admonition-title,.md-typeset details.warning>summary{border-bottom-color:.1rem solid rgba(255,145,0,.1);background-color:rgba(255,145,0,.1)}.md-typeset .admonition.attention>.admonition-title:before,.md-typeset .admonition.attention>summary:before,.md-typeset .admonition.caution>.admonition-title:before,.md-typeset .admonition.caution>summary:before,.md-typeset .admonition.warning>.admonition-title:before,.md-typeset .admonition.warning>summary:before,.md-typeset details.attention>.admonition-title:before,.md-typeset details.attention>summary:before,.md-typeset details.caution>.admonition-title:before,.md-typeset details.caution>summary:before,.md-typeset details.warning>.admonition-title:before,.md-typeset details.warning>summary:before{color:#ff9100;content:"\E002"}.md-typeset .admonition.fail,.md-typeset .admonition.failure,.md-typeset .admonition.missing,.md-typeset details.fail,.md-typeset details.failure,.md-typeset details.missing{border-left-color:#ff5252}[dir=rtl] .md-typeset .admonition.fail,[dir=rtl] .md-typeset .admonition.failure,[dir=rtl] .md-typeset .admonition.missing,[dir=rtl] .md-typeset details.fail,[dir=rtl] .md-typeset details.failure,[dir=rtl] .md-typeset details.missing{border-right-color:#ff5252}.md-typeset .admonition.fail>.admonition-title,.md-typeset .admonition.fail>summary,.md-typeset .admonition.failure>.admonition-title,.md-typeset .admonition.failure>summary,.md-typeset .admonition.missing>.admonition-title,.md-typeset .admonition.missing>summary,.md-typeset details.fail>.admonition-title,.md-typeset details.fail>summary,.md-typeset details.failure>.admonition-title,.md-typeset details.failure>summary,.md-typeset details.missing>.admonition-title,.md-typeset details.missing>summary{border-bottom-color:.1rem solid rgba(255,82,82,.1);background-color:rgba(255,82,82,.1)}.md-typeset .admonition.fail>.admonition-title:before,.md-typeset .admonition.fail>summary:before,.md-typeset .admonition.failure>.admonition-title:before,.md-typeset .admonition.failure>summary:before,.md-typeset .admonition.missing>.admonition-title:before,.md-typeset .admonition.missing>summary:before,.md-typeset details.fail>.admonition-title:before,.md-typeset details.fail>summary:before,.md-typeset details.failure>.admonition-title:before,.md-typeset details.failure>summary:before,.md-typeset details.missing>.admonition-title:before,.md-typeset details.missing>summary:before{color:#ff5252;content:"\E14C"}.md-typeset .admonition.danger,.md-typeset .admonition.error,.md-typeset details.danger,.md-typeset details.error{border-left-color:#ff1744}[dir=rtl] .md-typeset .admonition.danger,[dir=rtl] .md-typeset .admonition.error,[dir=rtl] .md-typeset details.danger,[dir=rtl] .md-typeset details.error{border-right-color:#ff1744}.md-typeset .admonition.danger>.admonition-title,.md-typeset .admonition.danger>summary,.md-typeset .admonition.error>.admonition-title,.md-typeset .admonition.error>summary,.md-typeset details.danger>.admonition-title,.md-typeset details.danger>summary,.md-typeset details.error>.admonition-title,.md-typeset details.error>summary{border-bottom-color:.1rem solid rgba(255,23,68,.1);background-color:rgba(255,23,68,.1)}.md-typeset .admonition.danger>.admonition-title:before,.md-typeset .admonition.danger>summary:before,.md-typeset .admonition.error>.admonition-title:before,.md-typeset .admonition.error>summary:before,.md-typeset details.danger>.admonition-title:before,.md-typeset details.danger>summary:before,.md-typeset details.error>.admonition-title:before,.md-typeset details.error>summary:before{color:#ff1744;content:"\E3E7"}.md-typeset .admonition.bug,.md-typeset details.bug{border-left-color:#f50057}[dir=rtl] .md-typeset .admonition.bug,[dir=rtl] .md-typeset details.bug{border-right-color:#f50057}.md-typeset .admonition.bug>.admonition-title,.md-typeset .admonition.bug>summary,.md-typeset details.bug>.admonition-title,.md-typeset details.bug>summary{border-bottom-color:.1rem solid rgba(245,0,87,.1);background-color:rgba(245,0,87,.1)}.md-typeset .admonition.bug>.admonition-title:before,.md-typeset .admonition.bug>summary:before,.md-typeset details.bug>.admonition-title:before,.md-typeset details.bug>summary:before{color:#f50057;content:"\E868"}.md-typeset .admonition.example,.md-typeset details.example{border-left-color:#651fff}[dir=rtl] .md-typeset .admonition.example,[dir=rtl] .md-typeset details.example{border-right-color:#651fff}.md-typeset .admonition.example>.admonition-title,.md-typeset .admonition.example>summary,.md-typeset details.example>.admonition-title,.md-typeset details.example>summary{border-bottom-color:.1rem solid rgba(101,31,255,.1);background-color:rgba(101,31,255,.1)}.md-typeset .admonition.example>.admonition-title:before,.md-typeset .admonition.example>summary:before,.md-typeset details.example>.admonition-title:before,.md-typeset details.example>summary:before{color:#651fff;content:"\E242"}.md-typeset .admonition.cite,.md-typeset .admonition.quote,.md-typeset details.cite,.md-typeset details.quote{border-left-color:#9e9e9e}[dir=rtl] .md-typeset .admonition.cite,[dir=rtl] .md-typeset .admonition.quote,[dir=rtl] .md-typeset details.cite,[dir=rtl] .md-typeset details.quote{border-right-color:#9e9e9e}.md-typeset .admonition.cite>.admonition-title,.md-typeset .admonition.cite>summary,.md-typeset .admonition.quote>.admonition-title,.md-typeset .admonition.quote>summary,.md-typeset details.cite>.admonition-title,.md-typeset details.cite>summary,.md-typeset details.quote>.admonition-title,.md-typeset details.quote>summary{border-bottom-color:.1rem solid hsla(0,0%,62%,.1);background-color:hsla(0,0%,62%,.1)}.md-typeset .admonition.cite>.admonition-title:before,.md-typeset .admonition.cite>summary:before,.md-typeset .admonition.quote>.admonition-title:before,.md-typeset .admonition.quote>summary:before,.md-typeset details.cite>.admonition-title:before,.md-typeset details.cite>summary:before,.md-typeset details.quote>.admonition-title:before,.md-typeset details.quote>summary:before{color:#9e9e9e;content:"\E244"}.codehilite .o,.codehilite .ow,.md-typeset .highlight .o,.md-typeset .highlight .ow{color:inherit}.codehilite .ge,.md-typeset .highlight .ge{color:#000}.codehilite .gr,.md-typeset .highlight .gr{color:#a00}.codehilite .gh,.md-typeset .highlight .gh{color:#999}.codehilite .go,.md-typeset .highlight .go{color:#888}.codehilite .gp,.md-typeset .highlight .gp{color:#555}.codehilite .gs,.md-typeset .highlight .gs{color:inherit}.codehilite .gu,.md-typeset .highlight .gu{color:#aaa}.codehilite .gt,.md-typeset .highlight .gt{color:#a00}.codehilite .gd,.md-typeset .highlight .gd{background-color:#fdd}.codehilite .gi,.md-typeset .highlight .gi{background-color:#dfd}.codehilite .k,.md-typeset .highlight .k{color:#3b78e7}.codehilite .kc,.md-typeset .highlight .kc{color:#a71d5d}.codehilite .kd,.codehilite .kn,.md-typeset .highlight .kd,.md-typeset .highlight .kn{color:#3b78e7}.codehilite .kp,.md-typeset .highlight .kp{color:#a71d5d}.codehilite .kr,.codehilite .kt,.md-typeset .highlight .kr,.md-typeset .highlight .kt{color:#3e61a2}.codehilite .c,.codehilite .cm,.md-typeset .highlight .c,.md-typeset .highlight .cm{color:#999}.codehilite .cp,.md-typeset .highlight .cp{color:#666}.codehilite .c1,.codehilite .ch,.codehilite .cs,.md-typeset .highlight .c1,.md-typeset .highlight .ch,.md-typeset .highlight .cs{color:#999}.codehilite .na,.codehilite .nb,.md-typeset .highlight .na,.md-typeset .highlight .nb{color:#c2185b}.codehilite .bp,.md-typeset .highlight .bp{color:#3e61a2}.codehilite .nc,.md-typeset .highlight .nc{color:#c2185b}.codehilite .no,.md-typeset .highlight .no{color:#3e61a2}.codehilite .nd,.codehilite .ni,.md-typeset .highlight .nd,.md-typeset .highlight .ni{color:#666}.codehilite .ne,.codehilite .nf,.md-typeset .highlight .ne,.md-typeset .highlight .nf{color:#c2185b}.codehilite .nl,.md-typeset .highlight .nl{color:#3b5179}.codehilite .nn,.md-typeset .highlight .nn{color:#ec407a}.codehilite .nt,.md-typeset .highlight .nt{color:#3b78e7}.codehilite .nv,.codehilite .vc,.codehilite .vg,.codehilite .vi,.md-typeset .highlight .nv,.md-typeset .highlight .vc,.md-typeset .highlight .vg,.md-typeset .highlight .vi{color:#3e61a2}.codehilite .nx,.md-typeset .highlight .nx{color:#ec407a}.codehilite .il,.codehilite .m,.codehilite .mf,.codehilite .mh,.codehilite .mi,.codehilite .mo,.md-typeset .highlight .il,.md-typeset .highlight .m,.md-typeset .highlight .mf,.md-typeset .highlight .mh,.md-typeset .highlight .mi,.md-typeset .highlight .mo{color:#e74c3c}.codehilite .s,.codehilite .sb,.codehilite .sc,.md-typeset .highlight .s,.md-typeset .highlight .sb,.md-typeset .highlight .sc{color:#0d904f}.codehilite .sd,.md-typeset .highlight .sd{color:#999}.codehilite .s2,.md-typeset .highlight .s2{color:#0d904f}.codehilite .se,.codehilite .sh,.codehilite .si,.codehilite .sx,.md-typeset .highlight .se,.md-typeset .highlight .sh,.md-typeset .highlight .si,.md-typeset .highlight .sx{color:#183691}.codehilite .sr,.md-typeset .highlight .sr{color:#009926}.codehilite .s1,.codehilite .ss,.md-typeset .highlight .s1,.md-typeset .highlight .ss{color:#0d904f}.codehilite .err,.md-typeset .highlight .err{color:#a61717}.codehilite .w,.md-typeset .highlight .w{color:transparent}.codehilite .hll,.md-typeset .highlight .hll{display:block;margin:0 -1.2rem;padding:0 1.2rem;background-color:rgba(255,235,59,.5)}.md-typeset .codehilite,.md-typeset .highlight{position:relative;margin:1em 0;padding:0;border-radius:.2rem;background-color:hsla(0,0%,93%,.5);color:#37474f;line-height:1.4;-webkit-overflow-scrolling:touch}.md-typeset .codehilite code,.md-typeset .codehilite pre,.md-typeset .highlight code,.md-typeset .highlight pre{display:block;margin:0;padding:1.05rem 1.2rem;background-color:transparent;overflow:auto;vertical-align:top}.md-typeset .codehilite code::-webkit-scrollbar,.md-typeset .codehilite pre::-webkit-scrollbar,.md-typeset .highlight code::-webkit-scrollbar,.md-typeset .highlight pre::-webkit-scrollbar{width:.4rem;height:.4rem}.md-typeset .codehilite code::-webkit-scrollbar-thumb,.md-typeset .codehilite pre::-webkit-scrollbar-thumb,.md-typeset .highlight code::-webkit-scrollbar-thumb,.md-typeset .highlight pre::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-typeset .codehilite code::-webkit-scrollbar-thumb:hover,.md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover,.md-typeset .highlight code::-webkit-scrollbar-thumb:hover,.md-typeset .highlight pre::-webkit-scrollbar-thumb:hover{background-color:#536dfe}.md-typeset pre.codehilite,.md-typeset pre.highlight{overflow:visible}.md-typeset pre.codehilite code,.md-typeset pre.highlight code{display:block;padding:1.05rem 1.2rem;overflow:auto}.md-typeset .codehilitetable{display:block;margin:1em 0;border-radius:.2em;font-size:1.6rem;overflow:hidden}.md-typeset .codehilitetable tbody,.md-typeset .codehilitetable td{display:block;padding:0}.md-typeset .codehilitetable tr{display:flex}.md-typeset .codehilitetable .codehilite,.md-typeset .codehilitetable .highlight,.md-typeset .codehilitetable .linenodiv{margin:0;border-radius:0}.md-typeset .codehilitetable .linenodiv{padding:1.05rem 1.2rem}.md-typeset .codehilitetable .linenos{background-color:rgba(0,0,0,.07);color:rgba(0,0,0,.26);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.md-typeset .codehilitetable .linenos pre{margin:0;padding:0;background-color:transparent;color:inherit;text-align:right}.md-typeset .codehilitetable .code{flex:1;overflow:hidden}.md-typeset>.codehilitetable{box-shadow:none}.md-typeset [id^="fnref:"]{display:inline-block}.md-typeset [id^="fnref:"]:target{margin-top:-7.6rem;padding-top:7.6rem;pointer-events:none}.md-typeset [id^="fn:"]:before{display:none;height:0;content:""}.md-typeset [id^="fn:"]:target:before{display:block;margin-top:-7rem;padding-top:7rem;pointer-events:none}.md-typeset .footnote{color:rgba(0,0,0,.54);font-size:1.28rem}.md-typeset .footnote ol{margin-left:0}.md-typeset .footnote li{transition:color .25s}.md-typeset .footnote li:target{color:rgba(0,0,0,.87)}.md-typeset .footnote li :first-child{margin-top:0}.md-typeset .footnote li:hover .footnote-backref,.md-typeset .footnote li:target .footnote-backref{-webkit-transform:translateX(0);transform:translateX(0);opacity:1}.md-typeset .footnote li:hover .footnote-backref:hover,.md-typeset .footnote li:target .footnote-backref{color:#536dfe}.md-typeset .footnote-ref{display:inline-block;pointer-events:auto}.md-typeset .footnote-ref:before{display:inline;margin:0 .2em;border-left:.1rem solid rgba(0,0,0,.26);font-size:1.25em;content:"";vertical-align:-.5rem}.md-typeset .footnote-backref{display:inline-block;-webkit-transform:translateX(.5rem);transform:translateX(.5rem);transition:color .25s,opacity .125s .125s,-webkit-transform .25s .125s;transition:transform .25s .125s,color .25s,opacity .125s .125s;transition:transform .25s .125s,color .25s,opacity .125s .125s,-webkit-transform .25s .125s;color:rgba(0,0,0,.26);font-size:0;opacity:0;vertical-align:text-bottom}[dir=rtl] .md-typeset .footnote-backref{-webkit-transform:translateX(-.5rem);transform:translateX(-.5rem)}.md-typeset .footnote-backref:before{display:inline-block;font-size:1.6rem;content:"\E31B"}[dir=rtl] .md-typeset .footnote-backref:before{-webkit-transform:scaleX(-1);transform:scaleX(-1)}.md-typeset .headerlink{display:inline-block;margin-left:1rem;-webkit-transform:translateY(.5rem);transform:translateY(.5rem);transition:color .25s,opacity .125s .25s,-webkit-transform .25s .25s;transition:transform .25s .25s,color .25s,opacity .125s .25s;transition:transform .25s .25s,color .25s,opacity .125s .25s,-webkit-transform .25s .25s;opacity:0}[dir=rtl] .md-typeset .headerlink{margin-right:1rem;margin-left:0}html body .md-typeset .headerlink{color:rgba(0,0,0,.26)}.md-typeset h1[id]:before{display:block;margin-top:-.9rem;padding-top:.9rem;content:""}.md-typeset h1[id]:target:before{margin-top:-6.9rem;padding-top:6.9rem}.md-typeset h1[id] .headerlink:focus,.md-typeset h1[id]:hover .headerlink,.md-typeset h1[id]:target .headerlink{-webkit-transform:translate(0);transform:translate(0);opacity:1}.md-typeset h1[id] .headerlink:focus,.md-typeset h1[id]:hover .headerlink:hover,.md-typeset h1[id]:target .headerlink{color:#536dfe}.md-typeset h2[id]:before{display:block;margin-top:-.8rem;padding-top:.8rem;content:""}.md-typeset h2[id]:target:before{margin-top:-6.8rem;padding-top:6.8rem}.md-typeset h2[id] .headerlink:focus,.md-typeset h2[id]:hover .headerlink,.md-typeset h2[id]:target .headerlink{-webkit-transform:translate(0);transform:translate(0);opacity:1}.md-typeset h2[id] .headerlink:focus,.md-typeset h2[id]:hover .headerlink:hover,.md-typeset h2[id]:target .headerlink{color:#536dfe}.md-typeset h3[id]:before{display:block;margin-top:-.9rem;padding-top:.9rem;content:""}.md-typeset h3[id]:target:before{margin-top:-6.9rem;padding-top:6.9rem}.md-typeset h3[id] .headerlink:focus,.md-typeset h3[id]:hover .headerlink,.md-typeset h3[id]:target .headerlink{-webkit-transform:translate(0);transform:translate(0);opacity:1}.md-typeset h3[id] .headerlink:focus,.md-typeset h3[id]:hover .headerlink:hover,.md-typeset h3[id]:target .headerlink{color:#536dfe}.md-typeset h4[id]:before{display:block;margin-top:-.9rem;padding-top:.9rem;content:""}.md-typeset h4[id]:target:before{margin-top:-6.9rem;padding-top:6.9rem}.md-typeset h4[id] .headerlink:focus,.md-typeset h4[id]:hover .headerlink,.md-typeset h4[id]:target .headerlink{-webkit-transform:translate(0);transform:translate(0);opacity:1}.md-typeset h4[id] .headerlink:focus,.md-typeset h4[id]:hover .headerlink:hover,.md-typeset h4[id]:target .headerlink{color:#536dfe}.md-typeset h5[id]:before{display:block;margin-top:-1.1rem;padding-top:1.1rem;content:""}.md-typeset h5[id]:target:before{margin-top:-7.1rem;padding-top:7.1rem}.md-typeset h5[id] .headerlink:focus,.md-typeset h5[id]:hover .headerlink,.md-typeset h5[id]:target .headerlink{-webkit-transform:translate(0);transform:translate(0);opacity:1}.md-typeset h5[id] .headerlink:focus,.md-typeset h5[id]:hover .headerlink:hover,.md-typeset h5[id]:target .headerlink{color:#536dfe}.md-typeset h6[id]:before{display:block;margin-top:-1.1rem;padding-top:1.1rem;content:""}.md-typeset h6[id]:target:before{margin-top:-7.1rem;padding-top:7.1rem}.md-typeset h6[id] .headerlink:focus,.md-typeset h6[id]:hover .headerlink,.md-typeset h6[id]:target .headerlink{-webkit-transform:translate(0);transform:translate(0);opacity:1}.md-typeset h6[id] .headerlink:focus,.md-typeset h6[id]:hover .headerlink:hover,.md-typeset h6[id]:target .headerlink{color:#536dfe}.md-typeset .MJXc-display{margin:.75em 0;padding:.75em 0;overflow:auto;-webkit-overflow-scrolling:touch}.md-typeset .MathJax_CHTML{outline:0}.md-typeset .critic.comment,.md-typeset del.critic,.md-typeset ins.critic{margin:0 .25em;padding:.0625em 0;border-radius:.2rem;-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset del.critic{background-color:#fdd;box-shadow:.25em 0 0 #fdd,-.25em 0 0 #fdd}.md-typeset ins.critic{background-color:#dfd;box-shadow:.25em 0 0 #dfd,-.25em 0 0 #dfd}.md-typeset .critic.comment{background-color:hsla(0,0%,93%,.5);color:#37474f;box-shadow:.25em 0 0 hsla(0,0%,93%,.5),-.25em 0 0 hsla(0,0%,93%,.5)}.md-typeset .critic.comment:before{padding-right:.125em;color:rgba(0,0,0,.26);content:"\E0B7";vertical-align:-.125em}.md-typeset .critic.block{display:block;margin:1em 0;padding-right:1.6rem;padding-left:1.6rem;box-shadow:none}.md-typeset .critic.block :first-child{margin-top:.5em}.md-typeset .critic.block :last-child{margin-bottom:.5em}.md-typeset details{display:block;padding-top:0}.md-typeset details[open]>summary:after{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.md-typeset details:not([open]){padding-bottom:0}.md-typeset details:not([open])>summary{border-bottom:none}.md-typeset details summary{padding-right:4rem}[dir=rtl] .md-typeset details summary{padding-left:4rem}.no-details .md-typeset details:not([open])>*{display:none}.no-details .md-typeset details:not([open]) summary{display:block}.md-typeset summary{display:block;outline:none;cursor:pointer}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset summary:after{position:absolute;top:.8rem;right:1.2rem;color:rgba(0,0,0,.26);font-size:2rem;content:"\E313"}[dir=rtl] .md-typeset summary:after{right:auto;left:1.2rem}.md-typeset .emojione{width:2rem;vertical-align:text-top}.md-typeset code.codehilite,.md-typeset code.highlight{margin:0 .29412em;padding:.07353em 0}.md-typeset .task-list-item{position:relative;list-style-type:none}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em;left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em;left:auto}.md-typeset .task-list-control .task-list-indicator:before{position:absolute;top:.15em;left:-1.25em;color:rgba(0,0,0,.26);font-size:1.25em;content:"\E835";vertical-align:-.25em}[dir=rtl] .md-typeset .task-list-control .task-list-indicator:before{right:-1.25em;left:auto}.md-typeset .task-list-control [type=checkbox]:checked+.task-list-indicator:before{content:"\E834"}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}@media print{.md-typeset a:after{color:rgba(0,0,0,.54);content:" [" attr(href) "]"}.md-typeset code,.md-typeset pre{white-space:pre-wrap}.md-typeset code{box-shadow:none;-webkit-box-decoration-break:initial;box-decoration-break:slice}.md-clipboard,.md-content__icon,.md-footer,.md-header,.md-sidebar,.md-tabs,.md-typeset .headerlink{display:none}}@media only screen and (max-width:44.9375em){.md-typeset pre{margin:1em -1.6rem;border-radius:0}.md-typeset pre>code{padding:1.05rem 1.6rem}.md-footer-nav__link--prev .md-footer-nav__title{display:none}.md-search-result__teaser{max-height:5rem;-webkit-line-clamp:3}.codehilite .hll,.md-typeset .highlight .hll{margin:0 -1.6rem;padding:0 1.6rem}.md-typeset>.codehilite,.md-typeset>.highlight{margin:1em -1.6rem;border-radius:0}.md-typeset>.codehilite code,.md-typeset>.codehilite pre,.md-typeset>.highlight code,.md-typeset>.highlight pre{padding:1.05rem 1.6rem}.md-typeset>.codehilitetable{margin:1em -1.6rem;border-radius:0}.md-typeset>.codehilitetable .codehilite>code,.md-typeset>.codehilitetable .codehilite>pre,.md-typeset>.codehilitetable .highlight>code,.md-typeset>.codehilitetable .highlight>pre,.md-typeset>.codehilitetable .linenodiv{padding:1rem 1.6rem}.md-typeset>p>.MJXc-display{margin:.75em -1.6rem;padding:.25em 1.6rem}}@media only screen and (min-width:100em){html{font-size:68.75%}}@media only screen and (min-width:125em){html{font-size:75%}}@media only screen and (max-width:59.9375em){body[data-md-state=lock]{overflow:hidden}.ios body[data-md-state=lock] .md-container{display:none}html .md-nav__link[for=toc]{display:block;padding-right:4.8rem}html .md-nav__link[for=toc]:after{color:inherit;content:"\E8DE"}html .md-nav__link[for=toc]+.md-nav__link{display:none}html .md-nav__link[for=toc]~.md-nav{display:flex}html [dir=rtl] .md-nav__link{padding-right:1.6rem;padding-left:4.8rem}.md-nav__source{display:block;padding:0 .4rem;background-color:rgba(50,64,144,.9675);color:#fff}.md-search__overlay{position:absolute;top:.4rem;left:.4rem;width:3.6rem;height:3.6rem;-webkit-transform-origin:center;transform-origin:center;transition:opacity .2s .2s,-webkit-transform .3s .1s;transition:transform .3s .1s,opacity .2s .2s;transition:transform .3s .1s,opacity .2s .2s,-webkit-transform .3s .1s;border-radius:2rem;background-color:#fff;overflow:hidden;pointer-events:none}[dir=rtl] .md-search__overlay{right:.4rem;left:auto}[data-md-toggle=search]:checked~.md-header .md-search__overlay{transition:opacity .1s,-webkit-transform .4s;transition:transform .4s,opacity .1s;transition:transform .4s,opacity .1s,-webkit-transform .4s;opacity:1}.md-search__inner{position:fixed;top:0;left:100%;width:100%;height:100%;-webkit-transform:translateX(5%);transform:translateX(5%);transition:right 0s .3s,left 0s .3s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.4,0,.2,1) .15s;transition:right 0s .3s,left 0s .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;transition:right 0s .3s,left 0s .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.4,0,.2,1) .15s;opacity:0;z-index:2}[data-md-toggle=search]:checked~.md-header .md-search__inner{left:0;-webkit-transform:translateX(0);transform:translateX(0);transition:right 0s 0s,left 0s 0s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.1,.7,.1,1) .15s;transition:right 0s 0s,left 0s 0s,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;transition:right 0s 0s,left 0s 0s,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s,-webkit-transform .15s cubic-bezier(.1,.7,.1,1) .15s;opacity:1}[dir=rtl] [data-md-toggle=search]:checked~.md-header .md-search__inner{right:0;left:auto}html [dir=rtl] .md-search__inner{right:100%;left:auto;-webkit-transform:translateX(-5%);transform:translateX(-5%)}.md-search__input{width:100%;height:4.8rem;font-size:1.8rem}.md-search__icon[for=search]{top:1.2rem;left:1.6rem}.md-search__icon[for=search][for=search]:before{content:"\E5C4"}[dir=rtl] .md-search__icon[for=search][for=search]:before{content:"\E5C8"}.md-search__icon[type=reset]{top:1.2rem;right:1.6rem}.md-search__output{top:4.8rem;bottom:0}.md-search-result__article--document:before{display:none}}@media only screen and (max-width:76.1875em){[data-md-toggle=drawer]:checked~.md-overlay{width:100%;height:100%;transition:width 0s,height 0s,opacity .25s;opacity:1}.md-header-nav__button.md-icon--home,.md-header-nav__button.md-logo{display:none}.md-hero__inner{margin-top:4.8rem;margin-bottom:2.4rem}.md-nav{background-color:#fff}.md-nav--primary,.md-nav--primary .md-nav{display:flex;position:absolute;top:0;right:0;left:0;flex-direction:column;height:100%;z-index:1}.md-nav--primary .md-nav__item,.md-nav--primary .md-nav__title{font-size:1.6rem;line-height:1.5}html .md-nav--primary .md-nav__title{position:relative;height:11.2rem;padding:6rem 1.6rem .4rem;background-color:rgba(0,0,0,.07);color:rgba(0,0,0,.54);font-weight:400;line-height:4.8rem;white-space:nowrap;cursor:pointer}html .md-nav--primary .md-nav__title:before{display:block;position:absolute;top:.4rem;left:.4rem;width:4rem;height:4rem;color:rgba(0,0,0,.54)}html .md-nav--primary .md-nav__title~.md-nav__list{background-color:#fff;box-shadow:inset 0 .1rem 0 rgba(0,0,0,.07)}html .md-nav--primary .md-nav__title~.md-nav__list>.md-nav__item:first-child{border-top:0}html .md-nav--primary .md-nav__title--site{position:relative;background-color:#3f51b5;color:#fff}html .md-nav--primary .md-nav__title--site .md-nav__button{display:block;position:absolute;top:.4rem;left:.4rem;width:6.4rem;height:6.4rem;font-size:4.8rem}html .md-nav--primary .md-nav__title--site:before{display:none}html [dir=rtl] .md-nav--primary .md-nav__title--site .md-nav__button,html [dir=rtl] .md-nav--primary .md-nav__title:before{right:.4rem;left:auto}.md-nav--primary .md-nav__list{flex:1;overflow-y:auto}.md-nav--primary .md-nav__item{padding:0;border-top:.1rem solid rgba(0,0,0,.07)}[dir=rtl] .md-nav--primary .md-nav__item{padding:0}.md-nav--primary .md-nav__item--nested>.md-nav__link{padding-right:4.8rem}[dir=rtl] .md-nav--primary .md-nav__item--nested>.md-nav__link{padding-right:1.6rem;padding-left:4.8rem}.md-nav--primary .md-nav__item--nested>.md-nav__link:after{content:"\E315"}[dir=rtl] .md-nav--primary .md-nav__item--nested>.md-nav__link:after{content:"\E314"}.md-nav--primary .md-nav__link{position:relative;margin-top:0;padding:1.2rem 1.6rem}.md-nav--primary .md-nav__link:after{position:absolute;top:50%;right:1.2rem;margin-top:-1.2rem;color:inherit;font-size:2.4rem}[dir=rtl] .md-nav--primary .md-nav__link:after{right:auto;left:1.2rem}.md-nav--primary .md-nav--secondary .md-nav__link{position:static}.md-nav--primary .md-nav--secondary .md-nav{position:static;background-color:transparent}.md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:2.8rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-right:2.8rem;padding-left:0}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-right:4rem;padding-left:0}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:5.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-right:5.2rem;padding-left:0}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:6.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-right:6.4rem;padding-left:0}.md-nav__toggle~.md-nav{display:flex;-webkit-transform:translateX(100%);transform:translateX(100%);transition:opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity .125s .05s;transition:transform .25s cubic-bezier(.8,0,.6,1),opacity .125s .05s,-webkit-transform .25s cubic-bezier(.8,0,.6,1);opacity:0}[dir=rtl] .md-nav__toggle~.md-nav{-webkit-transform:translateX(-100%);transform:translateX(-100%)}.no-csstransforms3d .md-nav__toggle~.md-nav{display:none}.md-nav__toggle:checked~.md-nav{-webkit-transform:translateX(0);transform:translateX(0);transition:opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .125s .125s;transition:transform .25s cubic-bezier(.4,0,.2,1),opacity .125s .125s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);opacity:1}.no-csstransforms3d .md-nav__toggle:checked~.md-nav{display:flex}.md-sidebar--primary{position:fixed;top:0;left:-24.2rem;width:24.2rem;height:100%;-webkit-transform:translateX(0);transform:translateX(0);transition:box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s,-webkit-transform .25s cubic-bezier(.4,0,.2,1);background-color:#fff;z-index:3}[dir=rtl] .md-sidebar--primary{right:-24.2rem;left:auto}.no-csstransforms3d .md-sidebar--primary{display:none}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12),0 5px 5px -3px rgba(0,0,0,.4);-webkit-transform:translateX(24.2rem);transform:translateX(24.2rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{-webkit-transform:translateX(-24.2rem);transform:translateX(-24.2rem)}.no-csstransforms3d [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{display:block}.md-sidebar--primary .md-sidebar__scrollwrap{overflow:hidden;position:absolute;top:0;right:0;bottom:0;left:0;margin:0}.md-tabs{display:none}}@media only screen and (min-width:60em){.md-content{margin-right:24.2rem}[dir=rtl] .md-content{margin-right:0;margin-left:24.2rem}.md-header-nav__button.md-icon--search{display:none}.md-header-nav__source{display:block;width:23rem;max-width:23rem;margin-left:2.8rem;padding-right:1.2rem}[dir=rtl] .md-header-nav__source{margin-right:2.8rem;margin-left:0;padding-right:0;padding-left:1.2rem}.md-search{padding:.4rem}.md-search__overlay{position:fixed;top:0;left:0;width:0;height:0;transition:width 0s .25s,height 0s .25s,opacity .25s;background-color:rgba(0,0,0,.54);cursor:pointer}[dir=rtl] .md-search__overlay{right:0;left:auto}[data-md-toggle=search]:checked~.md-header .md-search__overlay{width:100%;height:100%;transition:width 0s,height 0s,opacity .25s;opacity:1}.md-search__inner{position:relative;width:23rem;padding:.2rem 0;float:right;transition:width .25s cubic-bezier(.1,.7,.1,1)}[dir=rtl] .md-search__inner{float:left}.md-search__form,.md-search__input{border-radius:.2rem}.md-search__input{width:100%;height:3.6rem;padding-left:4.4rem;transition:background-color .25s cubic-bezier(.1,.7,.1,1),color .25s cubic-bezier(.1,.7,.1,1);background-color:rgba(0,0,0,.26);color:inherit;font-size:1.6rem}[dir=rtl] .md-search__input{padding-right:4.4rem}.md-search__input+.md-search__icon{color:inherit}.md-search__input::-webkit-input-placeholder{color:hsla(0,0%,100%,.7)}.md-search__input:-ms-input-placeholder,.md-search__input::-ms-input-placeholder{color:hsla(0,0%,100%,.7)}.md-search__input::placeholder{color:hsla(0,0%,100%,.7)}.md-search__input:hover{background-color:hsla(0,0%,100%,.12)}[data-md-toggle=search]:checked~.md-header .md-search__input{border-radius:.2rem .2rem 0 0;background-color:#fff;color:rgba(0,0,0,.87);text-overflow:none}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::-webkit-input-placeholder{color:rgba(0,0,0,.54)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input:-ms-input-placeholder,[data-md-toggle=search]:checked~.md-header .md-search__input::-ms-input-placeholder{color:rgba(0,0,0,.54)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:rgba(0,0,0,.54)}.md-search__output{top:3.8rem;transition:opacity .4s;opacity:0}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:0 6px 10px 0 rgba(0,0,0,.14),0 1px 18px 0 rgba(0,0,0,.12),0 3px 5px -1px rgba(0,0,0,.4);opacity:1}.md-search__scrollwrap{max-height:0}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap::-webkit-scrollbar{width:.4rem;height:.4rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.26)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:#536dfe}.md-search-result__meta{padding-left:4.4rem}[dir=rtl] .md-search-result__meta{padding-right:4.4rem;padding-left:0}.md-search-result__article{padding-left:4.4rem}[dir=rtl] .md-search-result__article{padding-right:4.4rem;padding-left:1.6rem}.md-sidebar--secondary{display:block;margin-left:100%;-webkit-transform:translate(-100%);transform:translate(-100%)}[dir=rtl] .md-sidebar--secondary{margin-right:100%;margin-left:0;-webkit-transform:translate(100%);transform:translate(100%)}}@media only screen and (min-width:76.25em){.md-content{margin-left:24.2rem}[dir=rtl] .md-content{margin-right:24.2rem}.md-content__inner{margin-right:2.4rem;margin-left:2.4rem}.md-header-nav__button.md-icon--menu{display:none}.md-nav[data-md-state=animate]{transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav__toggle~.md-nav{max-height:0;overflow:hidden}.no-js .md-nav__toggle~.md-nav{display:none}.md-nav[data-md-state=expand],.md-nav__toggle:checked~.md-nav{max-height:100%}.no-js .md-nav[data-md-state=expand],.no-js .md-nav__toggle:checked~.md-nav{display:block}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--nested>.md-nav__link:after{display:inline-block;-webkit-transform-origin:.45em .45em;transform-origin:.45em .45em;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;vertical-align:-.125em}.js .md-nav__item--nested>.md-nav__link:after{transition:-webkit-transform .4s;transition:transform .4s;transition:transform .4s,-webkit-transform .4s}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link:after{-webkit-transform:rotateX(180deg);transform:rotateX(180deg)}.md-search__scrollwrap,[data-md-toggle=search]:checked~.md-header .md-search__inner{width:68.8rem}.md-sidebar--secondary{margin-left:122rem}[dir=rtl] .md-sidebar--secondary{margin-right:122rem;margin-left:0}.md-tabs~.md-main .md-nav--primary>.md-nav__list>.md-nav__item--nested{font-size:0;visibility:hidden}.md-tabs--active~.md-main .md-nav--primary .md-nav__title{display:block;padding:0}.md-tabs--active~.md-main .md-nav--primary .md-nav__title--site{display:none}.no-js .md-tabs--active~.md-main .md-nav--primary .md-nav{display:block}.md-tabs--active~.md-main .md-nav--primary>.md-nav__list>.md-nav__item{font-size:0;visibility:hidden}.md-tabs--active~.md-main .md-nav--primary>.md-nav__list>.md-nav__item--nested{display:none;font-size:1.4rem;overflow:auto;visibility:visible}.md-tabs--active~.md-main .md-nav--primary>.md-nav__list>.md-nav__item--nested>.md-nav__link{display:none}.md-tabs--active~.md-main .md-nav--primary>.md-nav__list>.md-nav__item--active{display:block}.md-tabs--active~.md-main .md-nav[data-md-level="1"]{max-height:none;overflow:visible}.md-tabs--active~.md-main .md-nav[data-md-level="1"]>.md-nav__list>.md-nav__item{padding-left:0}.md-tabs--active~.md-main .md-nav[data-md-level="1"] .md-nav .md-nav__title{display:none}}@media only screen and (min-width:45em){.md-footer-nav__link{width:50%}.md-footer-copyright{max-width:75%;float:left}[dir=rtl] .md-footer-copyright{float:right}.md-footer-social{padding:1.2rem 0;float:right}[dir=rtl] .md-footer-social{float:left}}@media only screen and (max-width:29.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{-webkit-transform:scale(45);transform:scale(45)}}@media only screen and (min-width:30em) and (max-width:44.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{-webkit-transform:scale(60);transform:scale(60)}}@media only screen and (min-width:45em) and (max-width:59.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{-webkit-transform:scale(75);transform:scale(75)}}@media only screen and (min-width:60em) and (max-width:76.1875em){.md-search__scrollwrap,[data-md-toggle=search]:checked~.md-header .md-search__inner{width:46.8rem}.md-search-result__teaser{max-height:5rem;-webkit-line-clamp:3}} +/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsImZpbGUiOiJhc3NldHMvc3R5bGVzaGVldHMvYXBwbGljYXRpb24uOGQ0MGQ4OWIuY3NzIiwic291cmNlUm9vdCI6IiJ9*/ \ No newline at end of file diff --git a/deploy/index.html b/deploy/index.html new file mode 100644 index 000000000..18b6e714b --- /dev/null +++ b/deploy/index.html @@ -0,0 +1,1685 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Installation Guide - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + + + + +
+
+ + + + + +

Installation Guide

+

Contents

+ +

Generic Deployment

+

The following resources are required for a generic deployment.

+

Mandatory commands

+
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/namespace.yaml \
+    | kubectl apply -f -
+
+curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/default-backend.yaml \
+    | kubectl apply -f -
+
+curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/configmap.yaml \
+    | kubectl apply -f -
+
+curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/tcp-services-configmap.yaml \
+    | kubectl apply -f -
+
+curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/udp-services-configmap.yaml \
+    | kubectl apply -f -
+
+ + +

Install without RBAC roles

+
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/without-rbac.yaml \
+    | kubectl apply -f -
+
+ + +

Install with RBAC roles

+

Please check the RBAC document.

+
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/rbac.yaml \
+    | kubectl apply -f -
+
+curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/with-rbac.yaml \
+    | kubectl apply -f -
+
+ + +

Custom Service Provider Deployment

+

There are cloud provider specific yaml files.

+

Docker for Mac

+

Kubernetes is available for Docker for Mac's Edge channel. Switch to the Edge +channel and enable Kubernetes.

+

Patch the nginx ingress controller deployment to add the flag --publish-service

+
kubectl patch deployment -n ingress-nginx nginx-ingress-controller --type='json' \
+    --patch="$(curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/publish-service-patch.yaml)"
+
+ + +

Create a service

+
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/docker-for-mac/service.yaml \
+    | kubectl apply -f -
+
+ + +

minikube

+

For standard usage:

+
minikube addons enable ingress
+
+ + +

For development:

+
    +
  1. Disable the ingress addon:
  2. +
+
$ minikube addons disable ingress
+
+ + +
    +
  1. Use the docker daemon
  2. +
  3. Build the image
  4. +
  5. Perform Mandatory commands
  6. +
  7. Install the nginx-ingress-controller deployment without RBAC roles or with RBAC roles
  8. +
  9. Edit the nginx-ingress-controller deployment to use your custom image. Local images can be seen by performing docker images.
  10. +
+
$ kubectl edit deployment nginx-ingress-controller -n ingress-nginx
+
+ + +

edit the following section:

+
image: <IMAGE-NAME>:<TAG>
+imagePullPolicy: IfNotPresent
+name: nginx-ingress-controller
+
+ + +
    +
  1. Confirm the nginx-ingress-controller deployment exists:
  2. +
+
$ kubectl get pods -n ingress-nginx 
+NAME                                       READY     STATUS    RESTARTS   AGE
+default-http-backend-66b447d9cf-rrlf9      1/1       Running   0          12s
+nginx-ingress-controller-fdcdcd6dd-vvpgs   1/1       Running   0          11s
+
+ + +

AWS

+

In AWS we use an Elastic Load Balancer (ELB) to expose the NGINX Ingress controller behind a Service of Type=LoadBalancer. +Since Kubernetes v1.9.0 it is possible to use a classic load balancer (ELB) or network load balancer (NLB) +Please check the elastic load balancing AWS details page

+

Elastic Load Balancer - ELB

+

This setup requires to choose in which layer (L4 or L7) we want to configure the ELB:

+
    +
  • Layer 4: use TCP as the listener protocol for ports 80 and 443.
  • +
  • Layer 7: use HTTP as the listener protocol for port 80 and terminate TLS in the ELB
  • +
+

Patch the nginx ingress controller deployment to add the flag --publish-service

+
kubectl patch deployment -n ingress-nginx nginx-ingress-controller --type='json' \
+  --patch="$(curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/publish-service-patch.yaml)"
+
+ + +

For L4:

+
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/service-l4.yaml
+kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/patch-configmap-l4.yaml
+
+ + +

For L7:

+

Change line of the file provider/aws/service-l7.yaml replacing the dummy id with a valid one "arn:aws:acm:us-west-2:XXXXXXXX:certificate/XXXXXX-XXXXXXX-XXXXXXX-XXXXXXXX" +Then execute:

+
kubectl apply -f provider/aws/service-l7.yaml
+kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/patch-configmap-l7.yaml
+
+ + +

This example creates an ELB with just two listeners, one in port 80 and another in port 443

+

Listeners

+

If the ingress controller uses RBAC run:

+
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-with-rbac.yaml
+
+ + +

If not run:

+
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-without-rbac.yaml
+
+ + +

Network Load Balancer (NLB)

+

This type of load balancer is supported since v1.10.0 as an ALPHA feature.

+
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/service-nlb.yaml
+
+ + +

If the ingress controller uses RBAC run:

+
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-with-rbac.yaml
+
+ + +

If not run:

+
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-without-rbac.yaml
+
+ + +

GCE - GKE

+

Patch the nginx ingress controller deployment to add the flag --publish-service

+
kubectl patch deployment -n ingress-nginx nginx-ingress-controller --type='json' \
+  --patch="$(curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/publish-service-patch.yaml)"
+
+ + +
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/gce-gke/service.yaml \
+    | kubectl apply -f -
+
+ + +

If the ingress controller uses RBAC run:

+
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-with-rbac.yaml | kubectl apply -f -
+
+ + +

If not run:

+
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-without-rbac.yaml | kubectl apply -f -
+
+ + +

Important Note: proxy protocol is not supported in GCE/GKE

+

Azure

+

Patch the nginx ingress controller deployment to add the flag --publish-service

+
kubectl patch deployment -n ingress-nginx nginx-ingress-controller --type='json' \
+  --patch="$(curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/publish-service-patch.yaml)"
+
+ + +
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/azure/service.yaml \
+    | kubectl apply -f -
+
+ + +

If the ingress controller uses RBAC run:

+
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-with-rbac.yaml
+
+ + +

If not run:

+
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-without-rbac.yaml
+
+ + +

Important Note: proxy protocol is not supported in GCE/GKE

+

Baremetal

+

Using NodePort:

+
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml \
+    | kubectl apply -f -
+
+ + +

Using Helm

+

NGINX Ingress controller can be installed via Helm using the chart stable/nginx from the official charts repository. +To install the chart with the release name my-nginx:

+
helm install stable/nginx-ingress --name my-nginx
+
+ + +

If the kubernetes cluster has RBAC enabled, then run:

+
helm install stable/nginx-ingress --name my-nginx --set rbac.create=true
+
+ + +

Verify installation

+

To check if the ingress controller pods have started, run the following command:

+
kubectl get pods --all-namespaces -l app=ingress-nginx --watch
+
+ + +

Once the operator pods are running, you can cancel the above command by typing Ctrl+C. +Now, you are ready to create your first ingress.

+

Detect installed version

+

To detect which version of the ingress controller is running, exec into the pod and run nginx-ingress-controller version command.

+
POD_NAMESPACE=ingress-nginx
+POD_NAME=$(kubectl get pods -n $POD_NAMESPACE -l app=ingress-nginx -o jsonpath={.items[0].metadata.name})
+kubectl exec -it $POD_NAME -n $POD_NAMESPACE -- /nginx-ingress-controller --version
+
+ + +

Deploying the config-map

+

A config map can be used to configure system components for the nginx-controller. In order to begin using a config-map +make sure it has been created and is being used in the deployment.

+

It is created as seen in the Mandatory Commands section above.

+
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/configmap.yaml \
+    | kubectl apply -f -
+
+ + +

and is setup to be used in the deployment without-rbac or with-rbac with the following line:

+
- --configmap=$(POD_NAMESPACE)/nginx-configuration
+
+ + +

For information on using the config-map, see its user-guide.

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/deploy/rbac/index.html b/deploy/rbac/index.html new file mode 100644 index 000000000..aebd7b3a8 --- /dev/null +++ b/deploy/rbac/index.html @@ -0,0 +1,1290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Role Based Access Control (RBAC) - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Role Based Access Control (RBAC)

+

Overview

+

This example applies to nginx-ingress-controllers being deployed in an environment with RBAC enabled.

+

Role Based Access Control is comprised of four layers:

+
    +
  1. ClusterRole - permissions assigned to a role that apply to an entire cluster
  2. +
  3. ClusterRoleBinding - binding a ClusterRole to a specific account
  4. +
  5. Role - permissions assigned to a role that apply to a specific namespace
  6. +
  7. RoleBinding - binding a Role to a specific account
  8. +
+

In order for RBAC to be applied to an nginx-ingress-controller, that controller +should be assigned to a ServiceAccount. That ServiceAccount should be +bound to the Roles and ClusterRoles defined for the nginx-ingress-controller.

+

Service Accounts created in this example

+

One ServiceAccount is created in this example, nginx-ingress-serviceaccount.

+

Permissions Granted in this example

+

There are two sets of permissions defined in this example. Cluster-wide +permissions defined by the ClusterRole named nginx-ingress-clusterrole, and +namespace specific permissions defined by the Role named nginx-ingress-role.

+

Cluster Permissions

+

These permissions are granted in order for the nginx-ingress-controller to be +able to function as an ingress across the cluster. These permissions are +granted to the ClusterRole named nginx-ingress-clusterrole

+
    +
  • configmaps, endpoints, nodes, pods, secrets: list, watch
  • +
  • nodes: get
  • +
  • services, ingresses: get, list, watch
  • +
  • events: create, patch
  • +
  • ingresses/status: update
  • +
+

Namespace Permissions

+

These permissions are granted specific to the nginx-ingress namespace. These +permissions are granted to the Role named nginx-ingress-role

+
    +
  • configmaps, pods, secrets: get
  • +
  • endpoints: get
  • +
+

Furthermore to support leader-election, the nginx-ingress-controller needs to +have access to a configmap using the resourceName ingress-controller-leader-nginx

+
+

Note that resourceNames can NOT be used to limit requests using the “create” +verb because authorizers only have access to information that can be obtained +from the request URL, method, and headers (resource names in a “create” request +are part of the request body).

+
+
    +
  • configmaps: get, update (for resourceName ingress-controller-leader-nginx)
  • +
  • configmaps: create
  • +
+

This resourceName is the concatenation of the election-id and the +ingress-class as defined by the ingress-controller, which defaults to:

+
    +
  • election-id: ingress-controller-leader
  • +
  • ingress-class: nginx
  • +
  • resourceName : <election-id>-<ingress-class>
  • +
+

Please adapt accordingly if you overwrite either parameter when launching the +nginx-ingress-controller.

+

Bindings

+

The ServiceAccount nginx-ingress-serviceaccount is bound to the Role +nginx-ingress-role and the ClusterRole nginx-ingress-clusterrole.

+

The serviceAccountName associated with the containers in the deployment must +match the serviceAccount. The namespace references in the Deployment metadata, +container arguments, and POD_NAMESPACE should be in the nginx-ingress namespace.

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/development/index.html b/development/index.html new file mode 100644 index 000000000..2cee76cae --- /dev/null +++ b/development/index.html @@ -0,0 +1,1407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Developing for NGINX Ingress controller - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Developing for NGINX Ingress controller

+

This document explains how to get started with developing for NGINX Ingress controller. +It includes how to build, test, and release ingress controllers.

+

Quick Start

+

Initial developer environment build

+

Prequisites: Minikube must be installed; See releases for installation instructions.

+

If you are using MacOS and deploying to minikube, the following command will build the local nginx controller container image and deploy the ingress controller onto a minikube cluster with RBAC enabled in the namespace ingress-nginx:

+
$ make dev-env
+
+ + +

Updating the deployment

+

The nginx controller container image can be rebuilt using:

+
$ ARCH=amd64 TAG=dev REGISTRY=$USER/ingress-controller make build container
+
+ + +

The image will only be used by pods created after the rebuild. To delete old pods which will cause new ones to spin up:

+
$ kubectl get pods -n ingress-nginx
+$ kubectl delete pod -n ingress-nginx nginx-ingress-controller-<unique-pod-id>
+
+ + +

Dependencies

+

The build uses dependencies in the vendor directory, which +must be installed before building a binary/image. Occasionally, you +might need to update the dependencies.

+

This guide requires you to install the dep dependency tool.

+

Check the version of dep you are using and make sure it is up to date.

+
$ dep version
+dep:
+ version     : devel
+ build date  : 
+ git hash    : 
+ go version  : go1.9
+ go compiler : gc
+ platform    : linux/amd64
+
+ + +

If you have an older version of dep, you can update it as follows:

+
$ go get -u github.com/golang/dep
+
+ + +

This will automatically save the dependencies to the vendor/ directory.

+
$ cd $GOPATH/src/k8s.io/ingress-nginx
+$ dep ensure
+$ dep ensure -update
+$ dep prune
+
+ + +

Building

+

All ingress controllers are built through a Makefile. Depending on your +requirements you can build a raw server binary, a local container image, +or push an image to a remote repository.

+

In order to use your local Docker, you may need to set the following environment variables:

+
# "gcloud docker" (default) or "docker"
+$ export DOCKER=<docker>
+
+# "quay.io/kubernetes-ingress-controller" (default), "index.docker.io", or your own registry
+$ export REGISTRY=<your-docker-registry>
+
+ + +

To find the registry simply run: docker system info | grep Registry

+

Nginx Controller

+

Build a raw server binary

+
$ make build
+
+ + +

TODO: add more specific instructions needed for raw server binary.

+

Build a local container image

+
$ TAG=<tag> REGISTRY=$USER/ingress-controller make docker-build
+
+ + +

Push the container image to a remote repository

+
$ TAG=<tag> REGISTRY=$USER/ingress-controller make docker-push
+
+ + +

Deploying

+

There are several ways to deploy the ingress controller onto a cluster. +Please check the deployment guide

+

Testing

+

To run unit-tests, just run

+
$ cd $GOPATH/src/k8s.io/ingress-nginx
+$ make test
+
+ + +

If you have access to a Kubernetes cluster, you can also run e2e tests using ginkgo.

+
$ cd $GOPATH/src/k8s.io/ingress-nginx
+$ make e2e-test
+
+ + +

To run unit-tests for lua code locally, run:

+
$ cd $GOPATH/src/k8s.io/ingress-nginx
+$ ./rootfs/etc/nginx/lua/test/up.sh
+$ make lua-test
+
+ + +

Lua tests are located in $GOPATH/src/k8s.io/ingress-nginx/rootfs/etc/nginx/lua/test. When creating a new test file it must follow the naming convention <mytest>_test.lua or it will be ignored.

+

Releasing

+

All Makefiles will produce a release binary, as shown above. To publish this +to a wider Kubernetes user base, push the image to a container registry, like +gcr.io. All release images are hosted under gcr.io/google_containers and +tagged according to a semver scheme.

+

An example release might look like:

+
$ make release
+
+ + +

Please follow these guidelines to cut a release:

+
    +
  • Update the release +page with a short description of the major changes that correspond to a given +image tag.
  • +
  • Cut a release branch, if appropriate. Release branches follow the format of +controller-release-version. Typically, pre-releases are cut from HEAD. +All major feature work is done in HEAD. Specific bug fixes are +cherry-picked into a release branch.
  • +
  • If you're not confident about the stability of the code, +tag it as alpha or beta. +Typically, a release branch should have stable code.
  • +
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/PREREQUISITES/index.html b/examples/PREREQUISITES/index.html new file mode 100644 index 000000000..eebae4c80 --- /dev/null +++ b/examples/PREREQUISITES/index.html @@ -0,0 +1,1395 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Prerequisites - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Prerequisites

+

Many of the examples in this directory have common prerequisites.

+

TLS certificates

+

Unless otherwise mentioned, the TLS secret used in examples is a 2048 bit RSA +key/cert pair with an arbitrarily chosen hostname, created as follows

+
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
+Generating a 2048 bit RSA private key
+................+++
+................+++
+writing new private key to 'tls.key'
+-----
+
+$ kubectl create secret tls tls-secret --key tls.key --cert tls.crt
+secret "tls-secret" created
+
+ + +

CA Authentication

+

You can act as your very own CA, or use an existing one. As an exercise / learning, we're going to generate our +own CA, and also generate a client certificate.

+

These instructions are based on CoreOS OpenSSL instructions

+

Generating a CA

+

First of all, you've to generate a CA. This is going to be the one who will sign your client certificates. +In real production world, you may face CAs with intermediate certificates, as the following:

+
$ openssl s_client -connect www.google.com:443
+[...]
+---
+Certificate chain
+ 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=www.google.com
+   i:/C=US/O=Google Inc/CN=Google Internet Authority G2
+ 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
+   i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
+ 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
+   i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
+
+ + +

To generate our CA Certificate, we've to run the following commands:

+
$ openssl genrsa -out ca.key 2048
+$ openssl req -x509 -new -nodes -key ca.key -days 10000 -out ca.crt -subj "/CN=example-ca"
+
+ + +

This will generate two files: A private key (ca.key) and a public key (ca.crt). This CA is valid for 10000 days. +The ca.crt can be used later in the step of creation of CA authentication secret.

+

Generating the client certificate

+

The following steps generate a client certificate signed by the CA generated above. This client can be +used to authenticate in a tls-auth configured ingress.

+

First, we need to generate an 'openssl.cnf' file that will be used while signing the keys:

+
[req]
+req_extensions = v3_req
+distinguished_name = req_distinguished_name
+[req_distinguished_name]
+[ v3_req ]
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+ + +

Then, a user generates his very own private key (that he needs to keep secret) +and a CSR (Certificate Signing Request) that will be sent to the CA to sign and generate a certificate.

+
$ openssl genrsa -out client1.key 2048
+$ openssl req -new -key client1.key -out client1.csr -subj "/CN=client1" -config openssl.cnf
+
+ + +

As the CA receives the generated 'client1.csr' file, it signs it and generates a client.crt certificate:

+
$ openssl x509 -req -in client1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client1.crt -days 365 -extensions v3_req -extfile openssl.cnf
+
+ + +

Then, you'll have 3 files: the client.key (user's private key), client.crt (user's public key) and client.csr (disposable CSR).

+

Creating the CA Authentication secret

+

If you're using the CA Authentication feature, you need to generate a secret containing +all the authorized CAs. You must download them from your CA site in PEM format (like the following):

+
-----BEGIN CERTIFICATE-----
+[....]
+-----END CERTIFICATE-----
+
+ + +

You can have as many certificates as you want. If they're in the binary DER format, +you can convert them as the following:

+
$ openssl x509 -in certificate.der -inform der -out certificate.crt -outform pem
+
+ + +

Then, you've to concatenate them all in only one file, named 'ca.crt' as the following:

+
$ cat certificate1.crt certificate2.crt certificate3.crt >> ca.crt
+
+ + +

The final step is to create a secret with the content of this file. This secret is going to be used in +the TLS Auth directive:

+
$ kubectl create secret generic caingress --namespace=default --from-file=ca.crt=<ca.crt>
+
+ + +

Note: You can also generate the CA Authentication Secret along with the TLS Secret by using:

+
$ kubectl create secret generic caingress --namespace=default --from-file=ca.crt=<ca.crt> --from-file=tls.crt=<tls.crt> --from-file=tls.key=<tls.key>
+
+ + +

Test HTTP Service

+

All examples that require a test HTTP Service use the standard http-svc pod, +which you can deploy as follows

+
$ kubectl create -f http-svc.yaml
+service "http-svc" created
+replicationcontroller "http-svc" created
+
+$ kubectl get po
+NAME             READY     STATUS    RESTARTS   AGE
+http-svc-p1t3t   1/1       Running   0          1d
+
+$ kubectl get svc
+NAME             CLUSTER-IP     EXTERNAL-IP   PORT(S)            AGE
+http-svc         10.0.122.116   <pending>     80:30301/TCP       1d
+
+ + +

You can test that the HTTP Service works by exposing it temporarily

+
$ kubectl patch svc http-svc -p '{"spec":{"type": "LoadBalancer"}}'
+"http-svc" patched
+
+$ kubectl get svc http-svc
+NAME             CLUSTER-IP     EXTERNAL-IP   PORT(S)            AGE
+http-svc         10.0.122.116   <pending>     80:30301/TCP       1d
+
+$ kubectl describe svc http-svc
+Name:                   http-svc
+Namespace:              default
+Labels:                 app=http-svc
+Selector:               app=http-svc
+Type:                   LoadBalancer
+IP:                     10.0.122.116
+LoadBalancer Ingress:   108.59.87.136
+Port:                   http    80/TCP
+NodePort:               http    30301/TCP
+Endpoints:              10.180.1.6:8080
+Session Affinity:       None
+Events:
+  FirstSeen LastSeen    Count   From            SubObjectPath   Type        Reason          Message
+  --------- --------    -----   ----            -------------   --------    ------          -------
+  1m        1m      1   {service-controller }           Normal      Type            ClusterIP -> LoadBalancer
+  1m        1m      1   {service-controller }           Normal      CreatingLoadBalancer    Creating load balancer
+  16s       16s     1   {service-controller }           Normal      CreatedLoadBalancer Created load balancer
+
+$ curl 108.59.87.126
+CLIENT VALUES:
+client_address=10.240.0.3
+command=GET
+real path=/
+query=nil
+request_version=1.1
+request_uri=http://108.59.87.136:8080/
+
+SERVER VALUES:
+server_version=nginx: 1.9.11 - lua: 10001
+
+HEADERS RECEIVED:
+accept=*/*
+host=108.59.87.136
+user-agent=curl/7.46.0
+BODY:
+-no body in request-
+
+$ kubectl patch svc http-svc -p '{"spec":{"type": "NodePort"}}'
+"http-svc" patched
+
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/README/index.html b/examples/README/index.html new file mode 100644 index 000000000..de90b4d94 --- /dev/null +++ b/examples/README/index.html @@ -0,0 +1,1273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ingress examples - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Ingress examples

+

This directory contains a catalog of examples on how to run, configure and +scale Ingress. Please review the prerequisites before +trying them.

+

Scaling

+ + + + + + + + + + + + + + + +
NameDescriptionComplexity Level
Static-ipa single ingress gets a single static ipIntermediate
+

Algorithms

+ + + + + + + + + + + + + + + +
NameDescriptionComplexity Level
Session stickynessroute requests consistently to the same endpointAdvanced
+

Auth

+ + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescriptionComplexity Level
Basic authpassword protect your websitenginx
Client certificate authenticationsecure your website with client certificate authenticationnginx
External auth plugindefer to an external auth serviceIntermediate
+

Customization

+ + + + + + + + + + + + + + + + + + + + +
NameDescriptionComplexity Level
configuration-snippetscustomize nginx location configuration using annotationsAdvanced
custom-headersset custom headers before send traffic to backendsAdvanced
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/affinity/cookie/README/index.html b/examples/affinity/cookie/README/index.html new file mode 100644 index 000000000..a880cdd14 --- /dev/null +++ b/examples/affinity/cookie/README/index.html @@ -0,0 +1,1236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sticky Session - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Sticky Session

+

This example demonstrates how to achieve session affinity using cookies

+

Deployment

+

Session stickiness is achieved through 3 annotations on the Ingress, as shown in the example.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescriptionValues
nginx.ingress.kubernetes.io/affinitySets the affinity typestring (in NGINX only cookie is possible
nginx.ingress.kubernetes.io/session-cookie-nameName of the cookie that will be usedstring (default to INGRESSCOOKIE)
nginx.ingress.kubernetes.io/session-cookie-hashType of hash that will be used in cookie valuesha1/md5/index
+

You can create the ingress to test this

+
kubectl create -f ingress.yaml
+
+ + +

Validation

+

You can confirm that the Ingress works.

+
$ kubectl describe ing nginx-test
+Name:           nginx-test
+Namespace:      default
+Address:        
+Default backend:    default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080)
+Rules:
+  Host                          Path    Backends
+  ----                          ----    --------
+  stickyingress.example.com     
+                                /        nginx-service:80 (<none>)
+Annotations:
+  affinity: cookie
+  session-cookie-hash:      sha1
+  session-cookie-name:      INGRESSCOOKIE
+Events:
+  FirstSeen LastSeen    Count   From                SubObjectPath   Type        Reason  Message
+  --------- --------    -----   ----                -------------   --------    ------  -------
+  7s        7s      1   {nginx-ingress-controller }         Normal      CREATE  default/nginx-test
+
+
+$ curl -I http://stickyingress.example.com
+HTTP/1.1 200 OK
+Server: nginx/1.11.9
+Date: Fri, 10 Feb 2017 14:11:12 GMT
+Content-Type: text/html
+Content-Length: 612
+Connection: keep-alive
+Set-Cookie: INGRESSCOOKIE=a9907b79b248140b56bb13723f72b67697baac3d; Path=/; HttpOnly
+Last-Modified: Tue, 24 Jan 2017 14:02:19 GMT
+ETag: "58875e6b-264"
+Accept-Ranges: bytes
+
+ + +

In the example above, you can see a line containing the 'Set-Cookie: INGRESSCOOKIE' setting the right defined stickiness cookie. +This cookie is created by NGINX containing the hash of the used upstream in that request. +If the user changes this cookie, NGINX creates a new one and redirect the user to another upstream.

+

If the backend pool grows up NGINX will keep sending the requests through the same server of the first request, even if it's overloaded.

+

When the backend server is removed, the requests are then re-routed to another upstream server and NGINX creates a new cookie, as the previous hash became invalid.

+

When you have more than one Ingress Object pointing to the same Service, but one containing affinity configuration and other don't, the first created Ingress will be used. +This means that you can face the situation that you've configured Session Affinity in one Ingress and it doesn't reflects in NGINX configuration, because there is another Ingress Object pointing to the same service that doesn't configure this.

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/affinity/cookie/ingress.yaml b/examples/affinity/cookie/ingress.yaml new file mode 100644 index 000000000..b44752804 --- /dev/null +++ b/examples/affinity/cookie/ingress.yaml @@ -0,0 +1,18 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: nginx-test + annotations: + nginx.ingress.kubernetes.io/affinity: "cookie" + nginx.ingress.kubernetes.io/session-cookie-name: "route" + nginx.ingress.kubernetes.io/session-cookie-hash: "sha1" + +spec: + rules: + - host: stickyingress.example.com + http: + paths: + - backend: + serviceName: http-svc + servicePort: 80 + path: / diff --git a/examples/auth/basic/README/index.html b/examples/auth/basic/README/index.html new file mode 100644 index 000000000..0e62f7583 --- /dev/null +++ b/examples/auth/basic/README/index.html @@ -0,0 +1,1224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Basic Authentication - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Basic Authentication

+

This example shows how to add authentication in a Ingress rule using a secret that contains a file generated with htpasswd.

+
$ htpasswd -c auth foo
+New password: <bar>
+New password:
+Re-type new password:
+Adding password for user foo
+
+ + +
$ kubectl create secret generic basic-auth --from-file=auth
+secret "basic-auth" created
+
+ + +
$ kubectl get secret basic-auth -o yaml
+apiVersion: v1
+data:
+  auth: Zm9vOiRhcHIxJE9GRzNYeWJwJGNrTDBGSERBa29YWUlsSDkuY3lzVDAK
+kind: Secret
+metadata:
+  name: basic-auth
+  namespace: default
+type: Opaque
+
+ + +
echo "
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  name: ingress-with-auth
+  annotations:
+    # type of authentication
+    nginx.ingress.kubernetes.io/auth-type: basic
+    # name of the secret that contains the user/password definitions
+    nginx.ingress.kubernetes.io/auth-secret: basic-auth
+    # message to display with an appropriate context why the authentication is required
+    nginx.ingress.kubernetes.io/auth-realm: "Authentication Required - foo"
+spec:
+  rules:
+  - host: foo.bar.com
+    http:
+      paths:
+      - path: /
+        backend:
+          serviceName: http-svc
+          servicePort: 80
+" | kubectl create -f -
+
+ + +
$ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com'
+*   Trying 10.2.29.4...
+* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0)
+> GET / HTTP/1.1
+> Host: foo.bar.com
+> User-Agent: curl/7.43.0
+> Accept: */*
+>
+< HTTP/1.1 401 Unauthorized
+< Server: nginx/1.10.0
+< Date: Wed, 11 May 2016 05:27:23 GMT
+< Content-Type: text/html
+< Content-Length: 195
+< Connection: keep-alive
+< WWW-Authenticate: Basic realm="Authentication Required - foo"
+<
+<html>
+<head><title>401 Authorization Required</title></head>
+<body bgcolor="white">
+<center><h1>401 Authorization Required</h1></center>
+<hr><center>nginx/1.10.0</center>
+</body>
+</html>
+* Connection #0 to host 10.2.29.4 left intact
+
+ + +
$ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com' -u 'foo:bar'
+*   Trying 10.2.29.4...
+* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0)
+* Server auth using Basic with user 'foo'
+> GET / HTTP/1.1
+> Host: foo.bar.com
+> Authorization: Basic Zm9vOmJhcg==
+> User-Agent: curl/7.43.0
+> Accept: */*
+>
+< HTTP/1.1 200 OK
+< Server: nginx/1.10.0
+< Date: Wed, 11 May 2016 06:05:26 GMT
+< Content-Type: text/plain
+< Transfer-Encoding: chunked
+< Connection: keep-alive
+< Vary: Accept-Encoding
+<
+CLIENT VALUES:
+client_address=10.2.29.4
+command=GET
+real path=/
+query=nil
+request_version=1.1
+request_uri=http://foo.bar.com:8080/
+
+SERVER VALUES:
+server_version=nginx: 1.9.11 - lua: 10001
+
+HEADERS RECEIVED:
+accept=*/*
+authorization=Basic Zm9vOmJhcg==
+connection=close
+host=foo.bar.com
+user-agent=curl/7.43.0
+x-forwarded-for=10.2.29.1
+x-forwarded-host=foo.bar.com
+x-forwarded-port=80
+x-forwarded-proto=http
+x-real-ip=10.2.29.1
+BODY:
+* Connection #0 to host 10.2.29.4 left intact
+-no body in request-
+
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/auth/client-certs/README/index.html b/examples/auth/client-certs/README/index.html new file mode 100644 index 000000000..747d2981e --- /dev/null +++ b/examples/auth/client-certs/README/index.html @@ -0,0 +1,1161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Client Certificate Authentication - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Client Certificate Authentication

+

It is possible to enable Client Certificate Authentication using additional annotations in the Ingress.

+

Setup instructions

+
    +
  1. +

    Create a file named ca.crt containing the trusted certificate authority chain (all ca certificates in PEM format) to verify client certificates.

    +
  2. +
  3. +

    Create a secret from this file: +kubectl create secret generic auth-tls-chain --from-file=ca.crt --namespace=default

    +
  4. +
  5. +

    Add the annotations as provided in the ingress.yaml example to your ingress object.

    +
  6. +
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/auth/client-certs/ingress.yaml b/examples/auth/client-certs/ingress.yaml new file mode 100644 index 000000000..0d0ccd0c0 --- /dev/null +++ b/examples/auth/client-certs/ingress.yaml @@ -0,0 +1,30 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + # Enable client certificate authentication + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + # Create the secret containing the trusted ca certificates with `kubectl create secret generic auth-tls-chain --from-file=ca.crt --namespace=default` + nginx.ingress.kubernetes.io/auth-tls-secret: "default/auth-tls-chain" + # Specify the verification depth in the client certificates chain + nginx.ingress.kubernetes.io/auth-tls-verify-depth: "1" + # Specify an error page to be redirected to on verification errors + nginx.ingress.kubernetes.io/auth-tls-error-page: "http://www.mysite.com/error-cert.html" + # Specify if certificates are be passed to upstream server + nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "false" + name: nginx-test + namespace: default +spec: + rules: + - host: ingress.test.com + http: + paths: + - backend: + serviceName: http-svc:80 + servicePort: 80 + path: / + tls: + - hosts: + - ingress.test.com + secretName: tls-secret + diff --git a/examples/auth/external-auth/README/index.html b/examples/auth/external-auth/README/index.html new file mode 100644 index 000000000..ac0da34c9 --- /dev/null +++ b/examples/auth/external-auth/README/index.html @@ -0,0 +1,1292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + External authentication - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

External authentication

+

Example 1:

+

Use an external service (Basic Auth) located in https://httpbin.org

+
$ kubectl create -f ingress.yaml
+ingress "external-auth" created
+
+$ kubectl get ing external-auth
+NAME            HOSTS                         ADDRESS       PORTS     AGE
+external-auth   external-auth-01.sample.com   172.17.4.99   80        13s
+
+$ kubectl get ing external-auth -o yaml
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  annotations:
+    nginx.ingress.kubernetes.io/auth-url: https://httpbin.org/basic-auth/user/passwd
+  creationTimestamp: 2016-10-03T13:50:35Z
+  generation: 1
+  name: external-auth
+  namespace: default
+  resourceVersion: "2068378"
+  selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/external-auth
+  uid: 5c388f1d-8970-11e6-9004-080027d2dc94
+spec:
+  rules:
+  - host: external-auth-01.sample.com
+    http:
+      paths:
+      - backend:
+          serviceName: http-svc
+          servicePort: 80
+        path: /
+status:
+  loadBalancer:
+    ingress:
+    - ip: 172.17.4.99
+$
+
+ + +

Test 1: no username/password (expect code 401)

+
$ curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com'
+* Rebuilt URL to: http://172.17.4.99/
+*   Trying 172.17.4.99...
+* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)
+> GET / HTTP/1.1
+> Host: external-auth-01.sample.com
+> User-Agent: curl/7.50.1
+> Accept: */*
+>
+< HTTP/1.1 401 Unauthorized
+< Server: nginx/1.11.3
+< Date: Mon, 03 Oct 2016 14:52:08 GMT
+< Content-Type: text/html
+< Content-Length: 195
+< Connection: keep-alive
+< WWW-Authenticate: Basic realm="Fake Realm"
+<
+<html>
+<head><title>401 Authorization Required</title></head>
+<body bgcolor="white">
+<center><h1>401 Authorization Required</h1></center>
+<hr><center>nginx/1.11.3</center>
+</body>
+</html>
+* Connection #0 to host 172.17.4.99 left intact
+
+ + +

Test 2: valid username/password (expect code 200)

+
$ curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -u 'user:passwd'
+* Rebuilt URL to: http://172.17.4.99/
+*   Trying 172.17.4.99...
+* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)
+* Server auth using Basic with user 'user'
+> GET / HTTP/1.1
+> Host: external-auth-01.sample.com
+> Authorization: Basic dXNlcjpwYXNzd2Q=
+> User-Agent: curl/7.50.1
+> Accept: */*
+>
+< HTTP/1.1 200 OK
+< Server: nginx/1.11.3
+< Date: Mon, 03 Oct 2016 14:52:50 GMT
+< Content-Type: text/plain
+< Transfer-Encoding: chunked
+< Connection: keep-alive
+<
+CLIENT VALUES:
+client_address=10.2.60.2
+command=GET
+real path=/
+query=nil
+request_version=1.1
+request_uri=http://external-auth-01.sample.com:8080/
+
+SERVER VALUES:
+server_version=nginx: 1.9.11 - lua: 10001
+
+HEADERS RECEIVED:
+accept=*/*
+authorization=Basic dXNlcjpwYXNzd2Q=
+connection=close
+host=external-auth-01.sample.com
+user-agent=curl/7.50.1
+x-forwarded-for=10.2.60.1
+x-forwarded-host=external-auth-01.sample.com
+x-forwarded-port=80
+x-forwarded-proto=http
+x-real-ip=10.2.60.1
+BODY:
+* Connection #0 to host 172.17.4.99 left intact
+-no body in request-
+
+ + +

Test 3: invalid username/password (expect code 401)

+
curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -u 'user:user'
+* Rebuilt URL to: http://172.17.4.99/
+*   Trying 172.17.4.99...
+* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)
+* Server auth using Basic with user 'user'
+> GET / HTTP/1.1
+> Host: external-auth-01.sample.com
+> Authorization: Basic dXNlcjp1c2Vy
+> User-Agent: curl/7.50.1
+> Accept: */*
+>
+< HTTP/1.1 401 Unauthorized
+< Server: nginx/1.11.3
+< Date: Mon, 03 Oct 2016 14:53:04 GMT
+< Content-Type: text/html
+< Content-Length: 195
+< Connection: keep-alive
+* Authentication problem. Ignoring this.
+< WWW-Authenticate: Basic realm="Fake Realm"
+<
+<html>
+<head><title>401 Authorization Required</title></head>
+<body bgcolor="white">
+<center><h1>401 Authorization Required</h1></center>
+<hr><center>nginx/1.11.3</center>
+</body>
+</html>
+* Connection #0 to host 172.17.4.99 left intact
+
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/auth/external-auth/ingress.yaml b/examples/auth/external-auth/ingress.yaml new file mode 100644 index 000000000..4cec37653 --- /dev/null +++ b/examples/auth/external-auth/ingress.yaml @@ -0,0 +1,15 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-url: "https://httpbin.org/basic-auth/user/passwd" + name: external-auth +spec: + rules: + - host: external-auth-01.sample.com + http: + paths: + - backend: + serviceName: http-svc + servicePort: 80 + path: / \ No newline at end of file diff --git a/examples/customization/configuration-snippets/README/index.html b/examples/customization/configuration-snippets/README/index.html new file mode 100644 index 000000000..003f647d2 --- /dev/null +++ b/examples/customization/configuration-snippets/README/index.html @@ -0,0 +1,1170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Configuration Snippets - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Configuration Snippets

+

Ingress

+

The Ingress in this example adds a custom header to Nginx configuration that only applies to that specific Ingress. If you want to add headers that apply globally to all Ingresses, please have a look at this example.

+
$ kubectl apply -f ingress.yaml
+
+ + +

Test

+

Check if the contents of the annotation are present in the nginx.conf file using: +kubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/customization/configuration-snippets/ingress.yaml b/examples/customization/configuration-snippets/ingress.yaml new file mode 100644 index 000000000..87ce21db2 --- /dev/null +++ b/examples/customization/configuration-snippets/ingress.yaml @@ -0,0 +1,17 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: nginx-configuration-snippet + annotations: + nginx.ingress.kubernetes.io/configuration-snippet: | + more_set_headers "Request-Id: $req_id"; + +spec: + rules: + - host: custom.configuration.com + http: + paths: + - backend: + serviceName: http-svc + servicePort: 80 + path: / diff --git a/examples/customization/custom-configuration/README/index.html b/examples/customization/custom-configuration/README/index.html new file mode 100644 index 000000000..a1f7bc2cc --- /dev/null +++ b/examples/customization/custom-configuration/README/index.html @@ -0,0 +1,1122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Custom Configuration - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Custom Configuration

+

Using a ConfigMap is possible to customize the NGINX configuration

+

For example, if we want to change the timeouts we need to create a ConfigMap:

+
$ cat configmap.yaml
+apiVersion: v1
+data:
+  proxy-connect-timeout: "10"
+  proxy-read-timeout: "120"
+  proxy-send-timeout: "120"
+kind: ConfigMap
+metadata:
+  name: nginx-load-balancer-conf
+
+ + +
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-configuration/configmap.yaml \
+    | kubectl apply -f -
+
+ + +

If the Configmap it is updated, NGINX will be reloaded with the new configuration.

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/customization/custom-configuration/configmap.yaml b/examples/customization/custom-configuration/configmap.yaml new file mode 100644 index 000000000..b5b5c02fd --- /dev/null +++ b/examples/customization/custom-configuration/configmap.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: nginx-configuration + namespace: ingress-nginx + labels: + app: ingress-nginx +data: + proxy-connect-timeout: "10" + proxy-read-timeout: "120" + proxy-send-timeout: "120" diff --git a/examples/customization/custom-errors/README/index.html b/examples/customization/custom-errors/README/index.html new file mode 100644 index 000000000..ce3175fde --- /dev/null +++ b/examples/customization/custom-errors/README/index.html @@ -0,0 +1,1175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Custom Errors - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Custom Errors

+

This example shows how is possible to use a custom backend to render custom error pages. The code of this example is located here custom-error-pages

+

The idea is to use the headers X-Code and X-Format that NGINX pass to the backend in case of an error to find out the best existent representation of the response to be returned. i.e. if the request contains an Accept header of type json the error should be in that format and not in html (the default in NGINX).

+

First create the custom backend to use in the Ingress controller

+
$ kubectl create -f custom-default-backend.yaml
+service "nginx-errors" created
+replicationcontroller "nginx-errors" created
+
+ + +
$ kubectl get svc
+NAME                    CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
+echoheaders             10.3.0.7     nodes         80/TCP          23d
+kubernetes              10.3.0.1     <none>        443/TCP         34d
+nginx-errors            10.3.0.102   <none>        80/TCP          11s
+
+ + +
$ kubectl get rc
+CONTROLLER             REPLICAS   AGE
+echoheaders            1          19d
+nginx-errors           1          19s
+
+ + +

Next create the Ingress controller executing

+
$ kubectl create -f rc-custom-errors.yaml
+
+ + +

Now to check if this is working we use curl:

+
$ curl -v http://172.17.4.99/
+*   Trying 172.17.4.99...
+* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)
+> GET / HTTP/1.1
+> Host: 172.17.4.99
+> User-Agent: curl/7.43.0
+> Accept: */*
+>
+< HTTP/1.1 404 Not Found
+< Server: nginx/1.10.0
+< Date: Wed, 04 May 2016 02:53:45 GMT
+< Content-Type: text/html
+< Transfer-Encoding: chunked
+< Connection: keep-alive
+< Vary: Accept-Encoding
+<
+<span>The page you're looking for could not be found.</span>
+
+* Connection #0 to host 172.17.4.99 left intact
+
+ + +

Specifying json as expected format:

+
$ curl -v http://172.17.4.99/ -H 'Accept: application/json'
+*   Trying 172.17.4.99...
+* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)
+> GET / HTTP/1.1
+> Host: 172.17.4.99
+> User-Agent: curl/7.43.0
+> Accept: application/json
+>
+< HTTP/1.1 404 Not Found
+< Server: nginx/1.10.0
+< Date: Wed, 04 May 2016 02:54:00 GMT
+< Content-Type: text/html
+< Transfer-Encoding: chunked
+< Connection: keep-alive
+< Vary: Accept-Encoding
+<
+{ "message": "The page you're looking for could not be found" }
+
+* Connection #0 to host 172.17.4.99 left intact
+
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/customization/custom-errors/custom-default-backend.yaml b/examples/customization/custom-errors/custom-default-backend.yaml new file mode 100644 index 000000000..fce7c0bcb --- /dev/null +++ b/examples/customization/custom-errors/custom-default-backend.yaml @@ -0,0 +1,31 @@ +apiVersion: v1 +kind: Service +metadata: + name: nginx-errors + labels: + app: nginx-errors +spec: + ports: + - port: 80 + targetPort: 80 + protocol: TCP + name: http + selector: + app: nginx-errors +--- +apiVersion: v1 +kind: ReplicationController +metadata: + name: nginx-errors +spec: + replicas: 1 + template: + metadata: + labels: + app: nginx-errors + spec: + containers: + - name: nginx-errors + image: aledbf/nginx-error-server:0.1 + ports: + - containerPort: 80 \ No newline at end of file diff --git a/examples/customization/custom-errors/rc-custom-errors.yaml b/examples/customization/custom-errors/rc-custom-errors.yaml new file mode 100644 index 000000000..c400e5fee --- /dev/null +++ b/examples/customization/custom-errors/rc-custom-errors.yaml @@ -0,0 +1,51 @@ +apiVersion: v1 +kind: ReplicationController +metadata: + name: nginx-ingress-controller + labels: + k8s-app: nginx-ingress-lb +spec: + replicas: 1 + selector: + k8s-app: nginx-ingress-lb + template: + metadata: + labels: + k8s-app: nginx-ingress-lb + name: nginx-ingress-lb + spec: + terminationGracePeriodSeconds: 60 + containers: + - image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.13.0 + name: nginx-ingress-lb + imagePullPolicy: Always + readinessProbe: + httpGet: + path: /healthz + port: 10254 + scheme: HTTP + livenessProbe: + httpGet: + path: /healthz + port: 10254 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 1 + # use downward API + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + ports: + - containerPort: 80 + hostPort: 80 + - containerPort: 443 + hostPort: 443 + args: + - /nginx-ingress-controller + - --default-backend-service=$(POD_NAMESPACE)/nginx-errors diff --git a/examples/customization/custom-headers/README/index.html b/examples/customization/custom-headers/README/index.html new file mode 100644 index 000000000..9c1b04818 --- /dev/null +++ b/examples/customization/custom-headers/README/index.html @@ -0,0 +1,1161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Custom Headers - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Custom Headers

+

This example aims to demonstrate the deployment of an nginx ingress controller and +use a ConfigMap to configure a custom list of headers to be passed to the upstream +server

+
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-headers/configmap.yaml \
+    | kubectl apply -f -
+
+curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-headers/custom-headers.yaml \
+    | kubectl apply -f -
+
+ + +

Test

+

Check the contents of the configmap is present in the nginx.conf file using: +kubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/customization/custom-headers/configmap.yaml b/examples/customization/custom-headers/configmap.yaml new file mode 100644 index 000000000..27fed44c8 --- /dev/null +++ b/examples/customization/custom-headers/configmap.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +data: + proxy-set-headers: "ingress-nginx/custom-headers" +kind: ConfigMap +metadata: + name: nginx-configuration + namespace: ingress-nginx + labels: + app: ingress-nginx \ No newline at end of file diff --git a/examples/customization/custom-headers/custom-headers.yaml b/examples/customization/custom-headers/custom-headers.yaml new file mode 100644 index 000000000..dac9f6714 --- /dev/null +++ b/examples/customization/custom-headers/custom-headers.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +data: + X-Different-Name: "true" + X-Request-Start: t=${msec} + X-Using-Nginx-Controller: "true" +kind: ConfigMap +metadata: + name: custom-headers + namespace: ingress-nginx diff --git a/examples/customization/custom-upstream-check/README/index.html b/examples/customization/custom-upstream-check/README/index.html new file mode 100644 index 000000000..49d75f937 --- /dev/null +++ b/examples/customization/custom-upstream-check/README/index.html @@ -0,0 +1,1144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Custom Upstream server checks - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Custom Upstream server checks

+

This example shows how is possible to create a custom configuration for a particular upstream associated with an Ingress rule.

+
echo "
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  name: http-svc
+  annotations:
+    nginx.ingress.kubernetes.io/upstream-fail-timeout: "30"
+spec:
+  rules:
+  - host: foo.bar.com
+    http:
+      paths:
+      - path: /
+        backend:
+          serviceName: http-svc
+          servicePort: 80
+" | kubectl create -f -
+
+ + +

Check the annotation is present in the Ingress rule:

+
kubectl get ingress http-svc -o yaml
+
+ + +

Check the NGINX configuration is updated using kubectl or the status page:

+
$ kubectl exec nginx-ingress-controller-v1ppm cat /etc/nginx/nginx.conf
+
+ + +
....
+    upstream default-http-svc-x-80 {
+        least_conn;
+        server 10.2.92.2:8080 max_fails=5 fail_timeout=30;
+
+    }
+....
+
+ + +

nginx-module-vts

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/customization/custom-upstream-check/custom-upstream.png b/examples/customization/custom-upstream-check/custom-upstream.png new file mode 100644 index 000000000..30417894b Binary files /dev/null and b/examples/customization/custom-upstream-check/custom-upstream.png differ diff --git a/examples/customization/custom-vts-metrics-prometheus/README/index.html b/examples/customization/custom-vts-metrics-prometheus/README/index.html new file mode 100644 index 000000000..803b23924 --- /dev/null +++ b/examples/customization/custom-vts-metrics-prometheus/README/index.html @@ -0,0 +1,1352 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Deploying the Nginx Ingress controller - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Deploying the Nginx Ingress controller

+

This example aims to demonstrate the deployment of an nginx ingress controller and use a ConfigMap to enable nginx vts module to export metrics in prometheus format.

+

vts-metrics

+

Vts-metrics export NGINX metrics. To deploy all the files simply run kubectl apply -f nginx. A deployment and service will be +created which already has a prometheus.io/scrape: 'true' annotation and if you added +the recommended Prometheus service-endpoint scraping configuration, +Prometheus will scrape it automatically and you start using the generated metrics right away.

+

Custom configuration

+
apiVersion: v1
+data:
+  enable-vts-status: "true"
+kind: ConfigMap
+metadata:
+  name: nginx-configuration
+  namespace: ingress-nginx
+  labels:
+    app: ingress-nginx
+
+ + +
$ kubectl apply -f nginx-vts-metrics-conf.yaml
+
+ + +

Result

+

Check whether the ingress controller successfully generated the NGINX vts status:

+
$ kubectl exec nginx-ingress-controller-873061567-4n3k2 -n ingress-nginx cat /etc/nginx/nginx.conf|grep vhost_traffic_status_display
+ vhost_traffic_status_display;
+ vhost_traffic_status_display_format html;
+
+ + +

NGINX vts dashboard

+

The vts dashboard provides real time metrics.

+

vts dashboard

+

Because the vts port it's not yet exposed, you should forward the controller port to see it.

+
$ kubectl port-forward $(kubectl get pods --selector=k8s-app=nginx-ingress-controller -n ingress-nginx --output=jsonpath={.items..metadata.name}) -n ingress-nginx 18080
+
+ + +

Now open the url http://localhost:18080/nginx_status in your browser.

+

Prometheus metrics output

+

NGINX Ingress controller already has a parser to convert vts metrics to Prometheus format. It exports prometheus metrics to the address :10254/metrics.

+
$ kubectl exec -ti -n ingress-nginx $(kubectl get pods --selector=k8s-app=nginx-ingress-controller -n kube-system --output=jsonpath={.items..metadata.name}) curl localhost:10254/metrics
+ingress_controller_ssl_expire_time_seconds{host="foo.bar.com"} -6.21355968e+10
+# HELP ingress_controller_success Cumulative number of Ingress controller reload operations
+# TYPE ingress_controller_success counter
+ingress_controller_success{count="reloads"} 3
+# HELP nginx_bytes_total Nginx bytes count
+# TYPE nginx_bytes_total counter
+nginx_bytes_total{direction="in",ingress_class="nginx",namespace="",server_zone="*"} 3708
+nginx_bytes_total{direction="in",ingress_class="nginx",namespace="",server_zone="_"} 3708
+nginx_bytes_total{direction="out",ingress_class="nginx",namespace="",server_zone="*"} 5256
+nginx_bytes_total{direction="out",ingress_class="nginx",namespace="",server_zone="_"} 5256
+
+ + +

Customize metrics

+

The default vts vhost key is $geoip_country_code country::* that expose metrics grouped by server and country code. The example below show how to have metrics grouped by server and server path.

+

vts dashboard

+

NGINX custom configuration ( http level )

+
  apiVersion: v1
+  kind: ConfigMap
+  data:
+    enable-vts-status: "true"
+    vts-default-filter-key: "$server_name"
+...
+
+ + +

Customize ingress

+
 apiVersion: extensions/v1beta1
+  kind: Ingress
+  metadata:
+    annotations:
+      nginx.ingress.kubernetes.io/vts-filter-key: $uri $server_name
+    name: ingress
+
+ + +

Result

+

prometheus filter key path

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/customization/custom-vts-metrics-prometheus/imgs/prometheus-filter-key-path.png b/examples/customization/custom-vts-metrics-prometheus/imgs/prometheus-filter-key-path.png new file mode 100644 index 000000000..a266d4048 Binary files /dev/null and b/examples/customization/custom-vts-metrics-prometheus/imgs/prometheus-filter-key-path.png differ diff --git a/examples/customization/custom-vts-metrics-prometheus/imgs/vts-dashboard-filter-key-path.png b/examples/customization/custom-vts-metrics-prometheus/imgs/vts-dashboard-filter-key-path.png new file mode 100644 index 000000000..b9b3238f6 Binary files /dev/null and b/examples/customization/custom-vts-metrics-prometheus/imgs/vts-dashboard-filter-key-path.png differ diff --git a/examples/customization/custom-vts-metrics-prometheus/imgs/vts-dashboard.png b/examples/customization/custom-vts-metrics-prometheus/imgs/vts-dashboard.png new file mode 100644 index 000000000..0370f5ce9 Binary files /dev/null and b/examples/customization/custom-vts-metrics-prometheus/imgs/vts-dashboard.png differ diff --git a/examples/customization/custom-vts-metrics-prometheus/nginx-vts-metrics-conf.yaml b/examples/customization/custom-vts-metrics-prometheus/nginx-vts-metrics-conf.yaml new file mode 100644 index 000000000..6a6e795cd --- /dev/null +++ b/examples/customization/custom-vts-metrics-prometheus/nginx-vts-metrics-conf.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +data: + enable-vts-status: "true" +kind: ConfigMap +metadata: + name: nginx-configuration + namespace: ingress-nginx + labels: + app: ingress-nginx diff --git a/examples/customization/external-auth-headers/Makefile b/examples/customization/external-auth-headers/Makefile new file mode 100644 index 000000000..1ee7e06ac --- /dev/null +++ b/examples/customization/external-auth-headers/Makefile @@ -0,0 +1,23 @@ +all: push + +TAG=0.1 +PREFIX?=electroma/ingress-demo- +ARCH?=amd64 +GOLANG_VERSION=1.9 +TEMP_DIR:=$(shell mktemp -d) + +build: clean + CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -o authsvc/authsvc authsvc/authsvc.go + CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -o echosvc/echosvc echosvc/echosvc.go + +container: build + docker build --pull -t $(PREFIX)authsvc-$(ARCH):$(TAG) authsvc + docker build --pull -t $(PREFIX)echosvc-$(ARCH):$(TAG) echosvc + +push: container + docker push $(PREFIX)authsvc-$(ARCH):$(TAG) + docker push $(PREFIX)echosvc-$(ARCH):$(TAG) + +clean: + rm -f authsvc/authsvc echosvc/echosvc + diff --git a/examples/customization/external-auth-headers/README/index.html b/examples/customization/external-auth-headers/README/index.html new file mode 100644 index 000000000..8f815ec84 --- /dev/null +++ b/examples/customization/external-auth-headers/README/index.html @@ -0,0 +1,1232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + External authentication, authentication service response headers propagation - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

External authentication, authentication service response headers propagation

+

This example demonstrates propagation of selected authentication service response headers +to backend service.

+

Sample configuration includes:

+
    +
  • Sample authentication service producing several response headers
  • +
  • Authentication logic is based on HTTP header: requests with header User containing string internal are considered authenticated
  • +
  • After successful authentication service generates response headers UserID and UserRole
  • +
  • Sample echo service displaying header information
  • +
  • Two ingress objects pointing to echo service
  • +
  • Public, which allows access from unauthenticated users
  • +
  • Private, which allows access from authenticated users only
  • +
+

You can deploy the controller as +follows:

+
$ kubectl create -f deploy/
+deployment "demo-auth-service" created
+service "demo-auth-service" created
+ingress "demo-auth-service" created
+deployment "demo-echo-service" created
+service "demo-echo-service" created
+ingress "public-demo-echo-service" created
+ingress "secure-demo-echo-service" created
+
+$ kubectl get po
+NAME                                        READY     STATUS    RESTARTS   AGE
+NAME                                        READY     STATUS    RESTARTS   AGE
+demo-auth-service-2769076528-7g9mh          1/1       Running            0          30s
+demo-echo-service-3636052215-3vw8c          1/1       Running            0          29s
+
+kubectl get ing
+NAME                       HOSTS                                 ADDRESS   PORTS     AGE
+public-demo-echo-service   public-demo-echo-service.kube.local             80        1m
+secure-demo-echo-service   secure-demo-echo-service.kube.local             80        1m
+
+ + +

Test 1: public service with no auth header

+
$ curl -H 'Host: public-demo-echo-service.kube.local' -v 192.168.99.100
+* Rebuilt URL to: 192.168.99.100/
+*   Trying 192.168.99.100...
+* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)
+> GET / HTTP/1.1
+> Host: public-demo-echo-service.kube.local
+> User-Agent: curl/7.43.0
+> Accept: */*
+>
+< HTTP/1.1 200 OK
+< Server: nginx/1.11.10
+< Date: Mon, 13 Mar 2017 20:19:21 GMT
+< Content-Type: text/plain; charset=utf-8
+< Content-Length: 20
+< Connection: keep-alive
+<
+* Connection #0 to host 192.168.99.100 left intact
+UserID: , UserRole:
+
+ + +

Test 2: secure service with no auth header

+
$ curl -H 'Host: secure-demo-echo-service.kube.local' -v 192.168.99.100
+* Rebuilt URL to: 192.168.99.100/
+*   Trying 192.168.99.100...
+* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)
+> GET / HTTP/1.1
+> Host: secure-demo-echo-service.kube.local
+> User-Agent: curl/7.43.0
+> Accept: */*
+>
+< HTTP/1.1 403 Forbidden
+< Server: nginx/1.11.10
+< Date: Mon, 13 Mar 2017 20:18:48 GMT
+< Content-Type: text/html
+< Content-Length: 170
+< Connection: keep-alive
+<
+<html>
+<head><title>403 Forbidden</title></head>
+<body bgcolor="white">
+<center><h1>403 Forbidden</h1></center>
+<hr><center>nginx/1.11.10</center>
+</body>
+</html>
+* Connection #0 to host 192.168.99.100 left intact
+
+ + +

Test 3: public service with valid auth header

+
$ curl -H 'Host: public-demo-echo-service.kube.local' -H 'User:internal' -v 192.168.99.100
+* Rebuilt URL to: 192.168.99.100/
+*   Trying 192.168.99.100...
+* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)
+> GET / HTTP/1.1
+> Host: public-demo-echo-service.kube.local
+> User-Agent: curl/7.43.0
+> Accept: */*
+> User:internal
+>
+< HTTP/1.1 200 OK
+< Server: nginx/1.11.10
+< Date: Mon, 13 Mar 2017 20:19:59 GMT
+< Content-Type: text/plain; charset=utf-8
+< Content-Length: 44
+< Connection: keep-alive
+<
+* Connection #0 to host 192.168.99.100 left intact
+UserID: 1443635317331776148, UserRole: admin
+
+ + +

Test 4: public service with valid auth header

+
$ curl -H 'Host: secure-demo-echo-service.kube.local' -H 'User:internal' -v 192.168.99.100
+* Rebuilt URL to: 192.168.99.100/
+*   Trying 192.168.99.100...
+* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)
+> GET / HTTP/1.1
+> Host: secure-demo-echo-service.kube.local
+> User-Agent: curl/7.43.0
+> Accept: */*
+> User:internal
+>
+< HTTP/1.1 200 OK
+< Server: nginx/1.11.10
+< Date: Mon, 13 Mar 2017 20:17:23 GMT
+< Content-Type: text/plain; charset=utf-8
+< Content-Length: 43
+< Connection: keep-alive
+<
+* Connection #0 to host 192.168.99.100 left intact
+UserID: 605394647632969758, UserRole: admin
+
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/customization/external-auth-headers/authsvc/Dockerfile b/examples/customization/external-auth-headers/authsvc/Dockerfile new file mode 100644 index 000000000..318eab4e8 --- /dev/null +++ b/examples/customization/external-auth-headers/authsvc/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine:3.5 +MAINTAINER Roman Safronov +COPY authsvc / +EXPOSE 8080 +ENTRYPOINT ["/authsvc"] diff --git a/examples/customization/external-auth-headers/authsvc/authsvc.go b/examples/customization/external-auth-headers/authsvc/authsvc.go new file mode 100644 index 000000000..7f254fc83 --- /dev/null +++ b/examples/customization/external-auth-headers/authsvc/authsvc.go @@ -0,0 +1,49 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "math/rand" + "net/http" + "strconv" + "strings" +) + +// Sample authentication service returning several HTTP headers in response +func main() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + if strings.ContainsAny(r.Header.Get("User"), "internal") { + w.Header().Add("UserID", strconv.Itoa(rand.Int())) + w.Header().Add("UserRole", "admin") + w.Header().Add("Other", "not used") + fmt.Fprint(w, "ok") + } else { + rc := http.StatusForbidden + if c := r.URL.Query().Get("code"); len(c) > 0 { + c, _ := strconv.Atoi(c) + if c > 0 && c < 600 { + rc = c + } + } + + w.WriteHeader(rc) + fmt.Fprint(w, "unauthorized") + } + }) + http.ListenAndServe(":8080", nil) +} diff --git a/examples/customization/external-auth-headers/deploy/auth-service.yaml b/examples/customization/external-auth-headers/deploy/auth-service.yaml new file mode 100644 index 000000000..af8f09518 --- /dev/null +++ b/examples/customization/external-auth-headers/deploy/auth-service.yaml @@ -0,0 +1,44 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: demo-auth-service + labels: + k8s-app: demo-auth-service + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + k8s-app: demo-auth-service + template: + metadata: + labels: + k8s-app: demo-auth-service + spec: + terminationGracePeriodSeconds: 60 + containers: + - name: auth-service + image: electroma/ingress-demo-authsvc-amd64:0.1 + ports: + - containerPort: 8080 + resources: + limits: + cpu: 10m + memory: 20Mi + requests: + cpu: 10m + memory: 20Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: demo-auth-service + labels: + k8s-app: demo-auth-service + namespace: default +spec: + ports: + - port: 80 + targetPort: 8080 + selector: + k8s-app: demo-auth-service diff --git a/examples/customization/external-auth-headers/deploy/echo-service.yaml b/examples/customization/external-auth-headers/deploy/echo-service.yaml new file mode 100644 index 000000000..363c4bf3d --- /dev/null +++ b/examples/customization/external-auth-headers/deploy/echo-service.yaml @@ -0,0 +1,80 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: demo-echo-service + labels: + k8s-app: demo-echo-service + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + k8s-app: demo-echo-service + template: + metadata: + labels: + k8s-app: demo-echo-service + spec: + terminationGracePeriodSeconds: 60 + containers: + - name: echo-service + image: electroma/ingress-demo-echosvc-amd64:0.1 + ports: + - containerPort: 8080 + resources: + limits: + cpu: 10m + memory: 20Mi + requests: + cpu: 10m + memory: 20Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: demo-echo-service + labels: + k8s-app: demo-echo-service + namespace: default +spec: + ports: + - port: 80 + targetPort: 8080 + selector: + k8s-app: demo-echo-service +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: public-demo-echo-service + annotations: + nginx.ingress.kubernetes.io/auth-url: http://demo-auth-service.default.svc.cluster.local?code=200 + nginx.ingress.kubernetes.io/auth-response-headers: UserID, UserRole + namespace: default +spec: + rules: + - host: public-demo-echo-service.kube.local + http: + paths: + - backend: + serviceName: demo-echo-service + servicePort: 80 + path: / +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: secure-demo-echo-service + annotations: + nginx.ingress.kubernetes.io/auth-url: http://demo-auth-service.default.svc.cluster.local + nginx.ingress.kubernetes.io/auth-response-headers: UserID, UserRole + namespace: default +spec: + rules: + - host: secure-demo-echo-service.kube.local + http: + paths: + - backend: + serviceName: demo-echo-service + servicePort: 80 + path: / diff --git a/examples/customization/external-auth-headers/echosvc/Dockerfile b/examples/customization/external-auth-headers/echosvc/Dockerfile new file mode 100644 index 000000000..a8fac219d --- /dev/null +++ b/examples/customization/external-auth-headers/echosvc/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine:3.5 +MAINTAINER Roman Safronov +COPY echosvc / +EXPOSE 8080 +ENTRYPOINT ["/echosvc"] diff --git a/examples/customization/external-auth-headers/echosvc/echosvc.go b/examples/customization/external-auth-headers/echosvc/echosvc.go new file mode 100644 index 000000000..ba9702aa0 --- /dev/null +++ b/examples/customization/external-auth-headers/echosvc/echosvc.go @@ -0,0 +1,32 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "net/http" +) + +func handler(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "UserID: %s, UserRole: %s", r.Header.Get("UserID"), r.Header.Get("UserRole")) +} + +// Sample "echo" service displaying UserID and UserRole HTTP request headers +func main() { + http.HandleFunc("/", handler) + http.ListenAndServe(":8080", nil) +} diff --git a/examples/customization/ssl-dh-param/README/index.html b/examples/customization/ssl-dh-param/README/index.html new file mode 100644 index 000000000..6fc7403f0 --- /dev/null +++ b/examples/customization/ssl-dh-param/README/index.html @@ -0,0 +1,1222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Deploying the Nginx Ingress controller - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Deploying the Nginx Ingress controller

+

This example aims to demonstrate the deployment of an nginx ingress controller and +use a ConfigMap to configure custom Diffie-Hellman parameters file to help with +"Perfect Forward Secrecy".

+

Custom configuration

+
$ cat configmap.yaml
+apiVersion: v1
+data:
+  ssl-dh-param: "ingress-nginx/lb-dhparam"
+kind: ConfigMap
+metadata:
+  name: nginx-configuration
+  namespace: ingress-nginx
+  labels:
+    app: ingress-nginx
+
+ + +
$ kubectl create -f configmap.yaml
+
+ + +

Custom DH parameters secret

+
$> openssl dhparam 1024 2> /dev/null | base64
+LS0tLS1CRUdJTiBESCBQQVJBTUVURVJ...
+
+ + +
$ cat ssl-dh-param.yaml
+apiVersion: v1
+data:
+  dhparam.pem: "LS0tLS1CRUdJTiBESCBQQVJBTUVURVJ..."
+kind: ConfigMap
+metadata:
+  name: nginx-configuration
+  namespace: ingress-nginx
+  labels:
+    app: ingress-nginx
+
+ + +
$ kubectl create -f ssl-dh-param.yaml
+
+ + +

Test

+

Check the contents of the configmap is present in the nginx.conf file using: +kubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/customization/ssl-dh-param/configmap.yaml b/examples/customization/ssl-dh-param/configmap.yaml new file mode 100644 index 000000000..71dd2903c --- /dev/null +++ b/examples/customization/ssl-dh-param/configmap.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +data: + ssl-dh-param: "ingress-nginx/lb-dhparam" +kind: ConfigMap +metadata: + name: nginx-configuration + namespace: ingress-nginx + labels: + app: ingress-nginx diff --git a/examples/customization/ssl-dh-param/ssl-dh-param.yaml b/examples/customization/ssl-dh-param/ssl-dh-param.yaml new file mode 100644 index 000000000..ba260b153 --- /dev/null +++ b/examples/customization/ssl-dh-param/ssl-dh-param.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +data: + dhparam.pem: "...base64 encoded data..." +kind: Secret +type: Opaque +metadata: + name: lb-dhparam + namespace: ingress-nginx diff --git a/examples/customization/sysctl/README/index.html b/examples/customization/sysctl/README/index.html new file mode 100644 index 000000000..fe64fdecd --- /dev/null +++ b/examples/customization/sysctl/README/index.html @@ -0,0 +1,1106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sysctl tuning - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Sysctl tuning

+

This example aims to demonstrate the use of an Init Container to adjust sysctl default values +using kubectl patch

+
kubectl patch deployment -n ingress-nginx nginx-ingress-controller --patch="$(cat patch.json)"
+
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/customization/sysctl/patch.json b/examples/customization/sysctl/patch.json new file mode 100644 index 000000000..56482f511 --- /dev/null +++ b/examples/customization/sysctl/patch.json @@ -0,0 +1,16 @@ +{ + "spec": { + "template": { + "spec": { + "initContainers": [{ + "name": "sysctl", + "image": "alpine:3.6", + "securityContext": { + "privileged": true + }, + "command": ["sh", "-c", "sysctl -w net.core.somaxconn=32768; sysctl -w net.ipv4.ip_local_port_range=1024 65535"] + }] + } + } + } +} \ No newline at end of file diff --git a/examples/docker-registry/README/index.html b/examples/docker-registry/README/index.html new file mode 100644 index 000000000..5c62a5ad1 --- /dev/null +++ b/examples/docker-registry/README/index.html @@ -0,0 +1,1233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Docker registry - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Docker registry

+

This example demonstrates how to deploy a docker registry in the cluster and configure Ingress enable access from Internet

+

Deployment

+

First we deploy the docker registry in the cluster:

+
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/deployment.yaml
+
+ + +

Important: DO NOT RUN THIS IN PRODUCTION. +This deployment uses emptyDir in the volumeMount which means the contents of the registry will be deleted when the pod dies.

+

The next required step is creation of the ingress rules. To do this we have two options: with and without TLS

+

Without TLS

+

Download and edit the yaml deployment replacing registry.<your domain> with a valid DNS name pointing to the ingress controller:

+
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/ingress-without-tls.yaml
+
+ + +

Important: running a docker registry without TLS requires we configure our local docker daemon with the insecure registry flag. +Please check deploy a plain http registry

+

With TLS

+

Download and edit the yaml deployment replacing registry.<your domain> with a valid DNS name pointing to the ingress controller:

+
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/ingress-with-tls.yaml
+
+ + +

Deploy kube lego use Let's Encrypt certificates or edit the ingress rule to use a secret with an existing SSL certificate.

+

Testing

+

To test the registry is working correctly we download a known image from docker hub, create a tag pointing to the new registry and upload the image:

+
docker pull ubuntu:16.04
+docker tag ubuntu:16.04 `registry.<your domain>/ubuntu:16.04`
+docker push `registry.<your domain>/ubuntu:16.04`
+
+ + +

Please replace registry.<your domain> with your domain.

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/docker-registry/deployment.yaml b/examples/docker-registry/deployment.yaml new file mode 100644 index 000000000..c9044b488 --- /dev/null +++ b/examples/docker-registry/deployment.yaml @@ -0,0 +1,56 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: docker-registry + +--- + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: docker-registry + namespace: docker-registry +spec: + replicas: 1 + selector: + matchLabels: + app: docker-registry + template: + metadata: + labels: + app: docker-registry + spec: + containers: + - name: docker-registry + image: registry:2.6.2 + env: + - name: REGISTRY_HTTP_ADDR + value: ":5000" + - name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY + value: "/var/lib/registry" + ports: + - name: http + containerPort: 5000 + volumeMounts: + - name: image-store + mountPath: "/var/lib/registry" + volumes: + - name: image-store + emptyDir: {} + +--- + +kind: Service +apiVersion: v1 +metadata: + name: docker-registry + namespace: docker-registry + labels: + app: docker-registry +spec: + selector: + app: docker-registry + ports: + - name: http + port: 5000 + targetPort: 5000 diff --git a/examples/docker-registry/ingress-with-tls.yaml b/examples/docker-registry/ingress-with-tls.yaml new file mode 100644 index 000000000..817d3d85f --- /dev/null +++ b/examples/docker-registry/ingress-with-tls.yaml @@ -0,0 +1,23 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/proxy-read-timeout: "600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "600" + kubernetes.io/tls-acme: 'true' + name: docker-registry + namespace: docker-registry +spec: + tls: + - hosts: + - registry. + secretName: registry-tls + rules: + - host: registry. + http: + paths: + - backend: + serviceName: docker-registry + servicePort: 5000 + path: / diff --git a/examples/docker-registry/ingress-without-tls.yaml b/examples/docker-registry/ingress-without-tls.yaml new file mode 100644 index 000000000..6c89101b6 --- /dev/null +++ b/examples/docker-registry/ingress-without-tls.yaml @@ -0,0 +1,18 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/proxy-read-timeout: "600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "600" + name: docker-registry + namespace: docker-registry +spec: + rules: + - host: registry. + http: + paths: + - backend: + serviceName: docker-registry + servicePort: 5000 + path: / diff --git a/examples/external-auth/README/index.html b/examples/external-auth/README/index.html new file mode 100644 index 000000000..3e20e8e46 --- /dev/null +++ b/examples/external-auth/README/index.html @@ -0,0 +1,1267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + External Authentication - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

External Authentication

+

Overview

+

The auth-url and auth-signin annotations allow you to use an external +authentication provider to protect your Ingress resources.

+

(Note, this annotation requires nginx-ingress-controller v0.9.0 or greater.)

+

Key Detail

+

This functionality is enabled by deploying multiple Ingress objects for a single host. +One Ingress object has no special annotations and handles authentication.

+

Other Ingress objects can then be annotated in such a way that require the user to +authenticate against the first Ingress's endpoint, and can redirect 401s to the +same endpoint.

+

Sample:

+
...
+metadata:
+  name: application
+  annotations:
+    "nginx.ingress.kubernetes.io/auth-url": "https://$host/oauth2/auth"
+    "nginx.ingress.kubernetes.io/auth-signin": "https://$host/oauth2/sign_in"
+...
+
+ + +

Example: OAuth2 Proxy + Kubernetes-Dashboard

+

This example will show you how to deploy oauth2_proxy +into a Kubernetes cluster and use it to protect the Kubernetes Dashboard using github as oAuth2 provider

+

Prepare

+
    +
  1. Install the kubernetes dashboard
  2. +
+
kubectl create -f https://raw.githubusercontent.com/kubernetes/kops/master/addons/kubernetes-dashboard/v1.5.0.yaml
+
+ + +
    +
  1. Create a custom Github OAuth application https://github.com/settings/applications/new
  2. +
+

Register OAuth2 Application

+
    +
  • Homepage URL is the FQDN in the Ingress rule, like https://foo.bar.com
  • +
  • Authorization callback URL is the same as the base FQDN plus /oauth2, like https://foo.bar.com/oauth2
  • +
+

Register OAuth2 Application

+
    +
  1. +

    Configure oauth2_proxy values in the file oauth2-proxy.yaml with the values:

    +
  2. +
  3. +

    OAUTH2_PROXY_CLIENT_ID with the github <Client ID>

    +
  4. +
  5. OAUTH2_PROXY_CLIENT_SECRET with the github <Client Secret>
  6. +
  7. +

    OAUTH2_PROXY_COOKIE_SECRET with value of python -c 'import os,base64; print base64.b64encode(os.urandom(16))'

    +
  8. +
  9. +

    Customize the contents of the file dashboard-ingress.yaml:

    +
  10. +
+

Replace __INGRESS_HOST__ with a valid FQDN and __INGRESS_SECRET__ with a Secret with a valid SSL certificate.

+
    +
  1. Deploy the oauth2 proxy and the ingress rules running:
  2. +
+
$ kubectl create -f oauth2-proxy.yaml,dashboard-ingress.yaml
+
+ + +

Test the oauth integration accessing the configured URL, like https://foo.bar.com

+

Register OAuth2 Application

+

Github authentication

+

Kubernetes dashboard

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/external-auth/dashboard-ingress.yaml b/examples/external-auth/dashboard-ingress.yaml new file mode 100644 index 000000000..3980a76a0 --- /dev/null +++ b/examples/external-auth/dashboard-ingress.yaml @@ -0,0 +1,38 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/auth-signin: https://$host/oauth2/start + nginx.ingress.kubernetes.io/auth-url: https://$host/oauth2/auth + name: external-auth-oauth2 + namespace: kube-system +spec: + rules: + - host: __INGRESS_HOST__ + http: + paths: + - backend: + serviceName: kubernetes-dashboard + servicePort: 80 + path: / + +--- + +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: oauth2-proxy + namespace: kube-system +spec: + rules: + - host: __INGRESS_HOST__ + http: + paths: + - backend: + serviceName: oauth2-proxy + servicePort: 4180 + path: /oauth2 + tls: + - hosts: + - __INGRESS_HOST__ + secretName: __INGRESS_SECRET__ diff --git a/examples/external-auth/images/dashboard.png b/examples/external-auth/images/dashboard.png new file mode 100644 index 000000000..3acb7bb11 Binary files /dev/null and b/examples/external-auth/images/dashboard.png differ diff --git a/examples/external-auth/images/github-auth.png b/examples/external-auth/images/github-auth.png new file mode 100644 index 000000000..a7ee97d7e Binary files /dev/null and b/examples/external-auth/images/github-auth.png differ diff --git a/examples/external-auth/images/oauth-login.png b/examples/external-auth/images/oauth-login.png new file mode 100644 index 000000000..c8f7f8b17 Binary files /dev/null and b/examples/external-auth/images/oauth-login.png differ diff --git a/examples/external-auth/images/register-oauth-app-2.png b/examples/external-auth/images/register-oauth-app-2.png new file mode 100644 index 000000000..ef69149bb Binary files /dev/null and b/examples/external-auth/images/register-oauth-app-2.png differ diff --git a/examples/external-auth/images/register-oauth-app.png b/examples/external-auth/images/register-oauth-app.png new file mode 100644 index 000000000..9d6baa87e Binary files /dev/null and b/examples/external-auth/images/register-oauth-app.png differ diff --git a/examples/external-auth/oauth2-proxy.yaml b/examples/external-auth/oauth2-proxy.yaml new file mode 100644 index 000000000..ed367b563 --- /dev/null +++ b/examples/external-auth/oauth2-proxy.yaml @@ -0,0 +1,57 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + labels: + k8s-app: oauth2-proxy + name: oauth2-proxy + namespace: kube-system +spec: + replicas: 1 + selector: + matchLabels: + k8s-app: oauth2-proxy + template: + metadata: + labels: + k8s-app: oauth2-proxy + spec: + containers: + - args: + - --provider=github + - --email-domain=* + - --upstream=file:///dev/null + - --http-address=0.0.0.0:4180 + # Register a new application + # https://github.com/settings/applications/new + env: + - name: OAUTH2_PROXY_CLIENT_ID + value: + - name: OAUTH2_PROXY_CLIENT_SECRET + value: + # python -c 'import os,base64; print base64.b64encode(os.urandom(16))' + - name: OAUTH2_PROXY_COOKIE_SECRET + value: SECRET + image: docker.io/colemickens/oauth2_proxy:latest + imagePullPolicy: Always + name: oauth2-proxy + ports: + - containerPort: 4180 + protocol: TCP + +--- + +apiVersion: v1 +kind: Service +metadata: + labels: + k8s-app: oauth2-proxy + name: oauth2-proxy + namespace: kube-system +spec: + ports: + - name: http + port: 4180 + protocol: TCP + targetPort: 4180 + selector: + k8s-app: oauth2-proxy diff --git a/examples/http-svc.yaml b/examples/http-svc.yaml new file mode 100644 index 000000000..ad074b9d0 --- /dev/null +++ b/examples/http-svc.yaml @@ -0,0 +1,53 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: http-svc +spec: + replicas: 1 + selector: + matchLabels: + app: http-svc + template: + metadata: + labels: + app: http-svc + spec: + containers: + - name: http-svc + image: gcr.io/google_containers/echoserver:1.8 + ports: + - containerPort: 8080 + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + +--- + +apiVersion: v1 +kind: Service +metadata: + name: http-svc + labels: + app: http-svc +spec: + ports: + - port: 80 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: http-svc diff --git a/examples/multi-tls/README/index.html b/examples/multi-tls/README/index.html new file mode 100644 index 000000000..7b0ca7bab --- /dev/null +++ b/examples/multi-tls/README/index.html @@ -0,0 +1,1191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Multi TLS certificate termination - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Multi TLS certificate termination

+

This example uses 2 different certificates to terminate SSL for 2 hostnames.

+
    +
  1. Deploy the controller by creating the rc in the parent dir
  2. +
  3. Create tls secrets for foo.bar.com and bar.baz.com as indicated in the yaml
  4. +
  5. Create multi-tls.yaml
  6. +
+

This should generate a segment like:

+
$ kubectl exec -it nginx-ingress-controller-6vwd1 -- cat /etc/nginx/nginx.conf | grep "foo.bar.com" -B 7 -A 35
+    server {
+        listen 80;
+        listen 443 ssl http2;
+        ssl_certificate /etc/nginx-ssl/default-foobar.pem;
+        ssl_certificate_key /etc/nginx-ssl/default-foobar.pem;
+
+
+        server_name foo.bar.com;
+
+
+        if ($scheme = http) {
+            return 301 https://$host$request_uri;
+        }
+
+
+
+        location / {
+            proxy_set_header Host                   $host;
+
+            # Pass Real IP
+            proxy_set_header X-Real-IP              $remote_addr;
+
+            # Allow websocket connections
+            proxy_set_header                        Upgrade           $http_upgrade;
+            proxy_set_header                        Connection        $connection_upgrade;
+
+            proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
+            proxy_set_header X-Forwarded-Host       $host;
+            proxy_set_header X-Forwarded-Proto      $pass_access_scheme;
+
+            proxy_connect_timeout                   5s;
+            proxy_send_timeout                      60s;
+            proxy_read_timeout                      60s;
+
+            proxy_redirect                          off;
+            proxy_buffering                         off;
+
+            proxy_http_version                      1.1;
+
+            proxy_pass http://default-http-svc-80;
+        }
+
+ + +

And you should be able to reach your nginx service or http-svc service using a hostname switch:

+
$  kubectl get ing
+NAME      RULE          BACKEND   ADDRESS                         AGE
+foo-tls   -                       104.154.30.67                   13m
+          foo.bar.com
+          /             http-svc:80
+          bar.baz.com
+          /             nginx:80
+
+$ curl https://104.154.30.67 -H 'Host:foo.bar.com' -k
+CLIENT VALUES:
+client_address=10.245.0.6
+command=GET
+real path=/
+query=nil
+request_version=1.1
+request_uri=http://foo.bar.com:8080/
+
+SERVER VALUES:
+server_version=nginx: 1.9.11 - lua: 10001
+
+HEADERS RECEIVED:
+accept=*/*
+connection=close
+host=foo.bar.com
+user-agent=curl/7.35.0
+x-forwarded-for=10.245.0.1
+x-forwarded-host=foo.bar.com
+x-forwarded-proto=https
+
+$ curl https://104.154.30.67 -H 'Host:bar.baz.com' -k
+<!DOCTYPE html>
+<html>
+<head>
+<title>Welcome to nginx on Debian!</title>
+
+$ curl 104.154.30.67
+default backend - 404
+
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/multi-tls/multi-tls.yaml b/examples/multi-tls/multi-tls.yaml new file mode 100644 index 000000000..f84ed1734 --- /dev/null +++ b/examples/multi-tls/multi-tls.yaml @@ -0,0 +1,116 @@ +apiVersion: v1 +kind: Service +metadata: + name: nginx + labels: + app: nginx +spec: + ports: + - port: 80 + targetPort: 80 + protocol: TCP + name: http + selector: + app: nginx +--- +apiVersion: v1 +kind: ReplicationController +metadata: + name: nginx +spec: + replicas: 1 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: gcr.io/google_containers/nginx + ports: + - containerPort: 80 +--- +apiVersion: v1 +kind: Service +metadata: + name: http-svc + labels: + app: http-svc +spec: + ports: + - port: 80 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: http-svc +--- +apiVersion: v1 +kind: ReplicationController +metadata: + name: http-svc +spec: + replicas: 1 + template: + metadata: + labels: + app: http-svc + spec: + containers: + - name: http-svc + image: gcr.io/google_containers/echoserver:1.8 + ports: + - containerPort: 8080 + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: foo-tls + namespace: default +spec: + tls: + - hosts: + - foo.bar.com + # This secret must exist beforehand + # The cert must also contain the subj-name foo.bar.com + # https://github.com/kubernetes/ingress-nginx/blob/master/docs/examples/PREREQUISITES.md#tls-certificates + secretName: foobar + - hosts: + - bar.baz.com + # This secret must exist beforehand + # The cert must also contain the subj-name bar.baz.com + # https://github.com/kubernetes/ingress-nginx/blob/master/docs/examples/PREREQUISITES.md#tls-certificates + secretName: barbaz + rules: + - host: foo.bar.com + http: + paths: + - backend: + serviceName: http-svc + servicePort: 80 + path: / + - host: bar.baz.com + http: + paths: + - backend: + serviceName: nginx + servicePort: 80 + path: / \ No newline at end of file diff --git a/examples/rewrite/README/index.html b/examples/rewrite/README/index.html new file mode 100644 index 000000000..a32689be7 --- /dev/null +++ b/examples/rewrite/README/index.html @@ -0,0 +1,1361 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Rewrite - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Rewrite

+

This example demonstrates how to use the Rewrite annotations

+

Prerequisites

+

You will need to make sure your Ingress targets exactly one Ingress +controller by specifying the ingress.class annotation, +and that you have an ingress controller running in your cluster.

+

Deployment

+

Rewriting can be controlled using the following annotations:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescriptionValues
nginx.ingress.kubernetes.io/rewrite-targetTarget URI where the traffic must be redirectedstring
nginx.ingress.kubernetes.io/add-base-urlindicates if is required to add a base tag in the head of the responses from the upstream serversbool
nginx.ingress.kubernetes.io/base-url-schemeOverride for the scheme passed to the base tagstring
nginx.ingress.kubernetes.io/ssl-redirectIndicates if the location section is accessible SSL only (defaults to True when Ingress contains a Certificate)bool
nginx.ingress.kubernetes.io/force-ssl-redirectForces the redirection to HTTPS even if the Ingress is not TLS Enabledbool
nginx.ingress.kubernetes.io/app-rootDefines the Application Root that the Controller must redirect if it's in '/' contextstring
+

Validation

+

Rewrite Target

+

Create an Ingress rule with a rewrite annotation:

+
$ echo "
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  annotations:
+    nginx.ingress.kubernetes.io/rewrite-target: /
+  name: rewrite
+  namespace: default
+spec:
+  rules:
+  - host: rewrite.bar.com
+    http:
+      paths:
+      - backend:
+          serviceName: http-svc
+          servicePort: 80
+        path: /something
+" | kubectl create -f -
+
+ + +

Check the rewrite is working

+
$ curl -v http://172.17.4.99/something -H 'Host: rewrite.bar.com'
+*   Trying 172.17.4.99...
+* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)
+> GET /something HTTP/1.1
+> Host: rewrite.bar.com
+> User-Agent: curl/7.43.0
+> Accept: */*
+>
+< HTTP/1.1 200 OK
+< Server: nginx/1.11.0
+< Date: Tue, 31 May 2016 16:07:31 GMT
+< Content-Type: text/plain
+< Transfer-Encoding: chunked
+< Connection: keep-alive
+<
+CLIENT VALUES:
+client_address=10.2.56.9
+command=GET
+real path=/
+query=nil
+request_version=1.1
+request_uri=http://rewrite.bar.com:8080/
+
+SERVER VALUES:
+server_version=nginx: 1.9.11 - lua: 10001
+
+HEADERS RECEIVED:
+accept=*/*
+connection=close
+host=rewrite.bar.com
+user-agent=curl/7.43.0
+x-forwarded-for=10.2.56.1
+x-forwarded-host=rewrite.bar.com
+x-forwarded-port=80
+x-forwarded-proto=http
+x-real-ip=10.2.56.1
+BODY:
+* Connection #0 to host 172.17.4.99 left intact
+-no body in request-
+
+ + +

App Root

+

Create an Ingress rule with a app-root annotation:

+
$ echo "
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  annotations:
+    nginx.ingress.kubernetes.io/app-root: /app1
+  name: approot
+  namespace: default
+spec:
+  rules:
+  - host: approot.bar.com
+    http:
+      paths:
+      - backend:
+          serviceName: http-svc
+          servicePort: 80
+        path: /
+" | kubectl create -f -
+
+ + +

Check the rewrite is working

+
$ curl -I -k http://approot.bar.com/
+HTTP/1.1 302 Moved Temporarily
+Server: nginx/1.11.10
+Date: Mon, 13 Mar 2017 14:57:15 GMT
+Content-Type: text/html
+Content-Length: 162
+Location: http://stickyingress.example.com/app1
+Connection: keep-alive
+
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/static-ip/README/index.html b/examples/static-ip/README/index.html new file mode 100644 index 000000000..1f641c922 --- /dev/null +++ b/examples/static-ip/README/index.html @@ -0,0 +1,1300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Static IPs - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Static IPs

+

This example demonstrates how to assign a static-ip to an Ingress on through the Nginx controller.

+

Prerequisites

+

You need a TLS cert and a test HTTP service for this example. +You will also need to make sure your Ingress targets exactly one Ingress +controller by specifying the ingress.class annotation, +and that you have an ingress controller running in your cluster.

+

Acquiring an IP

+

Since instances of the nginx controller actually run on nodes in your cluster, +by default nginx Ingresses will only get static IPs if your cloudprovider +supports static IP assignments to nodes. On GKE/GCE for example, even though +nodes get static IPs, the IPs are not retained across upgrade.

+

To acquire a static IP for the nginx ingress controller, simply put it +behind a Service of Type=LoadBalancer.

+

First, create a loadbalancer Service and wait for it to acquire an IP

+
$ kubectl create -f static-ip-svc.yaml
+service "nginx-ingress-lb" created
+
+$ kubectl get svc nginx-ingress-lb
+NAME               CLUSTER-IP     EXTERNAL-IP       PORT(S)                      AGE
+nginx-ingress-lb   10.0.138.113   104.154.109.191   80:31457/TCP,443:32240/TCP   15m
+
+ + +

then, update the ingress controller so it adopts the static IP of the Service +by passing the --publish-service flag (the example yaml used in the next step +already has it set to "nginx-ingress-lb").

+
$ kubectl create -f nginx-ingress-controller.yaml
+deployment "nginx-ingress-controller" created
+
+ + +

Assigning the IP to an Ingress

+

From here on every Ingress created with the ingress.class annotation set to +nginx will get the IP allocated in the previous step

+
$ kubectl create -f nginx-ingress.yaml
+ingress "nginx-ingress" created
+
+$ kubectl get ing nginx-ingress
+NAME            HOSTS     ADDRESS           PORTS     AGE
+nginx-ingress   *         104.154.109.191   80, 443   13m
+
+$ curl 104.154.109.191 -kL
+CLIENT VALUES:
+client_address=10.180.1.25
+command=GET
+real path=/
+query=nil
+request_version=1.1
+request_uri=http://104.154.109.191:8080/
+...
+
+ + +

Retaining the IP

+

You can test retention by deleting the Ingress

+
$ kubectl delete ing nginx-ingress
+ingress "nginx-ingress" deleted
+
+$ kubectl create -f nginx-ingress.yaml
+ingress "nginx-ingress" created
+
+$ kubectl get ing nginx-ingress
+NAME            HOSTS     ADDRESS           PORTS     AGE
+nginx-ingress   *         104.154.109.191   80, 443   13m
+
+ + +

Note that unlike the GCE Ingress, the same loadbalancer IP is shared amongst all +Ingresses, because all requests are proxied through the same set of nginx +controllers.

+

Promote ephemeral to static IP

+

To promote the allocated IP to static, you can update the Service manifest

+
$ kubectl patch svc nginx-ingress-lb -p '{"spec": {"loadBalancerIP": "104.154.109.191"}}'
+"nginx-ingress-lb" patched
+
+ + +

and promote the IP to static (promotion works differently for cloudproviders, +provided example is for GKE/GCE) +`

+
$ gcloud compute addresses create nginx-ingress-lb --addresses 104.154.109.191 --region us-central1
+Created [https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb].
+---
+address: 104.154.109.191
+creationTimestamp: '2017-01-31T16:34:50.089-08:00'
+description: ''
+id: '5208037144487826373'
+kind: compute#address
+name: nginx-ingress-lb
+region: us-central1
+selfLink: https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb
+status: IN_USE
+users:
+- us-central1/forwardingRules/a09f6913ae80e11e6a8c542010af0000
+
+ + +

Now even if the Service is deleted, the IP will persist, so you can recreate the +Service with spec.loadBalancerIP set to 104.154.109.191.

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/static-ip/nginx-ingress-controller.yaml b/examples/static-ip/nginx-ingress-controller.yaml new file mode 100644 index 000000000..5b97148a3 --- /dev/null +++ b/examples/static-ip/nginx-ingress-controller.yaml @@ -0,0 +1,55 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: nginx-ingress-controller + labels: + k8s-app: nginx-ingress-controller +spec: + replicas: 1 + selector: + matchLabels: + k8s-app: nginx-ingress-controller + template: + metadata: + labels: + k8s-app: nginx-ingress-controller + spec: + # hostNetwork makes it possible to use ipv6 and to preserve the source IP correctly regardless of docker configuration + # however, it is not a hard dependency of the nginx-ingress-controller itself and it may cause issues if port 10254 already is taken on the host + # that said, since hostPort is broken on CNI (https://github.com/kubernetes/kubernetes/issues/31307) we have to use hostNetwork where CNI is used + # like with kubeadm + # hostNetwork: true + terminationGracePeriodSeconds: 60 + containers: + - image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.13.0 + name: nginx-ingress-controller + readinessProbe: + httpGet: + path: /healthz + port: 10254 + scheme: HTTP + livenessProbe: + httpGet: + path: /healthz + port: 10254 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 1 + ports: + - containerPort: 80 + hostPort: 80 + - containerPort: 443 + hostPort: 443 + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + args: + - /nginx-ingress-controller + - --default-backend-service=$(POD_NAMESPACE)/default-http-backend + - --publish-service=$(POD_NAMESPACE)/nginx-ingress-lb diff --git a/examples/static-ip/nginx-ingress.yaml b/examples/static-ip/nginx-ingress.yaml new file mode 100644 index 000000000..1db6ee335 --- /dev/null +++ b/examples/static-ip/nginx-ingress.yaml @@ -0,0 +1,15 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: ingress-nginx +spec: + tls: + # This assumes tls-secret exists. + - secretName: tls-secret + rules: + - http: + paths: + - backend: + # This assumes http-svc exists and routes to healthy endpoints. + serviceName: http-svc + servicePort: 80 diff --git a/examples/static-ip/static-ip-svc.yaml b/examples/static-ip/static-ip-svc.yaml new file mode 100644 index 000000000..27de0690d --- /dev/null +++ b/examples/static-ip/static-ip-svc.yaml @@ -0,0 +1,22 @@ +# This is the backend service +apiVersion: v1 +kind: Service +metadata: + name: nginx-ingress-lb + labels: + app: nginx-ingress-lb +spec: + externalTrafficPolicy: Local + type: LoadBalancer + loadBalancerIP: 104.154.109.191 + ports: + - port: 80 + name: http + targetPort: 80 + - port: 443 + name: https + targetPort: 443 + selector: + # Selects nginx-ingress-controller pods + k8s-app: nginx-ingress-controller + diff --git a/examples/tls-termination/README/index.html b/examples/tls-termination/README/index.html new file mode 100644 index 000000000..3add061aa --- /dev/null +++ b/examples/tls-termination/README/index.html @@ -0,0 +1,1233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TLS termination - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

TLS termination

+

This example demonstrates how to terminate TLS through the nginx Ingress controller.

+

Prerequisites

+

You need a TLS cert and a test HTTP service for this example.

+

Deployment

+

The following command instructs the controller to terminate traffic using the provided +TLS cert, and forward un-encrypted HTTP traffic to the test HTTP service.

+
kubectl apply -f ingress.yaml
+
+ + +

Validation

+

You can confirm that the Ingress works.

+
$ kubectl describe ing nginx-test
+Name:           nginx-test
+Namespace:      default
+Address:        104.198.183.6
+Default backend:    default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080)
+TLS:
+  tls-secret terminates
+Rules:
+  Host  Path    Backends
+  ----  ----    --------
+  *
+            http-svc:80 (<none>)
+Annotations:
+Events:
+  FirstSeen LastSeen    Count   From                SubObjectPath   Type        Reason  Message
+  --------- --------    -----   ----                -------------   --------    ------  -------
+  7s        7s      1   {nginx-ingress-controller }         Normal      CREATE  default/nginx-test
+  7s        7s      1   {nginx-ingress-controller }         Normal      UPDATE  default/nginx-test
+  7s        7s      1   {nginx-ingress-controller }         Normal      CREATE  ip: 104.198.183.6
+  7s        7s      1   {nginx-ingress-controller }         Warning     MAPPING Ingress rule 'default/nginx-test' contains no path definition. Assuming /
+
+$ curl 104.198.183.6 -L
+curl: (60) SSL certificate problem: self signed certificate
+More details here: http://curl.haxx.se/docs/sslcerts.html
+
+$ curl 104.198.183.6 -Lk
+CLIENT VALUES:
+client_address=10.240.0.4
+command=GET
+real path=/
+query=nil
+request_version=1.1
+request_uri=http://35.186.221.137:8080/
+
+SERVER VALUES:
+server_version=nginx: 1.9.11 - lua: 10001
+
+HEADERS RECEIVED:
+accept=*/*
+connection=Keep-Alive
+host=35.186.221.137
+user-agent=curl/7.46.0
+via=1.1 google
+x-cloud-trace-context=f708ea7e369d4514fc90d51d7e27e91d/13322322294276298106
+x-forwarded-for=104.132.0.80, 35.186.221.137
+x-forwarded-proto=https
+BODY:
+
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/examples/tls-termination/ingress.yaml b/examples/tls-termination/ingress.yaml new file mode 100644 index 000000000..b5decf8f2 --- /dev/null +++ b/examples/tls-termination/ingress.yaml @@ -0,0 +1,20 @@ +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: nginx-test +spec: + tls: + - hosts: + - foo.bar.com + # This assumes tls-secret exists and the SSL + # certificate contains a CN for foo.bar.com + secretName: tls-secret + rules: + - host: foo.bar.com + http: + paths: + - path: / + backend: + # This assumes http-svc exists and routes to healthy endpoints + serviceName: http-svc + servicePort: 80 diff --git a/images/elb-l7-listener.png b/images/elb-l7-listener.png new file mode 100644 index 000000000..006c69871 Binary files /dev/null and b/images/elb-l7-listener.png differ diff --git a/images/zipkin-demo.png b/images/zipkin-demo.png new file mode 100644 index 000000000..8b5970b72 Binary files /dev/null and b/images/zipkin-demo.png differ diff --git a/index.html b/index.html new file mode 100644 index 000000000..6d7bfd552 --- /dev/null +++ b/index.html @@ -0,0 +1,1132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Welcome

+

This is the documentation for the NGINX Ingress Controller.

+

It is built around the Kubernetes Ingress resource, using a ConfigMap to store the NGINX configuration.

+

Learn more about using Ingress on k8s.io.

+

Getting Started

+

See Deployment for a whirlwind tour that will get you started.

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/ingress-controller-catalog/index.html b/ingress-controller-catalog/index.html new file mode 100644 index 000000000..f1e4e4bac --- /dev/null +++ b/ingress-controller-catalog/index.html @@ -0,0 +1,1109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ingress Controller Catalog - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Ingress Controller Catalog

+

This is a non-comprehensive list of existing ingress controllers.

+ + + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 000000000..a63dfd263 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1,1689 @@ +{ + "docs": [ + { + "location": "/", + "text": "Welcome\n\u00b6\n\n\nThis is the documentation for the NGINX Ingress Controller.\n\n\nIt is built around the \nKubernetes Ingress resource\n, using a \nConfigMap\n to store the NGINX configuration.\n\n\nLearn more about using Ingress on \nk8s.io\n.\n\n\nGetting Started\n\u00b6\n\n\nSee \nDeployment\n for a whirlwind tour that will get you started.", + "title": "Welcome" + }, + { + "location": "/#welcome", + "text": "This is the documentation for the NGINX Ingress Controller. It is built around the Kubernetes Ingress resource , using a ConfigMap to store the NGINX configuration. Learn more about using Ingress on k8s.io .", + "title": "Welcome" + }, + { + "location": "/#getting-started", + "text": "See Deployment for a whirlwind tour that will get you started.", + "title": "Getting Started" + }, + { + "location": "/deploy/", + "text": "Installation Guide\n\u00b6\n\n\nContents\n\u00b6\n\n\n\n\nMandatory commands\n\n\nInstall without RBAC roles\n\n\nInstall with RBAC roles\n\n\nCustom Provider\n\n\nDocker for Mac\n\n\nminikube\n\n\nAWS\n\n\nGCE - GKE\n\n\nAzure\n\n\nBaremetal\n\n\nUsing Helm\n\n\nVerify installation\n\n\nDetect installed version\n\n\nDeploying the config-map\n\n\n\n\nGeneric Deployment\n\u00b6\n\n\nThe following resources are required for a generic deployment.\n\n\nMandatory commands\n\u00b6\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/namespace.yaml \\\n\n\n | kubectl apply -f -\n\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/default-backend.yaml \\\n\n\n | kubectl apply -f -\n\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/configmap.yaml \\\n\n\n | kubectl apply -f -\n\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/tcp-services-configmap.yaml \\\n\n\n | kubectl apply -f -\n\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/udp-services-configmap.yaml \\\n\n\n | kubectl apply -f -\n\n\n\n\n\n\nInstall without RBAC roles\n\u00b6\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/without-rbac.yaml \\\n\n\n | kubectl apply -f -\n\n\n\n\n\n\nInstall with RBAC roles\n\u00b6\n\n\nPlease check the \nRBAC\n document.\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/rbac.yaml \\\n\n\n | kubectl apply -f -\n\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/with-rbac.yaml \\\n\n\n | kubectl apply -f -\n\n\n\n\n\n\nCustom Service Provider Deployment\n\u00b6\n\n\nThere are cloud provider specific yaml files.\n\n\nDocker for Mac\n\u00b6\n\n\nKubernetes is available for Docker for Mac's Edge channel. Switch to the \nEdge\nchannel\n and \nenable Kubernetes\n.\n\n\nPatch the nginx ingress controller deployment to add the flag \n--publish-service\n\n\nkubectl patch deployment -n ingress-nginx nginx-ingress-controller --type='json' \\\n\n\n --patch=\"$(curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/publish-service-patch.yaml)\"\n\n\n\n\n\n\nCreate a service\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/docker-for-mac/service.yaml \\\n\n\n | kubectl apply -f -\n\n\n\n\n\n\nminikube\n\u00b6\n\n\nFor standard usage:\n\n\nminikube addons enable ingress\n\n\n\n\n\n\nFor development:\n\n\n\n\nDisable the ingress addon:\n\n\n\n\n$\n minikube addons disable ingress\n\n\n\n\n\n\n\nUse the \ndocker daemon\n\n\nBuild the image\n\n\nPerform \nMandatory commands\n\n\nInstall the \nnginx-ingress-controller\n deployment \nwithout RBAC roles\n or \nwith RBAC roles\n\n\nEdit the \nnginx-ingress-controller\n deployment to use your custom image. Local images can be seen by performing \ndocker images\n.\n\n\n\n\n$\n kubectl edit deployment nginx-ingress-controller -n ingress-nginx\n\n\n\n\n\nedit the following section:\n\n\nimage\n:\n \n:\n\n\nimagePullPolicy\n:\n \nIfNotPresent\n\n\nname\n:\n \nnginx-ingress-controller\n\n\n\n\n\n\n\n\nConfirm the \nnginx-ingress-controller\n deployment exists:\n\n\n\n\n$\n kubectl get pods -n ingress-nginx \n\nNAME READY STATUS RESTARTS AGE\n\n\ndefault-http-backend-66b447d9cf-rrlf9 1/1 Running 0 12s\n\n\nnginx-ingress-controller-fdcdcd6dd-vvpgs 1/1 Running 0 11s\n\n\n\n\n\n\nAWS\n\u00b6\n\n\nIn AWS we use an Elastic Load Balancer (ELB) to expose the NGINX Ingress controller behind a Service of \nType=LoadBalancer\n.\nSince Kubernetes v1.9.0 it is possible to use a classic load balancer (ELB) or network load balancer (NLB)\nPlease check the \nelastic load balancing AWS details page\n\n\nElastic Load Balancer - ELB\n\u00b6\n\n\nThis setup requires to choose in which layer (L4 or L7) we want to configure the ELB:\n\n\n\n\nLayer 4\n: use TCP as the listener protocol for ports 80 and 443.\n\n\nLayer 7\n: use HTTP as the listener protocol for port 80 and terminate TLS in the ELB\n\n\n\n\nPatch the nginx ingress controller deployment to add the flag \n--publish-service\n\n\nkubectl patch deployment -n ingress-nginx nginx-ingress-controller --type='json' \\\n\n\n --patch=\"$(curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/publish-service-patch.yaml)\"\n\n\n\n\n\n\nFor L4:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/service-l4.yaml\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/patch-configmap-l4.yaml\n\n\n\n\n\n\nFor L7:\n\n\nChange line of the file \nprovider/aws/service-l7.yaml\n replacing the dummy id with a valid one \n\"arn:aws:acm:us-west-2:XXXXXXXX:certificate/XXXXXX-XXXXXXX-XXXXXXX-XXXXXXXX\"\n\nThen execute:\n\n\nkubectl apply -f provider/aws/service-l7.yaml\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/patch-configmap-l7.yaml\n\n\n\n\n\n\nThis example creates an ELB with just two listeners, one in port 80 and another in port 443\n\n\n\n\nIf the ingress controller uses RBAC run:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-with-rbac.yaml\n\n\n\n\n\n\nIf not run:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-without-rbac.yaml\n\n\n\n\n\n\nNetwork Load Balancer (NLB)\n\u00b6\n\n\nThis type of load balancer is supported since v1.10.0 as an ALPHA feature.\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/service-nlb.yaml\n\n\n\n\n\n\nIf the ingress controller uses RBAC run:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-with-rbac.yaml\n\n\n\n\n\n\nIf not run:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-without-rbac.yaml\n\n\n\n\n\n\nGCE - GKE\n\u00b6\n\n\nPatch the nginx ingress controller deployment to add the flag \n--publish-service\n\n\nkubectl patch deployment -n ingress-nginx nginx-ingress-controller --type='json' \\\n\n\n --patch=\"$(curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/publish-service-patch.yaml)\"\n\n\n\n\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/gce-gke/service.yaml \\\n\n\n | kubectl apply -f -\n\n\n\n\n\n\nIf the ingress controller uses RBAC run:\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-with-rbac.yaml | kubectl apply -f -\n\n\n\n\n\n\nIf not run:\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-without-rbac.yaml | kubectl apply -f -\n\n\n\n\n\n\nImportant Note:\n proxy protocol is not supported in GCE/GKE\n\n\nAzure\n\u00b6\n\n\nPatch the nginx ingress controller deployment to add the flag \n--publish-service\n\n\nkubectl patch deployment -n ingress-nginx nginx-ingress-controller --type='json' \\\n\n\n --patch=\"$(curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/publish-service-patch.yaml)\"\n\n\n\n\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/azure/service.yaml \\\n\n\n | kubectl apply -f -\n\n\n\n\n\n\nIf the ingress controller uses RBAC run:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-with-rbac.yaml\n\n\n\n\n\n\nIf not run:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-without-rbac.yaml\n\n\n\n\n\n\nImportant Note:\n proxy protocol is not supported in GCE/GKE\n\n\nBaremetal\n\u00b6\n\n\nUsing \nNodePort\n:\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml \\\n\n\n | kubectl apply -f -\n\n\n\n\n\n\nUsing Helm\n\u00b6\n\n\nNGINX Ingress controller can be installed via \nHelm\n using the chart \nstable/nginx\n from the official charts repository. \nTo install the chart with the release name \nmy-nginx\n:\n\n\nhelm install stable/nginx-ingress --name my-nginx\n\n\n\n\n\n\nIf the kubernetes cluster has RBAC enabled, then run:\n\n\nhelm install stable/nginx-ingress --name my-nginx --set rbac.create=true\n\n\n\n\n\n\nVerify installation\n\u00b6\n\n\nTo check if the ingress controller pods have started, run the following command:\n\n\nkubectl get pods --all-namespaces -l app=ingress-nginx --watch\n\n\n\n\n\n\nOnce the operator pods are running, you can cancel the above command by typing \nCtrl+C\n.\nNow, you are ready to create your first ingress.\n\n\nDetect installed version\n\u00b6\n\n\nTo detect which version of the ingress controller is running, exec into the pod and run \nnginx-ingress-controller version\n command.\n\n\nPOD_NAMESPACE=ingress-nginx\n\n\nPOD_NAME=$(kubectl get pods -n $POD_NAMESPACE -l app=ingress-nginx -o jsonpath={.items[0].metadata.name})\n\n\nkubectl exec -it $POD_NAME -n $POD_NAMESPACE -- /nginx-ingress-controller --version\n\n\n\n\n\n\nDeploying the config-map\n\u00b6\n\n\nA config map can be used to configure system components for the nginx-controller. In order to begin using a config-map\nmake sure it has been created and is being used in the deployment.\n\n\nIt is created as seen in the \nMandatory Commands\n section above.\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/configmap.yaml \\\n\n\n | kubectl apply -f -\n\n\n\n\n\n\nand is setup to be used in the deployment \nwithout-rbac\n or \nwith-rbac\n with the following line:\n\n\n-\n \n--configmap=$(POD_NAMESPACE)/nginx-configuration\n\n\n\n\n\n\nFor information on using the config-map, see its \nuser-guide\n.", + "title": "Installation Guide" + }, + { + "location": "/deploy/#installation-guide", + "text": "", + "title": "Installation Guide" + }, + { + "location": "/deploy/#contents", + "text": "Mandatory commands Install without RBAC roles Install with RBAC roles Custom Provider Docker for Mac minikube AWS GCE - GKE Azure Baremetal Using Helm Verify installation Detect installed version Deploying the config-map", + "title": "Contents" + }, + { + "location": "/deploy/#generic-deployment", + "text": "The following resources are required for a generic deployment.", + "title": "Generic Deployment" + }, + { + "location": "/deploy/#mandatory-commands", + "text": "curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/namespace.yaml \\ | kubectl apply -f - curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/default-backend.yaml \\ | kubectl apply -f - curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/configmap.yaml \\ | kubectl apply -f - curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/tcp-services-configmap.yaml \\ | kubectl apply -f - curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/udp-services-configmap.yaml \\ | kubectl apply -f -", + "title": "Mandatory commands" + }, + { + "location": "/deploy/#install-without-rbac-roles", + "text": "curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/without-rbac.yaml \\ | kubectl apply -f -", + "title": "Install without RBAC roles" + }, + { + "location": "/deploy/#install-with-rbac-roles", + "text": "Please check the RBAC document. curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/rbac.yaml \\ | kubectl apply -f - curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/with-rbac.yaml \\ | kubectl apply -f -", + "title": "Install with RBAC roles" + }, + { + "location": "/deploy/#custom-service-provider-deployment", + "text": "There are cloud provider specific yaml files.", + "title": "Custom Service Provider Deployment" + }, + { + "location": "/deploy/#docker-for-mac", + "text": "Kubernetes is available for Docker for Mac's Edge channel. Switch to the Edge\nchannel and enable Kubernetes . Patch the nginx ingress controller deployment to add the flag --publish-service kubectl patch deployment -n ingress-nginx nginx-ingress-controller --type='json' \\ --patch=\"$(curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/publish-service-patch.yaml)\" Create a service curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/docker-for-mac/service.yaml \\ | kubectl apply -f -", + "title": "Docker for Mac" + }, + { + "location": "/deploy/#minikube", + "text": "For standard usage: minikube addons enable ingress For development: Disable the ingress addon: $ minikube addons disable ingress Use the docker daemon Build the image Perform Mandatory commands Install the nginx-ingress-controller deployment without RBAC roles or with RBAC roles Edit the nginx-ingress-controller deployment to use your custom image. Local images can be seen by performing docker images . $ kubectl edit deployment nginx-ingress-controller -n ingress-nginx edit the following section: image : : imagePullPolicy : IfNotPresent name : nginx-ingress-controller Confirm the nginx-ingress-controller deployment exists: $ kubectl get pods -n ingress-nginx NAME READY STATUS RESTARTS AGE default-http-backend-66b447d9cf-rrlf9 1/1 Running 0 12s nginx-ingress-controller-fdcdcd6dd-vvpgs 1/1 Running 0 11s", + "title": "minikube" + }, + { + "location": "/deploy/#aws", + "text": "In AWS we use an Elastic Load Balancer (ELB) to expose the NGINX Ingress controller behind a Service of Type=LoadBalancer .\nSince Kubernetes v1.9.0 it is possible to use a classic load balancer (ELB) or network load balancer (NLB)\nPlease check the elastic load balancing AWS details page", + "title": "AWS" + }, + { + "location": "/deploy/#elastic-load-balancer-elb", + "text": "This setup requires to choose in which layer (L4 or L7) we want to configure the ELB: Layer 4 : use TCP as the listener protocol for ports 80 and 443. Layer 7 : use HTTP as the listener protocol for port 80 and terminate TLS in the ELB Patch the nginx ingress controller deployment to add the flag --publish-service kubectl patch deployment -n ingress-nginx nginx-ingress-controller --type='json' \\ --patch=\"$(curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/publish-service-patch.yaml)\" For L4: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/service-l4.yaml kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/patch-configmap-l4.yaml For L7: Change line of the file provider/aws/service-l7.yaml replacing the dummy id with a valid one \"arn:aws:acm:us-west-2:XXXXXXXX:certificate/XXXXXX-XXXXXXX-XXXXXXX-XXXXXXXX\" \nThen execute: kubectl apply -f provider/aws/service-l7.yaml kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/patch-configmap-l7.yaml This example creates an ELB with just two listeners, one in port 80 and another in port 443 If the ingress controller uses RBAC run: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-with-rbac.yaml If not run: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-without-rbac.yaml", + "title": "Elastic Load Balancer - ELB" + }, + { + "location": "/deploy/#network-load-balancer-nlb", + "text": "This type of load balancer is supported since v1.10.0 as an ALPHA feature. kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/aws/service-nlb.yaml If the ingress controller uses RBAC run: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-with-rbac.yaml If not run: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-without-rbac.yaml", + "title": "Network Load Balancer (NLB)" + }, + { + "location": "/deploy/#gce-gke", + "text": "Patch the nginx ingress controller deployment to add the flag --publish-service kubectl patch deployment -n ingress-nginx nginx-ingress-controller --type='json' \\ --patch=\"$(curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/publish-service-patch.yaml)\" curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/gce-gke/service.yaml \\ | kubectl apply -f - If the ingress controller uses RBAC run: curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-with-rbac.yaml | kubectl apply -f - If not run: curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-without-rbac.yaml | kubectl apply -f - Important Note: proxy protocol is not supported in GCE/GKE", + "title": "GCE - GKE" + }, + { + "location": "/deploy/#azure", + "text": "Patch the nginx ingress controller deployment to add the flag --publish-service kubectl patch deployment -n ingress-nginx nginx-ingress-controller --type='json' \\ --patch=\"$(curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/publish-service-patch.yaml)\" curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/azure/service.yaml \\ | kubectl apply -f - If the ingress controller uses RBAC run: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-with-rbac.yaml If not run: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/patch-service-without-rbac.yaml Important Note: proxy protocol is not supported in GCE/GKE", + "title": "Azure" + }, + { + "location": "/deploy/#baremetal", + "text": "Using NodePort : curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml \\ | kubectl apply -f -", + "title": "Baremetal" + }, + { + "location": "/deploy/#using-helm", + "text": "NGINX Ingress controller can be installed via Helm using the chart stable/nginx from the official charts repository. \nTo install the chart with the release name my-nginx : helm install stable/nginx-ingress --name my-nginx If the kubernetes cluster has RBAC enabled, then run: helm install stable/nginx-ingress --name my-nginx --set rbac.create=true", + "title": "Using Helm" + }, + { + "location": "/deploy/#verify-installation", + "text": "To check if the ingress controller pods have started, run the following command: kubectl get pods --all-namespaces -l app=ingress-nginx --watch Once the operator pods are running, you can cancel the above command by typing Ctrl+C .\nNow, you are ready to create your first ingress.", + "title": "Verify installation" + }, + { + "location": "/deploy/#detect-installed-version", + "text": "To detect which version of the ingress controller is running, exec into the pod and run nginx-ingress-controller version command. POD_NAMESPACE=ingress-nginx POD_NAME=$(kubectl get pods -n $POD_NAMESPACE -l app=ingress-nginx -o jsonpath={.items[0].metadata.name}) kubectl exec -it $POD_NAME -n $POD_NAMESPACE -- /nginx-ingress-controller --version", + "title": "Detect installed version" + }, + { + "location": "/deploy/#deploying-the-config-map", + "text": "A config map can be used to configure system components for the nginx-controller. In order to begin using a config-map\nmake sure it has been created and is being used in the deployment. It is created as seen in the Mandatory Commands section above. curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/configmap.yaml \\ | kubectl apply -f - and is setup to be used in the deployment without-rbac or with-rbac with the following line: - --configmap=$(POD_NAMESPACE)/nginx-configuration For information on using the config-map, see its user-guide .", + "title": "Deploying the config-map" + }, + { + "location": "/deploy/rbac/", + "text": "Role Based Access Control (RBAC)\n\u00b6\n\n\nOverview\n\u00b6\n\n\nThis example applies to nginx-ingress-controllers being deployed in an environment with RBAC enabled.\n\n\nRole Based Access Control is comprised of four layers:\n\n\n\n\nClusterRole\n - permissions assigned to a role that apply to an entire cluster\n\n\nClusterRoleBinding\n - binding a ClusterRole to a specific account\n\n\nRole\n - permissions assigned to a role that apply to a specific namespace\n\n\nRoleBinding\n - binding a Role to a specific account\n\n\n\n\nIn order for RBAC to be applied to an nginx-ingress-controller, that controller\nshould be assigned to a \nServiceAccount\n. That \nServiceAccount\n should be\nbound to the \nRole\ns and \nClusterRole\ns defined for the nginx-ingress-controller.\n\n\nService Accounts created in this example\n\u00b6\n\n\nOne ServiceAccount is created in this example, \nnginx-ingress-serviceaccount\n.\n\n\nPermissions Granted in this example\n\u00b6\n\n\nThere are two sets of permissions defined in this example. Cluster-wide\npermissions defined by the \nClusterRole\n named \nnginx-ingress-clusterrole\n, and\nnamespace specific permissions defined by the \nRole\n named \nnginx-ingress-role\n.\n\n\nCluster Permissions\n\u00b6\n\n\nThese permissions are granted in order for the nginx-ingress-controller to be\nable to function as an ingress across the cluster. These permissions are\ngranted to the ClusterRole named \nnginx-ingress-clusterrole\n\n\n\n\nconfigmaps\n, \nendpoints\n, \nnodes\n, \npods\n, \nsecrets\n: list, watch\n\n\nnodes\n: get\n\n\nservices\n, \ningresses\n: get, list, watch\n\n\nevents\n: create, patch\n\n\ningresses/status\n: update\n\n\n\n\nNamespace Permissions\n\u00b6\n\n\nThese permissions are granted specific to the nginx-ingress namespace. These\npermissions are granted to the Role named \nnginx-ingress-role\n\n\n\n\nconfigmaps\n, \npods\n, \nsecrets\n: get\n\n\nendpoints\n: get\n\n\n\n\nFurthermore to support leader-election, the nginx-ingress-controller needs to\nhave access to a \nconfigmap\n using the resourceName \ningress-controller-leader-nginx\n\n\n\n\nNote that resourceNames can NOT be used to limit requests using the \u201ccreate\u201d\nverb because authorizers only have access to information that can be obtained\nfrom the request URL, method, and headers (resource names in a \u201ccreate\u201d request\nare part of the request body).\n\n\n\n\n\n\nconfigmaps\n: get, update (for resourceName \ningress-controller-leader-nginx\n)\n\n\nconfigmaps\n: create\n\n\n\n\nThis resourceName is the concatenation of the \nelection-id\n and the\n\ningress-class\n as defined by the ingress-controller, which defaults to:\n\n\n\n\nelection-id\n: \ningress-controller-leader\n\n\ningress-class\n: \nnginx\n\n\nresourceName\n : \n-\n\n\n\n\nPlease adapt accordingly if you overwrite either parameter when launching the\nnginx-ingress-controller.\n\n\nBindings\n\u00b6\n\n\nThe ServiceAccount \nnginx-ingress-serviceaccount\n is bound to the Role\n\nnginx-ingress-role\n and the ClusterRole \nnginx-ingress-clusterrole\n.\n\n\nThe serviceAccountName associated with the containers in the deployment must\nmatch the serviceAccount. The namespace references in the Deployment metadata, \ncontainer arguments, and POD_NAMESPACE should be in the nginx-ingress namespace.", + "title": "Role Based Access Control (RBAC)" + }, + { + "location": "/deploy/rbac/#role-based-access-control-rbac", + "text": "", + "title": "Role Based Access Control (RBAC)" + }, + { + "location": "/deploy/rbac/#overview", + "text": "This example applies to nginx-ingress-controllers being deployed in an environment with RBAC enabled. Role Based Access Control is comprised of four layers: ClusterRole - permissions assigned to a role that apply to an entire cluster ClusterRoleBinding - binding a ClusterRole to a specific account Role - permissions assigned to a role that apply to a specific namespace RoleBinding - binding a Role to a specific account In order for RBAC to be applied to an nginx-ingress-controller, that controller\nshould be assigned to a ServiceAccount . That ServiceAccount should be\nbound to the Role s and ClusterRole s defined for the nginx-ingress-controller.", + "title": "Overview" + }, + { + "location": "/deploy/rbac/#service-accounts-created-in-this-example", + "text": "One ServiceAccount is created in this example, nginx-ingress-serviceaccount .", + "title": "Service Accounts created in this example" + }, + { + "location": "/deploy/rbac/#permissions-granted-in-this-example", + "text": "There are two sets of permissions defined in this example. Cluster-wide\npermissions defined by the ClusterRole named nginx-ingress-clusterrole , and\nnamespace specific permissions defined by the Role named nginx-ingress-role .", + "title": "Permissions Granted in this example" + }, + { + "location": "/deploy/rbac/#cluster-permissions", + "text": "These permissions are granted in order for the nginx-ingress-controller to be\nable to function as an ingress across the cluster. These permissions are\ngranted to the ClusterRole named nginx-ingress-clusterrole configmaps , endpoints , nodes , pods , secrets : list, watch nodes : get services , ingresses : get, list, watch events : create, patch ingresses/status : update", + "title": "Cluster Permissions" + }, + { + "location": "/deploy/rbac/#namespace-permissions", + "text": "These permissions are granted specific to the nginx-ingress namespace. These\npermissions are granted to the Role named nginx-ingress-role configmaps , pods , secrets : get endpoints : get Furthermore to support leader-election, the nginx-ingress-controller needs to\nhave access to a configmap using the resourceName ingress-controller-leader-nginx Note that resourceNames can NOT be used to limit requests using the \u201ccreate\u201d\nverb because authorizers only have access to information that can be obtained\nfrom the request URL, method, and headers (resource names in a \u201ccreate\u201d request\nare part of the request body). configmaps : get, update (for resourceName ingress-controller-leader-nginx ) configmaps : create This resourceName is the concatenation of the election-id and the ingress-class as defined by the ingress-controller, which defaults to: election-id : ingress-controller-leader ingress-class : nginx resourceName : - Please adapt accordingly if you overwrite either parameter when launching the\nnginx-ingress-controller.", + "title": "Namespace Permissions" + }, + { + "location": "/deploy/rbac/#bindings", + "text": "The ServiceAccount nginx-ingress-serviceaccount is bound to the Role nginx-ingress-role and the ClusterRole nginx-ingress-clusterrole . The serviceAccountName associated with the containers in the deployment must\nmatch the serviceAccount. The namespace references in the Deployment metadata, \ncontainer arguments, and POD_NAMESPACE should be in the nginx-ingress namespace.", + "title": "Bindings" + }, + { + "location": "/user-guide/nginx-configuration/", + "text": "NGINX Configuration\n\u00b6\n\n\nThere are three ways to customize NGINX:\n\n\n\n\nConfigMap\n: using a Configmap to set global configurations in NGINX.\n\n\nAnnotations\n: use this if you want a specific configuration for a particular Ingress rule.\n\n\nCustom template\n: when more specific settings are required, like \nopen_file_cache\n, adjust \nlisten\n options as \nrcvbuf\n or when is not possible to change the configuration through the ConfigMap.", + "title": "NGINX Configuration" + }, + { + "location": "/user-guide/nginx-configuration/#nginx-configuration", + "text": "There are three ways to customize NGINX: ConfigMap : using a Configmap to set global configurations in NGINX. Annotations : use this if you want a specific configuration for a particular Ingress rule. Custom template : when more specific settings are required, like open_file_cache , adjust listen options as rcvbuf or when is not possible to change the configuration through the ConfigMap.", + "title": "NGINX Configuration" + }, + { + "location": "/user-guide/nginx-configuration/annotations/", + "text": "Annotations\n\u00b6\n\n\nYou can add these Kubernetes annotations to specific Ingress objects to customize their behavior.\n\n\n\n\nTip\n\n\nAnnotation keys and values can only be strings.\nOther types, such as boolean or numeric values must be quoted,\ni.e. \n\"true\"\n, \n\"false\"\n, \n\"100\"\n.\n\n\n\n\n\n\n\n\n\n\nName\n\n\ntype\n\n\n\n\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/add-base-url\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/app-root\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/affinity\n\n\ncookie\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-realm\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-secret\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-type\n\n\nbasic or digest\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-secret\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-verify-depth\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-verify-client\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-error-page\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/auth-url\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/base-url-scheme\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/configuration-snippet\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/default-backend\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/enable-cors\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-origin\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-methods\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-headers\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-credentials\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/cors-max-age\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/force-ssl-redirect\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/from-to-www-redirect\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/limit-connections\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/limit-rps\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/permanent-redirect\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-body-size\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-connect-timeout\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-send-timeout\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-read-timeout\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-next-upstream\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-next-upstream-tries\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-request-buffering\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-redirect-from\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-redirect-to\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/rewrite-target\n\n\nURI\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/secure-backends\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/secure-verify-ca-secret\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/server-alias\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/server-snippet\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/service-upstream\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/session-cookie-name\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/session-cookie-hash\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/ssl-redirect\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/ssl-passthrough\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/upstream-max-fails\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/upstream-fail-timeout\n\n\nnumber\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/upstream-hash-by\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/load-balance\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/upstream-vhost\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/whitelist-source-range\n\n\nCIDR\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-buffering\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/ssl-ciphers\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/connection-proxy-header\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/enable-access-log\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-debug\n\n\n\"true\" or \"false\"\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-extra-rules\n\n\nstring\n\n\n\n\n\n\n\n\nRewrite\n\u00b6\n\n\nIn some scenarios the exposed URL in the backend service differs from the specified path in the Ingress rule. Without a rewrite any request will return 404.\nSet the annotation \nnginx.ingress.kubernetes.io/rewrite-target\n to the path expected by the service.\n\n\nIf the application contains relative links it is possible to add an additional annotation \nnginx.ingress.kubernetes.io/add-base-url\n that will prepend a \nbase\n tag\n in the header of the returned HTML from the backend.\n\n\nIf the scheme of \nbase\n tag\n need to be specific, set the annotation \nnginx.ingress.kubernetes.io/base-url-scheme\n to the scheme such as \nhttp\n and \nhttps\n.\n\n\nIf the Application Root is exposed in a different path and needs to be redirected, set the annotation \nnginx.ingress.kubernetes.io/app-root\n to redirect requests for \n/\n.\n\n\nPlease check the \nrewrite\n example.\n\n\nSession Affinity\n\u00b6\n\n\nThe annotation \nnginx.ingress.kubernetes.io/affinity\n enables and sets the affinity type in all Upstreams of an Ingress. This way, a request will always be directed to the same upstream server.\nThe only affinity type available for NGINX is \ncookie\n.\n\n\nPlease check the \naffinity\n example.\n\n\nAuthentication\n\u00b6\n\n\nIs possible to add authentication adding additional annotations in the Ingress rule. The source of the authentication is a secret that contains usernames and passwords inside the key \nauth\n.\n\n\nThe annotations are:\n\n\nnginx.ingress.kubernetes.io/auth-type: [basic|digest]\n\n\n\n\n\nIndicates the \nHTTP Authentication Type: Basic or Digest Access Authentication\n.\n\n\nnginx.ingress.kubernetes.io/auth-secret: secretName\n\n\n\n\n\nThe name of the Secret that contains the usernames and passwords which are granted access to the \npath\ns defined in the Ingress rules.\nThis annotation also accepts the alternative form \"namespace/secretName\", in which case the Secret lookup is performed in the referenced namespace instead of the Ingress namespace.\n\n\nnginx.ingress.kubernetes.io/auth-realm: \"realm string\"\n\n\n\n\n\nPlease check the \nauth\n example.\n\n\nCustom NGINX upstream checks\n\u00b6\n\n\nNGINX exposes some flags in the \nupstream configuration\n that enable the configuration of each server in the upstream. The Ingress controller allows custom \nmax_fails\n and \nfail_timeout\n parameters in a global context using \nupstream-max-fails\n and \nupstream-fail-timeout\n in the NGINX ConfigMap or in a particular Ingress rule. \nupstream-max-fails\n defaults to 0. This means NGINX will respect the container's \nreadinessProbe\n if it is defined. If there is no probe and no values for \nupstream-max-fails\n NGINX will continue to send traffic to the container.\n\n\nWith the default configuration NGINX will not health check your backends. Whenever the endpoints controller notices a readiness probe failure, that pod's IP will be removed from the list of endpoints. This will trigger the NGINX controller to also remove it from the upstreams.\n\n\nTo use custom values in an Ingress rule define these annotations:\n\n\nnginx.ingress.kubernetes.io/upstream-max-fails\n: number of unsuccessful attempts to communicate with the server that should occur in the duration set by the \nupstream-fail-timeout\n parameter to consider the server unavailable.\n\n\nnginx.ingress.kubernetes.io/upstream-fail-timeout\n: time in seconds during which the specified number of unsuccessful attempts to communicate with the server should occur to consider the server unavailable. This is also the period of time the server will be considered unavailable.\n\n\nIn NGINX, backend server pools are called \"\nupstreams\n\". Each upstream contains the endpoints for a service. An upstream is created for each service that has Ingress rules defined.\n\n\nImportant:\n All Ingress rules using the same service will use the same upstream. Only one of the Ingress rules should define annotations to configure the upstream servers.\n\n\nPlease check the \ncustom upstream check\n example.\n\n\nCustom NGINX upstream hashing\n\u00b6\n\n\nNGINX supports load balancing by client-server mapping based on \nconsistent hashing\n for a given key. The key can contain text, variables or any combination thereof. This feature allows for request stickiness other than client IP or cookies. The \nketama\n consistent hashing method will be used which ensures only a few keys would be remapped to different servers on upstream group changes.\n\n\nTo enable consistent hashing for a backend:\n\n\nnginx.ingress.kubernetes.io/upstream-hash-by\n: the nginx variable, text value or any combination thereof to use for consistent hashing. For example \nnginx.ingress.kubernetes.io/upstream-hash-by: \"$request_uri\"\n to consistently hash upstream requests by the current request URI.\n\n\nCustom NGINX load balancing\n\u00b6\n\n\nThis is similar to https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/configmap.md#load-balance but configures load balancing algorithm per ingress.\nNote that \nnginx.ingress.kubernetes.io/upstream-hash-by\n takes preference over this. If this and \nnginx.ingress.kubernetes.io/upstream-hash-by\n are not set then we fallback to using globally configured load balancing algorithm.\n\n\nCustom NGINX upstream vhost\n\u00b6\n\n\nThis configuration setting allows you to control the value for host in the following statement: \nproxy_set_header Host $host\n, which forms part of the location block. This is useful if you need to call the upstream server by something other than \n$host\n.\n\n\nClient Certificate Authentication\n\u00b6\n\n\nIt is possible to enable Client Certificate Authentication using additional annotations in Ingress Rule.\n\n\nThe annotations are:\n\n\nnginx.ingress.kubernetes.io/auth-tls-secret: secretName\n\n\n\n\n\nThe name of the Secret that contains the full Certificate Authority chain \nca.crt\n that is enabled to authenticate against this Ingress.\nThis annotation also accepts the alternative form \"namespace/secretName\", in which case the Secret lookup is performed in the referenced namespace instead of the Ingress namespace.\n\n\nnginx.ingress.kubernetes.io/auth-tls-verify-depth\n\n\n\n\n\nThe validation depth between the provided client certificate and the Certification Authority chain.\n\n\nnginx.ingress.kubernetes.io/auth-tls-verify-client\n\n\n\n\n\nEnables verification of client certificates.\n\n\nnginx.ingress.kubernetes.io/auth-tls-error-page\n\n\n\n\n\nThe URL/Page that user should be redirected in case of a Certificate Authentication Error\n\n\nnginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream\n\n\n\n\n\nIndicates if the received certificates should be passed or not to the upstream server.\nBy default this is disabled.\n\n\nPlease check the \nclient-certs\n example.\n\n\nImportant:\n\n\nTLS with Client Authentication is NOT possible in Cloudflare as is not allowed it and might result in unexpected behavior.\n\n\nCloudflare only allows Authenticated Origin Pulls and is required to use their own certificate:\nhttps://blog.cloudflare.com/protecting-the-origin-with-tls-authenticated-origin-pulls/\n\n\nOnly Authenticated Origin Pulls are allowed and can be configured by following their tutorial:\nhttps://support.cloudflare.com/hc/en-us/articles/204494148-Setting-up-NGINX-to-use-TLS-Authenticated-Origin-Pulls\n\n\nConfiguration snippet\n\u00b6\n\n\nUsing this annotation you can add additional configuration to the NGINX location. For example:\n\n\nnginx.ingress.kubernetes.io/configuration-snippet\n:\n \n|\n\n \nmore_set_headers \"Request-Id: $req_id\";\n\n\n\n\n\n\nDefault Backend\n\u00b6\n\n\nThe ingress controller requires a default backend. This service handles the response when the service in the Ingress rule does not have endpoints.\nThis is a global configuration for the ingress controller. In some cases could be required to return a custom content or format. In this scenario we can use the annotation \nnginx.ingress.kubernetes.io/default-backend: \n to specify a custom default backend.\n\n\nEnable CORS\n\u00b6\n\n\nTo enable Cross-Origin Resource Sharing (CORS) in an Ingress rule add the annotation \nnginx.ingress.kubernetes.io/enable-cors: \"true\"\n. This will add a section in the server location enabling this functionality.\n\n\nCORS can be controlled with the following annotations:\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-methods\n controls which methods are accepted. This is a multi-valued field, separated by ',' and accepts only letters (upper and lower case).\n\n\n\n\nExample: \nnginx.ingress.kubernetes.io/cors-allow-methods: \"PUT, GET, POST, OPTIONS\"\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-headers\n controls which headers are accepted. This is a multi-valued field, separated by ',' and accepts letters, numbers, _ and -.\n\n\n\n\nExample: \nnginx.ingress.kubernetes.io/cors-allow-headers: \"X-Forwarded-For, X-app123-XPTO\"\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-origin\n controls what's the accepted Origin for CORS and defaults to '*'. This is a single field value, with the following format: http(s)://origin-site.com or http(s)://origin-site.com:port\n\n\n\n\nExample: \nnginx.ingress.kubernetes.io/cors-allow-origin: \"https://origin-site.com:4443\"\n\n\n\n\nnginx.ingress.kubernetes.io/cors-allow-credentials\n controls if credentials can be passed during CORS operations.\n\n\n\n\nExample: \nnginx.ingress.kubernetes.io/cors-allow-credentials: \"true\"\n\n\n\n\nnginx.ingress.kubernetes.io/cors-max-age\n controls how long preflight requests can be cached.\n\n\n\n\nExample: \nnginx.ingress.kubernetes.io/cors-max-age: 600\n\n\nFor more information please check https://enable-cors.org/server_nginx.html\n\n\nServer Alias\n\u00b6\n\n\nTo add Server Aliases to an Ingress rule add the annotation \nnginx.ingress.kubernetes.io/server-alias: \"\"\n.\nThis will create a server with the same configuration, but a different server_name as the provided host.\n\n\nNote:\n A server-alias name cannot conflict with the hostname of an existing server. If it does the server-alias\nannotation will be ignored. If a server-alias is created and later a new server with the same hostname is created\nthe new server configuration will take place over the alias configuration.\n\n\nFor more information please see http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name\n\n\nServer snippet\n\u00b6\n\n\nUsing the annotation \nnginx.ingress.kubernetes.io/server-snippet\n it is possible to add custom configuration in the server configuration block.\n\n\napiVersion\n:\n \nextensions/v1beta1\n\n\nkind\n:\n \nIngress\n\n\nmetadata\n:\n\n \nannotations\n:\n\n \nnginx.ingress.kubernetes.io/server-snippet\n:\n \n|\n\n\nset $agentflag 0;\n\n\n\nif ($http_user_agent ~* \"(Mobile)\" ){\n\n \nset $agentflag 1;\n\n\n}\n\n\n\nif ( $agentflag = 1 ) {\n\n \nreturn 301 https://m.example.com;\n\n\n}\n\n\n\n\n\n\nImportant:\n This annotation can be used only once per host\n\n\nClient Body Buffer Size\n\u00b6\n\n\nSets buffer size for reading client request body per location. In case the request body is larger than the buffer,\nthe whole body or only its part is written to a temporary file. By default, buffer size is equal to two memory pages.\nThis is 8K on x86, other 32-bit platforms, and x86-64. It is usually 16K on other 64-bit platforms. This annotation is\napplied to each location provided in the ingress rule.\n\n\nNote:\n The annotation value must be given in a valid format otherwise the\nFor example to set the client-body-buffer-size the following can be done:\n\n\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: \"1000\"\n # 1000 bytes\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: 1k\n # 1 kilobyte\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: 1K\n # 1 kilobyte\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: 1m\n # 1 megabyte\n\n\nnginx.ingress.kubernetes.io/client-body-buffer-size: 1M\n # 1 megabyte\n\n\n\n\nFor more information please see http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size\n\n\nExternal Authentication\n\u00b6\n\n\nTo use an existing service that provides authentication the Ingress rule can be annotated with \nnginx.ingress.kubernetes.io/auth-url\n to indicate the URL where the HTTP request should be sent.\n\n\nnginx.ingress.kubernetes.io/auth-url\n:\n \n\"URL\n \nto\n \nthe\n \nauthentication\n \nservice\"\n\n\n\n\n\n\nAdditionally it is possible to set:\n\n\nnginx.ingress.kubernetes.io/auth-method\n: \n\n to specify the HTTP method to use.\n\n\nnginx.ingress.kubernetes.io/auth-signin\n: \n\n to specify the location of the error page.\n\n\nnginx.ingress.kubernetes.io/auth-response-headers\n: \n\n to specify headers to pass to backend once authorization request completes.\n\n\nnginx.ingress.kubernetes.io/auth-request-redirect\n: \n\n to specify the X-Auth-Request-Redirect header value.\n\n\nPlease check the \nexternal-auth\n example.\n\n\nRate limiting\n\u00b6\n\n\nThe annotations \nnginx.ingress.kubernetes.io/limit-connections\n, \nnginx.ingress.kubernetes.io/limit-rps\n, and \nnginx.ingress.kubernetes.io/limit-rpm\n define a limit on the connections that can be opened by a single client IP address. This can be used to mitigate \nDDoS Attacks\n.\n\n\nnginx.ingress.kubernetes.io/limit-connections\n: number of concurrent connections allowed from a single IP address.\n\n\nnginx.ingress.kubernetes.io/limit-rps\n: number of connections that may be accepted from a given IP each second.\n\n\nnginx.ingress.kubernetes.io/limit-rpm\n: number of connections that may be accepted from a given IP each minute.\n\n\nYou can specify the client IP source ranges to be excluded from rate-limiting through the \nnginx.ingress.kubernetes.io/limit-whitelist\n annotation. The value is a comma separated list of CIDRs.\n\n\nIf you specify multiple annotations in a single Ingress rule, \nlimit-rpm\n, and then \nlimit-rps\n takes precedence.\n\n\nThe annotation \nnginx.ingress.kubernetes.io/limit-rate\n, \nnginx.ingress.kubernetes.io/limit-rate-after\n define a limit the rate of response transmission to a client. The rate is specified in bytes per second. The zero value disables rate limiting. The limit is set per a request, and so if a client simultaneously opens two connections, the overall rate will be twice as much as the specified limit.\n\n\nnginx.ingress.kubernetes.io/limit-rate-after\n: sets the initial amount after which the further transmission of a response to a client will be rate limited.\n\n\nnginx.ingress.kubernetes.io/limit-rate\n: rate of request that accepted from a client each second.\n\n\nTo configure this setting globally for all Ingress rules, the \nlimit-rate-after\n and \nlimit-rate\n value may be set in the NGINX ConfigMap. if you set the value in ingress annotation will cover global setting.\n\n\nPermanent Redirect\n\u00b6\n\n\nThis annotation allows to return a permanent redirect instead of sending data to the upstream. For example \nnginx.ingress.kubernetes.io/permanent-redirect: https://www.google.com\n would redirect everything to Google.\n\n\nSSL Passthrough\n\u00b6\n\n\nThe annotation \nnginx.ingress.kubernetes.io/ssl-passthrough\n allows to configure TLS termination in the pod and not in NGINX.\n\n\nImportant:\n\n\n\n\nUsing the annotation \nnginx.ingress.kubernetes.io/ssl-passthrough\n invalidates all the other available annotations. This is because SSL Passthrough works in L4 (TCP).\n\n\nThe use of this annotation requires Proxy Protocol to be enabled in the load-balancer. For example enabling Proxy Protocol for AWS ELB is described \nhere\n. If you're using ingress-controller without load balancer then the flag \n--enable-ssl-passthrough\n is required (by default it is disabled).\n\n\n\n\nSecure backends\n\u00b6\n\n\nBy default NGINX uses \nhttp\n to reach the services. Adding the annotation \nnginx.ingress.kubernetes.io/secure-backends: \"true\"\n in the Ingress rule changes the protocol to \nhttps\n.\nIf you want to validate the upstream against a specific certificate, you can create a secret with it and reference the secret with the annotation \nnginx.ingress.kubernetes.io/secure-verify-ca-secret\n.\n\n\nPlease note that if an invalid or non-existent secret is given, the NGINX ingress controller will ignore the \nsecure-backends\n annotation.\n\n\nService Upstream\n\u00b6\n\n\nBy default the NGINX ingress controller uses a list of all endpoints (Pod IP/port) in the NGINX upstream configuration. This annotation disables that behavior and instead uses a single upstream in NGINX, the service's Cluster IP and port. This can be desirable for things like zero-downtime deployments as it reduces the need to reload NGINX configuration when Pods come up and down. See issue \n#257\n.\n\n\nKnown Issues\n\u00b6\n\n\nIf the \nservice-upstream\n annotation is specified the following things should be taken into consideration:\n\n\n\n\nSticky Sessions will not work as only round-robin load balancing is supported.\n\n\nThe \nproxy_next_upstream\n directive will not have any effect meaning on error the request will not be dispatched to another upstream.\n\n\n\n\nServer-side HTTPS enforcement through redirect\n\u00b6\n\n\nBy default the controller redirects (301) to \nHTTPS\n if TLS is enabled for that ingress. If you want to disable that behavior globally, you can use \nssl-redirect: \"false\"\n in the NGINX config map.\n\n\nTo configure this feature for specific ingress resources, you can use the \nnginx.ingress.kubernetes.io/ssl-redirect: \"false\"\n annotation in the particular resource.\n\n\nWhen using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a redirect to \nHTTPS\n even when there is not TLS cert available. This can be achieved by using the \nnginx.ingress.kubernetes.io/force-ssl-redirect: \"true\"\n annotation in the particular resource.\n\n\nRedirect from to www\n\u00b6\n\n\nIn some scenarios is required to redirect from \nwww.domain.com\n to \ndomain.com\n or viceversa.\nTo enable this feature use the annotation \nnginx.ingress.kubernetes.io/from-to-www-redirect: \"true\"\n\n\nImportant:\n\nIf at some point a new Ingress is created with a host equal to one of the options (like \ndomain.com\n) the annotation will be omitted.\n\n\nWhitelist source range\n\u00b6\n\n\nYou can specify the allowed client IP source ranges through the \nnginx.ingress.kubernetes.io/whitelist-source-range\n annotation. The value is a comma separated list of \nCIDRs\n, e.g. \n10.0.0.0/24,172.10.0.1\n.\n\n\nTo configure this setting globally for all Ingress rules, the \nwhitelist-source-range\n value may be set in the NGINX ConfigMap.\n\n\nNote:\n Adding an annotation to an Ingress rule overrides any global restriction.\n\n\nCookie affinity\n\u00b6\n\n\nIf you use the \ncookie\n type you can also specify the name of the cookie that will be used to route the requests with the annotation \nnginx.ingress.kubernetes.io/session-cookie-name\n. The default is to create a cookie named 'INGRESSCOOKIE'.\n\n\nIn case of NGINX the annotation \nnginx.ingress.kubernetes.io/session-cookie-hash\n defines which algorithm will be used to 'hash' the used upstream. Default value is \nmd5\n and possible values are \nmd5\n, \nsha1\n and \nindex\n.\nThe \nindex\n option is not hashed, an in-memory index is used instead, it's quicker and the overhead is shorter Warning: the matching against upstream servers list is inconsistent. So, at reload, if upstreams servers has changed, index values are not guaranteed to correspond to the same server as before! USE IT WITH CAUTION and only if you need to!\n\n\nIn NGINX this feature is implemented by the third party module \nnginx-sticky-module-ng\n. The workflow used to define which upstream server will be used is explained \nhere\n\n\nCustom timeouts\n\u00b6\n\n\nUsing the configuration configmap it is possible to set the default global timeout for connections to the upstream servers.\nIn some scenarios is required to have different values. To allow this we provide annotations that allows this customization:\n\n\n\n\nnginx.ingress.kubernetes.io/proxy-connect-timeout\n\n\nnginx.ingress.kubernetes.io/proxy-send-timeout\n\n\nnginx.ingress.kubernetes.io/proxy-read-timeout\n\n\nnginx.ingress.kubernetes.io/proxy-next-upstream\n\n\nnginx.ingress.kubernetes.io/proxy-next-upstream-tries\n\n\nnginx.ingress.kubernetes.io/proxy-request-buffering\n\n\n\n\nProxy redirect\n\u00b6\n\n\nWith the annotations \nnginx.ingress.kubernetes.io/proxy-redirect-from\n and \nnginx.ingress.kubernetes.io/proxy-redirect-to\n it is possible to set the text that should be changed in the \nLocation\n and \nRefresh\n header fields of a proxied server response (http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect)\nSetting \"off\" or \"default\" in the annotation \nnginx.ingress.kubernetes.io/proxy-redirect-from\n disables \nnginx.ingress.kubernetes.io/proxy-redirect-to\n\nBoth annotations will be used in any other case\nBy default the value is \"off\".\n\n\nCustom max body size\n\u00b6\n\n\nFor NGINX, 413 error will be returned to the client when the size in a request exceeds the maximum allowed size of the client request body. This size can be configured by the parameter \nclient_max_body_size\n.\n\n\nTo configure this setting globally for all Ingress rules, the \nproxy-body-size\n value may be set in the NGINX ConfigMap.\nTo use custom values in an Ingress rule define these annotation:\n\n\nnginx.ingress.kubernetes.io/proxy-body-size\n:\n \n8m\n\n\n\n\n\n\nProxy buffering\n\u00b6\n\n\nEnable or disable proxy buffering \nproxy_buffering\n.\nBy default proxy buffering is disabled in the nginx config.\n\n\nTo configure this setting globally for all Ingress rules, the \nproxy-buffering\n value may be set in the NGINX ConfigMap.\nTo use custom values in an Ingress rule define these annotation:\n\n\nnginx.ingress.kubernetes.io/proxy-buffering\n:\n \n\"on\"\n\n\n\n\n\n\nSSL ciphers\n\u00b6\n\n\nSpecifies the \nenabled ciphers\n.\n\n\nUsing this annotation will set the \nssl_ciphers\n directive at the server level. This configuration is active for all the paths in the host.\n\n\nnginx.ingress.kubernetes.io/ssl-ciphers\n:\n \n\"ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP\"\n\n\n\n\n\n\nConnection proxy header\n\u00b6\n\n\nUsing this annotation will override the default connection header set by nginx. To use custom values in an Ingress rule, define the annotation:\n\n\nnginx.ingress.kubernetes.io/connection-proxy-header\n:\n \n\"keep-alive\"\n\n\n\n\n\n\nEnable Access Log\n\u00b6\n\n\nIn some scenarios could be required to disable NGINX access logs. To enable this feature use the annotation:\n\n\nnginx.ingress.kubernetes.io/enable-access-log\n:\n \n\"false\"\n\n\n\n\n\n\nLua Resty WAF\n\u00b6\n\n\nUsing \nlua-resty-waf-*\n annotations we can enable and control \nlua-resty-waf\n per location.\nFollowing configuration will enable WAF for the paths defined in the corresponding ingress:\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf\n:\n \n\"active\"\n\n\n\n\n\n\nIn order to run it in debugging mode you can set \nnginx.ingress.kubernetes.io/lua-resty-waf-debug\n to \n\"true\"\n in addition to the above configuration.\nThe other possible values for \nnginx.ingress.kubernetes.io/lua-resty-waf\n are \ninactive\n and \nsimulate\n. In \ninactive\n mode WAF won't do anything, whereas\nin \nsimulate\n mode it will log a warning message if there's a matching WAF rule for given request. This is useful to debug a rule and eliminate possible false positives before fully deploying it.\n\n\nlua-resty-waf\n comes with predefined set of rules(https://github.com/p0pr0ck5/lua-resty-waf/tree/84b4f40362500dd0cb98b9e71b5875cb1a40f1ad/rules) that covers ModSecurity CRS.\nYou can use \nnginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets\n to ignore subset of those rulesets. For an example:\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets\n:\n \n\"41000_sqli,\n \n42000_xss\"\n\n\n\n\n\n\nwill ignore the two mentioned rulesets.\n\n\nIt is also possible to configure custom WAF rules per ingress using \nnginx.ingress.kubernetes.io/lua-resty-waf-extra-rules\n annotation. For an example the following snippet will\nconfigure a WAF rule to deny requests with query string value that contains word \nfoo\n:\n\n\nnginx.ingress.kubernetes.io/lua-resty-waf-extra-rules\n:\n \n'[=[\n \n{\n \n\"access\":\n \n[\n \n{\n \n\"actions\":\n \n{\n \n\"disrupt\"\n \n:\n \n\"DENY\"\n \n},\n \n\"id\":\n \n10001,\n \n\"msg\":\n \n\"my\n \ncustom\n \nrule\",\n \n\"operator\":\n \n\"STR_CONTAINS\",\n \n\"pattern\":\n \n\"foo\",\n \n\"vars\":\n \n[\n \n{\n \n\"parse\":\n \n[\n \n\"values\",\n \n1\n \n],\n \n\"type\":\n \n\"REQUEST_ARGS\"\n \n}\n \n]\n \n}\n \n],\n \n\"body_filter\":\n \n[],\n \n\"header_filter\":[]\n \n}\n \n]=]'\n\n\n\n\n\n\nFor details on how to write WAF rules, please refer to https://github.com/p0pr0ck5/lua-resty-waf.", + "title": "Annotations" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#annotations", + "text": "You can add these Kubernetes annotations to specific Ingress objects to customize their behavior. Tip Annotation keys and values can only be strings.\nOther types, such as boolean or numeric values must be quoted,\ni.e. \"true\" , \"false\" , \"100\" . Name type nginx.ingress.kubernetes.io/add-base-url \"true\" or \"false\" nginx.ingress.kubernetes.io/app-root string nginx.ingress.kubernetes.io/affinity cookie nginx.ingress.kubernetes.io/auth-realm string nginx.ingress.kubernetes.io/auth-secret string nginx.ingress.kubernetes.io/auth-type basic or digest nginx.ingress.kubernetes.io/auth-tls-secret string nginx.ingress.kubernetes.io/auth-tls-verify-depth number nginx.ingress.kubernetes.io/auth-tls-verify-client string nginx.ingress.kubernetes.io/auth-tls-error-page string nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream \"true\" or \"false\" nginx.ingress.kubernetes.io/auth-url string nginx.ingress.kubernetes.io/base-url-scheme string nginx.ingress.kubernetes.io/client-body-buffer-size string nginx.ingress.kubernetes.io/configuration-snippet string nginx.ingress.kubernetes.io/default-backend string nginx.ingress.kubernetes.io/enable-cors \"true\" or \"false\" nginx.ingress.kubernetes.io/cors-allow-origin string nginx.ingress.kubernetes.io/cors-allow-methods string nginx.ingress.kubernetes.io/cors-allow-headers string nginx.ingress.kubernetes.io/cors-allow-credentials \"true\" or \"false\" nginx.ingress.kubernetes.io/cors-max-age number nginx.ingress.kubernetes.io/force-ssl-redirect \"true\" or \"false\" nginx.ingress.kubernetes.io/from-to-www-redirect \"true\" or \"false\" nginx.ingress.kubernetes.io/limit-connections number nginx.ingress.kubernetes.io/limit-rps number nginx.ingress.kubernetes.io/permanent-redirect string nginx.ingress.kubernetes.io/proxy-body-size string nginx.ingress.kubernetes.io/proxy-connect-timeout number nginx.ingress.kubernetes.io/proxy-send-timeout number nginx.ingress.kubernetes.io/proxy-read-timeout number nginx.ingress.kubernetes.io/proxy-next-upstream string nginx.ingress.kubernetes.io/proxy-next-upstream-tries number nginx.ingress.kubernetes.io/proxy-request-buffering string nginx.ingress.kubernetes.io/proxy-redirect-from string nginx.ingress.kubernetes.io/proxy-redirect-to string nginx.ingress.kubernetes.io/rewrite-target URI nginx.ingress.kubernetes.io/secure-backends \"true\" or \"false\" nginx.ingress.kubernetes.io/secure-verify-ca-secret string nginx.ingress.kubernetes.io/server-alias string nginx.ingress.kubernetes.io/server-snippet string nginx.ingress.kubernetes.io/service-upstream \"true\" or \"false\" nginx.ingress.kubernetes.io/session-cookie-name string nginx.ingress.kubernetes.io/session-cookie-hash string nginx.ingress.kubernetes.io/ssl-redirect \"true\" or \"false\" nginx.ingress.kubernetes.io/ssl-passthrough \"true\" or \"false\" nginx.ingress.kubernetes.io/upstream-max-fails number nginx.ingress.kubernetes.io/upstream-fail-timeout number nginx.ingress.kubernetes.io/upstream-hash-by string nginx.ingress.kubernetes.io/load-balance string nginx.ingress.kubernetes.io/upstream-vhost string nginx.ingress.kubernetes.io/whitelist-source-range CIDR nginx.ingress.kubernetes.io/proxy-buffering string nginx.ingress.kubernetes.io/ssl-ciphers string nginx.ingress.kubernetes.io/connection-proxy-header string nginx.ingress.kubernetes.io/enable-access-log \"true\" or \"false\" nginx.ingress.kubernetes.io/lua-resty-waf string nginx.ingress.kubernetes.io/lua-resty-waf-debug \"true\" or \"false\" nginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets string nginx.ingress.kubernetes.io/lua-resty-waf-extra-rules string", + "title": "Annotations" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#rewrite", + "text": "In some scenarios the exposed URL in the backend service differs from the specified path in the Ingress rule. Without a rewrite any request will return 404.\nSet the annotation nginx.ingress.kubernetes.io/rewrite-target to the path expected by the service. If the application contains relative links it is possible to add an additional annotation nginx.ingress.kubernetes.io/add-base-url that will prepend a base tag in the header of the returned HTML from the backend. If the scheme of base tag need to be specific, set the annotation nginx.ingress.kubernetes.io/base-url-scheme to the scheme such as http and https . If the Application Root is exposed in a different path and needs to be redirected, set the annotation nginx.ingress.kubernetes.io/app-root to redirect requests for / . Please check the rewrite example.", + "title": "Rewrite" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#session-affinity", + "text": "The annotation nginx.ingress.kubernetes.io/affinity enables and sets the affinity type in all Upstreams of an Ingress. This way, a request will always be directed to the same upstream server.\nThe only affinity type available for NGINX is cookie . Please check the affinity example.", + "title": "Session Affinity" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#authentication", + "text": "Is possible to add authentication adding additional annotations in the Ingress rule. The source of the authentication is a secret that contains usernames and passwords inside the key auth . The annotations are: nginx.ingress.kubernetes.io/auth-type: [basic|digest] Indicates the HTTP Authentication Type: Basic or Digest Access Authentication . nginx.ingress.kubernetes.io/auth-secret: secretName The name of the Secret that contains the usernames and passwords which are granted access to the path s defined in the Ingress rules.\nThis annotation also accepts the alternative form \"namespace/secretName\", in which case the Secret lookup is performed in the referenced namespace instead of the Ingress namespace. nginx.ingress.kubernetes.io/auth-realm: \"realm string\" Please check the auth example.", + "title": "Authentication" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#custom-nginx-upstream-checks", + "text": "NGINX exposes some flags in the upstream configuration that enable the configuration of each server in the upstream. The Ingress controller allows custom max_fails and fail_timeout parameters in a global context using upstream-max-fails and upstream-fail-timeout in the NGINX ConfigMap or in a particular Ingress rule. upstream-max-fails defaults to 0. This means NGINX will respect the container's readinessProbe if it is defined. If there is no probe and no values for upstream-max-fails NGINX will continue to send traffic to the container. With the default configuration NGINX will not health check your backends. Whenever the endpoints controller notices a readiness probe failure, that pod's IP will be removed from the list of endpoints. This will trigger the NGINX controller to also remove it from the upstreams. To use custom values in an Ingress rule define these annotations: nginx.ingress.kubernetes.io/upstream-max-fails : number of unsuccessful attempts to communicate with the server that should occur in the duration set by the upstream-fail-timeout parameter to consider the server unavailable. nginx.ingress.kubernetes.io/upstream-fail-timeout : time in seconds during which the specified number of unsuccessful attempts to communicate with the server should occur to consider the server unavailable. This is also the period of time the server will be considered unavailable. In NGINX, backend server pools are called \" upstreams \". Each upstream contains the endpoints for a service. An upstream is created for each service that has Ingress rules defined. Important: All Ingress rules using the same service will use the same upstream. Only one of the Ingress rules should define annotations to configure the upstream servers. Please check the custom upstream check example.", + "title": "Custom NGINX upstream checks" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#custom-nginx-upstream-hashing", + "text": "NGINX supports load balancing by client-server mapping based on consistent hashing for a given key. The key can contain text, variables or any combination thereof. This feature allows for request stickiness other than client IP or cookies. The ketama consistent hashing method will be used which ensures only a few keys would be remapped to different servers on upstream group changes. To enable consistent hashing for a backend: nginx.ingress.kubernetes.io/upstream-hash-by : the nginx variable, text value or any combination thereof to use for consistent hashing. For example nginx.ingress.kubernetes.io/upstream-hash-by: \"$request_uri\" to consistently hash upstream requests by the current request URI.", + "title": "Custom NGINX upstream hashing" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#custom-nginx-load-balancing", + "text": "This is similar to https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/configmap.md#load-balance but configures load balancing algorithm per ingress.\nNote that nginx.ingress.kubernetes.io/upstream-hash-by takes preference over this. If this and nginx.ingress.kubernetes.io/upstream-hash-by are not set then we fallback to using globally configured load balancing algorithm.", + "title": "Custom NGINX load balancing" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#custom-nginx-upstream-vhost", + "text": "This configuration setting allows you to control the value for host in the following statement: proxy_set_header Host $host , which forms part of the location block. This is useful if you need to call the upstream server by something other than $host .", + "title": "Custom NGINX upstream vhost" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#client-certificate-authentication", + "text": "It is possible to enable Client Certificate Authentication using additional annotations in Ingress Rule. The annotations are: nginx.ingress.kubernetes.io/auth-tls-secret: secretName The name of the Secret that contains the full Certificate Authority chain ca.crt that is enabled to authenticate against this Ingress.\nThis annotation also accepts the alternative form \"namespace/secretName\", in which case the Secret lookup is performed in the referenced namespace instead of the Ingress namespace. nginx.ingress.kubernetes.io/auth-tls-verify-depth The validation depth between the provided client certificate and the Certification Authority chain. nginx.ingress.kubernetes.io/auth-tls-verify-client Enables verification of client certificates. nginx.ingress.kubernetes.io/auth-tls-error-page The URL/Page that user should be redirected in case of a Certificate Authentication Error nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream Indicates if the received certificates should be passed or not to the upstream server.\nBy default this is disabled. Please check the client-certs example. Important: TLS with Client Authentication is NOT possible in Cloudflare as is not allowed it and might result in unexpected behavior. Cloudflare only allows Authenticated Origin Pulls and is required to use their own certificate:\nhttps://blog.cloudflare.com/protecting-the-origin-with-tls-authenticated-origin-pulls/ Only Authenticated Origin Pulls are allowed and can be configured by following their tutorial:\nhttps://support.cloudflare.com/hc/en-us/articles/204494148-Setting-up-NGINX-to-use-TLS-Authenticated-Origin-Pulls", + "title": "Client Certificate Authentication" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#configuration-snippet", + "text": "Using this annotation you can add additional configuration to the NGINX location. For example: nginx.ingress.kubernetes.io/configuration-snippet : | \n more_set_headers \"Request-Id: $req_id\";", + "title": "Configuration snippet" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#default-backend", + "text": "The ingress controller requires a default backend. This service handles the response when the service in the Ingress rule does not have endpoints.\nThis is a global configuration for the ingress controller. In some cases could be required to return a custom content or format. In this scenario we can use the annotation nginx.ingress.kubernetes.io/default-backend: to specify a custom default backend.", + "title": "Default Backend" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#enable-cors", + "text": "To enable Cross-Origin Resource Sharing (CORS) in an Ingress rule add the annotation nginx.ingress.kubernetes.io/enable-cors: \"true\" . This will add a section in the server location enabling this functionality. CORS can be controlled with the following annotations: nginx.ingress.kubernetes.io/cors-allow-methods controls which methods are accepted. This is a multi-valued field, separated by ',' and accepts only letters (upper and lower case). Example: nginx.ingress.kubernetes.io/cors-allow-methods: \"PUT, GET, POST, OPTIONS\" nginx.ingress.kubernetes.io/cors-allow-headers controls which headers are accepted. This is a multi-valued field, separated by ',' and accepts letters, numbers, _ and -. Example: nginx.ingress.kubernetes.io/cors-allow-headers: \"X-Forwarded-For, X-app123-XPTO\" nginx.ingress.kubernetes.io/cors-allow-origin controls what's the accepted Origin for CORS and defaults to '*'. This is a single field value, with the following format: http(s)://origin-site.com or http(s)://origin-site.com:port Example: nginx.ingress.kubernetes.io/cors-allow-origin: \"https://origin-site.com:4443\" nginx.ingress.kubernetes.io/cors-allow-credentials controls if credentials can be passed during CORS operations. Example: nginx.ingress.kubernetes.io/cors-allow-credentials: \"true\" nginx.ingress.kubernetes.io/cors-max-age controls how long preflight requests can be cached. Example: nginx.ingress.kubernetes.io/cors-max-age: 600 For more information please check https://enable-cors.org/server_nginx.html", + "title": "Enable CORS" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#server-alias", + "text": "To add Server Aliases to an Ingress rule add the annotation nginx.ingress.kubernetes.io/server-alias: \"\" .\nThis will create a server with the same configuration, but a different server_name as the provided host. Note: A server-alias name cannot conflict with the hostname of an existing server. If it does the server-alias\nannotation will be ignored. If a server-alias is created and later a new server with the same hostname is created\nthe new server configuration will take place over the alias configuration. For more information please see http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name", + "title": "Server Alias" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#server-snippet", + "text": "Using the annotation nginx.ingress.kubernetes.io/server-snippet it is possible to add custom configuration in the server configuration block. apiVersion : extensions/v1beta1 kind : Ingress metadata : \n annotations : \n nginx.ingress.kubernetes.io/server-snippet : | set $agentflag 0; if ($http_user_agent ~* \"(Mobile)\" ){ \n set $agentflag 1; } if ( $agentflag = 1 ) { \n return 301 https://m.example.com; } Important: This annotation can be used only once per host", + "title": "Server snippet" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#client-body-buffer-size", + "text": "Sets buffer size for reading client request body per location. In case the request body is larger than the buffer,\nthe whole body or only its part is written to a temporary file. By default, buffer size is equal to two memory pages.\nThis is 8K on x86, other 32-bit platforms, and x86-64. It is usually 16K on other 64-bit platforms. This annotation is\napplied to each location provided in the ingress rule. Note: The annotation value must be given in a valid format otherwise the\nFor example to set the client-body-buffer-size the following can be done: nginx.ingress.kubernetes.io/client-body-buffer-size: \"1000\" # 1000 bytes nginx.ingress.kubernetes.io/client-body-buffer-size: 1k # 1 kilobyte nginx.ingress.kubernetes.io/client-body-buffer-size: 1K # 1 kilobyte nginx.ingress.kubernetes.io/client-body-buffer-size: 1m # 1 megabyte nginx.ingress.kubernetes.io/client-body-buffer-size: 1M # 1 megabyte For more information please see http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size", + "title": "Client Body Buffer Size" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#external-authentication", + "text": "To use an existing service that provides authentication the Ingress rule can be annotated with nginx.ingress.kubernetes.io/auth-url to indicate the URL where the HTTP request should be sent. nginx.ingress.kubernetes.io/auth-url : \"URL to the authentication service\" Additionally it is possible to set: nginx.ingress.kubernetes.io/auth-method : to specify the HTTP method to use. nginx.ingress.kubernetes.io/auth-signin : to specify the location of the error page. nginx.ingress.kubernetes.io/auth-response-headers : to specify headers to pass to backend once authorization request completes. nginx.ingress.kubernetes.io/auth-request-redirect : to specify the X-Auth-Request-Redirect header value. Please check the external-auth example.", + "title": "External Authentication" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#rate-limiting", + "text": "The annotations nginx.ingress.kubernetes.io/limit-connections , nginx.ingress.kubernetes.io/limit-rps , and nginx.ingress.kubernetes.io/limit-rpm define a limit on the connections that can be opened by a single client IP address. This can be used to mitigate DDoS Attacks . nginx.ingress.kubernetes.io/limit-connections : number of concurrent connections allowed from a single IP address. nginx.ingress.kubernetes.io/limit-rps : number of connections that may be accepted from a given IP each second. nginx.ingress.kubernetes.io/limit-rpm : number of connections that may be accepted from a given IP each minute. You can specify the client IP source ranges to be excluded from rate-limiting through the nginx.ingress.kubernetes.io/limit-whitelist annotation. The value is a comma separated list of CIDRs. If you specify multiple annotations in a single Ingress rule, limit-rpm , and then limit-rps takes precedence. The annotation nginx.ingress.kubernetes.io/limit-rate , nginx.ingress.kubernetes.io/limit-rate-after define a limit the rate of response transmission to a client. The rate is specified in bytes per second. The zero value disables rate limiting. The limit is set per a request, and so if a client simultaneously opens two connections, the overall rate will be twice as much as the specified limit. nginx.ingress.kubernetes.io/limit-rate-after : sets the initial amount after which the further transmission of a response to a client will be rate limited. nginx.ingress.kubernetes.io/limit-rate : rate of request that accepted from a client each second. To configure this setting globally for all Ingress rules, the limit-rate-after and limit-rate value may be set in the NGINX ConfigMap. if you set the value in ingress annotation will cover global setting.", + "title": "Rate limiting" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#permanent-redirect", + "text": "This annotation allows to return a permanent redirect instead of sending data to the upstream. For example nginx.ingress.kubernetes.io/permanent-redirect: https://www.google.com would redirect everything to Google.", + "title": "Permanent Redirect" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#ssl-passthrough", + "text": "The annotation nginx.ingress.kubernetes.io/ssl-passthrough allows to configure TLS termination in the pod and not in NGINX. Important: Using the annotation nginx.ingress.kubernetes.io/ssl-passthrough invalidates all the other available annotations. This is because SSL Passthrough works in L4 (TCP). The use of this annotation requires Proxy Protocol to be enabled in the load-balancer. For example enabling Proxy Protocol for AWS ELB is described here . If you're using ingress-controller without load balancer then the flag --enable-ssl-passthrough is required (by default it is disabled).", + "title": "SSL Passthrough" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#secure-backends", + "text": "By default NGINX uses http to reach the services. Adding the annotation nginx.ingress.kubernetes.io/secure-backends: \"true\" in the Ingress rule changes the protocol to https .\nIf you want to validate the upstream against a specific certificate, you can create a secret with it and reference the secret with the annotation nginx.ingress.kubernetes.io/secure-verify-ca-secret . Please note that if an invalid or non-existent secret is given, the NGINX ingress controller will ignore the secure-backends annotation.", + "title": "Secure backends" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#service-upstream", + "text": "By default the NGINX ingress controller uses a list of all endpoints (Pod IP/port) in the NGINX upstream configuration. This annotation disables that behavior and instead uses a single upstream in NGINX, the service's Cluster IP and port. This can be desirable for things like zero-downtime deployments as it reduces the need to reload NGINX configuration when Pods come up and down. See issue #257 .", + "title": "Service Upstream" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#known-issues", + "text": "If the service-upstream annotation is specified the following things should be taken into consideration: Sticky Sessions will not work as only round-robin load balancing is supported. The proxy_next_upstream directive will not have any effect meaning on error the request will not be dispatched to another upstream.", + "title": "Known Issues" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#server-side-https-enforcement-through-redirect", + "text": "By default the controller redirects (301) to HTTPS if TLS is enabled for that ingress. If you want to disable that behavior globally, you can use ssl-redirect: \"false\" in the NGINX config map. To configure this feature for specific ingress resources, you can use the nginx.ingress.kubernetes.io/ssl-redirect: \"false\" annotation in the particular resource. When using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a redirect to HTTPS even when there is not TLS cert available. This can be achieved by using the nginx.ingress.kubernetes.io/force-ssl-redirect: \"true\" annotation in the particular resource.", + "title": "Server-side HTTPS enforcement through redirect" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#redirect-from-to-www", + "text": "In some scenarios is required to redirect from www.domain.com to domain.com or viceversa.\nTo enable this feature use the annotation nginx.ingress.kubernetes.io/from-to-www-redirect: \"true\" Important: \nIf at some point a new Ingress is created with a host equal to one of the options (like domain.com ) the annotation will be omitted.", + "title": "Redirect from to www" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#whitelist-source-range", + "text": "You can specify the allowed client IP source ranges through the nginx.ingress.kubernetes.io/whitelist-source-range annotation. The value is a comma separated list of CIDRs , e.g. 10.0.0.0/24,172.10.0.1 . To configure this setting globally for all Ingress rules, the whitelist-source-range value may be set in the NGINX ConfigMap. Note: Adding an annotation to an Ingress rule overrides any global restriction.", + "title": "Whitelist source range" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#cookie-affinity", + "text": "If you use the cookie type you can also specify the name of the cookie that will be used to route the requests with the annotation nginx.ingress.kubernetes.io/session-cookie-name . The default is to create a cookie named 'INGRESSCOOKIE'. In case of NGINX the annotation nginx.ingress.kubernetes.io/session-cookie-hash defines which algorithm will be used to 'hash' the used upstream. Default value is md5 and possible values are md5 , sha1 and index .\nThe index option is not hashed, an in-memory index is used instead, it's quicker and the overhead is shorter Warning: the matching against upstream servers list is inconsistent. So, at reload, if upstreams servers has changed, index values are not guaranteed to correspond to the same server as before! USE IT WITH CAUTION and only if you need to! In NGINX this feature is implemented by the third party module nginx-sticky-module-ng . The workflow used to define which upstream server will be used is explained here", + "title": "Cookie affinity" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#custom-timeouts", + "text": "Using the configuration configmap it is possible to set the default global timeout for connections to the upstream servers.\nIn some scenarios is required to have different values. To allow this we provide annotations that allows this customization: nginx.ingress.kubernetes.io/proxy-connect-timeout nginx.ingress.kubernetes.io/proxy-send-timeout nginx.ingress.kubernetes.io/proxy-read-timeout nginx.ingress.kubernetes.io/proxy-next-upstream nginx.ingress.kubernetes.io/proxy-next-upstream-tries nginx.ingress.kubernetes.io/proxy-request-buffering", + "title": "Custom timeouts" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#proxy-redirect", + "text": "With the annotations nginx.ingress.kubernetes.io/proxy-redirect-from and nginx.ingress.kubernetes.io/proxy-redirect-to it is possible to set the text that should be changed in the Location and Refresh header fields of a proxied server response (http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect)\nSetting \"off\" or \"default\" in the annotation nginx.ingress.kubernetes.io/proxy-redirect-from disables nginx.ingress.kubernetes.io/proxy-redirect-to \nBoth annotations will be used in any other case\nBy default the value is \"off\".", + "title": "Proxy redirect" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#custom-max-body-size", + "text": "For NGINX, 413 error will be returned to the client when the size in a request exceeds the maximum allowed size of the client request body. This size can be configured by the parameter client_max_body_size . To configure this setting globally for all Ingress rules, the proxy-body-size value may be set in the NGINX ConfigMap.\nTo use custom values in an Ingress rule define these annotation: nginx.ingress.kubernetes.io/proxy-body-size : 8m", + "title": "Custom max body size" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#proxy-buffering", + "text": "Enable or disable proxy buffering proxy_buffering .\nBy default proxy buffering is disabled in the nginx config. To configure this setting globally for all Ingress rules, the proxy-buffering value may be set in the NGINX ConfigMap.\nTo use custom values in an Ingress rule define these annotation: nginx.ingress.kubernetes.io/proxy-buffering : \"on\"", + "title": "Proxy buffering" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#ssl-ciphers", + "text": "Specifies the enabled ciphers . Using this annotation will set the ssl_ciphers directive at the server level. This configuration is active for all the paths in the host. nginx.ingress.kubernetes.io/ssl-ciphers : \"ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP\"", + "title": "SSL ciphers" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#connection-proxy-header", + "text": "Using this annotation will override the default connection header set by nginx. To use custom values in an Ingress rule, define the annotation: nginx.ingress.kubernetes.io/connection-proxy-header : \"keep-alive\"", + "title": "Connection proxy header" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#enable-access-log", + "text": "In some scenarios could be required to disable NGINX access logs. To enable this feature use the annotation: nginx.ingress.kubernetes.io/enable-access-log : \"false\"", + "title": "Enable Access Log" + }, + { + "location": "/user-guide/nginx-configuration/annotations/#lua-resty-waf", + "text": "Using lua-resty-waf-* annotations we can enable and control lua-resty-waf per location.\nFollowing configuration will enable WAF for the paths defined in the corresponding ingress: nginx.ingress.kubernetes.io/lua-resty-waf : \"active\" In order to run it in debugging mode you can set nginx.ingress.kubernetes.io/lua-resty-waf-debug to \"true\" in addition to the above configuration.\nThe other possible values for nginx.ingress.kubernetes.io/lua-resty-waf are inactive and simulate . In inactive mode WAF won't do anything, whereas\nin simulate mode it will log a warning message if there's a matching WAF rule for given request. This is useful to debug a rule and eliminate possible false positives before fully deploying it. lua-resty-waf comes with predefined set of rules(https://github.com/p0pr0ck5/lua-resty-waf/tree/84b4f40362500dd0cb98b9e71b5875cb1a40f1ad/rules) that covers ModSecurity CRS.\nYou can use nginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets to ignore subset of those rulesets. For an example: nginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets : \"41000_sqli, 42000_xss\" will ignore the two mentioned rulesets. It is also possible to configure custom WAF rules per ingress using nginx.ingress.kubernetes.io/lua-resty-waf-extra-rules annotation. For an example the following snippet will\nconfigure a WAF rule to deny requests with query string value that contains word foo : nginx.ingress.kubernetes.io/lua-resty-waf-extra-rules : '[=[ { \"access\": [ { \"actions\": { \"disrupt\" : \"DENY\" }, \"id\": 10001, \"msg\": \"my custom rule\", \"operator\": \"STR_CONTAINS\", \"pattern\": \"foo\", \"vars\": [ { \"parse\": [ \"values\", 1 ], \"type\": \"REQUEST_ARGS\" } ] } ], \"body_filter\": [], \"header_filter\":[] } ]=]' For details on how to write WAF rules, please refer to https://github.com/p0pr0ck5/lua-resty-waf.", + "title": "Lua Resty WAF" + }, + { + "location": "/user-guide/nginx-configuration/configmap/", + "text": "ConfigMaps\n\u00b6\n\n\nConfigMaps allow you to decouple configuration artifacts from image content to keep containerized applications portable.\n\n\nThe ConfigMap API resource stores configuration data as key-value pairs. The data provides the configurations for system\ncomponents for the nginx-controller. Before you can begin using a config-map it must be \ndeployed\n.\n\n\nIn order to overwrite nginx-controller configuration values as seen in \nconfig.go\n,\nyou can add key-value pairs to the data section of the config-map. For Example:\n\n\ndata\n:\n\n \nmap-hash-bucket-size\n:\n \n\"128\"\n\n \nssl-protocols\n:\n \nSSLv2\n\n\n\n\n\n\nIMPORTANT:\n\n\nThe key and values in a ConfigMap can only be strings.\nThis means that we want a value with boolean values we need to quote the values, like \"true\" or \"false\".\nSame for numbers, like \"100\".\n\n\n\"Slice\" types (defined below as \n[]string\n or \n[]int\n can be provided as a comma-delimited string.\n\n\nConfiguration options\n\u00b6\n\n\nThe following table shows a configuration option's name, type, and the default value:\n\n\n\n\n\n\n\n\nname\n\n\ntype\n\n\ndefault\n\n\n\n\n\n\n\n\n\n\nadd-headers\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nallow-backend-server-header\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nhide-headers\n\n\nstring array\n\n\nempty\n\n\n\n\n\n\naccess-log-path\n\n\nstring\n\n\n\"/var/log/nginx/access.log\"\n\n\n\n\n\n\nerror-log-path\n\n\nstring\n\n\n\"/var/log/nginx/error.log\"\n\n\n\n\n\n\nenable-dynamic-tls-records\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nenable-modsecurity\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nenable-owasp-modsecurity-crs\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nclient-header-buffer-size\n\n\nstring\n\n\n\"1k\"\n\n\n\n\n\n\nclient-header-timeout\n\n\nint\n\n\n60\n\n\n\n\n\n\nclient-body-buffer-size\n\n\nstring\n\n\n\"8k\"\n\n\n\n\n\n\nclient-body-timeout\n\n\nint\n\n\n60\n\n\n\n\n\n\ndisable-access-log\n\n\nbool\n\n\nfalse\n\n\n\n\n\n\ndisable-ipv6\n\n\nbool\n\n\nfalse\n\n\n\n\n\n\ndisable-ipv6-dns\n\n\nbool\n\n\nfalse\n\n\n\n\n\n\nenable-underscores-in-headers\n\n\nbool\n\n\nfalse\n\n\n\n\n\n\nignore-invalid-headers\n\n\nbool\n\n\ntrue\n\n\n\n\n\n\nenable-vts-status\n\n\nbool\n\n\nfalse\n\n\n\n\n\n\nvts-status-zone-size\n\n\nstring\n\n\n\"10m\"\n\n\n\n\n\n\nvts-sum-key\n\n\nstring\n\n\n\"*\"\n\n\n\n\n\n\nvts-default-filter-key\n\n\nstring\n\n\n\"$geoip_country_code country::*\"\n\n\n\n\n\n\nretry-non-idempotent\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nerror-log-level\n\n\nstring\n\n\n\"notice\"\n\n\n\n\n\n\nhttp2-max-field-size\n\n\nstring\n\n\n\"4k\"\n\n\n\n\n\n\nhttp2-max-header-size\n\n\nstring\n\n\n\"16k\"\n\n\n\n\n\n\nhsts\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nhsts-include-subdomains\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nhsts-max-age\n\n\nstring\n\n\n\"15724800\"\n\n\n\n\n\n\nhsts-preload\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nkeep-alive\n\n\nint\n\n\n75\n\n\n\n\n\n\nkeep-alive-requests\n\n\nint\n\n\n100\n\n\n\n\n\n\nlarge-client-header-buffers\n\n\nstring\n\n\n\"4 8k\"\n\n\n\n\n\n\nlog-format-escape-json\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nlog-format-upstream\n\n\nstring\n\n\n%v\n \n-\n \n[\n$the_real_ip\n]\n \n-\n \n$remote_user\n \n[\n$time_local\n]\n \n\"$request\"\n \n$status\n \n$body_bytes_sent\n \n\"$http_referer\"\n \n\"$http_user_agent\"\n \n$request_length\n \n$request_time\n \n[\n$proxy_upstream_name\n]\n \n$upstream_addr\n \n$upstream_response_length\n \n$upstream_response_time\n \n$upstream_status\n\n\n\n\n\n\nlog-format-stream\n\n\nstring\n\n\n[$time_local] $protocol $status $bytes_sent $bytes_received $session_time\n\n\n\n\n\n\nmax-worker-connections\n\n\nint\n\n\n16384\n\n\n\n\n\n\nmap-hash-bucket-size\n\n\nint\n\n\n64\n\n\n\n\n\n\nnginx-status-ipv4-whitelist\n\n\n[]string\n\n\n\"127.0.0.1\"\n\n\n\n\n\n\nnginx-status-ipv6-whitelist\n\n\n[]string\n\n\n\"::1\"\n\n\n\n\n\n\nproxy-real-ip-cidr\n\n\n[]string\n\n\n\"0.0.0.0/0\"\n\n\n\n\n\n\nproxy-set-headers\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nserver-name-hash-max-size\n\n\nint\n\n\n1024\n\n\n\n\n\n\nserver-name-hash-bucket-size\n\n\nint\n\n\n\n\n\n\n\n\n\nproxy-headers-hash-max-size\n\n\nint\n\n\n512\n\n\n\n\n\n\nproxy-headers-hash-bucket-size\n\n\nint\n\n\n64\n\n\n\n\n\n\nserver-tokens\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nssl-ciphers\n\n\nstring\n\n\n\"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\"\n\n\n\n\n\n\nssl-ecdh-curve\n\n\nstring\n\n\n\"auto\"\n\n\n\n\n\n\nssl-dh-param\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nssl-protocols\n\n\nstring\n\n\n\"TLSv1.2\"\n\n\n\n\n\n\nssl-session-cache\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nssl-session-cache-size\n\n\nstring\n\n\n\"10m\"\n\n\n\n\n\n\nssl-session-tickets\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nssl-session-ticket-key\n\n\nstring\n\n\n\n\n\n\n\n\n\nssl-session-timeout\n\n\nstring\n\n\n\"10m\"\n\n\n\n\n\n\nssl-buffer-size\n\n\nstring\n\n\n\"4k\"\n\n\n\n\n\n\nuse-proxy-protocol\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nuse-gzip\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nuse-geoip\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nenable-brotli\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nbrotli-level\n\n\nint\n\n\n4\n\n\n\n\n\n\nbrotli-types\n\n\nstring\n\n\n\"application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\"\n\n\n\n\n\n\nuse-http2\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\ngzip-types\n\n\nstring\n\n\n\"application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\"\n\n\n\n\n\n\nworker-processes\n\n\nstring\n\n\n\n\n\n\n\n\n\nworker-cpu-affinity\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nworker-shutdown-timeout\n\n\nstring\n\n\n\"10s\"\n\n\n\n\n\n\nload-balance\n\n\nstring\n\n\n\"least_conn\"\n\n\n\n\n\n\nvariables-hash-bucket-size\n\n\nint\n\n\n128\n\n\n\n\n\n\nvariables-hash-max-size\n\n\nint\n\n\n2048\n\n\n\n\n\n\nupstream-keepalive-connections\n\n\nint\n\n\n32\n\n\n\n\n\n\nlimit-conn-zone-variable\n\n\nstring\n\n\n\"$binary_remote_addr\"\n\n\n\n\n\n\nproxy-stream-timeout\n\n\nstring\n\n\n\"600s\"\n\n\n\n\n\n\nproxy-stream-responses\n\n\nint\n\n\n1\n\n\n\n\n\n\nbind-address-ipv4\n\n\n[]string\n\n\n\"\"\n\n\n\n\n\n\nbind-address-ipv6\n\n\n[]string\n\n\n\"\"\n\n\n\n\n\n\nforwarded-for-header\n\n\nstring\n\n\n\"X-Forwarded-For\"\n\n\n\n\n\n\ncompute-full-forwarded-for\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nproxy-add-original-uri-header\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nenable-opentracing\n\n\nbool\n\n\n\"false\"\n\n\n\n\n\n\nzipkin-collector-host\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nzipkin-collector-port\n\n\nint\n\n\n9411\n\n\n\n\n\n\nzipkin-service-name\n\n\nstring\n\n\n\"nginx\"\n\n\n\n\n\n\njaeger-collector-host\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\njaeger-collector-port\n\n\nint\n\n\n6831\n\n\n\n\n\n\njaeger-service-name\n\n\nstring\n\n\n\"nginx\"\n\n\n\n\n\n\njaeger-sampler-type\n\n\nstring\n\n\n\"const\"\n\n\n\n\n\n\njaeger-sampler-param\n\n\nstring\n\n\n\"1\"\n\n\n\n\n\n\nhttp-snippet\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nserver-snippet\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\nlocation-snippet\n\n\nstring\n\n\n\"\"\n\n\n\n\n\n\ncustom-http-errors\n\n\n[]int]\n\n\n[]int{}\n\n\n\n\n\n\nproxy-body-size\n\n\nstring\n\n\n\"1m\"\n\n\n\n\n\n\nproxy-connect-timeout\n\n\nint\n\n\n5\n\n\n\n\n\n\nproxy-read-timeout\n\n\nint\n\n\n60\n\n\n\n\n\n\nproxy-send-timeout\n\n\nint\n\n\n60\n\n\n\n\n\n\nproxy-buffer-size\n\n\nstring\n\n\n\"4k\"\n\n\n\n\n\n\nproxy-cookie-path\n\n\nstring\n\n\n\"off\"\n\n\n\n\n\n\nproxy-cookie-domain\n\n\nstring\n\n\n\"off\"\n\n\n\n\n\n\nproxy-next-upstream\n\n\nstring\n\n\n\"error timeout invalid_header http_502 http_503 http_504\"\n\n\n\n\n\n\nproxy-next-upstream-tries\n\n\nint\n\n\n0\n\n\n\n\n\n\nproxy-redirect-from\n\n\nstring\n\n\n\"off\"\n\n\n\n\n\n\nproxy-request-buffering\n\n\nstring\n\n\n\"on\"\n\n\n\n\n\n\nssl-redirect\n\n\nbool\n\n\n\"true\"\n\n\n\n\n\n\nwhitelist-source-range\n\n\n[]string\n\n\n[]string{}\n\n\n\n\n\n\nskip-access-log-urls\n\n\n[]string\n\n\n[]string{}\n\n\n\n\n\n\nlimit-rate\n\n\nint\n\n\n0\n\n\n\n\n\n\nlimit-rate-after\n\n\nint\n\n\n0\n\n\n\n\n\n\nhttp-redirect-code\n\n\nint\n\n\n308\n\n\n\n\n\n\nproxy-buffering\n\n\nstring\n\n\n\"off\"\n\n\n\n\n\n\nlimit-req-status-code\n\n\nint\n\n\n503\n\n\n\n\n\n\nno-tls-redirect-locations\n\n\nstring\n\n\n\"/.well-known/acme-challenge\"\n\n\n\n\n\n\nno-auth-locations\n\n\nstring\n\n\n\"/.well-known/acme-challenge\"\n\n\n\n\n\n\n\n\nadd-headers\n\u00b6\n\n\nSets custom headers from named configmap before sending traffic to the client. See \nproxy-set-headers\n. \nexample\n\n\nallow-backend-server-header\n\u00b6\n\n\nEnables the return of the header Server from the backend instead of the generic nginx string. By default this is disabled.\n\n\nhide-headers\n\u00b6\n\n\nSets additional header that will not be passed from the upstream server to the client response.\nDefault: empty\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header\n\n\naccess-log-path\n\u00b6\n\n\nAccess log path. Goes to \n/var/log/nginx/access.log\n by default.\n\n\nNote:\n the file \n/var/log/nginx/access.log\n is a symlink to \n/dev/stdout\n\n\nerror-log-path\n\u00b6\n\n\nError log path. Goes to \n/var/log/nginx/error.log\n by default.\n\n\nNote:\n the file \n/var/log/nginx/error.log\n is a symlink to \n/dev/stderr\n\n\nReferences:\n\n- http://nginx.org/en/docs/ngx_core_module.html#error_log\n\n\nenable-dynamic-tls-records\n\u00b6\n\n\nEnables dynamically sized TLS records to improve time-to-first-byte. By default this is enabled. See \nCloudFlare's blog\n for more information.\n\n\nenable-modsecurity\n\u00b6\n\n\nEnables the modsecurity module for NGINX. By default this is disabled.\n\n\nenable-owasp-modsecurity-crs\n\u00b6\n\n\nEnables the OWASP ModSecurity Core Rule Set (CRS). By default this is disabled.\n\n\nclient-header-buffer-size\n\u00b6\n\n\nAllows to configure a custom buffer size for reading client request header.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_buffer_size\n\n\nclient-header-timeout\n\u00b6\n\n\nDefines a timeout for reading client request header, in seconds.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_timeout\n\n\nclient-body-buffer-size\n\u00b6\n\n\nSets buffer size for reading client request body.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size\n\n\nclient-body-timeout\n\u00b6\n\n\nDefines a timeout for reading client request body, in seconds.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_timeout\n\n\ndisable-access-log\n\u00b6\n\n\nDisables the Access Log from the entire Ingress Controller. This is '\"false\"' by default.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_log_module.html#access_log\n\n\ndisable-ipv6\n\u00b6\n\n\nDisable listening on IPV6. By default this is disabled.\n\n\ndisable-ipv6-dns\n\u00b6\n\n\nDisable IPV6 for nginx DNS resolver. By default this is disabled.\n\n\nenable-underscores-in-headers\n\u00b6\n\n\nEnables underscores in header names. By default this is disabled.\n\n\nignore-invalid-headers\n\u00b6\n\n\nSet if header fields with invalid names should be ignored.\nBy default this is enabled.\n\n\nenable-vts-status\n\u00b6\n\n\nAllows the replacement of the default status page with a third party module named \nnginx-module-vts\n.\nBy default this is disabled.\n\n\nvts-status-zone-size\n\u00b6\n\n\nVts config on http level sets parameters for a shared memory zone that will keep states for various keys. The cache is shared between all worker processes. Default value is 10m\n\n\nReferences:\n\n- https://github.com/vozlt/nginx-module-vts#vhost_traffic_status_zone\n\n\nvts-default-filter-key\n\u00b6\n\n\nVts config on http level enables the keys by user defined variable. The key is a key string to calculate traffic. The name is a group string to calculate traffic. The key and name can contain variables such as $host, $server_name. The name's group belongs to filterZones if specified. The key's group belongs to serverZones if not specified second argument name. Default value is $geoip_country_code country::*\n\n\nReferences:\n\n- https://github.com/vozlt/nginx-module-vts#vhost_traffic_status_filter_by_set_key\n\n\nvts-sum-key\n\u00b6\n\n\nFor metrics keyed (or when using Prometheus, labeled) by server zone, this value is used to indicate metrics for all server zones combined. Default value is *\n\n\nReferences:\n\n- https://github.com/vozlt/nginx-module-vts#vhost_traffic_status_display_sum_key\n\n\nretry-non-idempotent\n\u00b6\n\n\nSince 1.9.13 NGINX will not retry non-idempotent requests (POST, LOCK, PATCH) in case of an error in the upstream server. The previous behavior can be restored using the value \"true\".\n\n\nerror-log-level\n\u00b6\n\n\nConfigures the logging level of errors. Log levels above are listed in the order of increasing severity.\n\n\nReferences:\n\n- http://nginx.org/en/docs/ngx_core_module.html#error_log\n\n\nhttp2-max-field-size\n\u00b6\n\n\nLimits the maximum size of an HPACK-compressed request header field.\n\n\nReferences:\n\n- https://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_field_size\n\n\nhttp2-max-header-size\n\u00b6\n\n\nLimits the maximum size of the entire request header list after HPACK decompression.\n\n\nReferences:\n\n- https://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_header_size\n\n\nhsts\n\u00b6\n\n\nEnables or disables the header HSTS in servers running SSL.\nHTTP Strict Transport Security (often abbreviated as HSTS) is a security feature (HTTP header) that tell browsers that it should only be communicated with using HTTPS, instead of using HTTP. It provides protection against protocol downgrade attacks and cookie theft.\n\n\nReferences:\n\n- https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security\n- https://blog.qualys.com/securitylabs/2016/03/28/the-importance-of-a-proper-http-strict-transport-security-implementation-on-your-web-server\n\n\nhsts-include-subdomains\n\u00b6\n\n\nEnables or disables the use of HSTS in all the subdomains of the server-name.\n\n\nhsts-max-age\n\u00b6\n\n\nSets the time, in seconds, that the browser should remember that this site is only to be accessed using HTTPS.\n\n\nhsts-preload\n\u00b6\n\n\nEnables or disables the preload attribute in the HSTS feature (when it is enabled) dd\n\n\nkeep-alive\n\u00b6\n\n\nSets the time during which a keep-alive client connection will stay open on the server side. The zero value disables keep-alive client connections.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout\n\n\nkeep-alive-requests\n\u00b6\n\n\nSets the maximum number of requests that can be served through one keep-alive connection.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_requests\n\n\nlarge-client-header-buffers\n\u00b6\n\n\nSets the maximum number and size of buffers used for reading large client request header. Default: 4 8k.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers\n\n\nlog-format-escape-json\n\u00b6\n\n\nSets if the escape parameter allows JSON (\"true\") or default characters escaping in variables (\"false\") Sets the nginx \nlog format\n.\n\n\nlog-format-upstream\n\u00b6\n\n\nSets the nginx \nlog format\n.\nExample for json output:\n\n\nconsolelog-format-upstream: '{ \"time\": \"$time_iso8601\", \"remote_addr\": \"$proxy_protocol_addr\",\"x-forward-for\": \"$proxy_add_x_forwarded_for\", \"request_id\": \"$req_id\", \"remote_user\":\"$remote_user\", \"bytes_sent\": $bytes_sent, \"request_time\": $request_time, \"status\":$status, \"vhost\": \"$host\", \"request_proto\": \"$server_protocol\", \"path\": \"$uri\",\"request_query\": \"$args\", \"request_length\": $request_length, \"duration\": $request_time,\"method\": \"$request_method\", \"http_referrer\": \"$http_referer\", \"http_user_agent\":\"$http_user_agent\" }'\n\n\nPlease check \nlog-format\n for definition of each field.\n\n\nlog-format-stream\n\u00b6\n\n\nSets the nginx \nstream format\n.\n\n\nmax-worker-connections\n\u00b6\n\n\nSets the maximum number of simultaneous connections that can be opened by each \nworker process\n\n\nmap-hash-bucket-size\n\u00b6\n\n\nSets the bucket size for the \nmap variables hash tables\n. The details of setting up hash tables are provided in a separate \ndocument\n.\n\n\nproxy-real-ip-cidr\n\u00b6\n\n\nIf use-proxy-protocol is enabled, proxy-real-ip-cidr defines the default the IP/network address of your external load balancer.\n\n\nproxy-set-headers\n\u00b6\n\n\nSets custom headers from named configmap before sending traffic to backends. The value format is namespace/name. See \nexample\n\n\nserver-name-hash-max-size\n\u00b6\n\n\nSets the maximum size of the \nserver names hash tables\n used in server names,map directive\u2019s values, MIME types, names of request header strings, etc.\n\n\nReferences:\n\n- http://nginx.org/en/docs/hash.html\n\n\nserver-name-hash-bucket-size\n\u00b6\n\n\nSets the size of the bucket for the server names hash tables.\n\n\nReferences:\n\n- http://nginx.org/en/docs/hash.html\n- http://nginx.org/en/docs/http/ngx_http_core_module.html#server_names_hash_bucket_size\n\n\nproxy-headers-hash-max-size\n\u00b6\n\n\nSets the maximum size of the proxy headers hash tables.\n\n\nReferences:\n\n- http://nginx.org/en/docs/hash.html\n- https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_max_size\n\n\nproxy-headers-hash-bucket-size\n\u00b6\n\n\nSets the size of the bucket for the proxy headers hash tables.\n\n\nReferences:\n\n- http://nginx.org/en/docs/hash.html\n- https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_bucket_size\n\n\nserver-tokens\n\u00b6\n\n\nSend NGINX Server header in responses and display NGINX version in error pages. By default this is enabled.\n\n\nssl-ciphers\n\u00b6\n\n\nSets the \nciphers\n list to enable. The ciphers are specified in the format understood by the OpenSSL library.\n\n\nThe default cipher list is:\n \nECDHE-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\n.\n\n\nThe ordering of a ciphersuite is very important because it decides which algorithms are going to be selected in priority. The recommendation above prioritizes algorithms that provide perfect \nforward secrecy\n.\n\n\nPlease check the \nMozilla SSL Configuration Generator\n.\n\n\nssl-ecdh-curve\n\u00b6\n\n\nSpecifies a curve for ECDHE ciphers.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_ecdh_curve\n\n\nssl-dh-param\n\u00b6\n\n\nSets the name of the secret that contains Diffie-Hellman key to help with \"Perfect Forward Secrecy\".\n\n\nReferences:\n\n- https://wiki.openssl.org/index.php/Manual:Dhparam(1)\n- https://wiki.mozilla.org/Security/Server_Side_TLS#DHE_handshake_and_dhparam\n- http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_dhparam\n\n\nssl-protocols\n\u00b6\n\n\nSets the \nSSL protocols\n to use. The default is: \nTLSv1.2\n.\n\n\nPlease check the result of the configuration using \nhttps://ssllabs.com/ssltest/analyze.html\n or \nhttps://testssl.sh\n.\n\n\nssl-session-cache\n\u00b6\n\n\nEnables or disables the use of shared \nSSL cache\n among worker processes.\n\n\nssl-session-cache-size\n\u00b6\n\n\nSets the size of the \nSSL shared session cache\n between all worker processes.\n\n\nssl-session-tickets\n\u00b6\n\n\nEnables or disables session resumption through \nTLS session tickets\n.\n\n\nssl-session-ticket-key\n\u00b6\n\n\nSets the secret key used to encrypt and decrypt TLS session tickets. The value must be a valid base64 string.\n\n\nTLS session ticket-key\n, by default, a randomly generated key is used. To create a ticket: \nopenssl rand 80 | base64 -w0\n\n\nssl-session-timeout\n\u00b6\n\n\nSets the time during which a client may \nreuse the session\n parameters stored in a cache.\n\n\nssl-buffer-size\n\u00b6\n\n\nSets the size of the \nSSL buffer\n used for sending data. The default of 4k helps NGINX to improve TLS Time To First Byte (TTTFB).\n\n\nReferences:\n\n- https://www.igvita.com/2013/12/16/optimizing-nginx-tls-time-to-first-byte/\n\n\nuse-proxy-protocol\n\u00b6\n\n\nEnables or disables the \nPROXY protocol\n to receive client connection (real IP address) information passed through proxy servers and load balancers such as HAProxy and Amazon Elastic Load Balancer (ELB).\n\n\nuse-gzip\n\u00b6\n\n\nEnables or disables compression of HTTP responses using the \n\"gzip\" module\n.\nThe default mime type list to compress is: \napplication/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\n.\n\n\nuse-geoip\n\u00b6\n\n\nEnables or disables \n\"geoip\" module\n that creates variables with values depending on the client IP address, using the precompiled MaxMind databases.\nThe default value is true.\n\n\nenable-brotli\n\u00b6\n\n\nEnables or disables compression of HTTP responses using the \n\"brotli\" module\n.\nThe default mime type list to compress is: \napplication/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\n. This is \ndisabled\n by default.\n\n\nNote:\n Brotli does not works in Safari < 11 https://caniuse.com/#feat=brotli\n\n\nbrotli-level\n\u00b6\n\n\nSets the Brotli Compression Level that will be used. \nDefaults to\n 4.\n\n\nbrotli-types\n\u00b6\n\n\nSets the MIME Types that will be compressed on-the-fly by brotli.\n\nDefaults to\n \napplication/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\n.\n\n\nuse-http2\n\u00b6\n\n\nEnables or disables \nHTTP/2\n support in secure connections.\n\n\ngzip-types\n\u00b6\n\n\nSets the MIME types in addition to \"text/html\" to compress. The special value \"*\" matches any MIME type. Responses with the \"text/html\" type are always compressed if \nuse-gzip\n is enabled.\n\n\nworker-processes\n\u00b6\n\n\nSets the number of \nworker processes\n.\nThe default of \"auto\" means number of available CPU cores.\n\n\nworker-cpu-affinity\n\u00b6\n\n\nBinds worker processes to the sets of CPUs. \nworker_cpu_affinity\n.\nBy default worker processes are not bound to any specific CPUs. The value can be:\n\n\n\n\n\"\": empty string indicate no affinity is applied.\n\n\ncpumask: e.g. \n0001 0010 0100 1000\n to bind processes to specific cpus.\n\n\nauto: binding worker processes automatically to available CPUs.\n\n\n\n\nworker-shutdown-timeout\n\u00b6\n\n\nSets a timeout for Nginx to \nwait for worker to gracefully shutdown\n. The default is \"10s\".\n\n\nload-balance\n\u00b6\n\n\nSets the algorithm to use for load balancing.\nThe value can either be:\n\n\n\n\nround_robin: to use the default round robin loadbalancer\n\n\nleast_conn: to use the least connected method\n\n\nip_hash: to use a hash of the server for routing.\n\n\newma: to use the peak ewma method for routing (only available with \nenable-dynamic-configuration\n flag) \n\n\n\n\nThe default is least_conn.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/load_balancing.html.\n\n\nvariables-hash-bucket-size\n\u00b6\n\n\nSets the bucket size for the variables hash table.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_map_module.html#variables_hash_bucket_size\n\n\nvariables-hash-max-size\n\u00b6\n\n\nSets the maximum size of the variables hash table.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_map_module.html#variables_hash_max_size\n\n\nupstream-keepalive-connections\n\u00b6\n\n\nActivates the cache for connections to upstream servers. The connections parameter sets the maximum number of idle keepalive connections to upstream servers that are preserved in the cache of each worker process. When this\nnumber is exceeded, the least recently used connections are closed. Default: 32\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive\n\n\nlimit-conn-zone-variable\n\u00b6\n\n\nSets parameters for a shared memory zone that will keep states for various keys of \nlimit_conn_zone\n. The default of \"$binary_remote_addr\" variable\u2019s size is always 4 bytes for IPv4 addresses or 16 bytes for IPv6 addresses.\n\n\nproxy-stream-timeout\n\u00b6\n\n\nSets the timeout between two successive read or write operations on client or proxied server connections. If no data is transmitted within this time, the connection is closed.\n\n\nReferences:\n\n- http://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_timeout\n\n\nproxy-stream-responses\n\u00b6\n\n\nSets the number of datagrams expected from the proxied server in response to the client request if the UDP protocol is used.\n\n\nReferences:\n\n- http://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_responses\n\n\nbind-address-ipv4\n\u00b6\n\n\nSets the addresses on which the server will accept requests instead of *. It should be noted that these addresses must exist in the runtime environment or the controller will crash loop.\n\n\nbind-address-ipv6\n\u00b6\n\n\nSets the addresses on which the server will accept requests instead of *. It should be noted that these addresses must exist in the runtime environment or the controller will crash loop.\n\n\nforwarded-for-header\n\u00b6\n\n\nSets the header field for identifying the originating IP address of a client. Default is X-Forwarded-For\n\n\ncompute-full-forwarded-for\n\u00b6\n\n\nAppend the remote address to the X-Forwarded-For header instead of replacing it. When this option is enabled, the upstream application is responsible for extracting the client IP based on its own list of trusted proxies.\n\n\nproxy-add-original-uri-header\n\u00b6\n\n\nAdds an X-Original-Uri header with the original request URI to the backend request\n\n\nenable-opentracing\n\u00b6\n\n\nEnables the nginx Opentracing extension. By default this is disabled.\n\n\nReferences:\n\n- https://github.com/opentracing-contrib/nginx-opentracing\n\n\nzipkin-collector-host\n\u00b6\n\n\nSpecifies the host to use when uploading traces. It must be a valid URL.\n\n\nzipkin-collector-port\n\u00b6\n\n\nSpecifies the port to use when uploading traces. Default: 9411\n\n\nzipkin-service-name\n\u00b6\n\n\nSpecifies the service name to use for any traces created. Default: nginx\n\n\njaeger-collector-host\n\u00b6\n\n\nSpecifies the host to use when uploading traces. It must be a valid URL.\n\n\njaeger-collector-port\n\u00b6\n\n\nSpecifies the port to use when uploading traces. Default: 6831\n\n\njaeger-service-name\n\u00b6\n\n\nSpecifies the service name to use for any traces created. Default: nginx\n\n\njaeger-sampler-type\n\u00b6\n\n\nSpecifies the sampler to be used when sampling traces. The available samplers are: const, probabilistic, ratelimiting, remote. Default const.\n\n\njaeger-sampler-param\n\u00b6\n\n\nSpecifies the argument to be passed to the sampler constructor. Must be a number.\nFor const this should be 0 to never sample and 1 to always sample. Default: 1\n\n\nhttp-snippet\n\u00b6\n\n\nAdds custom configuration to the http section of the nginx configuration.\nDefault: \"\"\n\n\nserver-snippet\n\u00b6\n\n\nAdds custom configuration to all the servers in the nginx configuration.\nDefault: \"\"\n\n\nlocation-snippet\n\u00b6\n\n\nAdds custom configuration to all the locations in the nginx configuration.\nDefault: \"\"\n\n\ncustom-http-errors\n\u00b6\n\n\nEnables which HTTP codes should be passed for processing with the \nerror_page directive\n\n\nSetting at least one code also enables \nproxy_intercept_errors\n which are required to process error_page.\n\n\nExample usage: \ncustom-http-errors: 404,415\n\n\nproxy-body-size\n\u00b6\n\n\nSets the maximum allowed size of the client request body.\nSee NGINX \nclient_max_body_size\n.\n\n\nproxy-connect-timeout\n\u00b6\n\n\nSets the timeout for \nestablishing a connection with a proxied server\n. It should be noted that this timeout cannot usually exceed 75 seconds.\n\n\nproxy-read-timeout\n\u00b6\n\n\nSets the timeout in seconds for \nreading a response from the proxied server\n. The timeout is set only between two successive read operations, not for the transmission of the whole response.\n\n\nproxy-send-timeout\n\u00b6\n\n\nSets the timeout in seconds for \ntransmitting a request to the proxied server\n. The timeout is set only between two successive write operations, not for the transmission of the whole request.\n\n\nproxy-buffer-size\n\u00b6\n\n\nSets the size of the buffer used for \nreading the first part of the response\n received from the proxied server. This part usually contains a small response header.\n\n\nproxy-cookie-path\n\u00b6\n\n\nSets a text that \nshould be changed in the path attribute\n of the \u201cSet-Cookie\u201d header fields of a proxied server response.\n\n\nproxy-cookie-domain\n\u00b6\n\n\nSets a text that \nshould be changed in the domain attribute\n of the \u201cSet-Cookie\u201d header fields of a proxied server response.\n\n\nproxy-next-upstream\n\u00b6\n\n\nSpecifies in \nwhich cases\n a request should be passed to the next server.\n\n\nproxy-next-upstream-tries\n\u00b6\n\n\nLimit the number of \npossible tries\n a request should be passed to the next server.\n\n\nproxy-redirect-from\n\u00b6\n\n\nSets the original text that should be changed in the \"Location\" and \"Refresh\" header fields of a proxied server response. Default: off.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect\n\n\nproxy-request-buffering\n\u00b6\n\n\nEnables or disables \nbuffering of a client request body\n.\n\n\nssl-redirect\n\u00b6\n\n\nSets the global value of redirects (301) to HTTPS if the server has a TLS certificate (defined in an Ingress rule).\nDefault is \"true\".\n\n\nwhitelist-source-range\n\u00b6\n\n\nSets the default whitelisted IPs for each \nserver\n block. This can be overwritten by an annotation on an Ingress rule.\nSee \nngx_http_access_module\n.\n\n\nskip-access-log-urls\n\u00b6\n\n\nSets a list of URLs that should not appear in the NGINX access log. This is useful with urls like \n/health\n or \nhealth-check\n that make \"complex\" reading the logs. By default this list is empty\n\n\nlimit-rate\n\u00b6\n\n\nLimits the rate of response transmission to a client. The rate is specified in bytes per second. The zero value disables rate limiting. The limit is set per a request, and so if a client simultaneously opens two connections, the overall rate will be twice as much as the specified limit.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate\n\n\nlimit-rate-after\n\u00b6\n\n\nSets the initial amount after which the further transmission of a response to a client will be rate limited.\n\n\nReferences:\n\n- http://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate_after\n\n\nhttp-redirect-code\n\u00b6\n\n\nSets the HTTP status code to be used in redirects.\nSupported codes are \n301\n,\n302\n,\n307\n and \n308\n\nDefault code is 308.\n\n\nWhy the default code is 308?\n\n\nRFC 7238\n was created to define the 308 (Permanent Redirect) status code that is similar to 301 (Moved Permanently) but it keeps the payload in the redirect. This is important if the we send a redirect in methods like POST.\n\n\nproxy-buffering\n\u00b6\n\n\nEnables or disables \nbuffering of responses from the proxied server\n.\n\n\nlimit-req-status-code\n\u00b6\n\n\nSets the \nstatus code to return in response to rejected requests\n.Default: 503\n\n\nno-tls-redirect-locations\n\u00b6\n\n\nA comma-separated list of locations on which http requests will never get redirected to their https counterpart.\nDefault: \"/.well-known/acme-challenge\"\n\n\nno-auth-locations\n\u00b6\n\n\nA comma-separated list of locations that should not get authenticated.\nDefault: \"/.well-known/acme-challenge\"", + "title": "ConfigMaps" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#configmaps", + "text": "ConfigMaps allow you to decouple configuration artifacts from image content to keep containerized applications portable. The ConfigMap API resource stores configuration data as key-value pairs. The data provides the configurations for system\ncomponents for the nginx-controller. Before you can begin using a config-map it must be deployed . In order to overwrite nginx-controller configuration values as seen in config.go ,\nyou can add key-value pairs to the data section of the config-map. For Example: data : \n map-hash-bucket-size : \"128\" \n ssl-protocols : SSLv2 IMPORTANT: The key and values in a ConfigMap can only be strings.\nThis means that we want a value with boolean values we need to quote the values, like \"true\" or \"false\".\nSame for numbers, like \"100\". \"Slice\" types (defined below as []string or []int can be provided as a comma-delimited string.", + "title": "ConfigMaps" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#configuration-options", + "text": "The following table shows a configuration option's name, type, and the default value: name type default add-headers string \"\" allow-backend-server-header bool \"false\" hide-headers string array empty access-log-path string \"/var/log/nginx/access.log\" error-log-path string \"/var/log/nginx/error.log\" enable-dynamic-tls-records bool \"true\" enable-modsecurity bool \"false\" enable-owasp-modsecurity-crs bool \"false\" client-header-buffer-size string \"1k\" client-header-timeout int 60 client-body-buffer-size string \"8k\" client-body-timeout int 60 disable-access-log bool false disable-ipv6 bool false disable-ipv6-dns bool false enable-underscores-in-headers bool false ignore-invalid-headers bool true enable-vts-status bool false vts-status-zone-size string \"10m\" vts-sum-key string \"*\" vts-default-filter-key string \"$geoip_country_code country::*\" retry-non-idempotent bool \"false\" error-log-level string \"notice\" http2-max-field-size string \"4k\" http2-max-header-size string \"16k\" hsts bool \"true\" hsts-include-subdomains bool \"true\" hsts-max-age string \"15724800\" hsts-preload bool \"false\" keep-alive int 75 keep-alive-requests int 100 large-client-header-buffers string \"4 8k\" log-format-escape-json bool \"false\" log-format-upstream string %v - [ $the_real_ip ] - $remote_user [ $time_local ] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" $request_length $request_time [ $proxy_upstream_name ] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status log-format-stream string [$time_local] $protocol $status $bytes_sent $bytes_received $session_time max-worker-connections int 16384 map-hash-bucket-size int 64 nginx-status-ipv4-whitelist []string \"127.0.0.1\" nginx-status-ipv6-whitelist []string \"::1\" proxy-real-ip-cidr []string \"0.0.0.0/0\" proxy-set-headers string \"\" server-name-hash-max-size int 1024 server-name-hash-bucket-size int proxy-headers-hash-max-size int 512 proxy-headers-hash-bucket-size int 64 server-tokens bool \"true\" ssl-ciphers string \"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\" ssl-ecdh-curve string \"auto\" ssl-dh-param string \"\" ssl-protocols string \"TLSv1.2\" ssl-session-cache bool \"true\" ssl-session-cache-size string \"10m\" ssl-session-tickets bool \"true\" ssl-session-ticket-key string ssl-session-timeout string \"10m\" ssl-buffer-size string \"4k\" use-proxy-protocol bool \"false\" use-gzip bool \"true\" use-geoip bool \"true\" enable-brotli bool \"true\" brotli-level int 4 brotli-types string \"application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\" use-http2 bool \"true\" gzip-types string \"application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component\" worker-processes string worker-cpu-affinity string \"\" worker-shutdown-timeout string \"10s\" load-balance string \"least_conn\" variables-hash-bucket-size int 128 variables-hash-max-size int 2048 upstream-keepalive-connections int 32 limit-conn-zone-variable string \"$binary_remote_addr\" proxy-stream-timeout string \"600s\" proxy-stream-responses int 1 bind-address-ipv4 []string \"\" bind-address-ipv6 []string \"\" forwarded-for-header string \"X-Forwarded-For\" compute-full-forwarded-for bool \"false\" proxy-add-original-uri-header bool \"true\" enable-opentracing bool \"false\" zipkin-collector-host string \"\" zipkin-collector-port int 9411 zipkin-service-name string \"nginx\" jaeger-collector-host string \"\" jaeger-collector-port int 6831 jaeger-service-name string \"nginx\" jaeger-sampler-type string \"const\" jaeger-sampler-param string \"1\" http-snippet string \"\" server-snippet string \"\" location-snippet string \"\" custom-http-errors []int] []int{} proxy-body-size string \"1m\" proxy-connect-timeout int 5 proxy-read-timeout int 60 proxy-send-timeout int 60 proxy-buffer-size string \"4k\" proxy-cookie-path string \"off\" proxy-cookie-domain string \"off\" proxy-next-upstream string \"error timeout invalid_header http_502 http_503 http_504\" proxy-next-upstream-tries int 0 proxy-redirect-from string \"off\" proxy-request-buffering string \"on\" ssl-redirect bool \"true\" whitelist-source-range []string []string{} skip-access-log-urls []string []string{} limit-rate int 0 limit-rate-after int 0 http-redirect-code int 308 proxy-buffering string \"off\" limit-req-status-code int 503 no-tls-redirect-locations string \"/.well-known/acme-challenge\" no-auth-locations string \"/.well-known/acme-challenge\"", + "title": "Configuration options" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#add-headers", + "text": "Sets custom headers from named configmap before sending traffic to the client. See proxy-set-headers . example", + "title": "add-headers" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#allow-backend-server-header", + "text": "Enables the return of the header Server from the backend instead of the generic nginx string. By default this is disabled.", + "title": "allow-backend-server-header" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#hide-headers", + "text": "Sets additional header that will not be passed from the upstream server to the client response.\nDefault: empty References: \n- http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header", + "title": "hide-headers" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#access-log-path", + "text": "Access log path. Goes to /var/log/nginx/access.log by default. Note: the file /var/log/nginx/access.log is a symlink to /dev/stdout", + "title": "access-log-path" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#error-log-path", + "text": "Error log path. Goes to /var/log/nginx/error.log by default. Note: the file /var/log/nginx/error.log is a symlink to /dev/stderr References: \n- http://nginx.org/en/docs/ngx_core_module.html#error_log", + "title": "error-log-path" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#enable-dynamic-tls-records", + "text": "Enables dynamically sized TLS records to improve time-to-first-byte. By default this is enabled. See CloudFlare's blog for more information.", + "title": "enable-dynamic-tls-records" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#enable-modsecurity", + "text": "Enables the modsecurity module for NGINX. By default this is disabled.", + "title": "enable-modsecurity" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#enable-owasp-modsecurity-crs", + "text": "Enables the OWASP ModSecurity Core Rule Set (CRS). By default this is disabled.", + "title": "enable-owasp-modsecurity-crs" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#client-header-buffer-size", + "text": "Allows to configure a custom buffer size for reading client request header. References: \n- http://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_buffer_size", + "title": "client-header-buffer-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#client-header-timeout", + "text": "Defines a timeout for reading client request header, in seconds. References: \n- http://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_timeout", + "title": "client-header-timeout" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#client-body-buffer-size", + "text": "Sets buffer size for reading client request body. References: \n- http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size", + "title": "client-body-buffer-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#client-body-timeout", + "text": "Defines a timeout for reading client request body, in seconds. References: \n- http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_timeout", + "title": "client-body-timeout" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#disable-access-log", + "text": "Disables the Access Log from the entire Ingress Controller. This is '\"false\"' by default. References: \n- http://nginx.org/en/docs/http/ngx_http_log_module.html#access_log", + "title": "disable-access-log" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#disable-ipv6", + "text": "Disable listening on IPV6. By default this is disabled.", + "title": "disable-ipv6" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#disable-ipv6-dns", + "text": "Disable IPV6 for nginx DNS resolver. By default this is disabled.", + "title": "disable-ipv6-dns" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#enable-underscores-in-headers", + "text": "Enables underscores in header names. By default this is disabled.", + "title": "enable-underscores-in-headers" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#ignore-invalid-headers", + "text": "Set if header fields with invalid names should be ignored.\nBy default this is enabled.", + "title": "ignore-invalid-headers" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#enable-vts-status", + "text": "Allows the replacement of the default status page with a third party module named nginx-module-vts .\nBy default this is disabled.", + "title": "enable-vts-status" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#vts-status-zone-size", + "text": "Vts config on http level sets parameters for a shared memory zone that will keep states for various keys. The cache is shared between all worker processes. Default value is 10m References: \n- https://github.com/vozlt/nginx-module-vts#vhost_traffic_status_zone", + "title": "vts-status-zone-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#vts-default-filter-key", + "text": "Vts config on http level enables the keys by user defined variable. The key is a key string to calculate traffic. The name is a group string to calculate traffic. The key and name can contain variables such as $host, $server_name. The name's group belongs to filterZones if specified. The key's group belongs to serverZones if not specified second argument name. Default value is $geoip_country_code country::* References: \n- https://github.com/vozlt/nginx-module-vts#vhost_traffic_status_filter_by_set_key", + "title": "vts-default-filter-key" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#vts-sum-key", + "text": "For metrics keyed (or when using Prometheus, labeled) by server zone, this value is used to indicate metrics for all server zones combined. Default value is * References: \n- https://github.com/vozlt/nginx-module-vts#vhost_traffic_status_display_sum_key", + "title": "vts-sum-key" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#retry-non-idempotent", + "text": "Since 1.9.13 NGINX will not retry non-idempotent requests (POST, LOCK, PATCH) in case of an error in the upstream server. The previous behavior can be restored using the value \"true\".", + "title": "retry-non-idempotent" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#error-log-level", + "text": "Configures the logging level of errors. Log levels above are listed in the order of increasing severity. References: \n- http://nginx.org/en/docs/ngx_core_module.html#error_log", + "title": "error-log-level" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#http2-max-field-size", + "text": "Limits the maximum size of an HPACK-compressed request header field. References: \n- https://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_field_size", + "title": "http2-max-field-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#http2-max-header-size", + "text": "Limits the maximum size of the entire request header list after HPACK decompression. References: \n- https://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_header_size", + "title": "http2-max-header-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#hsts", + "text": "Enables or disables the header HSTS in servers running SSL.\nHTTP Strict Transport Security (often abbreviated as HSTS) is a security feature (HTTP header) that tell browsers that it should only be communicated with using HTTPS, instead of using HTTP. It provides protection against protocol downgrade attacks and cookie theft. References: \n- https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security\n- https://blog.qualys.com/securitylabs/2016/03/28/the-importance-of-a-proper-http-strict-transport-security-implementation-on-your-web-server", + "title": "hsts" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#hsts-include-subdomains", + "text": "Enables or disables the use of HSTS in all the subdomains of the server-name.", + "title": "hsts-include-subdomains" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#hsts-max-age", + "text": "Sets the time, in seconds, that the browser should remember that this site is only to be accessed using HTTPS.", + "title": "hsts-max-age" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#hsts-preload", + "text": "Enables or disables the preload attribute in the HSTS feature (when it is enabled) dd", + "title": "hsts-preload" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#keep-alive", + "text": "Sets the time during which a keep-alive client connection will stay open on the server side. The zero value disables keep-alive client connections. References: \n- http://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout", + "title": "keep-alive" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#keep-alive-requests", + "text": "Sets the maximum number of requests that can be served through one keep-alive connection. References: \n- http://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_requests", + "title": "keep-alive-requests" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#large-client-header-buffers", + "text": "Sets the maximum number and size of buffers used for reading large client request header. Default: 4 8k. References: \n- http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers", + "title": "large-client-header-buffers" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#log-format-escape-json", + "text": "Sets if the escape parameter allows JSON (\"true\") or default characters escaping in variables (\"false\") Sets the nginx log format .", + "title": "log-format-escape-json" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#log-format-upstream", + "text": "Sets the nginx log format .\nExample for json output: consolelog-format-upstream: '{ \"time\": \"$time_iso8601\", \"remote_addr\": \"$proxy_protocol_addr\",\"x-forward-for\": \"$proxy_add_x_forwarded_for\", \"request_id\": \"$req_id\", \"remote_user\":\"$remote_user\", \"bytes_sent\": $bytes_sent, \"request_time\": $request_time, \"status\":$status, \"vhost\": \"$host\", \"request_proto\": \"$server_protocol\", \"path\": \"$uri\",\"request_query\": \"$args\", \"request_length\": $request_length, \"duration\": $request_time,\"method\": \"$request_method\", \"http_referrer\": \"$http_referer\", \"http_user_agent\":\"$http_user_agent\" }' Please check log-format for definition of each field.", + "title": "log-format-upstream" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#log-format-stream", + "text": "Sets the nginx stream format .", + "title": "log-format-stream" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#max-worker-connections", + "text": "Sets the maximum number of simultaneous connections that can be opened by each worker process", + "title": "max-worker-connections" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#map-hash-bucket-size", + "text": "Sets the bucket size for the map variables hash tables . The details of setting up hash tables are provided in a separate document .", + "title": "map-hash-bucket-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-real-ip-cidr", + "text": "If use-proxy-protocol is enabled, proxy-real-ip-cidr defines the default the IP/network address of your external load balancer.", + "title": "proxy-real-ip-cidr" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-set-headers", + "text": "Sets custom headers from named configmap before sending traffic to backends. The value format is namespace/name. See example", + "title": "proxy-set-headers" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#server-name-hash-max-size", + "text": "Sets the maximum size of the server names hash tables used in server names,map directive\u2019s values, MIME types, names of request header strings, etc. References: \n- http://nginx.org/en/docs/hash.html", + "title": "server-name-hash-max-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#server-name-hash-bucket-size", + "text": "Sets the size of the bucket for the server names hash tables. References: \n- http://nginx.org/en/docs/hash.html\n- http://nginx.org/en/docs/http/ngx_http_core_module.html#server_names_hash_bucket_size", + "title": "server-name-hash-bucket-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-headers-hash-max-size", + "text": "Sets the maximum size of the proxy headers hash tables. References: \n- http://nginx.org/en/docs/hash.html\n- https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_max_size", + "title": "proxy-headers-hash-max-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-headers-hash-bucket-size", + "text": "Sets the size of the bucket for the proxy headers hash tables. References: \n- http://nginx.org/en/docs/hash.html\n- https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_bucket_size", + "title": "proxy-headers-hash-bucket-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#server-tokens", + "text": "Send NGINX Server header in responses and display NGINX version in error pages. By default this is enabled.", + "title": "server-tokens" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#ssl-ciphers", + "text": "Sets the ciphers list to enable. The ciphers are specified in the format understood by the OpenSSL library. The default cipher list is:\n 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 . The ordering of a ciphersuite is very important because it decides which algorithms are going to be selected in priority. The recommendation above prioritizes algorithms that provide perfect forward secrecy . Please check the Mozilla SSL Configuration Generator .", + "title": "ssl-ciphers" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#ssl-ecdh-curve", + "text": "Specifies a curve for ECDHE ciphers. References: \n- http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_ecdh_curve", + "title": "ssl-ecdh-curve" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#ssl-dh-param", + "text": "Sets the name of the secret that contains Diffie-Hellman key to help with \"Perfect Forward Secrecy\". References: \n- https://wiki.openssl.org/index.php/Manual:Dhparam(1)\n- https://wiki.mozilla.org/Security/Server_Side_TLS#DHE_handshake_and_dhparam\n- http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_dhparam", + "title": "ssl-dh-param" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#ssl-protocols", + "text": "Sets the SSL protocols to use. The default is: TLSv1.2 . Please check the result of the configuration using https://ssllabs.com/ssltest/analyze.html or https://testssl.sh .", + "title": "ssl-protocols" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#ssl-session-cache", + "text": "Enables or disables the use of shared SSL cache among worker processes.", + "title": "ssl-session-cache" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#ssl-session-cache-size", + "text": "Sets the size of the SSL shared session cache between all worker processes.", + "title": "ssl-session-cache-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#ssl-session-tickets", + "text": "Enables or disables session resumption through TLS session tickets .", + "title": "ssl-session-tickets" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#ssl-session-ticket-key", + "text": "Sets the secret key used to encrypt and decrypt TLS session tickets. The value must be a valid base64 string. TLS session ticket-key , by default, a randomly generated key is used. To create a ticket: openssl rand 80 | base64 -w0", + "title": "ssl-session-ticket-key" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#ssl-session-timeout", + "text": "Sets the time during which a client may reuse the session parameters stored in a cache.", + "title": "ssl-session-timeout" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#ssl-buffer-size", + "text": "Sets the size of the SSL buffer used for sending data. The default of 4k helps NGINX to improve TLS Time To First Byte (TTTFB). References: \n- https://www.igvita.com/2013/12/16/optimizing-nginx-tls-time-to-first-byte/", + "title": "ssl-buffer-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#use-proxy-protocol", + "text": "Enables or disables the PROXY protocol to receive client connection (real IP address) information passed through proxy servers and load balancers such as HAProxy and Amazon Elastic Load Balancer (ELB).", + "title": "use-proxy-protocol" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#use-gzip", + "text": "Enables or disables compression of HTTP responses using the \"gzip\" module .\nThe default mime type list to compress is: application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component .", + "title": "use-gzip" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#use-geoip", + "text": "Enables or disables \"geoip\" module that creates variables with values depending on the client IP address, using the precompiled MaxMind databases.\nThe default value is true.", + "title": "use-geoip" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#enable-brotli", + "text": "Enables or disables compression of HTTP responses using the \"brotli\" module .\nThe default mime type list to compress is: application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component . This is disabled by default. Note: Brotli does not works in Safari < 11 https://caniuse.com/#feat=brotli", + "title": "enable-brotli" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#brotli-level", + "text": "Sets the Brotli Compression Level that will be used. Defaults to 4.", + "title": "brotli-level" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#brotli-types", + "text": "Sets the MIME Types that will be compressed on-the-fly by brotli. Defaults to application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component .", + "title": "brotli-types" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#use-http2", + "text": "Enables or disables HTTP/2 support in secure connections.", + "title": "use-http2" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#gzip-types", + "text": "Sets the MIME types in addition to \"text/html\" to compress. The special value \"*\" matches any MIME type. Responses with the \"text/html\" type are always compressed if use-gzip is enabled.", + "title": "gzip-types" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#worker-processes", + "text": "Sets the number of worker processes .\nThe default of \"auto\" means number of available CPU cores.", + "title": "worker-processes" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#worker-cpu-affinity", + "text": "Binds worker processes to the sets of CPUs. worker_cpu_affinity .\nBy default worker processes are not bound to any specific CPUs. The value can be: \"\": empty string indicate no affinity is applied. cpumask: e.g. 0001 0010 0100 1000 to bind processes to specific cpus. auto: binding worker processes automatically to available CPUs.", + "title": "worker-cpu-affinity" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#worker-shutdown-timeout", + "text": "Sets a timeout for Nginx to wait for worker to gracefully shutdown . The default is \"10s\".", + "title": "worker-shutdown-timeout" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#load-balance", + "text": "Sets the algorithm to use for load balancing.\nThe value can either be: round_robin: to use the default round robin loadbalancer least_conn: to use the least connected method ip_hash: to use a hash of the server for routing. ewma: to use the peak ewma method for routing (only available with enable-dynamic-configuration flag) The default is least_conn. References: \n- http://nginx.org/en/docs/http/load_balancing.html.", + "title": "load-balance" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#variables-hash-bucket-size", + "text": "Sets the bucket size for the variables hash table. References: \n- http://nginx.org/en/docs/http/ngx_http_map_module.html#variables_hash_bucket_size", + "title": "variables-hash-bucket-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#variables-hash-max-size", + "text": "Sets the maximum size of the variables hash table. References: \n- http://nginx.org/en/docs/http/ngx_http_map_module.html#variables_hash_max_size", + "title": "variables-hash-max-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#upstream-keepalive-connections", + "text": "Activates the cache for connections to upstream servers. The connections parameter sets the maximum number of idle keepalive connections to upstream servers that are preserved in the cache of each worker process. When this\nnumber is exceeded, the least recently used connections are closed. Default: 32 References: \n- http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive", + "title": "upstream-keepalive-connections" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#limit-conn-zone-variable", + "text": "Sets parameters for a shared memory zone that will keep states for various keys of limit_conn_zone . The default of \"$binary_remote_addr\" variable\u2019s size is always 4 bytes for IPv4 addresses or 16 bytes for IPv6 addresses.", + "title": "limit-conn-zone-variable" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-stream-timeout", + "text": "Sets the timeout between two successive read or write operations on client or proxied server connections. If no data is transmitted within this time, the connection is closed. References: \n- http://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_timeout", + "title": "proxy-stream-timeout" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-stream-responses", + "text": "Sets the number of datagrams expected from the proxied server in response to the client request if the UDP protocol is used. References: \n- http://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_responses", + "title": "proxy-stream-responses" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#bind-address-ipv4", + "text": "Sets the addresses on which the server will accept requests instead of *. It should be noted that these addresses must exist in the runtime environment or the controller will crash loop.", + "title": "bind-address-ipv4" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#bind-address-ipv6", + "text": "Sets the addresses on which the server will accept requests instead of *. It should be noted that these addresses must exist in the runtime environment or the controller will crash loop.", + "title": "bind-address-ipv6" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#forwarded-for-header", + "text": "Sets the header field for identifying the originating IP address of a client. Default is X-Forwarded-For", + "title": "forwarded-for-header" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#compute-full-forwarded-for", + "text": "Append the remote address to the X-Forwarded-For header instead of replacing it. When this option is enabled, the upstream application is responsible for extracting the client IP based on its own list of trusted proxies.", + "title": "compute-full-forwarded-for" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-add-original-uri-header", + "text": "Adds an X-Original-Uri header with the original request URI to the backend request", + "title": "proxy-add-original-uri-header" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#enable-opentracing", + "text": "Enables the nginx Opentracing extension. By default this is disabled. References: \n- https://github.com/opentracing-contrib/nginx-opentracing", + "title": "enable-opentracing" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#zipkin-collector-host", + "text": "Specifies the host to use when uploading traces. It must be a valid URL.", + "title": "zipkin-collector-host" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#zipkin-collector-port", + "text": "Specifies the port to use when uploading traces. Default: 9411", + "title": "zipkin-collector-port" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#zipkin-service-name", + "text": "Specifies the service name to use for any traces created. Default: nginx", + "title": "zipkin-service-name" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#jaeger-collector-host", + "text": "Specifies the host to use when uploading traces. It must be a valid URL.", + "title": "jaeger-collector-host" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#jaeger-collector-port", + "text": "Specifies the port to use when uploading traces. Default: 6831", + "title": "jaeger-collector-port" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#jaeger-service-name", + "text": "Specifies the service name to use for any traces created. Default: nginx", + "title": "jaeger-service-name" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#jaeger-sampler-type", + "text": "Specifies the sampler to be used when sampling traces. The available samplers are: const, probabilistic, ratelimiting, remote. Default const.", + "title": "jaeger-sampler-type" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#jaeger-sampler-param", + "text": "Specifies the argument to be passed to the sampler constructor. Must be a number.\nFor const this should be 0 to never sample and 1 to always sample. Default: 1", + "title": "jaeger-sampler-param" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#http-snippet", + "text": "Adds custom configuration to the http section of the nginx configuration.\nDefault: \"\"", + "title": "http-snippet" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#server-snippet", + "text": "Adds custom configuration to all the servers in the nginx configuration.\nDefault: \"\"", + "title": "server-snippet" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#location-snippet", + "text": "Adds custom configuration to all the locations in the nginx configuration.\nDefault: \"\"", + "title": "location-snippet" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#custom-http-errors", + "text": "Enables which HTTP codes should be passed for processing with the error_page directive Setting at least one code also enables proxy_intercept_errors which are required to process error_page. Example usage: custom-http-errors: 404,415", + "title": "custom-http-errors" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-body-size", + "text": "Sets the maximum allowed size of the client request body.\nSee NGINX client_max_body_size .", + "title": "proxy-body-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-connect-timeout", + "text": "Sets the timeout for establishing a connection with a proxied server . It should be noted that this timeout cannot usually exceed 75 seconds.", + "title": "proxy-connect-timeout" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-read-timeout", + "text": "Sets the timeout in seconds for reading a response from the proxied server . The timeout is set only between two successive read operations, not for the transmission of the whole response.", + "title": "proxy-read-timeout" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-send-timeout", + "text": "Sets the timeout in seconds for transmitting a request to the proxied server . The timeout is set only between two successive write operations, not for the transmission of the whole request.", + "title": "proxy-send-timeout" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-buffer-size", + "text": "Sets the size of the buffer used for reading the first part of the response received from the proxied server. This part usually contains a small response header.", + "title": "proxy-buffer-size" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-cookie-path", + "text": "Sets a text that should be changed in the path attribute of the \u201cSet-Cookie\u201d header fields of a proxied server response.", + "title": "proxy-cookie-path" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-cookie-domain", + "text": "Sets a text that should be changed in the domain attribute of the \u201cSet-Cookie\u201d header fields of a proxied server response.", + "title": "proxy-cookie-domain" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-next-upstream", + "text": "Specifies in which cases a request should be passed to the next server.", + "title": "proxy-next-upstream" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-next-upstream-tries", + "text": "Limit the number of possible tries a request should be passed to the next server.", + "title": "proxy-next-upstream-tries" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-redirect-from", + "text": "Sets the original text that should be changed in the \"Location\" and \"Refresh\" header fields of a proxied server response. Default: off. References: \n- http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect", + "title": "proxy-redirect-from" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-request-buffering", + "text": "Enables or disables buffering of a client request body .", + "title": "proxy-request-buffering" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#ssl-redirect", + "text": "Sets the global value of redirects (301) to HTTPS if the server has a TLS certificate (defined in an Ingress rule).\nDefault is \"true\".", + "title": "ssl-redirect" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#whitelist-source-range", + "text": "Sets the default whitelisted IPs for each server block. This can be overwritten by an annotation on an Ingress rule.\nSee ngx_http_access_module .", + "title": "whitelist-source-range" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#skip-access-log-urls", + "text": "Sets a list of URLs that should not appear in the NGINX access log. This is useful with urls like /health or health-check that make \"complex\" reading the logs. By default this list is empty", + "title": "skip-access-log-urls" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#limit-rate", + "text": "Limits the rate of response transmission to a client. The rate is specified in bytes per second. The zero value disables rate limiting. The limit is set per a request, and so if a client simultaneously opens two connections, the overall rate will be twice as much as the specified limit. References: \n- http://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate", + "title": "limit-rate" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#limit-rate-after", + "text": "Sets the initial amount after which the further transmission of a response to a client will be rate limited. References: \n- http://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate_after", + "title": "limit-rate-after" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#http-redirect-code", + "text": "Sets the HTTP status code to be used in redirects.\nSupported codes are 301 , 302 , 307 and 308 \nDefault code is 308. Why the default code is 308? RFC 7238 was created to define the 308 (Permanent Redirect) status code that is similar to 301 (Moved Permanently) but it keeps the payload in the redirect. This is important if the we send a redirect in methods like POST.", + "title": "http-redirect-code" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#proxy-buffering", + "text": "Enables or disables buffering of responses from the proxied server .", + "title": "proxy-buffering" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#limit-req-status-code", + "text": "Sets the status code to return in response to rejected requests .Default: 503", + "title": "limit-req-status-code" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#no-tls-redirect-locations", + "text": "A comma-separated list of locations on which http requests will never get redirected to their https counterpart.\nDefault: \"/.well-known/acme-challenge\"", + "title": "no-tls-redirect-locations" + }, + { + "location": "/user-guide/nginx-configuration/configmap/#no-auth-locations", + "text": "A comma-separated list of locations that should not get authenticated.\nDefault: \"/.well-known/acme-challenge\"", + "title": "no-auth-locations" + }, + { + "location": "/user-guide/nginx-configuration/custom-template/", + "text": "Custom NGINX template\n\u00b6\n\n\nThe NGINX template is located in the file \n/etc/nginx/template/nginx.tmpl\n.\n\n\nUsing a \nVolume\n it is possible to use a custom template. \nThis includes using a \nConfigmap\n as source of the template\n\n\n \nvolumeMounts\n:\n\n \n-\n \nmountPath\n:\n \n/etc/nginx/template\n\n \nname\n:\n \nnginx-template-volume\n\n \nreadOnly\n:\n \ntrue\n\n \n \nvolumes\n:\n\n \n-\n \nname\n:\n \nnginx-template-volume\n\n \nconfigMap\n:\n\n \nname\n:\n \nnginx-template\n\n \nitems\n:\n\n \n-\n \nkey\n:\n \nnginx.tmpl\n\n \npath\n:\n \nnginx.tmpl\n\n\n\n\n\n\nPlease note the template is tied to the Go code. Do not change names in the variable \n$cfg\n.\n\n\nFor more information about the template syntax please check the \nGo template package\n.\nIn addition to the built-in functions provided by the Go package the following functions are also available:\n\n\n\n\nempty: returns true if the specified parameter (string) is empty\n\n\ncontains: \nstrings.Contains\n\n\nhasPrefix: \nstrings.HasPrefix\n\n\nhasSuffix: \nstrings.HasSuffix\n\n\ntoUpper: \nstrings.ToUpper\n\n\ntoLower: \nstrings.ToLower\n\n\nbuildLocation: helps to build the NGINX Location section in each server\n\n\nbuildProxyPass: builds the reverse proxy configuration\n\n\nbuildRateLimit: helps to build a limit zone inside a location if contains a rate limit annotation\n\n\n\n\nTODO:\n\n\n\n\nbuildAuthLocation:\n\n\nbuildAuthResponseHeaders:\n\n\nbuildResolvers:\n\n\nbuildLogFormatUpstream:\n\n\nbuildDenyVariable:\n\n\nbuildUpstreamName:\n\n\nbuildForwardedFor:\n\n\nbuildAuthSignURL:\n\n\nbuildNextUpstream:\n\n\nfilterRateLimits:\n\n\nformatIP:\n\n\ngetenv:\n\n\ngetIngressInformation:\n\n\nserverConfig:\n\n\nisLocationAllowed:\n\n\nisValidClientBodyBufferSize:", + "title": "Custom NGINX template" + }, + { + "location": "/user-guide/nginx-configuration/custom-template/#custom-nginx-template", + "text": "The NGINX template is located in the file /etc/nginx/template/nginx.tmpl . Using a Volume it is possible to use a custom template. \nThis includes using a Configmap as source of the template volumeMounts : \n - mountPath : /etc/nginx/template \n name : nginx-template-volume \n readOnly : true \n volumes : \n - name : nginx-template-volume \n configMap : \n name : nginx-template \n items : \n - key : nginx.tmpl \n path : nginx.tmpl Please note the template is tied to the Go code. Do not change names in the variable $cfg . For more information about the template syntax please check the Go template package .\nIn addition to the built-in functions provided by the Go package the following functions are also available: empty: returns true if the specified parameter (string) is empty contains: strings.Contains hasPrefix: strings.HasPrefix hasSuffix: strings.HasSuffix toUpper: strings.ToUpper toLower: strings.ToLower buildLocation: helps to build the NGINX Location section in each server buildProxyPass: builds the reverse proxy configuration buildRateLimit: helps to build a limit zone inside a location if contains a rate limit annotation TODO: buildAuthLocation: buildAuthResponseHeaders: buildResolvers: buildLogFormatUpstream: buildDenyVariable: buildUpstreamName: buildForwardedFor: buildAuthSignURL: buildNextUpstream: filterRateLimits: formatIP: getenv: getIngressInformation: serverConfig: isLocationAllowed: isValidClientBodyBufferSize:", + "title": "Custom NGINX template" + }, + { + "location": "/user-guide/nginx-configuration/log-format/", + "text": "Log format\n\u00b6\n\n\nThe default configuration uses a custom logging format to add additional information about upstreams, response time and status\n\n\n log_format upstreaminfo '\n{{\n \nif\n \n$\ncfg.useProxyProtocol\n \n}}\n$proxy_protocol_addr\n{{\n \nelse\n \n}}\n$remote_addr\n{{\n \nend\n \n}}\n - '\n\n\n '[$the_real_ip] - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" '\n\n\n '$request_length $request_time [$proxy_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status';\n\n\n\n\n\n\nSources:\n\n\n\n\nupstream variables\n\n\nembedded variables\n\n\n\n\nDescription:\n\n\n\n\n$proxy_protocol_addr\n: if PROXY protocol is enabled\n\n\n$remote_addr\n: if PROXY protocol is disabled (default)\n\n\n$the_real_ip\n: the source IP address of the client\n\n\n$remote_user\n: user name supplied with the Basic authentication\n\n\n$time_local\n: local time in the Common Log Format\n\n\n$request\n: full original request line\n\n\n$status\n: response status\n\n\n$body_bytes_sent\n: number of bytes sent to a client, not counting the response header\n\n\n$http_referer\n: value of the Referer header\n\n\n$http_user_agent\n: value of User-Agent header\n\n\n$request_length\n: request length (including request line, header, and request body)\n\n\n$request_time\n: time elapsed since the first bytes were read from the client\n\n\n$proxy_upstream_name\n: name of the upstream. The format is \nupstream---\n\n\n$upstream_addr\n: keeps the IP address and port, or the path to the UNIX-domain socket of the upstream server. If several servers were contacted during request processing, their addresses are separated by commas\n\n\n$upstream_response_length\n: keeps the length of the response obtained from the upstream server\n\n\n$upstream_response_time\n: keeps time spent on receiving the response from the upstream server; the time is kept in seconds with millisecond resolution\n\n\n$upstream_status\n: keeps status code of the response obtained from the upstream server", + "title": "Log format" + }, + { + "location": "/user-guide/nginx-configuration/log-format/#log-format", + "text": "The default configuration uses a custom logging format to add additional information about upstreams, response time and status log_format upstreaminfo ' {{ if $ cfg.useProxyProtocol }} $proxy_protocol_addr {{ else }} $remote_addr {{ end }} - ' '[$the_real_ip] - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" ' '$request_length $request_time [$proxy_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status'; Sources: upstream variables embedded variables Description: $proxy_protocol_addr : if PROXY protocol is enabled $remote_addr : if PROXY protocol is disabled (default) $the_real_ip : the source IP address of the client $remote_user : user name supplied with the Basic authentication $time_local : local time in the Common Log Format $request : full original request line $status : response status $body_bytes_sent : number of bytes sent to a client, not counting the response header $http_referer : value of the Referer header $http_user_agent : value of User-Agent header $request_length : request length (including request line, header, and request body) $request_time : time elapsed since the first bytes were read from the client $proxy_upstream_name : name of the upstream. The format is upstream--- $upstream_addr : keeps the IP address and port, or the path to the UNIX-domain socket of the upstream server. If several servers were contacted during request processing, their addresses are separated by commas $upstream_response_length : keeps the length of the response obtained from the upstream server $upstream_response_time : keeps time spent on receiving the response from the upstream server; the time is kept in seconds with millisecond resolution $upstream_status : keeps status code of the response obtained from the upstream server", + "title": "Log format" + }, + { + "location": "/user-guide/cli-arguments/", + "text": "Command line arguments\n\u00b6\n\n\nThe following command line arguments are accepted by the main controller executable.\n\n\nThey are set in the container spec of the \nnginx-ingress-controller\n Deployment object (see \ndeploy/with-rbac.yaml\n or \ndeploy/without-rbac.yaml\n).\n\n\n\n\n\n\n\n\nArgument\n\n\nDescription\n\n\n\n\n\n\n\n\n\n\n--alsologtostderr\n\n\nlog to standard error as well as files\n\n\n\n\n\n\n--annotations-prefix string\n\n\nPrefix of the ingress annotations. (default \"nginx.ingress.kubernetes.io\")\n\n\n\n\n\n\n--apiserver-host string\n\n\nThe address of the Kubernetes Apiserver to connect to in the format of protocol://address:port, e.g., http://localhost:8080. If not specified, the assumption is that the binary runs inside a Kubernetes cluster and local discovery is attempted.\n\n\n\n\n\n\n--configmap string\n\n\nName of the ConfigMap that contains the custom configuration to use\n\n\n\n\n\n\n--default-backend-service string\n\n\nService used to serve a 404 page for the default backend. Takes the form namespace/name. The controller uses the first node port of this Service for the default backend.\n\n\n\n\n\n\n--default-server-port int\n\n\nDefault port to use for exposing the default server (catch all) (default 8181)\n\n\n\n\n\n\n--default-ssl-certificate string\n\n\nName of the secret that contains a SSL certificate to be used as default for a HTTPS catch-all server. Takes the form \n/\n.\n\n\n\n\n\n\n--election-id string\n\n\nElection id to use for status update. (default \"ingress-controller-leader\")\n\n\n\n\n\n\n--enable-dynamic-configuration\n\n\nWhen enabled controller will try to avoid Nginx reloads as much as possible by using Lua. Disabled by default.\n\n\n\n\n\n\n--enable-ssl-chain-completion\n\n\nDefines if the nginx ingress controller should check the secrets for missing intermediate CA certificates. If the certificate contain issues chain issues is not possible to enable OCSP. Default is true. (default true)\n\n\n\n\n\n\n--enable-ssl-passthrough\n\n\nEnable SSL passthrough feature. Default is disabled\n\n\n\n\n\n\n--force-namespace-isolation\n\n\nForce namespace isolation. This flag is required to avoid the reference of secrets or configmaps located in a different namespace than the specified in the flag --watch-namespace.\n\n\n\n\n\n\n--health-check-path string\n\n\nDefines the URL to be used as health check inside in the default server in NGINX. (default \"/healthz\")\n\n\n\n\n\n\n--healthz-port int\n\n\nport for healthz endpoint. (default 10254)\n\n\n\n\n\n\n--http-port int\n\n\nIndicates the port to use for HTTP traffic (default 80)\n\n\n\n\n\n\n--https-port int\n\n\nIndicates the port to use for HTTPS traffic (default 443)\n\n\n\n\n\n\n--ingress-class string\n\n\nName of the ingress class to route through this controller.\n\n\n\n\n\n\n--kubeconfig string\n\n\nPath to kubeconfig file with authorization and master location information.\n\n\n\n\n\n\n--log_backtrace_at traceLocation\n\n\nwhen logging hits line file:N, emit a stack trace (default :0)\n\n\n\n\n\n\n--log_dir string\n\n\nIf non-empty, write log files in this directory\n\n\n\n\n\n\n--logtostderr\n\n\nlog to standard error instead of files (default true)\n\n\n\n\n\n\n--profiling\n\n\nEnable profiling via web interface host:port/debug/pprof/ (default true)\n\n\n\n\n\n\n--publish-service string\n\n\nService fronting the ingress controllers. Takes the form namespace/name. The controller will set the endpoint records on the ingress objects to reflect those on the service.\n\n\n\n\n\n\n--publish-status-address string\n\n\nUser customized address to be set in the status of ingress resources. The controller will set the endpoint records on the ingress using this address.\n\n\n\n\n\n\n--report-node-internal-ip-address\n\n\nDefines if the nodes IP address to be returned in the ingress status should be the internal instead of the external IP address\n\n\n\n\n\n\n--sort-backends\n\n\nDefines if backends and its endpoints should be sorted\n\n\n\n\n\n\n--ssl-passtrough-proxy-port int\n\n\nDefault port to use internally for SSL when SSL Passthgough is enabled (default 442)\n\n\n\n\n\n\n--status-port int\n\n\nIndicates the TCP port to use for exposing the nginx status page (default 18080)\n\n\n\n\n\n\n--stderrthreshold severity\n\n\nlogs at or above this threshold go to stderr (default 2)\n\n\n\n\n\n\n--sync-period duration\n\n\nRelist and confirm cloud resources this often. Default is 10 minutes (default 10m0s)\n\n\n\n\n\n\n--sync-rate-limit float32\n\n\nDefine the sync frequency upper limit (default 0.3)\n\n\n\n\n\n\n--tcp-services-configmap string\n\n\nName of the ConfigMap that contains the definition of the TCP services to expose. The key in the map indicates the external port to be used. The value is the name of the service with the format namespace/serviceName and the port of the service could be a number of the name of the port. The ports 80 and 443 are not allowed as external ports. This ports are reserved for the backend\n\n\n\n\n\n\n--udp-services-configmap string\n\n\nName of the ConfigMap that contains the definition of the UDP services to expose. The key in the map indicates the external port to be used. The value is the name of the service with the format namespace/serviceName and the port of the service could be a number of the name of the port.\n\n\n\n\n\n\n--update-status\n\n\nIndicates if the ingress controller should update the Ingress status IP/hostname. Default is true (default true)\n\n\n\n\n\n\n--update-status-on-shutdown\n\n\nIndicates if the ingress controller should update the Ingress status IP/hostname when the controller is being stopped. Default is true (default true)\n\n\n\n\n\n\n-v\n, \n--v Level\n\n\nlog level for V logs\n\n\n\n\n\n\n--version\n\n\nShows release information about the NGINX Ingress controller\n\n\n\n\n\n\n--vmodule moduleSpec\n\n\ncomma-separated list of pattern=N settings for file-filtered logging\n\n\n\n\n\n\n--watch-namespace string\n\n\nNamespace to watch for Ingress. Default is to watch all namespaces", + "title": "Command line arguments" + }, + { + "location": "/user-guide/cli-arguments/#command-line-arguments", + "text": "The following command line arguments are accepted by the main controller executable. They are set in the container spec of the nginx-ingress-controller Deployment object (see deploy/with-rbac.yaml or deploy/without-rbac.yaml ). Argument Description --alsologtostderr log to standard error as well as files --annotations-prefix string Prefix of the ingress annotations. (default \"nginx.ingress.kubernetes.io\") --apiserver-host string The address of the Kubernetes Apiserver to connect to in the format of protocol://address:port, e.g., http://localhost:8080. If not specified, the assumption is that the binary runs inside a Kubernetes cluster and local discovery is attempted. --configmap string Name of the ConfigMap that contains the custom configuration to use --default-backend-service string Service used to serve a 404 page for the default backend. Takes the form namespace/name. The controller uses the first node port of this Service for the default backend. --default-server-port int Default port to use for exposing the default server (catch all) (default 8181) --default-ssl-certificate string Name of the secret that contains a SSL certificate to be used as default for a HTTPS catch-all server. Takes the form / . --election-id string Election id to use for status update. (default \"ingress-controller-leader\") --enable-dynamic-configuration When enabled controller will try to avoid Nginx reloads as much as possible by using Lua. Disabled by default. --enable-ssl-chain-completion Defines if the nginx ingress controller should check the secrets for missing intermediate CA certificates. If the certificate contain issues chain issues is not possible to enable OCSP. Default is true. (default true) --enable-ssl-passthrough Enable SSL passthrough feature. Default is disabled --force-namespace-isolation Force namespace isolation. This flag is required to avoid the reference of secrets or configmaps located in a different namespace than the specified in the flag --watch-namespace. --health-check-path string Defines the URL to be used as health check inside in the default server in NGINX. (default \"/healthz\") --healthz-port int port for healthz endpoint. (default 10254) --http-port int Indicates the port to use for HTTP traffic (default 80) --https-port int Indicates the port to use for HTTPS traffic (default 443) --ingress-class string Name of the ingress class to route through this controller. --kubeconfig string Path to kubeconfig file with authorization and master location information. --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory --logtostderr log to standard error instead of files (default true) --profiling Enable profiling via web interface host:port/debug/pprof/ (default true) --publish-service string Service fronting the ingress controllers. Takes the form namespace/name. The controller will set the endpoint records on the ingress objects to reflect those on the service. --publish-status-address string User customized address to be set in the status of ingress resources. The controller will set the endpoint records on the ingress using this address. --report-node-internal-ip-address Defines if the nodes IP address to be returned in the ingress status should be the internal instead of the external IP address --sort-backends Defines if backends and its endpoints should be sorted --ssl-passtrough-proxy-port int Default port to use internally for SSL when SSL Passthgough is enabled (default 442) --status-port int Indicates the TCP port to use for exposing the nginx status page (default 18080) --stderrthreshold severity logs at or above this threshold go to stderr (default 2) --sync-period duration Relist and confirm cloud resources this often. Default is 10 minutes (default 10m0s) --sync-rate-limit float32 Define the sync frequency upper limit (default 0.3) --tcp-services-configmap string Name of the ConfigMap that contains the definition of the TCP services to expose. The key in the map indicates the external port to be used. The value is the name of the service with the format namespace/serviceName and the port of the service could be a number of the name of the port. The ports 80 and 443 are not allowed as external ports. This ports are reserved for the backend --udp-services-configmap string Name of the ConfigMap that contains the definition of the UDP services to expose. The key in the map indicates the external port to be used. The value is the name of the service with the format namespace/serviceName and the port of the service could be a number of the name of the port. --update-status Indicates if the ingress controller should update the Ingress status IP/hostname. Default is true (default true) --update-status-on-shutdown Indicates if the ingress controller should update the Ingress status IP/hostname when the controller is being stopped. Default is true (default true) -v , --v Level log level for V logs --version Shows release information about the NGINX Ingress controller --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging --watch-namespace string Namespace to watch for Ingress. Default is to watch all namespaces", + "title": "Command line arguments" + }, + { + "location": "/user-guide/custom-errors/", + "text": "Custom errors\n\u00b6\n\n\nIn case of an error in a request the body of the response is obtained from the \ndefault backend\n.\nEach request to the default backend includes two headers:\n\n\n\n\nX-Code\n indicates the HTTP code to be returned to the client.\n\n\nX-Format\n the value of the \nAccept\n header.\n\n\n\n\nImportant:\n the custom backend must return the correct HTTP status code to be returned. NGINX do not changes the response from the custom default backend.\n\n\nUsing this two headers is possible to use a custom backend service like \nthis one\n that inspect each request and returns a custom error page with the format expected by the client. Please check the example \ncustom-errors\n\n\nNGINX sends additional headers that can be used to build custom response:\n\n\n\n\nX-Original-URI\n\n\nX-Namespace\n\n\nX-Ingress-Name\n\n\nX-Service-Name", + "title": "Custom errors" + }, + { + "location": "/user-guide/custom-errors/#custom-errors", + "text": "In case of an error in a request the body of the response is obtained from the default backend .\nEach request to the default backend includes two headers: X-Code indicates the HTTP code to be returned to the client. X-Format the value of the Accept header. Important: the custom backend must return the correct HTTP status code to be returned. NGINX do not changes the response from the custom default backend. Using this two headers is possible to use a custom backend service like this one that inspect each request and returns a custom error page with the format expected by the client. Please check the example custom-errors NGINX sends additional headers that can be used to build custom response: X-Original-URI X-Namespace X-Ingress-Name X-Service-Name", + "title": "Custom errors" + }, + { + "location": "/user-guide/exposing-tcp-udp-services/", + "text": "Exposing TCP and UDP services\n\u00b6\n\n\nIngress does not support TCP or UDP services. For this reason this Ingress controller uses the flags \n--tcp-services-configmap\n and \n--udp-services-configmap\n to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format:\n\n::[PROXY]:[PROXY]\n\n\nIt is also possible to use a number or the name of the port. The two last fields are optional.\nAdding \nPROXY\n in either or both of the two last fields we can use Proxy Protocol decoding (listen) and/or encoding (proxy_pass) in a TCP service (https://www.nginx.com/resources/admin-guide/proxy-protocol/).\n\n\nThe next example shows how to expose the service \nexample-go\n running in the namespace \ndefault\n in the port \n8080\n using the port \n9000\n\n\napiVersion\n:\n \nv1\n\n\nkind\n:\n \nConfigMap\n\n\nmetadata\n:\n\n \nname\n:\n \ntcp-configmap-example\n\n\ndata\n:\n\n \n9000\n:\n \n\"default/example-go:8080\"\n\n\n\n\n\n\nSince 1.9.13 NGINX provides \nUDP Load Balancing\n.\nThe next example shows how to expose the service \nkube-dns\n running in the namespace \nkube-system\n in the port \n53\n using the port \n53\n\n\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n name: udp-configmap-example\ndata:\n 53: \"kube-system/kube-dns:53\"", + "title": "Exposing TCP and UDP services" + }, + { + "location": "/user-guide/exposing-tcp-udp-services/#exposing-tcp-and-udp-services", + "text": "Ingress does not support TCP or UDP services. For this reason this Ingress controller uses the flags --tcp-services-configmap and --udp-services-configmap to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format: ::[PROXY]:[PROXY] It is also possible to use a number or the name of the port. The two last fields are optional.\nAdding PROXY in either or both of the two last fields we can use Proxy Protocol decoding (listen) and/or encoding (proxy_pass) in a TCP service (https://www.nginx.com/resources/admin-guide/proxy-protocol/). The next example shows how to expose the service example-go running in the namespace default in the port 8080 using the port 9000 apiVersion : v1 kind : ConfigMap metadata : \n name : tcp-configmap-example data : \n 9000 : \"default/example-go:8080\" Since 1.9.13 NGINX provides UDP Load Balancing .\nThe next example shows how to expose the service kube-dns running in the namespace kube-system in the port 53 using the port 53 ```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n name: udp-configmap-example\ndata:\n 53: \"kube-system/kube-dns:53\"", + "title": "Exposing TCP and UDP services" + }, + { + "location": "/user-guide/external-articles/", + "text": "External Articles\n\u00b6\n\n\n\n\nPain(less) NGINX Ingress\n\n\nAccessing Kubernetes Pods from Outside of the Cluster\n\n\nKubernetes - Redirect HTTP to HTTPS with ELB and the nginx ingress controller\n\n\nConfigure Nginx Ingress Controller for TLS termination on Kubernetes on Azure", + "title": "External Articles" + }, + { + "location": "/user-guide/external-articles/#external-articles", + "text": "Pain(less) NGINX Ingress Accessing Kubernetes Pods from Outside of the Cluster Kubernetes - Redirect HTTP to HTTPS with ELB and the nginx ingress controller Configure Nginx Ingress Controller for TLS termination on Kubernetes on Azure", + "title": "External Articles" + }, + { + "location": "/user-guide/miscellaneous/", + "text": "Miscellaneous\n\u00b6\n\n\nConventions\n\u00b6\n\n\nAnytime we reference a tls secret, we mean (x509, pem encoded, RSA 2048, etc). You can generate such a certificate with:\n\nopenssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout \n${\nKEY_FILE\n}\n -out \n${\nCERT_FILE\n}\n -subj \"/CN=\n${\nHOST\n}\n/O=\n${\nHOST\n}\n\"\n\nand create the secret via \nkubectl create secret tls \n${\nCERT_NAME\n}\n --key \n${\nKEY_FILE\n}\n --cert \n${\nCERT_FILE\n}\n\n\nRequirements\n\u00b6\n\n\nThe default backend is a service which handles all url paths and hosts the nginx controller doesn't understand (i.e., all the requests that are not mapped with an Ingress).\nBasically a default backend exposes two URLs:\n\n\n\n\n/healthz\n that returns 200\n\n\n/\n that returns 404\n\n\n\n\nThe sub-directory \n/images/404-server\n provides a service which satisfies the requirements for a default backend. The sub-directory \n/images/custom-error-pages\n provides an additional service for the purpose of customizing the error pages served via the default backend.\n\n\nSource IP address\n\u00b6\n\n\nBy default NGINX uses the content of the header \nX-Forwarded-For\n as the source of truth to get information about the client IP address. This works without issues in L7 \nif we configure the setting \nproxy-real-ip-cidr\n with the correct information of the IP/network address of trusted external load balancer.\n\n\nIf the ingress controller is running in AWS we need to use the VPC IPv4 CIDR.\n\n\nAnother option is to enable proxy protocol using \nuse-proxy-protocol: \"true\"\n.\n\n\nIn this mode NGINX does not use the content of the header to get the source IP address of the connection.\n\n\nProxy Protocol\n\u00b6\n\n\nIf you are using a L4 proxy to forward the traffic to the NGINX pods and terminate HTTP/HTTPS there, you will lose the remote endpoint's IP address. To prevent this you could use the \nProxy Protocol\n for forwarding traffic, this will send the connection details before forwarding the actual TCP connection itself.\n\n\nAmongst others \nELBs in AWS\n and \nHAProxy\n support Proxy Protocol.\n\n\nWebsockets\n\u00b6\n\n\nSupport for websockets is provided by NGINX out of the box. No special configuration required.\n\n\nThe only requirement to avoid the close of connections is the increase of the values of \nproxy-read-timeout\n and \nproxy-send-timeout\n.\n\n\nThe default value of this settings is \n60 seconds\n.\n\n\nA more adequate value to support websockets is a value higher than one hour (\n3600\n).\n\n\nImportant:\n If the NGINX ingress controller is exposed with a service \ntype=LoadBalancer\n make sure the protocol between the loadbalancer and NGINX is TCP.\n\n\nOptimizing TLS Time To First Byte (TTTFB)\n\u00b6\n\n\nNGINX provides the configuration option \nssl_buffer_size\n to allow the optimization of the TLS record size.\n\n\nThis improves the \nTLS Time To First Byte\n (TTTFB).\nThe default value in the Ingress controller is \n4k\n (NGINX default is \n16k\n).\n\n\nRetries in non-idempotent methods\n\u00b6\n\n\nSince 1.9.13 NGINX will not retry non-idempotent requests (POST, LOCK, PATCH) in case of an error.\nThe previous behavior can be restored using \nretry-non-idempotent=true\n in the configuration ConfigMap.\n\n\nLimitations\n\u00b6\n\n\n\n\nIngress rules for TLS require the definition of the field \nhost\n\n\n\n\nWhy endpoints and not services\n\u00b6\n\n\nThe NGINX ingress controller does not use \nServices\n to route traffic to the pods. Instead it uses the Endpoints API in order to bypass \nkube-proxy\n to allow NGINX features like session affinity and custom load balancing algorithms. It also removes some overhead, such as conntrack entries for iptables DNAT.", + "title": "Miscellaneous" + }, + { + "location": "/user-guide/miscellaneous/#miscellaneous", + "text": "", + "title": "Miscellaneous" + }, + { + "location": "/user-guide/miscellaneous/#conventions", + "text": "Anytime we reference a tls secret, we mean (x509, pem encoded, RSA 2048, etc). You can generate such a certificate with: openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ${ KEY_FILE } -out ${ CERT_FILE } -subj \"/CN= ${ HOST } /O= ${ HOST } \" \nand create the secret via kubectl create secret tls ${ CERT_NAME } --key ${ KEY_FILE } --cert ${ CERT_FILE }", + "title": "Conventions" + }, + { + "location": "/user-guide/miscellaneous/#requirements", + "text": "The default backend is a service which handles all url paths and hosts the nginx controller doesn't understand (i.e., all the requests that are not mapped with an Ingress).\nBasically a default backend exposes two URLs: /healthz that returns 200 / that returns 404 The sub-directory /images/404-server provides a service which satisfies the requirements for a default backend. The sub-directory /images/custom-error-pages provides an additional service for the purpose of customizing the error pages served via the default backend.", + "title": "Requirements" + }, + { + "location": "/user-guide/miscellaneous/#source-ip-address", + "text": "By default NGINX uses the content of the header X-Forwarded-For as the source of truth to get information about the client IP address. This works without issues in L7 if we configure the setting proxy-real-ip-cidr with the correct information of the IP/network address of trusted external load balancer. If the ingress controller is running in AWS we need to use the VPC IPv4 CIDR. Another option is to enable proxy protocol using use-proxy-protocol: \"true\" . In this mode NGINX does not use the content of the header to get the source IP address of the connection.", + "title": "Source IP address" + }, + { + "location": "/user-guide/miscellaneous/#proxy-protocol", + "text": "If you are using a L4 proxy to forward the traffic to the NGINX pods and terminate HTTP/HTTPS there, you will lose the remote endpoint's IP address. To prevent this you could use the Proxy Protocol for forwarding traffic, this will send the connection details before forwarding the actual TCP connection itself. Amongst others ELBs in AWS and HAProxy support Proxy Protocol.", + "title": "Proxy Protocol" + }, + { + "location": "/user-guide/miscellaneous/#websockets", + "text": "Support for websockets is provided by NGINX out of the box. No special configuration required. The only requirement to avoid the close of connections is the increase of the values of proxy-read-timeout and proxy-send-timeout . The default value of this settings is 60 seconds . A more adequate value to support websockets is a value higher than one hour ( 3600 ). Important: If the NGINX ingress controller is exposed with a service type=LoadBalancer make sure the protocol between the loadbalancer and NGINX is TCP.", + "title": "Websockets" + }, + { + "location": "/user-guide/miscellaneous/#optimizing-tls-time-to-first-byte-tttfb", + "text": "NGINX provides the configuration option ssl_buffer_size to allow the optimization of the TLS record size. This improves the TLS Time To First Byte (TTTFB).\nThe default value in the Ingress controller is 4k (NGINX default is 16k ).", + "title": "Optimizing TLS Time To First Byte (TTTFB)" + }, + { + "location": "/user-guide/miscellaneous/#retries-in-non-idempotent-methods", + "text": "Since 1.9.13 NGINX will not retry non-idempotent requests (POST, LOCK, PATCH) in case of an error.\nThe previous behavior can be restored using retry-non-idempotent=true in the configuration ConfigMap.", + "title": "Retries in non-idempotent methods" + }, + { + "location": "/user-guide/miscellaneous/#limitations", + "text": "Ingress rules for TLS require the definition of the field host", + "title": "Limitations" + }, + { + "location": "/user-guide/miscellaneous/#why-endpoints-and-not-services", + "text": "The NGINX ingress controller does not use Services to route traffic to the pods. Instead it uses the Endpoints API in order to bypass kube-proxy to allow NGINX features like session affinity and custom load balancing algorithms. It also removes some overhead, such as conntrack entries for iptables DNAT.", + "title": "Why endpoints and not services" + }, + { + "location": "/user-guide/multiple-ingress/", + "text": "Multiple ingress controllers\n\u00b6\n\n\nRunning multiple ingress controllers\n\u00b6\n\n\nIf you're running multiple ingress controllers, or running on a cloud provider that natively handles ingress, you need to specify the annotation \nkubernetes.io/ingress.class: \"nginx\"\n in all ingresses that you would like this controller to claim. This mechanism also provides users the ability to run \nmultiple\n NGINX ingress controllers (e.g. one which serves public traffic, one which serves \"internal\" traffic). When utilizing this functionality the option \n--ingress-class\n should be changed to a value unique for the cluster within the definition of the replication controller. Here is a partial example:\n\n\nspec\n:\n\n \ntemplate\n:\n\n \nspec\n:\n\n \ncontainers\n:\n\n \n-\n \nname\n:\n \nnginx\n-\ningress\n-\ninternal\n-\ncontroller\n\n \nargs\n:\n\n \n-\n \n/\nnginx\n-\ningress\n-\ncontroller\n\n \n-\n \n'--default-backend-service=ingress/nginx-ingress-default-backend'\n\n \n-\n \n'--election-id=ingress-controller-leader-internal'\n\n \n-\n \n'--ingress-class=nginx-internal'\n\n \n-\n \n'--configmap=ingress/nginx-ingress-internal-controller'\n\n\n\n\n\n\nAnnotation ingress.class\n\u00b6\n\n\nIf you have multiple Ingress controllers in a single cluster, you can pick one by specifying the \ningress.class\n \nannotation, eg creating an Ingress with an annotation like\n\n\nmetadata\n:\n\n \nname\n:\n \nfoo\n\n \nannotations\n:\n\n \nkubernetes.io/ingress.class\n:\n \n\"gce\"\n\n\n\n\n\n\nwill target the GCE controller, forcing the nginx controller to ignore it, while an annotation like\n\n\nmetadata\n:\n\n \nname\n:\n \nfoo\n\n \nannotations\n:\n\n \nkubernetes.io/ingress.class\n:\n \n\"nginx\"\n\n\n\n\n\n\nwill target the nginx controller, forcing the GCE controller to ignore it.\n\n\nNote\n: Deploying multiple ingress controller and not specifying the annotation will result in both controllers fighting to satisfy the Ingress.\n\n\nDisabling NGINX ingress controller\n\u00b6\n\n\nSetting the annotation \nkubernetes.io/ingress.class\n to any other value which does not match a valid ingress class will force the NGINX Ingress controller to ignore your Ingress. If you are only running a single NGINX ingress controller, this can be achieved by setting this to any value except \"nginx\" or an empty string.\n\n\nDo this if you wish to use one of the other Ingress controllers at the same time as the NGINX controller.", + "title": "Multiple ingress controllers" + }, + { + "location": "/user-guide/multiple-ingress/#multiple-ingress-controllers", + "text": "", + "title": "Multiple ingress controllers" + }, + { + "location": "/user-guide/multiple-ingress/#running-multiple-ingress-controllers", + "text": "If you're running multiple ingress controllers, or running on a cloud provider that natively handles ingress, you need to specify the annotation kubernetes.io/ingress.class: \"nginx\" in all ingresses that you would like this controller to claim. This mechanism also provides users the ability to run multiple NGINX ingress controllers (e.g. one which serves public traffic, one which serves \"internal\" traffic). When utilizing this functionality the option --ingress-class should be changed to a value unique for the cluster within the definition of the replication controller. Here is a partial example: spec : \n template : \n spec : \n containers : \n - name : nginx - ingress - internal - controller \n args : \n - / nginx - ingress - controller \n - '--default-backend-service=ingress/nginx-ingress-default-backend' \n - '--election-id=ingress-controller-leader-internal' \n - '--ingress-class=nginx-internal' \n - '--configmap=ingress/nginx-ingress-internal-controller'", + "title": "Running multiple ingress controllers" + }, + { + "location": "/user-guide/multiple-ingress/#annotation-ingressclass", + "text": "If you have multiple Ingress controllers in a single cluster, you can pick one by specifying the ingress.class \nannotation, eg creating an Ingress with an annotation like metadata : \n name : foo \n annotations : \n kubernetes.io/ingress.class : \"gce\" will target the GCE controller, forcing the nginx controller to ignore it, while an annotation like metadata : \n name : foo \n annotations : \n kubernetes.io/ingress.class : \"nginx\" will target the nginx controller, forcing the GCE controller to ignore it. Note : Deploying multiple ingress controller and not specifying the annotation will result in both controllers fighting to satisfy the Ingress.", + "title": "Annotation ingress.class" + }, + { + "location": "/user-guide/multiple-ingress/#disabling-nginx-ingress-controller", + "text": "Setting the annotation kubernetes.io/ingress.class to any other value which does not match a valid ingress class will force the NGINX Ingress controller to ignore your Ingress. If you are only running a single NGINX ingress controller, this can be achieved by setting this to any value except \"nginx\" or an empty string. Do this if you wish to use one of the other Ingress controllers at the same time as the NGINX controller.", + "title": "Disabling NGINX ingress controller" + }, + { + "location": "/user-guide/nginx-status-page/", + "text": "NGINX status page\n\u00b6\n\n\nThe \nngx_http_stub_status_module\n module provides access to basic status information.\nThis is the default module active in the url \n/nginx_status\n in the status port (default is 18080).\n\n\nThis controller provides an alternative to this module using the \nnginx-module-vts\n module.\nTo use this module just set in the configuration configmap \nenable-vts-status: \"true\"\n.\n\n\n\n\nTo extract the information in JSON format the module provides a custom URL: \n/nginx_status/format/json", + "title": "NGINX status page" + }, + { + "location": "/user-guide/nginx-status-page/#nginx-status-page", + "text": "The ngx_http_stub_status_module module provides access to basic status information.\nThis is the default module active in the url /nginx_status in the status port (default is 18080). This controller provides an alternative to this module using the nginx-module-vts module.\nTo use this module just set in the configuration configmap enable-vts-status: \"true\" . To extract the information in JSON format the module provides a custom URL: /nginx_status/format/json", + "title": "NGINX status page" + }, + { + "location": "/user-guide/tls/", + "text": "TLS\n\u00b6\n\n\n\n\nDefault SSL Certificate\n\n\nSSL Passthrough\n\n\nHTTPS enforcement\n\n\nHSTS\n\n\nServer-side HTTPS enforcement through redirect\n \n\n\nKube-Lego\n\n\nDefault TLS Version and Ciphers\n\n\nLegacy TLS\n\n\n\n\nDefault SSL Certificate\n\u00b6\n\n\nNGINX provides the option to configure a server as a catch-all with \nserver_name\n for requests that do not match any of the configured server names. This configuration works without issues for HTTP traffic.\nIn case of HTTPS, NGINX requires a certificate.\nFor this reason the Ingress controller provides the flag \n--default-ssl-certificate\n. The secret behind this flag contains the default certificate to be used in the mentioned scenario. If this flag is not provided NGINX will use a self signed certificate.\n\n\nRunning without the flag \n--default-ssl-certificate\n:\n\n\n$\n curl -v https://10.2.78.7:443 -k\n\n* Rebuilt URL to: https://10.2.78.7:443/\n\n\n* Trying 10.2.78.4...\n\n\n* Connected to 10.2.78.7 (10.2.78.7) port 443 (#0)\n\n\n* ALPN, offering http/1.1\n\n\n* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH\n\n\n* successfully set certificate verify locations:\n\n\n* CAfile: /etc/ssl/certs/ca-certificates.crt\n\n\n CApath: /etc/ssl/certs\n\n\n* TLSv1.2 (OUT), TLS header, Certificate Status (22):\n\n\n* TLSv1.2 (OUT), TLS handshake, Client hello (1):\n\n\n* TLSv1.2 (IN), TLS handshake, Server hello (2):\n\n\n* TLSv1.2 (IN), TLS handshake, Certificate (11):\n\n\n* TLSv1.2 (IN), TLS handshake, Server key exchange (12):\n\n\n* TLSv1.2 (IN), TLS handshake, Server finished (14):\n\n\n* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):\n\n\n* TLSv1.2 (OUT), TLS change cipher, Client hello (1):\n\n\n* TLSv1.2 (OUT), TLS handshake, Finished (20):\n\n\n* TLSv1.2 (IN), TLS change cipher, Client hello (1):\n\n\n* TLSv1.2 (IN), TLS handshake, Finished (20):\n\n\n* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256\n\n\n* ALPN, server accepted to use http/1.1\n\n\n* Server certificate:\n\n\n* subject: CN=foo.bar.com\n\n\n* start date: Apr 13 00:50:56 2016 GMT\n\n\n* expire date: Apr 13 00:50:56 2017 GMT\n\n\n* issuer: CN=foo.bar.com\n\n\n* SSL certificate verify result: self signed certificate (18), continuing anyway.\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: \n10\n.2.78.7\n\n>\n User-Agent: curl/7.47.1\n\n>\n Accept: */*\n\n>\n\n\n< HTTP/1.1 404 Not Found\n\n\n< Server: nginx/1.11.1\n\n\n< Date: Thu, 21 Jul 2016 15:38:46 GMT\n\n\n< Content-Type: text/html\n\n\n< Transfer-Encoding: chunked\n\n\n< Connection: keep-alive\n\n\n< Strict-Transport-Security: max-age=15724800; includeSubDomains; preload\n\n\n<\n\n\nThe page you're looking for could not be found.\n\n\n\n* Connection #0 to host 10.2.78.7 left intact\n\n\n\n\n\n\nSpecifying \n--default-ssl-certificate=default/foo-tls\n:\n\n\ncore@localhost ~ $\n curl -v https://10.2.78.7:443 -k\n\n* Rebuilt URL to: https://10.2.78.7:443/\n\n\n* Trying 10.2.78.7...\n\n\n* Connected to 10.2.78.7 (10.2.78.7) port 443 (#0)\n\n\n* ALPN, offering http/1.1\n\n\n* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH\n\n\n* successfully set certificate verify locations:\n\n\n* CAfile: /etc/ssl/certs/ca-certificates.crt\n\n\n CApath: /etc/ssl/certs\n\n\n* TLSv1.2 (OUT), TLS header, Certificate Status (22):\n\n\n* TLSv1.2 (OUT), TLS handshake, Client hello (1):\n\n\n* TLSv1.2 (IN), TLS handshake, Server hello (2):\n\n\n* TLSv1.2 (IN), TLS handshake, Certificate (11):\n\n\n* TLSv1.2 (IN), TLS handshake, Server key exchange (12):\n\n\n* TLSv1.2 (IN), TLS handshake, Server finished (14):\n\n\n* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):\n\n\n* TLSv1.2 (OUT), TLS change cipher, Client hello (1):\n\n\n* TLSv1.2 (OUT), TLS handshake, Finished (20):\n\n\n* TLSv1.2 (IN), TLS change cipher, Client hello (1):\n\n\n* TLSv1.2 (IN), TLS handshake, Finished (20):\n\n\n* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256\n\n\n* ALPN, server accepted to use http/1.1\n\n\n* Server certificate:\n\n\n* subject: CN=foo.bar.com\n\n\n* start date: Apr 13 00:50:56 2016 GMT\n\n\n* expire date: Apr 13 00:50:56 2017 GMT\n\n\n* issuer: CN=foo.bar.com\n\n\n* SSL certificate verify result: self signed certificate (18), continuing anyway.\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: \n10\n.2.78.7\n\n>\n User-Agent: curl/7.47.1\n\n>\n Accept: */*\n\n>\n\n\n< HTTP/1.1 404 Not Found\n\n\n< Server: nginx/1.11.1\n\n\n< Date: Mon, 18 Jul 2016 21:02:59 GMT\n\n\n< Content-Type: text/html\n\n\n< Transfer-Encoding: chunked\n\n\n< Connection: keep-alive\n\n\n< Strict-Transport-Security: max-age=15724800; includeSubDomains; preload\n\n\n<\n\n\nThe page you're looking for could not be found.\n\n\n\n* Connection #0 to host 10.2.78.7 left intact\n\n\n\n\n\n\nSSL Passthrough\n\u00b6\n\n\nThe flag \n--enable-ssl-passthrough\n enables SSL passthrough feature.\nBy default this feature is disabled\n\n\nHTTP Strict Transport Security\n\u00b6\n\n\nHTTP Strict Transport Security (HSTS) is an opt-in security enhancement specified through the use of a special response header. Once a supported browser receives this header that browser will prevent any communications from being sent over HTTP to the specified domain and will instead send all communications over HTTPS.\n\n\nBy default the controller redirects (301) to HTTPS if there is a TLS Ingress rule.\n\n\nTo disable this behavior use \nhsts: \"false\"\n in the configuration ConfigMap.\n\n\nServer-side HTTPS enforcement through redirect\n\u00b6\n\n\nBy default the controller redirects (301) to \nHTTPS\n if TLS is enabled for that ingress. If you want to disable that behavior globally, you can use \nssl-redirect: \"false\"\n in the NGINX config map.\n\n\nTo configure this feature for specific ingress resources, you can use the \nnginx.ingress.kubernetes.io/ssl-redirect: \"false\"\n annotation in the particular resource.\n\n\nWhen using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a redirect to \nHTTPS\n even when there is not TLS cert available. This can be achieved by using the \nnginx.ingress.kubernetes.io/force-ssl-redirect: \"true\"\n annotation in the particular resource.\n\n\nAutomated Certificate Management with Kube-Lego\n\u00b6\n\n\nKube-Lego\n automatically requests missing or expired certificates from \nLet's Encrypt\n by monitoring ingress resources and their referenced secrets. To enable this for an ingress resource you have to add an annotation:\n\n\nkubectl annotate ing ingress-demo kubernetes.io/tls-acme=\"true\"\n\n\n\n\n\n\nTo setup Kube-Lego you can take a look at this \nfull example\n. The first\nversion to fully support Kube-Lego is nginx Ingress controller 0.8.\n\n\nDefault TLS Version and Ciphers\n\u00b6\n\n\nTo provide the most secure baseline configuration possible, nginx-ingress defaults to using TLS 1.2 and a \nsecure set of TLS ciphers\n\n\nLegacy TLS\n\u00b6\n\n\nThe default configuration, though secure, does not support some older browsers and operating systems. For instance, 20% of Android phones in use today are not compatible with nginx-ingress's default configuration. To change this default behavior, use a \nConfigMap\n.\n\n\nA sample ConfigMap to allow these older clients connect could look something like the following:\n\n\nkind\n:\n \nConfigMap\n\n\napiVersion\n:\n \nv1\n\n\nmetadata\n:\n\n \nname\n:\n \nnginx\n-\nconfig\n\n\ndata\n:\n\n \nssl\n-\nciphers\n:\n \n\"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:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA\"\n\n \nssl\n-\nprotocols\n:\n \n\"TLSv1 TLSv1.1 TLSv1.2\"", + "title": "TLS" + }, + { + "location": "/user-guide/tls/#tls", + "text": "Default SSL Certificate SSL Passthrough HTTPS enforcement HSTS Server-side HTTPS enforcement through redirect Kube-Lego Default TLS Version and Ciphers Legacy TLS", + "title": "TLS" + }, + { + "location": "/user-guide/tls/#default-ssl-certificate", + "text": "NGINX provides the option to configure a server as a catch-all with server_name for requests that do not match any of the configured server names. This configuration works without issues for HTTP traffic.\nIn case of HTTPS, NGINX requires a certificate.\nFor this reason the Ingress controller provides the flag --default-ssl-certificate . The secret behind this flag contains the default certificate to be used in the mentioned scenario. If this flag is not provided NGINX will use a self signed certificate. Running without the flag --default-ssl-certificate : $ curl -v https://10.2.78.7:443 -k * Rebuilt URL to: https://10.2.78.7:443/ * Trying 10.2.78.4... * Connected to 10.2.78.7 (10.2.78.7) port 443 (#0) * ALPN, offering http/1.1 * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs * TLSv1.2 (OUT), TLS header, Certificate Status (22): * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Client hello (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Client hello (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: CN=foo.bar.com * start date: Apr 13 00:50:56 2016 GMT * expire date: Apr 13 00:50:56 2017 GMT * issuer: CN=foo.bar.com * SSL certificate verify result: self signed certificate (18), continuing anyway. > GET / HTTP/1.1 > Host: 10 .2.78.7 > User-Agent: curl/7.47.1 > Accept: */* > < HTTP/1.1 404 Not Found < Server: nginx/1.11.1 < Date: Thu, 21 Jul 2016 15:38:46 GMT < Content-Type: text/html < Transfer-Encoding: chunked < Connection: keep-alive < Strict-Transport-Security: max-age=15724800; includeSubDomains; preload < The page you're looking for could not be found. * Connection #0 to host 10.2.78.7 left intact Specifying --default-ssl-certificate=default/foo-tls : core@localhost ~ $ curl -v https://10.2.78.7:443 -k * Rebuilt URL to: https://10.2.78.7:443/ * Trying 10.2.78.7... * Connected to 10.2.78.7 (10.2.78.7) port 443 (#0) * ALPN, offering http/1.1 * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs * TLSv1.2 (OUT), TLS header, Certificate Status (22): * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Client hello (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Client hello (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: CN=foo.bar.com * start date: Apr 13 00:50:56 2016 GMT * expire date: Apr 13 00:50:56 2017 GMT * issuer: CN=foo.bar.com * SSL certificate verify result: self signed certificate (18), continuing anyway. > GET / HTTP/1.1 > Host: 10 .2.78.7 > User-Agent: curl/7.47.1 > Accept: */* > < HTTP/1.1 404 Not Found < Server: nginx/1.11.1 < Date: Mon, 18 Jul 2016 21:02:59 GMT < Content-Type: text/html < Transfer-Encoding: chunked < Connection: keep-alive < Strict-Transport-Security: max-age=15724800; includeSubDomains; preload < The page you're looking for could not be found. * Connection #0 to host 10.2.78.7 left intact", + "title": "Default SSL Certificate" + }, + { + "location": "/user-guide/tls/#ssl-passthrough", + "text": "The flag --enable-ssl-passthrough enables SSL passthrough feature.\nBy default this feature is disabled", + "title": "SSL Passthrough" + }, + { + "location": "/user-guide/tls/#http-strict-transport-security", + "text": "HTTP Strict Transport Security (HSTS) is an opt-in security enhancement specified through the use of a special response header. Once a supported browser receives this header that browser will prevent any communications from being sent over HTTP to the specified domain and will instead send all communications over HTTPS. By default the controller redirects (301) to HTTPS if there is a TLS Ingress rule. To disable this behavior use hsts: \"false\" in the configuration ConfigMap.", + "title": "HTTP Strict Transport Security" + }, + { + "location": "/user-guide/tls/#server-side-https-enforcement-through-redirect", + "text": "By default the controller redirects (301) to HTTPS if TLS is enabled for that ingress. If you want to disable that behavior globally, you can use ssl-redirect: \"false\" in the NGINX config map. To configure this feature for specific ingress resources, you can use the nginx.ingress.kubernetes.io/ssl-redirect: \"false\" annotation in the particular resource. When using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a redirect to HTTPS even when there is not TLS cert available. This can be achieved by using the nginx.ingress.kubernetes.io/force-ssl-redirect: \"true\" annotation in the particular resource.", + "title": "Server-side HTTPS enforcement through redirect" + }, + { + "location": "/user-guide/tls/#automated-certificate-management-with-kube-lego", + "text": "Kube-Lego automatically requests missing or expired certificates from Let's Encrypt by monitoring ingress resources and their referenced secrets. To enable this for an ingress resource you have to add an annotation: kubectl annotate ing ingress-demo kubernetes.io/tls-acme=\"true\" To setup Kube-Lego you can take a look at this full example . The first\nversion to fully support Kube-Lego is nginx Ingress controller 0.8.", + "title": "Automated Certificate Management with Kube-Lego" + }, + { + "location": "/user-guide/tls/#default-tls-version-and-ciphers", + "text": "To provide the most secure baseline configuration possible, nginx-ingress defaults to using TLS 1.2 and a secure set of TLS ciphers", + "title": "Default TLS Version and Ciphers" + }, + { + "location": "/user-guide/tls/#legacy-tls", + "text": "The default configuration, though secure, does not support some older browsers and operating systems. For instance, 20% of Android phones in use today are not compatible with nginx-ingress's default configuration. To change this default behavior, use a ConfigMap . A sample ConfigMap to allow these older clients connect could look something like the following: kind : ConfigMap apiVersion : v1 metadata : \n name : nginx - config data : \n ssl - ciphers : \"ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA\" \n ssl - protocols : \"TLSv1 TLSv1.1 TLSv1.2\"", + "title": "Legacy TLS" + }, + { + "location": "/user-guide/third-party-addons/modsecurity/", + "text": "ModSecurity Web Application Firewall\n\u00b6\n\n\nModSecurity is an open source, cross platform web application firewall (WAF) engine for Apache, IIS and Nginx that is developed by Trustwave's SpiderLabs. It has a robust event-based programming language which provides protection from a range of attacks against web applications and allows for HTTP traffic monitoring, logging and real-time analysis - https://www.modsecurity.org\n\n\nThe \nModSecurity-nginx\n connector is the connection point between NGINX and libmodsecurity (ModSecurity v3).\n\n\nThe default ModSecurity configuration file is located in \n/etc/nginx/modsecurity/modsecurity.conf\n. This is the only file located in this directory and contains the default recommended configuration. Using a volume we can replace this file with the desired configuration.\nTo enable the ModSecurity feature we need to specify \nenable-modsecurity: \"true\"\n in the configuration configmap.\n\n\nNOTE:\n the default configuration use detection only, because that minimises the chances of post-installation disruption.\nThe file \n/var/log/modsec_audit.log\n contains the log of ModSecurity.\n\n\nThe OWASP ModSecurity Core Rule Set (CRS) is a set of generic attack detection rules for use with ModSecurity or compatible web application firewalls. The CRS aims to protect web applications from a wide range of attacks, including the OWASP Top Ten, with a minimum of false alerts.\nThe directory \n/etc/nginx/owasp-modsecurity-crs\n contains the https://github.com/SpiderLabs/owasp-modsecurity-crs repository.\nUsing \nenable-owasp-modsecurity-crs: \"true\"\n we enable the use of the rules.", + "title": "ModSecurity Web Application Firewall" + }, + { + "location": "/user-guide/third-party-addons/modsecurity/#modsecurity-web-application-firewall", + "text": "ModSecurity is an open source, cross platform web application firewall (WAF) engine for Apache, IIS and Nginx that is developed by Trustwave's SpiderLabs. It has a robust event-based programming language which provides protection from a range of attacks against web applications and allows for HTTP traffic monitoring, logging and real-time analysis - https://www.modsecurity.org The ModSecurity-nginx connector is the connection point between NGINX and libmodsecurity (ModSecurity v3). The default ModSecurity configuration file is located in /etc/nginx/modsecurity/modsecurity.conf . This is the only file located in this directory and contains the default recommended configuration. Using a volume we can replace this file with the desired configuration.\nTo enable the ModSecurity feature we need to specify enable-modsecurity: \"true\" in the configuration configmap. NOTE: the default configuration use detection only, because that minimises the chances of post-installation disruption.\nThe file /var/log/modsec_audit.log contains the log of ModSecurity. The OWASP ModSecurity Core Rule Set (CRS) is a set of generic attack detection rules for use with ModSecurity or compatible web application firewalls. The CRS aims to protect web applications from a wide range of attacks, including the OWASP Top Ten, with a minimum of false alerts.\nThe directory /etc/nginx/owasp-modsecurity-crs contains the https://github.com/SpiderLabs/owasp-modsecurity-crs repository.\nUsing enable-owasp-modsecurity-crs: \"true\" we enable the use of the rules.", + "title": "ModSecurity Web Application Firewall" + }, + { + "location": "/user-guide/third-party-addons/opentracing/", + "text": "OpenTracing\n\u00b6\n\n\nUsing the third party module \nopentracing-contrib/nginx-opentracing\n the NGINX ingress controller can configure NGINX to enable \nOpenTracing\n instrumentation.\nBy default this feature is disabled.\n\n\nTo enable the instrumentation we just need to enable the instrumentation in the configuration configmap and set the host where we should send the traces.\n\n\nIn the \nrnburn/zipkin-date-server\n\ngithub repository is an example of a dockerized date service. To install the example and zipkin collector run:\n\n\nkubectl create -f https://raw.githubusercontent.com/rnburn/zipkin-date-server/master/kubernetes/zipkin.yaml\nkubectl create -f https://raw.githubusercontent.com/rnburn/zipkin-date-server/master/kubernetes/deployment.yaml\n\n\n\n\n\nAlso we need to configure the NGINX controller configmap with the required values:\n\n\n$ \necho\n \n'\n\n\napiVersion: v1\n\n\nkind: ConfigMap\n\n\ndata:\n\n\n enable-opentracing: \"true\"\n\n\n zipkin-collector-host: zipkin.default.svc.cluster.local\n\n\nmetadata:\n\n\n name: nginx-configuration\n\n\n namespace: ingress-nginx\n\n\n labels:\n\n\n app: ingress-nginx\n\n\n'\n \n|\n kubectl replace -f -\n\n\n\n\n\nUsing curl we can generate some traces:\n\n\n$\n curl -v http://\n$(\nminikube ip\n)\n\n\n$\n curl -v http://\n$(\nminikube ip\n)\n\n\n\n\n\n\nIn the zipkin interface we can see the details:", + "title": "OpenTracing" + }, + { + "location": "/user-guide/third-party-addons/opentracing/#opentracing", + "text": "Using the third party module opentracing-contrib/nginx-opentracing the NGINX ingress controller can configure NGINX to enable OpenTracing instrumentation.\nBy default this feature is disabled. To enable the instrumentation we just need to enable the instrumentation in the configuration configmap and set the host where we should send the traces. In the rnburn/zipkin-date-server \ngithub repository is an example of a dockerized date service. To install the example and zipkin collector run: kubectl create -f https://raw.githubusercontent.com/rnburn/zipkin-date-server/master/kubernetes/zipkin.yaml\nkubectl create -f https://raw.githubusercontent.com/rnburn/zipkin-date-server/master/kubernetes/deployment.yaml Also we need to configure the NGINX controller configmap with the required values: $ echo ' apiVersion: v1 kind: ConfigMap data: enable-opentracing: \"true\" zipkin-collector-host: zipkin.default.svc.cluster.local metadata: name: nginx-configuration namespace: ingress-nginx labels: app: ingress-nginx ' | kubectl replace -f - Using curl we can generate some traces: $ curl -v http:// $( minikube ip ) $ curl -v http:// $( minikube ip ) In the zipkin interface we can see the details:", + "title": "OpenTracing" + }, + { + "location": "/examples/PREREQUISITES/", + "text": "Prerequisites\n\u00b6\n\n\nMany of the examples in this directory have common prerequisites.\n\n\nTLS certificates\n\u00b6\n\n\nUnless otherwise mentioned, the TLS secret used in examples is a 2048 bit RSA\nkey/cert pair with an arbitrarily chosen hostname, created as follows\n\n\n$\n openssl req -x509 -nodes -days \n365\n -newkey rsa:2048 -keyout tls.key -out tls.crt -subj \n\"/CN=nginxsvc/O=nginxsvc\"\n\n\nGenerating a 2048 bit RSA private key\n\n\n................+++\n\n\n................+++\n\n\nwriting new private key to 'tls.key'\n\n\n-----\n\n\n\n$\n kubectl create secret tls tls-secret --key tls.key --cert tls.crt\n\nsecret \"tls-secret\" created\n\n\n\n\n\n\nCA Authentication\n\u00b6\n\n\nYou can act as your very own CA, or use an existing one. As an exercise / learning, we're going to generate our\nown CA, and also generate a client certificate.\n\n\nThese instructions are based on CoreOS OpenSSL \ninstructions\n\n\nGenerating a CA\n\u00b6\n\n\nFirst of all, you've to generate a CA. This is going to be the one who will sign your client certificates.\nIn real production world, you may face CAs with intermediate certificates, as the following:\n\n\n$\n openssl s_client -connect www.google.com:443\n\n[...]\n\n\n---\n\n\nCertificate chain\n\n\n 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=www.google.com\n\n\n i:/C=US/O=Google Inc/CN=Google Internet Authority G2\n\n\n 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2\n\n\n i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA\n\n\n 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA\n\n\n i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority\n\n\n\n\n\n\nTo generate our CA Certificate, we've to run the following commands:\n\n\n$\n openssl genrsa -out ca.key \n2048\n\n\n$\n openssl req -x509 -new -nodes -key ca.key -days \n10000\n -out ca.crt -subj \n\"/CN=example-ca\"\n\n\n\n\n\n\nThis will generate two files: A private key (ca.key) and a public key (ca.crt). This CA is valid for 10000 days.\nThe ca.crt can be used later in the step of creation of CA authentication secret.\n\n\nGenerating the client certificate\n\u00b6\n\n\nThe following steps generate a client certificate signed by the CA generated above. This client can be\nused to authenticate in a tls-auth configured ingress.\n\n\nFirst, we need to generate an 'openssl.cnf' file that will be used while signing the keys:\n\n\n[req]\n\n\nreq_extensions = v3_req\n\n\ndistinguished_name = req_distinguished_name\n\n\n[req_distinguished_name]\n\n\n[ v3_req ]\n\n\nbasicConstraints = CA:FALSE\n\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment\n\n\n\n\n\n\nThen, a user generates his very own private key (that he needs to keep secret)\nand a CSR (Certificate Signing Request) that will be sent to the CA to sign and generate a certificate.\n\n\n$\n openssl genrsa -out client1.key \n2048\n\n\n$\n openssl req -new -key client1.key -out client1.csr -subj \n\"/CN=client1\"\n -config openssl.cnf\n\n\n\n\n\nAs the CA receives the generated 'client1.csr' file, it signs it and generates a client.crt certificate:\n\n\n$\n openssl x509 -req -in client1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client1.crt -days \n365\n -extensions v3_req -extfile openssl.cnf\n\n\n\n\n\nThen, you'll have 3 files: the client.key (user's private key), client.crt (user's public key) and client.csr (disposable CSR).\n\n\nCreating the CA Authentication secret\n\u00b6\n\n\nIf you're using the CA Authentication feature, you need to generate a secret containing \nall the authorized CAs. You must download them from your CA site in PEM format (like the following):\n\n\n-----BEGIN CERTIFICATE-----\n[....]\n-----END CERTIFICATE-----\n\n\n\n\n\nYou can have as many certificates as you want. If they're in the binary DER format, \nyou can convert them as the following:\n\n\n$\n openssl x509 -in certificate.der -inform der -out certificate.crt -outform pem\n\n\n\n\n\nThen, you've to concatenate them all in only one file, named 'ca.crt' as the following:\n\n\n$\n cat certificate1.crt certificate2.crt certificate3.crt >> ca.crt\n\n\n\n\n\nThe final step is to create a secret with the content of this file. This secret is going to be used in \nthe TLS Auth directive:\n\n\n$\n kubectl create secret generic caingress --namespace\n=\ndefault --from-file\n=\nca.crt\n=\n\n\n\n\n\n\nNote: You can also generate the CA Authentication Secret along with the TLS Secret by using:\n\n\n$\n kubectl create secret generic caingress --namespace\n=\ndefault --from-file\n=\nca.crt\n=\n --from-file\n=\ntls.crt\n=\n --from-file\n=\ntls.key\n=\n\n\n\n\n\n\nTest HTTP Service\n\u00b6\n\n\nAll examples that require a test HTTP Service use the standard http-svc pod,\nwhich you can deploy as follows\n\n\n$\n kubectl create -f http-svc.yaml\n\nservice \"http-svc\" created\n\n\nreplicationcontroller \"http-svc\" created\n\n\n\n$\n kubectl get po\n\nNAME READY STATUS RESTARTS AGE\n\n\nhttp-svc-p1t3t 1/1 Running 0 1d\n\n\n\n$\n kubectl get svc\n\nNAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\nhttp-svc 10.0.122.116 80:30301/TCP 1d\n\n\n\n\n\n\nYou can test that the HTTP Service works by exposing it temporarily\n\n\n$\n kubectl patch svc http-svc -p \n'{\"spec\":{\"type\": \"LoadBalancer\"}}'\n\n\n\"http-svc\" patched\n\n\n\n$\n kubectl get svc http-svc\n\nNAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\nhttp-svc 10.0.122.116 80:30301/TCP 1d\n\n\n\n$\n kubectl describe svc http-svc\n\nName: http-svc\n\n\nNamespace: default\n\n\nLabels: app=http-svc\n\n\nSelector: app=http-svc\n\n\nType: LoadBalancer\n\n\nIP: 10.0.122.116\n\n\nLoadBalancer Ingress: 108.59.87.136\n\n\nPort: http 80/TCP\n\n\nNodePort: http 30301/TCP\n\n\nEndpoints: 10.180.1.6:8080\n\n\nSession Affinity: None\n\n\nEvents:\n\n\n FirstSeen LastSeen Count From SubObjectPath Type Reason Message\n\n\n --------- -------- ----- ---- ------------- -------- ------ -------\n\n\n 1m 1m 1 {service-controller } Normal Type ClusterIP -> LoadBalancer\n\n\n 1m 1m 1 {service-controller } Normal CreatingLoadBalancer Creating load balancer\n\n\n 16s 16s 1 {service-controller } Normal CreatedLoadBalancer Created load balancer\n\n\n\n$\n curl \n108\n.59.87.126\n\nCLIENT VALUES:\n\n\nclient_address=10.240.0.3\n\n\ncommand=GET\n\n\nreal path=/\n\n\nquery=nil\n\n\nrequest_version=1.1\n\n\nrequest_uri=http://108.59.87.136:8080/\n\n\n\nSERVER VALUES:\n\n\nserver_version=nginx: 1.9.11 - lua: 10001\n\n\n\nHEADERS RECEIVED:\n\n\naccept=*/*\n\n\nhost=108.59.87.136\n\n\nuser-agent=curl/7.46.0\n\n\nBODY:\n\n\n-no body in request-\n\n\n\n$\n kubectl patch svc http-svc -p \n'{\"spec\":{\"type\": \"NodePort\"}}'\n\n\n\"http-svc\" patched", + "title": "Prerequisites" + }, + { + "location": "/examples/PREREQUISITES/#prerequisites", + "text": "Many of the examples in this directory have common prerequisites.", + "title": "Prerequisites" + }, + { + "location": "/examples/PREREQUISITES/#tls-certificates", + "text": "Unless otherwise mentioned, the TLS secret used in examples is a 2048 bit RSA\nkey/cert pair with an arbitrarily chosen hostname, created as follows $ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj \"/CN=nginxsvc/O=nginxsvc\" Generating a 2048 bit RSA private key ................+++ ................+++ writing new private key to 'tls.key' ----- $ kubectl create secret tls tls-secret --key tls.key --cert tls.crt secret \"tls-secret\" created", + "title": "TLS certificates" + }, + { + "location": "/examples/PREREQUISITES/#ca-authentication", + "text": "You can act as your very own CA, or use an existing one. As an exercise / learning, we're going to generate our\nown CA, and also generate a client certificate. These instructions are based on CoreOS OpenSSL instructions", + "title": "CA Authentication" + }, + { + "location": "/examples/PREREQUISITES/#generating-a-ca", + "text": "First of all, you've to generate a CA. This is going to be the one who will sign your client certificates.\nIn real production world, you may face CAs with intermediate certificates, as the following: $ openssl s_client -connect www.google.com:443 [...] --- Certificate chain 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=www.google.com i:/C=US/O=Google Inc/CN=Google Internet Authority G2 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2 i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority To generate our CA Certificate, we've to run the following commands: $ openssl genrsa -out ca.key 2048 $ openssl req -x509 -new -nodes -key ca.key -days 10000 -out ca.crt -subj \"/CN=example-ca\" This will generate two files: A private key (ca.key) and a public key (ca.crt). This CA is valid for 10000 days.\nThe ca.crt can be used later in the step of creation of CA authentication secret.", + "title": "Generating a CA" + }, + { + "location": "/examples/PREREQUISITES/#generating-the-client-certificate", + "text": "The following steps generate a client certificate signed by the CA generated above. This client can be\nused to authenticate in a tls-auth configured ingress. First, we need to generate an 'openssl.cnf' file that will be used while signing the keys: [req] req_extensions = v3_req distinguished_name = req_distinguished_name [req_distinguished_name] [ v3_req ] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment Then, a user generates his very own private key (that he needs to keep secret)\nand a CSR (Certificate Signing Request) that will be sent to the CA to sign and generate a certificate. $ openssl genrsa -out client1.key 2048 $ openssl req -new -key client1.key -out client1.csr -subj \"/CN=client1\" -config openssl.cnf As the CA receives the generated 'client1.csr' file, it signs it and generates a client.crt certificate: $ openssl x509 -req -in client1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client1.crt -days 365 -extensions v3_req -extfile openssl.cnf Then, you'll have 3 files: the client.key (user's private key), client.crt (user's public key) and client.csr (disposable CSR).", + "title": "Generating the client certificate" + }, + { + "location": "/examples/PREREQUISITES/#creating-the-ca-authentication-secret", + "text": "If you're using the CA Authentication feature, you need to generate a secret containing \nall the authorized CAs. You must download them from your CA site in PEM format (like the following): -----BEGIN CERTIFICATE-----\n[....]\n-----END CERTIFICATE----- You can have as many certificates as you want. If they're in the binary DER format, \nyou can convert them as the following: $ openssl x509 -in certificate.der -inform der -out certificate.crt -outform pem Then, you've to concatenate them all in only one file, named 'ca.crt' as the following: $ cat certificate1.crt certificate2.crt certificate3.crt >> ca.crt The final step is to create a secret with the content of this file. This secret is going to be used in \nthe TLS Auth directive: $ kubectl create secret generic caingress --namespace = default --from-file = ca.crt = Note: You can also generate the CA Authentication Secret along with the TLS Secret by using: $ kubectl create secret generic caingress --namespace = default --from-file = ca.crt = --from-file = tls.crt = --from-file = tls.key = ", + "title": "Creating the CA Authentication secret" + }, + { + "location": "/examples/PREREQUISITES/#test-http-service", + "text": "All examples that require a test HTTP Service use the standard http-svc pod,\nwhich you can deploy as follows $ kubectl create -f http-svc.yaml service \"http-svc\" created replicationcontroller \"http-svc\" created $ kubectl get po NAME READY STATUS RESTARTS AGE http-svc-p1t3t 1/1 Running 0 1d $ kubectl get svc NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE http-svc 10.0.122.116 80:30301/TCP 1d You can test that the HTTP Service works by exposing it temporarily $ kubectl patch svc http-svc -p '{\"spec\":{\"type\": \"LoadBalancer\"}}' \"http-svc\" patched $ kubectl get svc http-svc NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE http-svc 10.0.122.116 80:30301/TCP 1d $ kubectl describe svc http-svc Name: http-svc Namespace: default Labels: app=http-svc Selector: app=http-svc Type: LoadBalancer IP: 10.0.122.116 LoadBalancer Ingress: 108.59.87.136 Port: http 80/TCP NodePort: http 30301/TCP Endpoints: 10.180.1.6:8080 Session Affinity: None Events: FirstSeen LastSeen Count From SubObjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 1m 1m 1 {service-controller } Normal Type ClusterIP -> LoadBalancer 1m 1m 1 {service-controller } Normal CreatingLoadBalancer Creating load balancer 16s 16s 1 {service-controller } Normal CreatedLoadBalancer Created load balancer $ curl 108 .59.87.126 CLIENT VALUES: client_address=10.240.0.3 command=GET real path=/ query=nil request_version=1.1 request_uri=http://108.59.87.136:8080/ SERVER VALUES: server_version=nginx: 1.9.11 - lua: 10001 HEADERS RECEIVED: accept=*/* host=108.59.87.136 user-agent=curl/7.46.0 BODY: -no body in request- $ kubectl patch svc http-svc -p '{\"spec\":{\"type\": \"NodePort\"}}' \"http-svc\" patched", + "title": "Test HTTP Service" + }, + { + "location": "/examples/README/", + "text": "Ingress examples\n\u00b6\n\n\nThis directory contains a catalog of examples on how to run, configure and\nscale Ingress. Please review the \nprerequisites\n before\ntrying them.\n\n\nScaling\n\u00b6\n\n\n\n\n\n\n\n\nName\n\n\nDescription\n\n\nComplexity Level\n\n\n\n\n\n\n\n\n\n\nStatic-ip\n\n\na single ingress gets a single static ip\n\n\nIntermediate\n\n\n\n\n\n\n\n\nAlgorithms\n\u00b6\n\n\n\n\n\n\n\n\nName\n\n\nDescription\n\n\nComplexity Level\n\n\n\n\n\n\n\n\n\n\nSession stickyness\n\n\nroute requests consistently to the same endpoint\n\n\nAdvanced\n\n\n\n\n\n\n\n\nAuth\n\u00b6\n\n\n\n\n\n\n\n\nName\n\n\nDescription\n\n\nComplexity Level\n\n\n\n\n\n\n\n\n\n\nBasic auth\n\n\npassword protect your website\n\n\nnginx\n\n\n\n\n\n\nClient certificate authentication\n\n\nsecure your website with client certificate authentication\n\n\nnginx\n\n\n\n\n\n\nExternal auth plugin\n\n\ndefer to an external auth service\n\n\nIntermediate\n\n\n\n\n\n\n\n\nCustomization\n\u00b6\n\n\n\n\n\n\n\n\nName\n\n\nDescription\n\n\nComplexity Level\n\n\n\n\n\n\n\n\n\n\nconfiguration-snippets\n\n\ncustomize nginx location configuration using annotations\n\n\nAdvanced\n\n\n\n\n\n\ncustom-headers\n\n\nset custom headers before send traffic to backends\n\n\nAdvanced", + "title": "Ingress examples" + }, + { + "location": "/examples/README/#ingress-examples", + "text": "This directory contains a catalog of examples on how to run, configure and\nscale Ingress. Please review the prerequisites before\ntrying them.", + "title": "Ingress examples" + }, + { + "location": "/examples/README/#scaling", + "text": "Name Description Complexity Level Static-ip a single ingress gets a single static ip Intermediate", + "title": "Scaling" + }, + { + "location": "/examples/README/#algorithms", + "text": "Name Description Complexity Level Session stickyness route requests consistently to the same endpoint Advanced", + "title": "Algorithms" + }, + { + "location": "/examples/README/#auth", + "text": "Name Description Complexity Level Basic auth password protect your website nginx Client certificate authentication secure your website with client certificate authentication nginx External auth plugin defer to an external auth service Intermediate", + "title": "Auth" + }, + { + "location": "/examples/README/#customization", + "text": "Name Description Complexity Level configuration-snippets customize nginx location configuration using annotations Advanced custom-headers set custom headers before send traffic to backends Advanced", + "title": "Customization" + }, + { + "location": "/examples/affinity/cookie/README/", + "text": "Sticky Session\n\u00b6\n\n\nThis example demonstrates how to achieve session affinity using cookies\n\n\nDeployment\n\u00b6\n\n\nSession stickiness is achieved through 3 annotations on the Ingress, as shown in the \nexample\n.\n\n\n\n\n\n\n\n\nName\n\n\nDescription\n\n\nValues\n\n\n\n\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/affinity\n\n\nSets the affinity type\n\n\nstring (in NGINX only \ncookie\n is possible\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/session-cookie-name\n\n\nName of the cookie that will be used\n\n\nstring (default to INGRESSCOOKIE)\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/session-cookie-hash\n\n\nType of hash that will be used in cookie value\n\n\nsha1/md5/index\n\n\n\n\n\n\n\n\nYou can create the ingress to test this\n\n\nkubectl create -f ingress.yaml\n\n\n\n\n\n\nValidation\n\u00b6\n\n\nYou can confirm that the Ingress works.\n\n\n$\n kubectl describe ing nginx-test\n\nName: nginx-test\n\n\nNamespace: default\n\n\nAddress: \n\n\nDefault backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080)\n\n\nRules:\n\n\n Host Path Backends\n\n\n ---- ---- --------\n\n\n stickyingress.example.com \n\n\n / nginx-service:80 ()\n\n\nAnnotations:\n\n\n affinity: cookie\n\n\n session-cookie-hash: sha1\n\n\n session-cookie-name: INGRESSCOOKIE\n\n\nEvents:\n\n\n FirstSeen LastSeen Count From SubObjectPath Type Reason Message\n\n\n --------- -------- ----- ---- ------------- -------- ------ -------\n\n\n 7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test\n\n\n\n\n$\n curl -I http://stickyingress.example.com\n\nHTTP/1.1 200 OK\n\n\nServer: nginx/1.11.9\n\n\nDate: Fri, 10 Feb 2017 14:11:12 GMT\n\n\nContent-Type: text/html\n\n\nContent-Length: 612\n\n\nConnection: keep-alive\n\n\nSet-Cookie: INGRESSCOOKIE=a9907b79b248140b56bb13723f72b67697baac3d; Path=/; HttpOnly\n\n\nLast-Modified: Tue, 24 Jan 2017 14:02:19 GMT\n\n\nETag: \"58875e6b-264\"\n\n\nAccept-Ranges: bytes\n\n\n\n\n\n\nIn the example above, you can see a line containing the 'Set-Cookie: INGRESSCOOKIE' setting the right defined stickiness cookie.\nThis cookie is created by NGINX containing the hash of the used upstream in that request. \nIf the user changes this cookie, NGINX creates a new one and redirect the user to another upstream.\n\n\nIf the backend pool grows up NGINX will keep sending the requests through the same server of the first request, even if it's overloaded.\n\n\nWhen the backend server is removed, the requests are then re-routed to another upstream server and NGINX creates a new cookie, as the previous hash became invalid.\n\n\nWhen you have more than one Ingress Object pointing to the same Service, but one containing affinity configuration and other don't, the first created Ingress will be used. \nThis means that you can face the situation that you've configured Session Affinity in one Ingress and it doesn't reflects in NGINX configuration, because there is another Ingress Object pointing to the same service that doesn't configure this.", + "title": "Sticky Session" + }, + { + "location": "/examples/affinity/cookie/README/#sticky-session", + "text": "This example demonstrates how to achieve session affinity using cookies", + "title": "Sticky Session" + }, + { + "location": "/examples/affinity/cookie/README/#deployment", + "text": "Session stickiness is achieved through 3 annotations on the Ingress, as shown in the example . Name Description Values nginx.ingress.kubernetes.io/affinity Sets the affinity type string (in NGINX only cookie is possible nginx.ingress.kubernetes.io/session-cookie-name Name of the cookie that will be used string (default to INGRESSCOOKIE) nginx.ingress.kubernetes.io/session-cookie-hash Type of hash that will be used in cookie value sha1/md5/index You can create the ingress to test this kubectl create -f ingress.yaml", + "title": "Deployment" + }, + { + "location": "/examples/affinity/cookie/README/#validation", + "text": "You can confirm that the Ingress works. $ kubectl describe ing nginx-test Name: nginx-test Namespace: default Address: Default backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080) Rules: Host Path Backends ---- ---- -------- stickyingress.example.com / nginx-service:80 () Annotations: affinity: cookie session-cookie-hash: sha1 session-cookie-name: INGRESSCOOKIE Events: FirstSeen LastSeen Count From SubObjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test $ curl -I http://stickyingress.example.com HTTP/1.1 200 OK Server: nginx/1.11.9 Date: Fri, 10 Feb 2017 14:11:12 GMT Content-Type: text/html Content-Length: 612 Connection: keep-alive Set-Cookie: INGRESSCOOKIE=a9907b79b248140b56bb13723f72b67697baac3d; Path=/; HttpOnly Last-Modified: Tue, 24 Jan 2017 14:02:19 GMT ETag: \"58875e6b-264\" Accept-Ranges: bytes In the example above, you can see a line containing the 'Set-Cookie: INGRESSCOOKIE' setting the right defined stickiness cookie.\nThis cookie is created by NGINX containing the hash of the used upstream in that request. \nIf the user changes this cookie, NGINX creates a new one and redirect the user to another upstream. If the backend pool grows up NGINX will keep sending the requests through the same server of the first request, even if it's overloaded. When the backend server is removed, the requests are then re-routed to another upstream server and NGINX creates a new cookie, as the previous hash became invalid. When you have more than one Ingress Object pointing to the same Service, but one containing affinity configuration and other don't, the first created Ingress will be used. \nThis means that you can face the situation that you've configured Session Affinity in one Ingress and it doesn't reflects in NGINX configuration, because there is another Ingress Object pointing to the same service that doesn't configure this.", + "title": "Validation" + }, + { + "location": "/examples/auth/basic/README/", + "text": "Basic Authentication\n\u00b6\n\n\nThis example shows how to add authentication in a Ingress rule using a secret that contains a file generated with \nhtpasswd\n.\n\n\n$\n htpasswd -c auth foo\n\nNew password: \n\n\nNew password:\n\n\nRe-type new password:\n\n\nAdding password for user foo\n\n\n\n\n\n\n$\n kubectl create secret generic basic-auth --from-file\n=\nauth\n\nsecret \"basic-auth\" created\n\n\n\n\n\n\n$\n kubectl get secret basic-auth -o yaml\n\napiVersion: v1\n\n\ndata:\n\n\n auth: Zm9vOiRhcHIxJE9GRzNYeWJwJGNrTDBGSERBa29YWUlsSDkuY3lzVDAK\n\n\nkind: Secret\n\n\nmetadata:\n\n\n name: basic-auth\n\n\n namespace: default\n\n\ntype: Opaque\n\n\n\n\n\n\necho \"\n\n\napiVersion: extensions/v1beta1\n\n\nkind: Ingress\n\n\nmetadata:\n\n\n name: ingress-with-auth\n\n\n annotations:\n\n\n #\n \ntype\n of authentication\n\n nginx.ingress.kubernetes.io/auth-type: basic\n\n\n #\n name of the secret that contains the user/password definitions\n\n nginx.ingress.kubernetes.io/auth-secret: basic-auth\n\n\n #\n message to display with an appropriate context why the authentication is required\n\n nginx.ingress.kubernetes.io/auth-realm: \"Authentication Required - foo\"\n\n\nspec:\n\n\n rules:\n\n\n - host: foo.bar.com\n\n\n http:\n\n\n paths:\n\n\n - path: /\n\n\n backend:\n\n\n serviceName: http-svc\n\n\n servicePort: 80\n\n\n\" | kubectl create -f -\n\n\n\n\n\n\n$ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com'\n* Trying 10.2.29.4...\n* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0)\n> GET / HTTP/1.1\n> Host: foo.bar.com\n> User-Agent: curl/7.43.0\n> Accept: */*\n>\n\n< HTTP\n/1.1\n \n401\n \nUnauthorized\n\n\n<\n \nServer:\n \nnginx/1.10.0\n\n\n<\n \nDate:\n \nWed,\n \n11\n \nMay\n \n2016\n \n05:27:23\n \nGMT\n\n\n<\n \nContent-Type:\n \ntext/html\n\n\n<\n \nContent-Length:\n \n195\n\n\n<\n \nConnection:\n \nkeep-alive\n\n\n<\n \nWWW-Authenticate:\n \nBasic\n \nrealm=\n\"Authentication Required - foo\"\n\n\n<\n\n\n\n\n\n\n401 Authorization Required\n\n\n\n\n\n\n

\n401 Authorization Required\n

\n\n\n
\nnginx/1.10.0\n
\n\n\n\n\n\n\n\n* Connection #0 to host 10.2.29.4 left intact\n\n\n\n\n\n$ curl -v http://10.2.29.4/ -H \n'Host: foo.bar.com'\n -u \n'foo:bar'\n\n* Trying \n10\n.2.29.4...\n* Connected to \n10\n.2.29.4 \n(\n10\n.2.29.4\n)\n port \n80\n \n(\n#0)\n\n* Server auth using Basic with user \n'foo'\n\n> GET / HTTP/1.1\n> Host: foo.bar.com\n> Authorization: Basic \nZm9vOmJhcg\n==\n\n> User-Agent: curl/7.43.0\n> Accept: */*\n>\n< HTTP/1.1 \n200\n OK\n< Server: nginx/1.10.0\n< Date: Wed, \n11\n May \n2016\n \n06\n:05:26 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n< Vary: Accept-Encoding\n<\nCLIENT VALUES:\n\nclient_address\n=\n10\n.2.29.4\n\ncommand\n=\nGET\nreal \npath\n=\n/\n\nquery\n=\nnil\n\nrequest_version\n=\n1\n.1\n\nrequest_uri\n=\nhttp://foo.bar.com:8080/\n\nSERVER VALUES:\n\nserver_version\n=\nnginx: \n1\n.9.11 - lua: \n10001\n\n\nHEADERS RECEIVED:\n\naccept\n=\n*/*\n\nauthorization\n=\nBasic \nZm9vOmJhcg\n==\n\n\nconnection\n=\nclose\n\nhost\n=\nfoo.bar.com\nuser-agent\n=\ncurl/7.43.0\nx-forwarded-for\n=\n10\n.2.29.1\nx-forwarded-host\n=\nfoo.bar.com\nx-forwarded-port\n=\n80\n\nx-forwarded-proto\n=\nhttp\nx-real-ip\n=\n10\n.2.29.1\nBODY:\n* Connection \n#0 to host 10.2.29.4 left intact\n\n-no body in request-", + "title": "Basic Authentication" + }, + { + "location": "/examples/auth/basic/README/#basic-authentication", + "text": "This example shows how to add authentication in a Ingress rule using a secret that contains a file generated with htpasswd . $ htpasswd -c auth foo New password: New password: Re-type new password: Adding password for user foo $ kubectl create secret generic basic-auth --from-file = auth secret \"basic-auth\" created $ kubectl get secret basic-auth -o yaml apiVersion: v1 data: auth: Zm9vOiRhcHIxJE9GRzNYeWJwJGNrTDBGSERBa29YWUlsSDkuY3lzVDAK kind: Secret metadata: name: basic-auth namespace: default type: Opaque echo \" apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-with-auth annotations: # type of authentication nginx.ingress.kubernetes.io/auth-type: basic # name of the secret that contains the user/password definitions nginx.ingress.kubernetes.io/auth-secret: basic-auth # message to display with an appropriate context why the authentication is required nginx.ingress.kubernetes.io/auth-realm: \"Authentication Required - foo\" spec: rules: - host: foo.bar.com http: paths: - path: / backend: serviceName: http-svc servicePort: 80 \" | kubectl create -f - $ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com'\n* Trying 10.2.29.4...\n* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0)\n> GET / HTTP/1.1\n> Host: foo.bar.com\n> User-Agent: curl/7.43.0\n> Accept: */*\n> < HTTP /1.1 401 Unauthorized < Server: nginx/1.10.0 < Date: Wed, 11 May 2016 05:27:23 GMT < Content-Type: text/html < Content-Length: 195 < Connection: keep-alive < WWW-Authenticate: Basic realm= \"Authentication Required - foo\" < 401 Authorization Required

401 Authorization Required


nginx/1.10.0
\n* Connection #0 to host 10.2.29.4 left intact $ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com' -u 'foo:bar' \n* Trying 10 .2.29.4...\n* Connected to 10 .2.29.4 ( 10 .2.29.4 ) port 80 ( #0) \n* Server auth using Basic with user 'foo' \n> GET / HTTP/1.1\n> Host: foo.bar.com\n> Authorization: Basic Zm9vOmJhcg == \n> User-Agent: curl/7.43.0\n> Accept: */*\n>\n< HTTP/1.1 200 OK\n< Server: nginx/1.10.0\n< Date: Wed, 11 May 2016 06 :05:26 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n< Vary: Accept-Encoding\n<\nCLIENT VALUES: client_address = 10 .2.29.4 command = GET\nreal path = / query = nil request_version = 1 .1 request_uri = http://foo.bar.com:8080/\n\nSERVER VALUES: server_version = nginx: 1 .9.11 - lua: 10001 \n\nHEADERS RECEIVED: accept = */* authorization = Basic Zm9vOmJhcg == connection = close host = foo.bar.com\nuser-agent = curl/7.43.0\nx-forwarded-for = 10 .2.29.1\nx-forwarded-host = foo.bar.com\nx-forwarded-port = 80 \nx-forwarded-proto = http\nx-real-ip = 10 .2.29.1\nBODY:\n* Connection #0 to host 10.2.29.4 left intact \n-no body in request-", + "title": "Basic Authentication" + }, + { + "location": "/examples/auth/client-certs/README/", + "text": "Client Certificate Authentication\n\u00b6\n\n\nIt is possible to enable Client Certificate Authentication using additional annotations in the Ingress.\n\n\nSetup instructions\n\u00b6\n\n\n\n\n\n\nCreate a file named \nca.crt\n containing the trusted certificate authority chain (all ca certificates in PEM format) to verify client certificates. \n\n\n\n\n\n\nCreate a secret from this file:\n\nkubectl create secret generic auth-tls-chain --from-file=ca.crt --namespace=default\n\n\n\n\n\n\nAdd the annotations as provided in the \ningress.yaml\n example to your ingress object.", + "title": "Client Certificate Authentication" + }, + { + "location": "/examples/auth/client-certs/README/#client-certificate-authentication", + "text": "It is possible to enable Client Certificate Authentication using additional annotations in the Ingress.", + "title": "Client Certificate Authentication" + }, + { + "location": "/examples/auth/client-certs/README/#setup-instructions", + "text": "Create a file named ca.crt containing the trusted certificate authority chain (all ca certificates in PEM format) to verify client certificates. Create a secret from this file: kubectl create secret generic auth-tls-chain --from-file=ca.crt --namespace=default Add the annotations as provided in the ingress.yaml example to your ingress object.", + "title": "Setup instructions" + }, + { + "location": "/examples/auth/external-auth/README/", + "text": "External authentication\n\u00b6\n\n\nExample 1:\n\u00b6\n\n\nUse an external service (Basic Auth) located in \nhttps://httpbin.org\n \n\n\n$ kubectl create -f ingress.yaml\ningress \n\"external-auth\"\n created\n\n$ kubectl get ing external-auth\nNAME HOSTS ADDRESS PORTS AGE\nexternal-auth external-auth-01.sample.com \n172\n.17.4.99 \n80\n 13s\n\n$ kubectl get ing external-auth -o yaml\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n annotations:\n nginx.ingress.kubernetes.io/auth-url: https://httpbin.org/basic-auth/user/passwd\n creationTimestamp: \n2016\n-10-03T13:50:35Z\n generation: \n1\n\n name: external-auth\n namespace: default\n resourceVersion: \n\"2068378\"\n\n selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/external-auth\n uid: 5c388f1d-8970-11e6-9004-080027d2dc94\nspec:\n rules:\n - host: external-auth-01.sample.com\n http:\n paths:\n - backend:\n serviceName: http-svc\n servicePort: \n80\n\n path: /\nstatus:\n loadBalancer:\n ingress:\n - ip: \n172\n.17.4.99\n$\n\n\n\n\n\nTest 1: no username/password (expect code 401)\n\n\n$\n curl -k http://172.17.4.99 -v -H \n'Host: external-auth-01.sample.com'\n\n\n* Rebuilt URL to: http://172.17.4.99/\n\n\n* Trying 172.17.4.99...\n\n\n* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: external-auth-01.sample.com\n\n>\n User-Agent: curl/7.50.1\n\n>\n Accept: */*\n\n>\n\n\n< HTTP/1.1 401 Unauthorized\n\n\n< Server: nginx/1.11.3\n\n\n< Date: Mon, 03 Oct 2016 14:52:08 GMT\n\n\n< Content-Type: text/html\n\n\n< Content-Length: 195\n\n\n< Connection: keep-alive\n\n\n< WWW-Authenticate: Basic realm=\"Fake Realm\"\n\n\n<\n\n\n\n\n\n401 Authorization Required\n\n\n\n\n\n

401 Authorization Required

\n\n\n
nginx/1.11.3
\n\n\n\n\n\n\n\n\n* Connection #0 to host 172.17.4.99 left intact\n\n\n\n\n\n\nTest 2: valid username/password (expect code 200)\n\n\n$ curl -k http://172.17.4.99 -v -H \n'Host: external-auth-01.sample.com'\n -u \n'user:passwd'\n\n* Rebuilt URL to: http://172.17.4.99/\n* Trying \n172\n.17.4.99...\n* Connected to \n172\n.17.4.99 \n(\n172\n.17.4.99\n)\n port \n80\n \n(\n#0)\n\n* Server auth using Basic with user \n'user'\n\n> GET / HTTP/1.1\n> Host: external-auth-01.sample.com\n> Authorization: Basic \ndXNlcjpwYXNzd2Q\n=\n\n> User-Agent: curl/7.50.1\n> Accept: */*\n>\n< HTTP/1.1 \n200\n OK\n< Server: nginx/1.11.3\n< Date: Mon, \n03\n Oct \n2016\n \n14\n:52:50 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n<\nCLIENT VALUES:\n\nclient_address\n=\n10\n.2.60.2\n\ncommand\n=\nGET\nreal \npath\n=\n/\n\nquery\n=\nnil\n\nrequest_version\n=\n1\n.1\n\nrequest_uri\n=\nhttp://external-auth-01.sample.com:8080/\n\nSERVER VALUES:\n\nserver_version\n=\nnginx: \n1\n.9.11 - lua: \n10001\n\n\nHEADERS RECEIVED:\n\naccept\n=\n*/*\n\nauthorization\n=\nBasic \ndXNlcjpwYXNzd2Q\n=\n\n\nconnection\n=\nclose\n\nhost\n=\nexternal-auth-01.sample.com\nuser-agent\n=\ncurl/7.50.1\nx-forwarded-for\n=\n10\n.2.60.1\nx-forwarded-host\n=\nexternal-auth-01.sample.com\nx-forwarded-port\n=\n80\n\nx-forwarded-proto\n=\nhttp\nx-real-ip\n=\n10\n.2.60.1\nBODY:\n* Connection \n#0 to host 172.17.4.99 left intact\n\n-no body in request-\n\n\n\n\n\nTest 3: invalid username/password (expect code 401)\n\n\ncurl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -u 'user:user'\n* Rebuilt URL to: http://172.17.4.99/\n* Trying 172.17.4.99...\n* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)\n* Server auth using Basic with user 'user'\n> GET / HTTP/1.1\n> Host: external-auth-01.sample.com\n> Authorization: Basic dXNlcjp1c2Vy\n> User-Agent: curl/7.50.1\n> Accept: */*\n>\n\n< HTTP\n/1.1\n \n401\n \nUnauthorized\n\n\n<\n \nServer:\n \nnginx/1.11.3\n\n\n<\n \nDate:\n \nMon,\n \n03\n \nOct\n \n2016\n \n14:53:04\n \nGMT\n\n\n<\n \nContent-Type:\n \ntext/html\n\n\n<\n \nContent-Length:\n \n195\n\n\n<\n \nConnection:\n \nkeep-alive\n\n\n*\n \nAuthentication\n \nproblem.\n \nIgnoring\n \nthis.\n\n\n<\n \nWWW-Authenticate:\n \nBasic\n \nrealm=\n\"Fake Realm\"\n\n\n<\n\n\n\n\n\n\n401 Authorization Required\n\n\n\n\n\n\n

\n401 Authorization Required\n

\n\n\n
\nnginx/1.11.3\n
\n\n\n\n\n\n\n\n* Connection #0 to host 172.17.4.99 left intact", + "title": "External authentication" + }, + { + "location": "/examples/auth/external-auth/README/#external-authentication", + "text": "", + "title": "External authentication" + }, + { + "location": "/examples/auth/external-auth/README/#example-1", + "text": "Use an external service (Basic Auth) located in https://httpbin.org $ kubectl create -f ingress.yaml\ningress \"external-auth\" created\n\n$ kubectl get ing external-auth\nNAME HOSTS ADDRESS PORTS AGE\nexternal-auth external-auth-01.sample.com 172 .17.4.99 80 13s\n\n$ kubectl get ing external-auth -o yaml\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n annotations:\n nginx.ingress.kubernetes.io/auth-url: https://httpbin.org/basic-auth/user/passwd\n creationTimestamp: 2016 -10-03T13:50:35Z\n generation: 1 \n name: external-auth\n namespace: default\n resourceVersion: \"2068378\" \n selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/external-auth\n uid: 5c388f1d-8970-11e6-9004-080027d2dc94\nspec:\n rules:\n - host: external-auth-01.sample.com\n http:\n paths:\n - backend:\n serviceName: http-svc\n servicePort: 80 \n path: /\nstatus:\n loadBalancer:\n ingress:\n - ip: 172 .17.4.99\n$ Test 1: no username/password (expect code 401) $ curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' * Rebuilt URL to: http://172.17.4.99/ * Trying 172.17.4.99... * Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) > GET / HTTP/1.1 > Host: external-auth-01.sample.com > User-Agent: curl/7.50.1 > Accept: */* > < HTTP/1.1 401 Unauthorized < Server: nginx/1.11.3 < Date: Mon, 03 Oct 2016 14:52:08 GMT < Content-Type: text/html < Content-Length: 195 < Connection: keep-alive < WWW-Authenticate: Basic realm=\"Fake Realm\" < 401 Authorization Required

401 Authorization Required


nginx/1.11.3
* Connection #0 to host 172.17.4.99 left intact Test 2: valid username/password (expect code 200) $ curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -u 'user:passwd' \n* Rebuilt URL to: http://172.17.4.99/\n* Trying 172 .17.4.99...\n* Connected to 172 .17.4.99 ( 172 .17.4.99 ) port 80 ( #0) \n* Server auth using Basic with user 'user' \n> GET / HTTP/1.1\n> Host: external-auth-01.sample.com\n> Authorization: Basic dXNlcjpwYXNzd2Q = \n> User-Agent: curl/7.50.1\n> Accept: */*\n>\n< HTTP/1.1 200 OK\n< Server: nginx/1.11.3\n< Date: Mon, 03 Oct 2016 14 :52:50 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n<\nCLIENT VALUES: client_address = 10 .2.60.2 command = GET\nreal path = / query = nil request_version = 1 .1 request_uri = http://external-auth-01.sample.com:8080/\n\nSERVER VALUES: server_version = nginx: 1 .9.11 - lua: 10001 \n\nHEADERS RECEIVED: accept = */* authorization = Basic dXNlcjpwYXNzd2Q = connection = close host = external-auth-01.sample.com\nuser-agent = curl/7.50.1\nx-forwarded-for = 10 .2.60.1\nx-forwarded-host = external-auth-01.sample.com\nx-forwarded-port = 80 \nx-forwarded-proto = http\nx-real-ip = 10 .2.60.1\nBODY:\n* Connection #0 to host 172.17.4.99 left intact \n-no body in request- Test 3: invalid username/password (expect code 401) curl -k http://172.17.4.99 -v -H 'Host: external-auth-01.sample.com' -u 'user:user'\n* Rebuilt URL to: http://172.17.4.99/\n* Trying 172.17.4.99...\n* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)\n* Server auth using Basic with user 'user'\n> GET / HTTP/1.1\n> Host: external-auth-01.sample.com\n> Authorization: Basic dXNlcjp1c2Vy\n> User-Agent: curl/7.50.1\n> Accept: */*\n> < HTTP /1.1 401 Unauthorized < Server: nginx/1.11.3 < Date: Mon, 03 Oct 2016 14:53:04 GMT < Content-Type: text/html < Content-Length: 195 < Connection: keep-alive * Authentication problem. Ignoring this. < WWW-Authenticate: Basic realm= \"Fake Realm\" < 401 Authorization Required

401 Authorization Required


nginx/1.11.3
\n* Connection #0 to host 172.17.4.99 left intact", + "title": "Example 1:" + }, + { + "location": "/examples/customization/configuration-snippets/README/", + "text": "Configuration Snippets\n\u00b6\n\n\nIngress\n\u00b6\n\n\nThe Ingress in this example adds a custom header to Nginx configuration that only applies to that specific Ingress. If you want to add headers that apply globally to all Ingresses, please have a look at \nthis example\n.\n\n\n$\n kubectl apply -f ingress.yaml\n\n\n\n\n\nTest\n\u00b6\n\n\nCheck if the contents of the annotation are present in the nginx.conf file using:\n\nkubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf", + "title": "Configuration Snippets" + }, + { + "location": "/examples/customization/configuration-snippets/README/#configuration-snippets", + "text": "", + "title": "Configuration Snippets" + }, + { + "location": "/examples/customization/configuration-snippets/README/#ingress", + "text": "The Ingress in this example adds a custom header to Nginx configuration that only applies to that specific Ingress. If you want to add headers that apply globally to all Ingresses, please have a look at this example . $ kubectl apply -f ingress.yaml", + "title": "Ingress" + }, + { + "location": "/examples/customization/configuration-snippets/README/#test", + "text": "Check if the contents of the annotation are present in the nginx.conf file using: kubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf", + "title": "Test" + }, + { + "location": "/examples/customization/custom-configuration/README/", + "text": "Custom Configuration\n\u00b6\n\n\nUsing a \nConfigMap\n is possible to customize the NGINX configuration\n\n\nFor example, if we want to change the timeouts we need to create a ConfigMap:\n\n\n$ cat configmap.yaml\napiVersion: v1\ndata:\n proxy-connect-timeout: \n\"10\"\n\n proxy-read-timeout: \n\"120\"\n\n proxy-send-timeout: \n\"120\"\n\nkind: ConfigMap\nmetadata:\n name: nginx-load-balancer-conf\n\n\n\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-configuration/configmap.yaml \\\n | kubectl apply -f -\n\n\n\n\n\nIf the Configmap it is updated, NGINX will be reloaded with the new configuration.", + "title": "Custom Configuration" + }, + { + "location": "/examples/customization/custom-configuration/README/#custom-configuration", + "text": "Using a ConfigMap is possible to customize the NGINX configuration For example, if we want to change the timeouts we need to create a ConfigMap: $ cat configmap.yaml\napiVersion: v1\ndata:\n proxy-connect-timeout: \"10\" \n proxy-read-timeout: \"120\" \n proxy-send-timeout: \"120\" \nkind: ConfigMap\nmetadata:\n name: nginx-load-balancer-conf curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-configuration/configmap.yaml \\\n | kubectl apply -f - If the Configmap it is updated, NGINX will be reloaded with the new configuration.", + "title": "Custom Configuration" + }, + { + "location": "/examples/customization/custom-errors/README/", + "text": "Custom Errors\n\u00b6\n\n\nThis example shows how is possible to use a custom backend to render custom error pages. The code of this example is located here \ncustom-error-pages\n\n\nThe idea is to use the headers \nX-Code\n and \nX-Format\n that NGINX pass to the backend in case of an error to find out the best existent representation of the response to be returned. i.e. if the request contains an \nAccept\n header of type \njson\n the error should be in that format and not in \nhtml\n (the default in NGINX).\n\n\nFirst create the custom backend to use in the Ingress controller\n\n\n$ kubectl create -f custom-default-backend.yaml\nservice \n\"nginx-errors\"\n created\nreplicationcontroller \n\"nginx-errors\"\n created\n\n\n\n\n\n$ kubectl get svc\nNAME CLUSTER-IP EXTERNAL-IP PORT\n(\nS\n)\n AGE\nechoheaders \n10\n.3.0.7 nodes \n80\n/TCP 23d\nkubernetes \n10\n.3.0.1 \n443\n/TCP 34d\nnginx-errors \n10\n.3.0.102 \n80\n/TCP 11s\n\n\n\n\n\n$ kubectl get rc\nCONTROLLER REPLICAS AGE\nechoheaders \n1\n 19d\nnginx-errors \n1\n 19s\n\n\n\n\n\nNext create the Ingress controller executing\n\n\n$ kubectl create -f rc-custom-errors.yaml\n\n\n\n\n\nNow to check if this is working we use curl:\n\n\n$ curl -v http://172.17.4.99/\n* Trying 172.17.4.99...\n* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)\n> GET / HTTP/1.1\n> Host: 172.17.4.99\n> User-Agent: curl/7.43.0\n> Accept: */*\n>\n\n< HTTP\n/1.1\n \n404\n \nNot\n \nFound\n\n\n<\n \nServer:\n \nnginx/1.10.0\n\n\n<\n \nDate:\n \nWed,\n \n04\n \nMay\n \n2016\n \n02:53:45\n \nGMT\n\n\n<\n \nContent-Type:\n \ntext/html\n\n\n<\n \nTransfer-Encoding:\n \nchunked\n\n\n<\n \nConnection:\n \nkeep-alive\n\n\n<\n \nVary:\n \nAccept-Encoding\n\n\n<\n\n\n\nThe page you're looking for could not be found.\n\n\n\n* Connection #0 to host 172.17.4.99 left intact\n\n\n\n\n\nSpecifying json as expected format:\n\n\n$ curl -v http://172.17.4.99/ -H \n'Accept: application/json'\n\n* Trying \n172\n.17.4.99...\n* Connected to \n172\n.17.4.99 \n(\n172\n.17.4.99\n)\n port \n80\n \n(\n#0)\n\n> GET / HTTP/1.1\n> Host: \n172\n.17.4.99\n> User-Agent: curl/7.43.0\n> Accept: application/json\n>\n< HTTP/1.1 \n404\n Not Found\n< Server: nginx/1.10.0\n< Date: Wed, \n04\n May \n2016\n \n02\n:54:00 GMT\n< Content-Type: text/html\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n< Vary: Accept-Encoding\n<\n\n{\n \n\"message\"\n: \n\"The page you're looking for could not be found\"\n \n}\n\n\n* Connection \n#0 to host 172.17.4.99 left intact", + "title": "Custom Errors" + }, + { + "location": "/examples/customization/custom-errors/README/#custom-errors", + "text": "This example shows how is possible to use a custom backend to render custom error pages. The code of this example is located here custom-error-pages The idea is to use the headers X-Code and X-Format that NGINX pass to the backend in case of an error to find out the best existent representation of the response to be returned. i.e. if the request contains an Accept header of type json the error should be in that format and not in html (the default in NGINX). First create the custom backend to use in the Ingress controller $ kubectl create -f custom-default-backend.yaml\nservice \"nginx-errors\" created\nreplicationcontroller \"nginx-errors\" created $ kubectl get svc\nNAME CLUSTER-IP EXTERNAL-IP PORT ( S ) AGE\nechoheaders 10 .3.0.7 nodes 80 /TCP 23d\nkubernetes 10 .3.0.1 443 /TCP 34d\nnginx-errors 10 .3.0.102 80 /TCP 11s $ kubectl get rc\nCONTROLLER REPLICAS AGE\nechoheaders 1 19d\nnginx-errors 1 19s Next create the Ingress controller executing $ kubectl create -f rc-custom-errors.yaml Now to check if this is working we use curl: $ curl -v http://172.17.4.99/\n* Trying 172.17.4.99...\n* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0)\n> GET / HTTP/1.1\n> Host: 172.17.4.99\n> User-Agent: curl/7.43.0\n> Accept: */*\n> < HTTP /1.1 404 Not Found < Server: nginx/1.10.0 < Date: Wed, 04 May 2016 02:53:45 GMT < Content-Type: text/html < Transfer-Encoding: chunked < Connection: keep-alive < Vary: Accept-Encoding < The page you're looking for could not be found. \n\n* Connection #0 to host 172.17.4.99 left intact Specifying json as expected format: $ curl -v http://172.17.4.99/ -H 'Accept: application/json' \n* Trying 172 .17.4.99...\n* Connected to 172 .17.4.99 ( 172 .17.4.99 ) port 80 ( #0) \n> GET / HTTP/1.1\n> Host: 172 .17.4.99\n> User-Agent: curl/7.43.0\n> Accept: application/json\n>\n< HTTP/1.1 404 Not Found\n< Server: nginx/1.10.0\n< Date: Wed, 04 May 2016 02 :54:00 GMT\n< Content-Type: text/html\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n< Vary: Accept-Encoding\n< { \"message\" : \"The page you're looking for could not be found\" } \n\n* Connection #0 to host 172.17.4.99 left intact", + "title": "Custom Errors" + }, + { + "location": "/examples/customization/custom-headers/README/", + "text": "Custom Headers\n\u00b6\n\n\nThis example aims to demonstrate the deployment of an nginx ingress controller and\nuse a ConfigMap to configure a custom list of headers to be passed to the upstream\nserver\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-headers/configmap.yaml \\\n\n\n | kubectl apply -f -\n\n\n\ncurl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-headers/custom-headers.yaml \\\n\n\n | kubectl apply -f -\n\n\n\n\n\n\nTest\n\u00b6\n\n\nCheck the contents of the configmap is present in the nginx.conf file using:\n\nkubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf", + "title": "Custom Headers" + }, + { + "location": "/examples/customization/custom-headers/README/#custom-headers", + "text": "This example aims to demonstrate the deployment of an nginx ingress controller and\nuse a ConfigMap to configure a custom list of headers to be passed to the upstream\nserver curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-headers/configmap.yaml \\ | kubectl apply -f - curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/customization/custom-headers/custom-headers.yaml \\ | kubectl apply -f -", + "title": "Custom Headers" + }, + { + "location": "/examples/customization/custom-headers/README/#test", + "text": "Check the contents of the configmap is present in the nginx.conf file using: kubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf", + "title": "Test" + }, + { + "location": "/examples/customization/custom-upstream-check/README/", + "text": "Custom Upstream server checks\n\u00b6\n\n\nThis example shows how is possible to create a custom configuration for a particular upstream associated with an Ingress rule.\n\n\necho \"\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n name: http-svc\n annotations:\n nginx.ingress.kubernetes.io/upstream-fail-timeout: \"30\"\nspec:\n rules:\n - host: foo.bar.com\n http:\n paths:\n - path: /\n backend:\n serviceName: http-svc\n servicePort: 80\n\" | kubectl create -f -\n\n\n\n\n\nCheck the annotation is present in the Ingress rule:\n\n\nkubectl get ingress http-svc -o yaml\n\n\n\n\n\nCheck the NGINX configuration is updated using kubectl or the status page:\n\n\n$ kubectl \nexec\n nginx-ingress-controller-v1ppm cat /etc/nginx/nginx.conf\n\n\n\n\n\n....\n\n \nupstream\n \ndefault-http-svc-x-80\n \n{\n\n \nleast_conn\n;\n\n \nserver\n \n10.2.92.2:8080\n \nmax_fails=5\n \nfail_timeout=30\n;\n\n\n \n}\n\n\n....", + "title": "Custom Upstream server checks" + }, + { + "location": "/examples/customization/custom-upstream-check/README/#custom-upstream-server-checks", + "text": "This example shows how is possible to create a custom configuration for a particular upstream associated with an Ingress rule. echo \"\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n name: http-svc\n annotations:\n nginx.ingress.kubernetes.io/upstream-fail-timeout: \"30\"\nspec:\n rules:\n - host: foo.bar.com\n http:\n paths:\n - path: /\n backend:\n serviceName: http-svc\n servicePort: 80\n\" | kubectl create -f - Check the annotation is present in the Ingress rule: kubectl get ingress http-svc -o yaml Check the NGINX configuration is updated using kubectl or the status page: $ kubectl exec nginx-ingress-controller-v1ppm cat /etc/nginx/nginx.conf .... \n upstream default-http-svc-x-80 { \n least_conn ; \n server 10.2.92.2:8080 max_fails=5 fail_timeout=30 ; \n\n } ....", + "title": "Custom Upstream server checks" + }, + { + "location": "/examples/customization/custom-vts-metrics-prometheus/README/", + "text": "Deploying the Nginx Ingress controller\n\u00b6\n\n\nThis example aims to demonstrate the deployment of an nginx ingress controller and use a ConfigMap to enable \nnginx vts module\n to export metrics in prometheus format. \n\n\nvts-metrics\n\u00b6\n\n\nVts-metrics export NGINX metrics. To deploy all the files simply run \nkubectl apply -f nginx\n. A deployment and service will be\ncreated which already has a \nprometheus.io/scrape: 'true'\n annotation and if you added\nthe recommended Prometheus service-endpoint scraping \nconfiguration\n,\nPrometheus will scrape it automatically and you start using the generated metrics right away.\n\n\nCustom configuration\n\u00b6\n\n\napiVersion: v1\n\n\ndata:\n\n\n enable-vts-status: \"true\"\n\n\nkind: ConfigMap\n\n\nmetadata:\n\n\n name: nginx-configuration\n\n\n namespace: ingress-nginx\n\n\n labels:\n\n\n app: ingress-nginx\n\n\n\n\n\n\n$\n kubectl apply -f nginx-vts-metrics-conf.yaml\n\n\n\n\n\nResult\n\u00b6\n\n\nCheck whether the ingress controller successfully generated the NGINX vts status:\n\n\n$\n kubectl \nexec\n nginx-ingress-controller-873061567-4n3k2 -n ingress-nginx cat /etc/nginx/nginx.conf\n|\ngrep vhost_traffic_status_display\n\n vhost_traffic_status_display;\n\n\n vhost_traffic_status_display_format html;\n\n\n\n\n\n\nNGINX vts dashboard\n\u00b6\n\n\nThe vts dashboard provides real time metrics. \n\n\n\n\nBecause the vts port it's not yet exposed, you should forward the controller port to see it.\n\n\n$\n kubectl port-forward \n$(\nkubectl get pods --selector\n=\nk8s-app\n=\nnginx-ingress-controller -n ingress-nginx --output\n=\njsonpath\n={\n.items..metadata.name\n}\n)\n -n ingress-nginx \n18080\n\n\n\n\n\n\nNow open the url \nhttp://localhost:18080/nginx_status\n in your browser.\n\n\nPrometheus metrics output\n\u00b6\n\n\nNGINX Ingress controller already has a parser to convert vts metrics to Prometheus format. It exports prometheus metrics to the address \n:10254/metrics\n.\n\n\n$\n kubectl \nexec\n -ti -n ingress-nginx \n$(\nkubectl get pods --selector\n=\nk8s-app\n=\nnginx-ingress-controller -n kube-system --output\n=\njsonpath\n={\n.items..metadata.name\n}\n)\n curl localhost:10254/metrics\n\ningress_controller_ssl_expire_time_seconds{host=\"foo.bar.com\"} -6.21355968e+10\n\n\n#\n HELP ingress_controller_success Cumulative number of Ingress controller reload operations\n\n#\n TYPE ingress_controller_success counter\n\ningress_controller_success{count=\"reloads\"} 3\n\n\n#\n HELP nginx_bytes_total Nginx bytes count\n\n#\n TYPE nginx_bytes_total counter\n\nnginx_bytes_total{direction=\"in\",ingress_class=\"nginx\",namespace=\"\",server_zone=\"*\"} 3708\n\n\nnginx_bytes_total{direction=\"in\",ingress_class=\"nginx\",namespace=\"\",server_zone=\"_\"} 3708\n\n\nnginx_bytes_total{direction=\"out\",ingress_class=\"nginx\",namespace=\"\",server_zone=\"*\"} 5256\n\n\nnginx_bytes_total{direction=\"out\",ingress_class=\"nginx\",namespace=\"\",server_zone=\"_\"} 5256\n\n\n\n\n\n\nCustomize metrics\n\u00b6\n\n\nThe default \nvts vhost key\n is \n$geoip_country_code country::*\n that expose metrics grouped by server and country code. The example below show how to have metrics grouped by server and server path.\n\n\n\n\nNGINX custom configuration ( http level )\n\u00b6\n\n\n apiVersion: v1\n kind: ConfigMap\n data:\n enable-vts-status: \"true\"\n vts-default-filter-key: \"$server_name\"\n...\n\n\n\n\n\nCustomize ingress\n\u00b6\n\n\n apiVersion: extensions/v1beta1\n kind: Ingress\n metadata:\n annotations:\n nginx.ingress.kubernetes.io/vts-filter-key: $uri $server_name\n name: ingress\n\n\n\n\n\nResult\n\u00b6", + "title": "Deploying the Nginx Ingress controller" + }, + { + "location": "/examples/customization/custom-vts-metrics-prometheus/README/#deploying-the-nginx-ingress-controller", + "text": "This example aims to demonstrate the deployment of an nginx ingress controller and use a ConfigMap to enable nginx vts module to export metrics in prometheus format.", + "title": "Deploying the Nginx Ingress controller" + }, + { + "location": "/examples/customization/custom-vts-metrics-prometheus/README/#vts-metrics", + "text": "Vts-metrics export NGINX metrics. To deploy all the files simply run kubectl apply -f nginx . A deployment and service will be\ncreated which already has a prometheus.io/scrape: 'true' annotation and if you added\nthe recommended Prometheus service-endpoint scraping configuration ,\nPrometheus will scrape it automatically and you start using the generated metrics right away.", + "title": "vts-metrics" + }, + { + "location": "/examples/customization/custom-vts-metrics-prometheus/README/#custom-configuration", + "text": "apiVersion: v1 data: enable-vts-status: \"true\" kind: ConfigMap metadata: name: nginx-configuration namespace: ingress-nginx labels: app: ingress-nginx $ kubectl apply -f nginx-vts-metrics-conf.yaml", + "title": "Custom configuration" + }, + { + "location": "/examples/customization/custom-vts-metrics-prometheus/README/#result", + "text": "Check whether the ingress controller successfully generated the NGINX vts status: $ kubectl exec nginx-ingress-controller-873061567-4n3k2 -n ingress-nginx cat /etc/nginx/nginx.conf | grep vhost_traffic_status_display vhost_traffic_status_display; vhost_traffic_status_display_format html;", + "title": "Result" + }, + { + "location": "/examples/customization/custom-vts-metrics-prometheus/README/#nginx-vts-dashboard", + "text": "The vts dashboard provides real time metrics. Because the vts port it's not yet exposed, you should forward the controller port to see it. $ kubectl port-forward $( kubectl get pods --selector = k8s-app = nginx-ingress-controller -n ingress-nginx --output = jsonpath ={ .items..metadata.name } ) -n ingress-nginx 18080 Now open the url http://localhost:18080/nginx_status in your browser.", + "title": "NGINX vts dashboard" + }, + { + "location": "/examples/customization/custom-vts-metrics-prometheus/README/#prometheus-metrics-output", + "text": "NGINX Ingress controller already has a parser to convert vts metrics to Prometheus format. It exports prometheus metrics to the address :10254/metrics . $ kubectl exec -ti -n ingress-nginx $( kubectl get pods --selector = k8s-app = nginx-ingress-controller -n kube-system --output = jsonpath ={ .items..metadata.name } ) curl localhost:10254/metrics ingress_controller_ssl_expire_time_seconds{host=\"foo.bar.com\"} -6.21355968e+10 # HELP ingress_controller_success Cumulative number of Ingress controller reload operations # TYPE ingress_controller_success counter ingress_controller_success{count=\"reloads\"} 3 # HELP nginx_bytes_total Nginx bytes count # TYPE nginx_bytes_total counter nginx_bytes_total{direction=\"in\",ingress_class=\"nginx\",namespace=\"\",server_zone=\"*\"} 3708 nginx_bytes_total{direction=\"in\",ingress_class=\"nginx\",namespace=\"\",server_zone=\"_\"} 3708 nginx_bytes_total{direction=\"out\",ingress_class=\"nginx\",namespace=\"\",server_zone=\"*\"} 5256 nginx_bytes_total{direction=\"out\",ingress_class=\"nginx\",namespace=\"\",server_zone=\"_\"} 5256", + "title": "Prometheus metrics output" + }, + { + "location": "/examples/customization/custom-vts-metrics-prometheus/README/#customize-metrics", + "text": "The default vts vhost key is $geoip_country_code country::* that expose metrics grouped by server and country code. The example below show how to have metrics grouped by server and server path.", + "title": "Customize metrics" + }, + { + "location": "/examples/customization/custom-vts-metrics-prometheus/README/#nginx-custom-configuration-http-level", + "text": "apiVersion: v1\n kind: ConfigMap\n data:\n enable-vts-status: \"true\"\n vts-default-filter-key: \"$server_name\"\n...", + "title": "NGINX custom configuration ( http level )" + }, + { + "location": "/examples/customization/custom-vts-metrics-prometheus/README/#customize-ingress", + "text": "apiVersion: extensions/v1beta1\n kind: Ingress\n metadata:\n annotations:\n nginx.ingress.kubernetes.io/vts-filter-key: $uri $server_name\n name: ingress", + "title": "Customize ingress" + }, + { + "location": "/examples/customization/custom-vts-metrics-prometheus/README/#result_1", + "text": "", + "title": "Result" + }, + { + "location": "/examples/customization/external-auth-headers/README/", + "text": "External authentication, authentication service response headers propagation\n\u00b6\n\n\nThis example demonstrates propagation of selected authentication service response headers\nto backend service.\n\n\nSample configuration includes:\n\n\n\n\nSample authentication service producing several response headers\n\n\nAuthentication logic is based on HTTP header: requests with header \nUser\n containing string \ninternal\n are considered authenticated\n\n\nAfter successful authentication service generates response headers \nUserID\n and \nUserRole\n\n\nSample echo service displaying header information\n\n\nTwo ingress objects pointing to echo service\n\n\nPublic, which allows access from unauthenticated users\n\n\nPrivate, which allows access from authenticated users only\n\n\n\n\nYou can deploy the controller as\nfollows:\n\n\n$\n kubectl create -f deploy/\n\ndeployment \"demo-auth-service\" created\n\n\nservice \"demo-auth-service\" created\n\n\ningress \"demo-auth-service\" created\n\n\ndeployment \"demo-echo-service\" created\n\n\nservice \"demo-echo-service\" created\n\n\ningress \"public-demo-echo-service\" created\n\n\ningress \"secure-demo-echo-service\" created\n\n\n\n$\n kubectl get po\n\nNAME READY STATUS RESTARTS AGE\n\n\nNAME READY STATUS RESTARTS AGE\n\n\ndemo-auth-service-2769076528-7g9mh 1/1 Running 0 30s\n\n\ndemo-echo-service-3636052215-3vw8c 1/1 Running 0 29s\n\n\n\nkubectl get ing\n\n\nNAME HOSTS ADDRESS PORTS AGE\n\n\npublic-demo-echo-service public-demo-echo-service.kube.local 80 1m\n\n\nsecure-demo-echo-service secure-demo-echo-service.kube.local 80 1m\n\n\n\n\n\n\nTest 1: public service with no auth header\n\n\n$\n curl -H \n'Host: public-demo-echo-service.kube.local'\n -v \n192\n.168.99.100\n\n* Rebuilt URL to: 192.168.99.100/\n\n\n* Trying 192.168.99.100...\n\n\n* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: public-demo-echo-service.kube.local\n\n>\n User-Agent: curl/7.43.0\n\n>\n Accept: */*\n\n>\n\n\n< HTTP/1.1 200 OK\n\n\n< Server: nginx/1.11.10\n\n\n< Date: Mon, 13 Mar 2017 20:19:21 GMT\n\n\n< Content-Type: text/plain; charset=utf-8\n\n\n< Content-Length: 20\n\n\n< Connection: keep-alive\n\n\n<\n\n\n* Connection #0 to host 192.168.99.100 left intact\n\n\nUserID: , UserRole:\n\n\n\n\n\n\nTest 2: secure service with no auth header\n\n\n$\n curl -H \n'Host: secure-demo-echo-service.kube.local'\n -v \n192\n.168.99.100\n\n* Rebuilt URL to: 192.168.99.100/\n\n\n* Trying 192.168.99.100...\n\n\n* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: secure-demo-echo-service.kube.local\n\n>\n User-Agent: curl/7.43.0\n\n>\n Accept: */*\n\n>\n\n\n< HTTP/1.1 403 Forbidden\n\n\n< Server: nginx/1.11.10\n\n\n< Date: Mon, 13 Mar 2017 20:18:48 GMT\n\n\n< Content-Type: text/html\n\n\n< Content-Length: 170\n\n\n< Connection: keep-alive\n\n\n<\n\n\n\n\n\n403 Forbidden\n\n\n\n\n\n

403 Forbidden

\n\n\n
nginx/1.11.10
\n\n\n\n\n\n\n\n\n* Connection #0 to host 192.168.99.100 left intact\n\n\n\n\n\n\nTest 3: public service with valid auth header\n\n\n$\n curl -H \n'Host: public-demo-echo-service.kube.local'\n -H \n'User:internal'\n -v \n192\n.168.99.100\n\n* Rebuilt URL to: 192.168.99.100/\n\n\n* Trying 192.168.99.100...\n\n\n* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: public-demo-echo-service.kube.local\n\n>\n User-Agent: curl/7.43.0\n\n>\n Accept: */*\n\n>\n User:internal\n\n>\n\n\n< HTTP/1.1 200 OK\n\n\n< Server: nginx/1.11.10\n\n\n< Date: Mon, 13 Mar 2017 20:19:59 GMT\n\n\n< Content-Type: text/plain; charset=utf-8\n\n\n< Content-Length: 44\n\n\n< Connection: keep-alive\n\n\n<\n\n\n* Connection #0 to host 192.168.99.100 left intact\n\n\nUserID: 1443635317331776148, UserRole: admin\n\n\n\n\n\n\nTest 4: public service with valid auth header\n\n\n$\n curl -H \n'Host: secure-demo-echo-service.kube.local'\n -H \n'User:internal'\n -v \n192\n.168.99.100\n\n* Rebuilt URL to: 192.168.99.100/\n\n\n* Trying 192.168.99.100...\n\n\n* Connected to 192.168.99.100 (192.168.99.100) port 80 (#0)\n\n\n>\n GET / HTTP/1.1\n\n>\n Host: secure-demo-echo-service.kube.local\n\n>\n User-Agent: curl/7.43.0\n\n>\n Accept: */*\n\n>\n User:internal\n\n>\n\n\n< HTTP/1.1 200 OK\n\n\n< Server: nginx/1.11.10\n\n\n< Date: Mon, 13 Mar 2017 20:17:23 GMT\n\n\n< Content-Type: text/plain; charset=utf-8\n\n\n< Content-Length: 43\n\n\n< Connection: keep-alive\n\n\n<\n\n\n* Connection #0 to host 192.168.99.100 left intact\n\n\nUserID: 605394647632969758, UserRole: admin", + "title": "External authentication, authentication service response headers propagation" + }, + { + "location": "/examples/customization/external-auth-headers/README/#external-authentication-authentication-service-response-headers-propagation", + "text": "This example demonstrates propagation of selected authentication service response headers\nto backend service. Sample configuration includes: Sample authentication service producing several response headers Authentication logic is based on HTTP header: requests with header User containing string internal are considered authenticated After successful authentication service generates response headers UserID and UserRole Sample echo service displaying header information Two ingress objects pointing to echo service Public, which allows access from unauthenticated users Private, which allows access from authenticated users only You can deploy the controller as\nfollows: $ kubectl create -f deploy/ deployment \"demo-auth-service\" created service \"demo-auth-service\" created ingress \"demo-auth-service\" created deployment \"demo-echo-service\" created service \"demo-echo-service\" created ingress \"public-demo-echo-service\" created ingress \"secure-demo-echo-service\" created $ kubectl get po NAME READY STATUS RESTARTS AGE NAME READY STATUS RESTARTS AGE demo-auth-service-2769076528-7g9mh 1/1 Running 0 30s demo-echo-service-3636052215-3vw8c 1/1 Running 0 29s kubectl get ing NAME HOSTS ADDRESS PORTS AGE public-demo-echo-service public-demo-echo-service.kube.local 80 1m secure-demo-echo-service secure-demo-echo-service.kube.local 80 1m Test 1: public service with no auth header $ curl -H 'Host: public-demo-echo-service.kube.local' -v 192 .168.99.100 * Rebuilt URL to: 192.168.99.100/ * Trying 192.168.99.100... * Connected to 192.168.99.100 (192.168.99.100) port 80 (#0) > GET / HTTP/1.1 > Host: public-demo-echo-service.kube.local > User-Agent: curl/7.43.0 > Accept: */* > < HTTP/1.1 200 OK < Server: nginx/1.11.10 < Date: Mon, 13 Mar 2017 20:19:21 GMT < Content-Type: text/plain; charset=utf-8 < Content-Length: 20 < Connection: keep-alive < * Connection #0 to host 192.168.99.100 left intact UserID: , UserRole: Test 2: secure service with no auth header $ curl -H 'Host: secure-demo-echo-service.kube.local' -v 192 .168.99.100 * Rebuilt URL to: 192.168.99.100/ * Trying 192.168.99.100... * Connected to 192.168.99.100 (192.168.99.100) port 80 (#0) > GET / HTTP/1.1 > Host: secure-demo-echo-service.kube.local > User-Agent: curl/7.43.0 > Accept: */* > < HTTP/1.1 403 Forbidden < Server: nginx/1.11.10 < Date: Mon, 13 Mar 2017 20:18:48 GMT < Content-Type: text/html < Content-Length: 170 < Connection: keep-alive < 403 Forbidden

403 Forbidden


nginx/1.11.10
* Connection #0 to host 192.168.99.100 left intact Test 3: public service with valid auth header $ curl -H 'Host: public-demo-echo-service.kube.local' -H 'User:internal' -v 192 .168.99.100 * Rebuilt URL to: 192.168.99.100/ * Trying 192.168.99.100... * Connected to 192.168.99.100 (192.168.99.100) port 80 (#0) > GET / HTTP/1.1 > Host: public-demo-echo-service.kube.local > User-Agent: curl/7.43.0 > Accept: */* > User:internal > < HTTP/1.1 200 OK < Server: nginx/1.11.10 < Date: Mon, 13 Mar 2017 20:19:59 GMT < Content-Type: text/plain; charset=utf-8 < Content-Length: 44 < Connection: keep-alive < * Connection #0 to host 192.168.99.100 left intact UserID: 1443635317331776148, UserRole: admin Test 4: public service with valid auth header $ curl -H 'Host: secure-demo-echo-service.kube.local' -H 'User:internal' -v 192 .168.99.100 * Rebuilt URL to: 192.168.99.100/ * Trying 192.168.99.100... * Connected to 192.168.99.100 (192.168.99.100) port 80 (#0) > GET / HTTP/1.1 > Host: secure-demo-echo-service.kube.local > User-Agent: curl/7.43.0 > Accept: */* > User:internal > < HTTP/1.1 200 OK < Server: nginx/1.11.10 < Date: Mon, 13 Mar 2017 20:17:23 GMT < Content-Type: text/plain; charset=utf-8 < Content-Length: 43 < Connection: keep-alive < * Connection #0 to host 192.168.99.100 left intact UserID: 605394647632969758, UserRole: admin", + "title": "External authentication, authentication service response headers propagation" + }, + { + "location": "/examples/customization/ssl-dh-param/README/", + "text": "Deploying the Nginx Ingress controller\n\u00b6\n\n\nThis example aims to demonstrate the deployment of an nginx ingress controller and\nuse a ConfigMap to configure custom Diffie-Hellman parameters file to help with\n\"Perfect Forward Secrecy\".\n\n\nCustom configuration\n\u00b6\n\n\n$\n cat configmap.yaml\n\napiVersion: v1\n\n\ndata:\n\n\n ssl-dh-param: \"ingress-nginx/lb-dhparam\"\n\n\nkind: ConfigMap\n\n\nmetadata:\n\n\n name: nginx-configuration\n\n\n namespace: ingress-nginx\n\n\n labels:\n\n\n app: ingress-nginx\n\n\n\n\n\n\n$\n kubectl create -f configmap.yaml\n\n\n\n\n\nCustom DH parameters secret\n\u00b6\n\n\n$\n> openssl dhparam \n1024\n \n2\n> /dev/null \n|\n base64\n\nLS0tLS1CRUdJTiBESCBQQVJBTUVURVJ...\n\n\n\n\n\n\n$\n cat ssl-dh-param.yaml\n\napiVersion: v1\n\n\ndata:\n\n\n dhparam.pem: \"LS0tLS1CRUdJTiBESCBQQVJBTUVURVJ...\"\n\n\nkind: ConfigMap\n\n\nmetadata:\n\n\n name: nginx-configuration\n\n\n namespace: ingress-nginx\n\n\n labels:\n\n\n app: ingress-nginx\n\n\n\n\n\n\n$\n kubectl create -f ssl-dh-param.yaml\n\n\n\n\n\nTest\n\u00b6\n\n\nCheck the contents of the configmap is present in the nginx.conf file using:\n\nkubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf", + "title": "Deploying the Nginx Ingress controller" + }, + { + "location": "/examples/customization/ssl-dh-param/README/#deploying-the-nginx-ingress-controller", + "text": "This example aims to demonstrate the deployment of an nginx ingress controller and\nuse a ConfigMap to configure custom Diffie-Hellman parameters file to help with\n\"Perfect Forward Secrecy\".", + "title": "Deploying the Nginx Ingress controller" + }, + { + "location": "/examples/customization/ssl-dh-param/README/#custom-configuration", + "text": "$ cat configmap.yaml apiVersion: v1 data: ssl-dh-param: \"ingress-nginx/lb-dhparam\" kind: ConfigMap metadata: name: nginx-configuration namespace: ingress-nginx labels: app: ingress-nginx $ kubectl create -f configmap.yaml", + "title": "Custom configuration" + }, + { + "location": "/examples/customization/ssl-dh-param/README/#custom-dh-parameters-secret", + "text": "$ > openssl dhparam 1024 2 > /dev/null | base64 LS0tLS1CRUdJTiBESCBQQVJBTUVURVJ... $ cat ssl-dh-param.yaml apiVersion: v1 data: dhparam.pem: \"LS0tLS1CRUdJTiBESCBQQVJBTUVURVJ...\" kind: ConfigMap metadata: name: nginx-configuration namespace: ingress-nginx labels: app: ingress-nginx $ kubectl create -f ssl-dh-param.yaml", + "title": "Custom DH parameters secret" + }, + { + "location": "/examples/customization/ssl-dh-param/README/#test", + "text": "Check the contents of the configmap is present in the nginx.conf file using: kubectl exec nginx-ingress-controller-873061567-4n3k2 -n kube-system cat /etc/nginx/nginx.conf", + "title": "Test" + }, + { + "location": "/examples/customization/sysctl/README/", + "text": "Sysctl tuning\n\u00b6\n\n\nThis example aims to demonstrate the use of an Init Container to adjust sysctl default values\nusing \nkubectl patch\n\n\nkubectl patch deployment -n ingress-nginx nginx-ingress-controller --patch=\"$(cat patch.json)\"", + "title": "Sysctl tuning" + }, + { + "location": "/examples/customization/sysctl/README/#sysctl-tuning", + "text": "This example aims to demonstrate the use of an Init Container to adjust sysctl default values\nusing kubectl patch kubectl patch deployment -n ingress-nginx nginx-ingress-controller --patch=\"$(cat patch.json)\"", + "title": "Sysctl tuning" + }, + { + "location": "/examples/docker-registry/README/", + "text": "Docker registry\n\u00b6\n\n\nThis example demonstrates how to deploy a \ndocker registry\n in the cluster and configure Ingress enable access from Internet\n\n\nDeployment\n\u00b6\n\n\nFirst we deploy the docker registry in the cluster:\n\n\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/deployment.yaml\n\n\n\n\n\n\nImportant:\n DO NOT RUN THIS IN PRODUCTION.\nThis deployment uses \nemptyDir\n in the \nvolumeMount\n which means the contents of the registry will be deleted when the pod dies.\n\n\nThe next required step is creation of the ingress rules. To do this we have two options: with and without TLS\n\n\nWithout TLS\n\u00b6\n\n\nDownload and edit the yaml deployment replacing \nregistry.\n with a valid DNS name pointing to the ingress controller:\n\n\nwget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/ingress-without-tls.yaml\n\n\n\n\n\n\nImportant:\n running a docker registry without TLS requires we configure our local docker daemon with the insecure registry flag.\nPlease check \ndeploy a plain http registry\n\n\nWith TLS\n\u00b6\n\n\nDownload and edit the yaml deployment replacing \nregistry.\n with a valid DNS name pointing to the ingress controller:\n\n\nwget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/ingress-with-tls.yaml\n\n\n\n\n\n\nDeploy \nkube lego\n use \nLet's Encrypt\n certificates or edit the ingress rule to use a secret with an existing SSL certificate.\n\n\nTesting\n\u00b6\n\n\nTo test the registry is working correctly we download a known image from \ndocker hub\n, create a tag pointing to the new registry and upload the image:\n\n\ndocker pull ubuntu:16.04\n\n\ndocker tag ubuntu:16.04 `registry./ubuntu:16.04`\n\n\ndocker push `registry./ubuntu:16.04`\n\n\n\n\n\n\nPlease replace \nregistry.\n with your domain.", + "title": "Docker registry" + }, + { + "location": "/examples/docker-registry/README/#docker-registry", + "text": "This example demonstrates how to deploy a docker registry in the cluster and configure Ingress enable access from Internet", + "title": "Docker registry" + }, + { + "location": "/examples/docker-registry/README/#deployment", + "text": "First we deploy the docker registry in the cluster: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/deployment.yaml Important: DO NOT RUN THIS IN PRODUCTION.\nThis deployment uses emptyDir in the volumeMount which means the contents of the registry will be deleted when the pod dies. The next required step is creation of the ingress rules. To do this we have two options: with and without TLS", + "title": "Deployment" + }, + { + "location": "/examples/docker-registry/README/#without-tls", + "text": "Download and edit the yaml deployment replacing registry. with a valid DNS name pointing to the ingress controller: wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/ingress-without-tls.yaml Important: running a docker registry without TLS requires we configure our local docker daemon with the insecure registry flag.\nPlease check deploy a plain http registry", + "title": "Without TLS" + }, + { + "location": "/examples/docker-registry/README/#with-tls", + "text": "Download and edit the yaml deployment replacing registry. with a valid DNS name pointing to the ingress controller: wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/docs/examples/docker-registry/ingress-with-tls.yaml Deploy kube lego use Let's Encrypt certificates or edit the ingress rule to use a secret with an existing SSL certificate.", + "title": "With TLS" + }, + { + "location": "/examples/docker-registry/README/#testing", + "text": "To test the registry is working correctly we download a known image from docker hub , create a tag pointing to the new registry and upload the image: docker pull ubuntu:16.04 docker tag ubuntu:16.04 `registry./ubuntu:16.04` docker push `registry./ubuntu:16.04` Please replace registry. with your domain.", + "title": "Testing" + }, + { + "location": "/examples/external-auth/README/", + "text": "External Authentication\n\u00b6\n\n\nOverview\n\u00b6\n\n\nThe \nauth-url\n and \nauth-signin\n annotations allow you to use an external\nauthentication provider to protect your Ingress resources.\n\n\n(Note, this annotation requires \nnginx-ingress-controller v0.9.0\n or greater.)\n\n\nKey Detail\n\u00b6\n\n\nThis functionality is enabled by deploying multiple Ingress objects for a single host.\nOne Ingress object has no special annotations and handles authentication.\n\n\nOther Ingress objects can then be annotated in such a way that require the user to\nauthenticate against the first Ingress's endpoint, and can redirect \n401\ns to the\nsame endpoint.\n\n\nSample:\n\n\n...\n\n\nmetadata\n:\n\n \nname\n:\n \napplication\n\n \nannotations\n:\n\n \n\"nginx.ingress.kubernetes.io/auth-url\"\n:\n \n\"https://$host/oauth2/auth\"\n\n \n\"nginx.ingress.kubernetes.io/auth-signin\"\n:\n \n\"https://$host/oauth2/sign_in\"\n\n\n...\n\n\n\n\n\n\nExample: OAuth2 Proxy + Kubernetes-Dashboard\n\u00b6\n\n\nThis example will show you how to deploy \noauth2_proxy\n\ninto a Kubernetes cluster and use it to protect the Kubernetes Dashboard using github as oAuth2 provider\n\n\nPrepare\n\u00b6\n\n\n\n\nInstall the kubernetes dashboard\n\n\n\n\nkubectl create -f https://raw.githubusercontent.com/kubernetes/kops/master/addons/kubernetes-dashboard/v1.5.0.yaml\n\n\n\n\n\n\n\n\nCreate a custom Github OAuth application https://github.com/settings/applications/new\n\n\n\n\n\n\n\n\nHomepage URL is the FQDN in the Ingress rule, like \nhttps://foo.bar.com\n\n\nAuthorization callback URL is the same as the base FQDN plus \n/oauth2\n, like \nhttps://foo.bar.com/oauth2\n\n\n\n\n\n\n\n\n\n\nConfigure oauth2_proxy values in the file oauth2-proxy.yaml with the values:\n\n\n\n\n\n\nOAUTH2_PROXY_CLIENT_ID with the github \n\n\n\n\n\nOAUTH2_PROXY_CLIENT_SECRET with the github \n\n\n\n\n\nOAUTH2_PROXY_COOKIE_SECRET with value of \npython\n \n-\nc\n \n'import os,base64; print base64.b64encode(os.urandom(16))'\n \n\n\n\n\n\n\nCustomize the contents of the file dashboard-ingress.yaml:\n\n\n\n\n\n\nReplace \n__INGRESS_HOST__\n with a valid FQDN and \n__INGRESS_SECRET__\n with a Secret with a valid SSL certificate.\n\n\n\n\nDeploy the oauth2 proxy and the ingress rules running:\n\n\n\n\n$\n kubectl create -f oauth2-proxy.yaml,dashboard-ingress.yaml\n\n\n\n\n\nTest the oauth integration accessing the configured URL, like \nhttps://foo.bar.com", + "title": "External Authentication" + }, + { + "location": "/examples/external-auth/README/#external-authentication", + "text": "", + "title": "External Authentication" + }, + { + "location": "/examples/external-auth/README/#overview", + "text": "The auth-url and auth-signin annotations allow you to use an external\nauthentication provider to protect your Ingress resources. (Note, this annotation requires nginx-ingress-controller v0.9.0 or greater.)", + "title": "Overview" + }, + { + "location": "/examples/external-auth/README/#key-detail", + "text": "This functionality is enabled by deploying multiple Ingress objects for a single host.\nOne Ingress object has no special annotations and handles authentication. Other Ingress objects can then be annotated in such a way that require the user to\nauthenticate against the first Ingress's endpoint, and can redirect 401 s to the\nsame endpoint. Sample: ... metadata : \n name : application \n annotations : \n \"nginx.ingress.kubernetes.io/auth-url\" : \"https://$host/oauth2/auth\" \n \"nginx.ingress.kubernetes.io/auth-signin\" : \"https://$host/oauth2/sign_in\" ...", + "title": "Key Detail" + }, + { + "location": "/examples/external-auth/README/#example-oauth2-proxy-kubernetes-dashboard", + "text": "This example will show you how to deploy oauth2_proxy \ninto a Kubernetes cluster and use it to protect the Kubernetes Dashboard using github as oAuth2 provider", + "title": "Example: OAuth2 Proxy + Kubernetes-Dashboard" + }, + { + "location": "/examples/external-auth/README/#prepare", + "text": "Install the kubernetes dashboard kubectl create -f https://raw.githubusercontent.com/kubernetes/kops/master/addons/kubernetes-dashboard/v1.5.0.yaml Create a custom Github OAuth application https://github.com/settings/applications/new Homepage URL is the FQDN in the Ingress rule, like https://foo.bar.com Authorization callback URL is the same as the base FQDN plus /oauth2 , like https://foo.bar.com/oauth2 Configure oauth2_proxy values in the file oauth2-proxy.yaml with the values: OAUTH2_PROXY_CLIENT_ID with the github OAUTH2_PROXY_CLIENT_SECRET with the github OAUTH2_PROXY_COOKIE_SECRET with value of python - c 'import os,base64; print base64.b64encode(os.urandom(16))' Customize the contents of the file dashboard-ingress.yaml: Replace __INGRESS_HOST__ with a valid FQDN and __INGRESS_SECRET__ with a Secret with a valid SSL certificate. Deploy the oauth2 proxy and the ingress rules running: $ kubectl create -f oauth2-proxy.yaml,dashboard-ingress.yaml Test the oauth integration accessing the configured URL, like https://foo.bar.com", + "title": "Prepare" + }, + { + "location": "/examples/multi-tls/README/", + "text": "Multi TLS certificate termination\n\u00b6\n\n\nThis example uses 2 different certificates to terminate SSL for 2 hostnames.\n\n\n\n\nDeploy the controller by creating the rc in the parent dir\n\n\nCreate tls secrets for foo.bar.com and bar.baz.com as indicated in the yaml\n\n\nCreate multi-tls.yaml\n\n\n\n\nThis should generate a segment like:\n\n\n$\n kubectl \nexec\n -it nginx-ingress-controller-6vwd1 -- cat /etc/nginx/nginx.conf \n|\n grep \n\"foo.bar.com\"\n -B \n7\n -A \n35\n\n\n server {\n\n\n listen 80;\n\n\n listen 443 ssl http2;\n\n\n ssl_certificate /etc/nginx-ssl/default-foobar.pem;\n\n\n ssl_certificate_key /etc/nginx-ssl/default-foobar.pem;\n\n\n\n\n server_name foo.bar.com;\n\n\n\n\n if ($scheme = http) {\n\n\n return 301 https://$host$request_uri;\n\n\n }\n\n\n\n\n\n location / {\n\n\n proxy_set_header Host $host;\n\n\n\n #\n Pass Real IP\n\n proxy_set_header X-Real-IP $remote_addr;\n\n\n\n #\n Allow websocket connections\n\n proxy_set_header Upgrade $http_upgrade;\n\n\n proxy_set_header Connection $connection_upgrade;\n\n\n\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n\n\n proxy_set_header X-Forwarded-Host $host;\n\n\n proxy_set_header X-Forwarded-Proto $pass_access_scheme;\n\n\n\n proxy_connect_timeout 5s;\n\n\n proxy_send_timeout 60s;\n\n\n proxy_read_timeout 60s;\n\n\n\n proxy_redirect off;\n\n\n proxy_buffering off;\n\n\n\n proxy_http_version 1.1;\n\n\n\n proxy_pass http://default-http-svc-80;\n\n\n }\n\n\n\n\n\n\nAnd you should be able to reach your nginx service or http-svc service using a hostname switch:\n\n\n$\n kubectl get ing\n\nNAME RULE BACKEND ADDRESS AGE\n\n\nfoo-tls - 104.154.30.67 13m\n\n\n foo.bar.com\n\n\n / http-svc:80\n\n\n bar.baz.com\n\n\n / nginx:80\n\n\n\n$\n curl https://104.154.30.67 -H \n'Host:foo.bar.com'\n -k\n\nCLIENT VALUES:\n\n\nclient_address=10.245.0.6\n\n\ncommand=GET\n\n\nreal path=/\n\n\nquery=nil\n\n\nrequest_version=1.1\n\n\nrequest_uri=http://foo.bar.com:8080/\n\n\n\nSERVER VALUES:\n\n\nserver_version=nginx: 1.9.11 - lua: 10001\n\n\n\nHEADERS RECEIVED:\n\n\naccept=*/*\n\n\nconnection=close\n\n\nhost=foo.bar.com\n\n\nuser-agent=curl/7.35.0\n\n\nx-forwarded-for=10.245.0.1\n\n\nx-forwarded-host=foo.bar.com\n\n\nx-forwarded-proto=https\n\n\n\n$\n curl https://104.154.30.67 -H \n'Host:bar.baz.com'\n -k\n\n\n\n\n\n\n\n\n\n\nWelcome to nginx on Debian!\n\n\n\n$\n curl \n104\n.154.30.67\n\ndefault backend - 404", + "title": "Multi TLS certificate termination" + }, + { + "location": "/examples/multi-tls/README/#multi-tls-certificate-termination", + "text": "This example uses 2 different certificates to terminate SSL for 2 hostnames. Deploy the controller by creating the rc in the parent dir Create tls secrets for foo.bar.com and bar.baz.com as indicated in the yaml Create multi-tls.yaml This should generate a segment like: $ kubectl exec -it nginx-ingress-controller-6vwd1 -- cat /etc/nginx/nginx.conf | grep \"foo.bar.com\" -B 7 -A 35 server { listen 80; listen 443 ssl http2; ssl_certificate /etc/nginx-ssl/default-foobar.pem; ssl_certificate_key /etc/nginx-ssl/default-foobar.pem; server_name foo.bar.com; if ($scheme = http) { return 301 https://$host$request_uri; } location / { proxy_set_header Host $host; # Pass Real IP proxy_set_header X-Real-IP $remote_addr; # Allow websocket connections proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Proto $pass_access_scheme; proxy_connect_timeout 5s; proxy_send_timeout 60s; proxy_read_timeout 60s; proxy_redirect off; proxy_buffering off; proxy_http_version 1.1; proxy_pass http://default-http-svc-80; } And you should be able to reach your nginx service or http-svc service using a hostname switch: $ kubectl get ing NAME RULE BACKEND ADDRESS AGE foo-tls - 104.154.30.67 13m foo.bar.com / http-svc:80 bar.baz.com / nginx:80 $ curl https://104.154.30.67 -H 'Host:foo.bar.com' -k CLIENT VALUES: client_address=10.245.0.6 command=GET real path=/ query=nil request_version=1.1 request_uri=http://foo.bar.com:8080/ SERVER VALUES: server_version=nginx: 1.9.11 - lua: 10001 HEADERS RECEIVED: accept=*/* connection=close host=foo.bar.com user-agent=curl/7.35.0 x-forwarded-for=10.245.0.1 x-forwarded-host=foo.bar.com x-forwarded-proto=https $ curl https://104.154.30.67 -H 'Host:bar.baz.com' -k Welcome to nginx on Debian! $ curl 104 .154.30.67 default backend - 404", + "title": "Multi TLS certificate termination" + }, + { + "location": "/examples/rewrite/README/", + "text": "Rewrite\n\u00b6\n\n\nThis example demonstrates how to use the Rewrite annotations\n\n\nPrerequisites\n\u00b6\n\n\nYou will need to make sure your Ingress targets exactly one Ingress\ncontroller by specifying the \ningress.class annotation\n,\nand that you have an ingress controller \nrunning\n in your cluster.\n\n\nDeployment\n\u00b6\n\n\nRewriting can be controlled using the following annotations:\n\n\n\n\n\n\n\n\nName\n\n\nDescription\n\n\nValues\n\n\n\n\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/rewrite-target\n\n\nTarget URI where the traffic must be redirected\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/add-base-url\n\n\nindicates if is required to add a base tag in the head of the responses from the upstream servers\n\n\nbool\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/base-url-scheme\n\n\nOverride for the scheme passed to the base tag\n\n\nstring\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/ssl-redirect\n\n\nIndicates if the location section is accessible SSL only (defaults to True when Ingress contains a Certificate)\n\n\nbool\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/force-ssl-redirect\n\n\nForces the redirection to HTTPS even if the Ingress is not TLS Enabled\n\n\nbool\n\n\n\n\n\n\nnginx.ingress.kubernetes.io/app-root\n\n\nDefines the Application Root that the Controller must redirect if it's in '/' context\n\n\nstring\n\n\n\n\n\n\n\n\nValidation\n\u00b6\n\n\nRewrite Target\n\u00b6\n\n\nCreate an Ingress rule with a rewrite annotation:\n\n\n$\n \necho\n \n\"\n\n\napiVersion: extensions/v1beta1\n\n\nkind: Ingress\n\n\nmetadata:\n\n\n annotations:\n\n\n nginx.ingress.kubernetes.io/rewrite-target: /\n\n\n name: rewrite\n\n\n namespace: default\n\n\nspec:\n\n\n rules:\n\n\n - host: rewrite.bar.com\n\n\n http:\n\n\n paths:\n\n\n - backend:\n\n\n serviceName: http-svc\n\n\n servicePort: 80\n\n\n path: /something\n\n\n\" | kubectl create -f -\n\n\n\n\n\n\nCheck the rewrite is working\n\n\n$ curl -v http://172.17.4.99/something -H \n'Host: rewrite.bar.com'\n\n* Trying \n172\n.17.4.99...\n* Connected to \n172\n.17.4.99 \n(\n172\n.17.4.99\n)\n port \n80\n \n(\n#0)\n\n> GET /something HTTP/1.1\n> Host: rewrite.bar.com\n> User-Agent: curl/7.43.0\n> Accept: */*\n>\n< HTTP/1.1 \n200\n OK\n< Server: nginx/1.11.0\n< Date: Tue, \n31\n May \n2016\n \n16\n:07:31 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n<\nCLIENT VALUES:\n\nclient_address\n=\n10\n.2.56.9\n\ncommand\n=\nGET\nreal \npath\n=\n/\n\nquery\n=\nnil\n\nrequest_version\n=\n1\n.1\n\nrequest_uri\n=\nhttp://rewrite.bar.com:8080/\n\nSERVER VALUES:\n\nserver_version\n=\nnginx: \n1\n.9.11 - lua: \n10001\n\n\nHEADERS RECEIVED:\n\naccept\n=\n*/*\n\nconnection\n=\nclose\n\nhost\n=\nrewrite.bar.com\nuser-agent\n=\ncurl/7.43.0\nx-forwarded-for\n=\n10\n.2.56.1\nx-forwarded-host\n=\nrewrite.bar.com\nx-forwarded-port\n=\n80\n\nx-forwarded-proto\n=\nhttp\nx-real-ip\n=\n10\n.2.56.1\nBODY:\n* Connection \n#0 to host 172.17.4.99 left intact\n\n-no body in request-\n\n\n\n\n\nApp Root\n\u00b6\n\n\nCreate an Ingress rule with a app-root annotation:\n\n\n$ \necho\n \n\"\n\n\napiVersion: extensions/v1beta1\n\n\nkind: Ingress\n\n\nmetadata:\n\n\n annotations:\n\n\n nginx.ingress.kubernetes.io/app-root: /app1\n\n\n name: approot\n\n\n namespace: default\n\n\nspec:\n\n\n rules:\n\n\n - host: approot.bar.com\n\n\n http:\n\n\n paths:\n\n\n - backend:\n\n\n serviceName: http-svc\n\n\n servicePort: 80\n\n\n path: /\n\n\n\"\n \n|\n kubectl create -f -\n\n\n\n\n\nCheck the rewrite is working\n\n\n$ curl -I -k http://approot.bar.com/\nHTTP/1.1 \n302\n Moved Temporarily\nServer: nginx/1.11.10\nDate: Mon, \n13\n Mar \n2017\n \n14\n:57:15 GMT\nContent-Type: text/html\nContent-Length: \n162\n\nLocation: http://stickyingress.example.com/app1\nConnection: keep-alive", + "title": "Rewrite" + }, + { + "location": "/examples/rewrite/README/#rewrite", + "text": "This example demonstrates how to use the Rewrite annotations", + "title": "Rewrite" + }, + { + "location": "/examples/rewrite/README/#prerequisites", + "text": "You will need to make sure your Ingress targets exactly one Ingress\ncontroller by specifying the ingress.class annotation ,\nand that you have an ingress controller running in your cluster.", + "title": "Prerequisites" + }, + { + "location": "/examples/rewrite/README/#deployment", + "text": "Rewriting can be controlled using the following annotations: Name Description Values nginx.ingress.kubernetes.io/rewrite-target Target URI where the traffic must be redirected string nginx.ingress.kubernetes.io/add-base-url indicates if is required to add a base tag in the head of the responses from the upstream servers bool nginx.ingress.kubernetes.io/base-url-scheme Override for the scheme passed to the base tag string nginx.ingress.kubernetes.io/ssl-redirect Indicates if the location section is accessible SSL only (defaults to True when Ingress contains a Certificate) bool nginx.ingress.kubernetes.io/force-ssl-redirect Forces the redirection to HTTPS even if the Ingress is not TLS Enabled bool nginx.ingress.kubernetes.io/app-root Defines the Application Root that the Controller must redirect if it's in '/' context string", + "title": "Deployment" + }, + { + "location": "/examples/rewrite/README/#validation", + "text": "", + "title": "Validation" + }, + { + "location": "/examples/rewrite/README/#rewrite-target", + "text": "Create an Ingress rule with a rewrite annotation: $ echo \" apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/rewrite-target: / name: rewrite namespace: default spec: rules: - host: rewrite.bar.com http: paths: - backend: serviceName: http-svc servicePort: 80 path: /something \" | kubectl create -f - Check the rewrite is working $ curl -v http://172.17.4.99/something -H 'Host: rewrite.bar.com' \n* Trying 172 .17.4.99...\n* Connected to 172 .17.4.99 ( 172 .17.4.99 ) port 80 ( #0) \n> GET /something HTTP/1.1\n> Host: rewrite.bar.com\n> User-Agent: curl/7.43.0\n> Accept: */*\n>\n< HTTP/1.1 200 OK\n< Server: nginx/1.11.0\n< Date: Tue, 31 May 2016 16 :07:31 GMT\n< Content-Type: text/plain\n< Transfer-Encoding: chunked\n< Connection: keep-alive\n<\nCLIENT VALUES: client_address = 10 .2.56.9 command = GET\nreal path = / query = nil request_version = 1 .1 request_uri = http://rewrite.bar.com:8080/\n\nSERVER VALUES: server_version = nginx: 1 .9.11 - lua: 10001 \n\nHEADERS RECEIVED: accept = */* connection = close host = rewrite.bar.com\nuser-agent = curl/7.43.0\nx-forwarded-for = 10 .2.56.1\nx-forwarded-host = rewrite.bar.com\nx-forwarded-port = 80 \nx-forwarded-proto = http\nx-real-ip = 10 .2.56.1\nBODY:\n* Connection #0 to host 172.17.4.99 left intact \n-no body in request-", + "title": "Rewrite Target" + }, + { + "location": "/examples/rewrite/README/#app-root", + "text": "Create an Ingress rule with a app-root annotation: $ echo \" apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/app-root: /app1 name: approot namespace: default spec: rules: - host: approot.bar.com http: paths: - backend: serviceName: http-svc servicePort: 80 path: / \" | kubectl create -f - Check the rewrite is working $ curl -I -k http://approot.bar.com/\nHTTP/1.1 302 Moved Temporarily\nServer: nginx/1.11.10\nDate: Mon, 13 Mar 2017 14 :57:15 GMT\nContent-Type: text/html\nContent-Length: 162 \nLocation: http://stickyingress.example.com/app1\nConnection: keep-alive", + "title": "App Root" + }, + { + "location": "/examples/static-ip/README/", + "text": "Static IPs\n\u00b6\n\n\nThis example demonstrates how to assign a static-ip to an Ingress on through the Nginx controller.\n\n\nPrerequisites\n\u00b6\n\n\nYou need a \nTLS cert\n and a \ntest HTTP service\n for this example.\nYou will also need to make sure your Ingress targets exactly one Ingress\ncontroller by specifying the \ningress.class annotation\n,\nand that you have an ingress controller \nrunning\n in your cluster.\n\n\nAcquiring an IP\n\u00b6\n\n\nSince instances of the nginx controller actually run on nodes in your cluster,\nby default nginx Ingresses will only get static IPs if your cloudprovider\nsupports static IP assignments to nodes. On GKE/GCE for example, even though\nnodes get static IPs, the IPs are not retained across upgrade.\n\n\nTo acquire a static IP for the nginx ingress controller, simply put it\nbehind a Service of \nType=LoadBalancer\n.\n\n\nFirst, create a loadbalancer Service and wait for it to acquire an IP\n\n\n$\n kubectl create -f static-ip-svc.yaml\n\nservice \"nginx-ingress-lb\" created\n\n\n\n$\n kubectl get svc nginx-ingress-lb\n\nNAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n\n\nnginx-ingress-lb 10.0.138.113 104.154.109.191 80:31457/TCP,443:32240/TCP 15m\n\n\n\n\n\n\nthen, update the ingress controller so it adopts the static IP of the Service\nby passing the \n--publish-service\n flag (the example yaml used in the next step\nalready has it set to \"nginx-ingress-lb\").\n\n\n$\n kubectl create -f nginx-ingress-controller.yaml\n\ndeployment \"nginx-ingress-controller\" created\n\n\n\n\n\n\nAssigning the IP to an Ingress\n\u00b6\n\n\nFrom here on every Ingress created with the \ningress.class\n annotation set to\n\nnginx\n will get the IP allocated in the previous step\n\n\n$\n kubectl create -f nginx-ingress.yaml\n\ningress \"nginx-ingress\" created\n\n\n\n$\n kubectl get ing nginx-ingress\n\nNAME HOSTS ADDRESS PORTS AGE\n\n\nnginx-ingress * 104.154.109.191 80, 443 13m\n\n\n\n$\n curl \n104\n.154.109.191 -kL\n\nCLIENT VALUES:\n\n\nclient_address=10.180.1.25\n\n\ncommand=GET\n\n\nreal path=/\n\n\nquery=nil\n\n\nrequest_version=1.1\n\n\nrequest_uri=http://104.154.109.191:8080/\n\n\n...\n\n\n\n\n\n\nRetaining the IP\n\u00b6\n\n\nYou can test retention by deleting the Ingress\n\n\n$\n kubectl delete ing nginx-ingress\n\ningress \"nginx-ingress\" deleted\n\n\n\n$\n kubectl create -f nginx-ingress.yaml\n\ningress \"nginx-ingress\" created\n\n\n\n$\n kubectl get ing nginx-ingress\n\nNAME HOSTS ADDRESS PORTS AGE\n\n\nnginx-ingress * 104.154.109.191 80, 443 13m\n\n\n\n\n\n\nNote that unlike the GCE Ingress, the same loadbalancer IP is shared amongst all\nIngresses, because all requests are proxied through the same set of nginx\ncontrollers.\n\n\nPromote ephemeral to static IP\n\u00b6\n\n\nTo promote the allocated IP to static, you can update the Service manifest\n\n\n$\n kubectl patch svc nginx-ingress-lb -p \n'{\"spec\": {\"loadBalancerIP\": \"104.154.109.191\"}}'\n\n\n\"nginx-ingress-lb\" patched\n\n\n\n\n\n\nand promote the IP to static (promotion works differently for cloudproviders,\nprovided example is for GKE/GCE)\n`\n\n\n$\n gcloud compute addresses create nginx-ingress-lb --addresses \n104\n.154.109.191 --region us-central1\n\nCreated [https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb].\n\n\n---\n\n\naddress: 104.154.109.191\n\n\ncreationTimestamp: '2017-01-31T16:34:50.089-08:00'\n\n\ndescription: ''\n\n\nid: '5208037144487826373'\n\n\nkind: compute#address\n\n\nname: nginx-ingress-lb\n\n\nregion: us-central1\n\n\nselfLink: https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb\n\n\nstatus: IN_USE\n\n\nusers:\n\n\n- us-central1/forwardingRules/a09f6913ae80e11e6a8c542010af0000\n\n\n\n\n\n\nNow even if the Service is deleted, the IP will persist, so you can recreate the\nService with \nspec.loadBalancerIP\n set to \n104.154.109.191\n.", + "title": "Static IPs" + }, + { + "location": "/examples/static-ip/README/#static-ips", + "text": "This example demonstrates how to assign a static-ip to an Ingress on through the Nginx controller.", + "title": "Static IPs" + }, + { + "location": "/examples/static-ip/README/#prerequisites", + "text": "You need a TLS cert and a test HTTP service for this example.\nYou will also need to make sure your Ingress targets exactly one Ingress\ncontroller by specifying the ingress.class annotation ,\nand that you have an ingress controller running in your cluster.", + "title": "Prerequisites" + }, + { + "location": "/examples/static-ip/README/#acquiring-an-ip", + "text": "Since instances of the nginx controller actually run on nodes in your cluster,\nby default nginx Ingresses will only get static IPs if your cloudprovider\nsupports static IP assignments to nodes. On GKE/GCE for example, even though\nnodes get static IPs, the IPs are not retained across upgrade. To acquire a static IP for the nginx ingress controller, simply put it\nbehind a Service of Type=LoadBalancer . First, create a loadbalancer Service and wait for it to acquire an IP $ kubectl create -f static-ip-svc.yaml service \"nginx-ingress-lb\" created $ kubectl get svc nginx-ingress-lb NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-ingress-lb 10.0.138.113 104.154.109.191 80:31457/TCP,443:32240/TCP 15m then, update the ingress controller so it adopts the static IP of the Service\nby passing the --publish-service flag (the example yaml used in the next step\nalready has it set to \"nginx-ingress-lb\"). $ kubectl create -f nginx-ingress-controller.yaml deployment \"nginx-ingress-controller\" created", + "title": "Acquiring an IP" + }, + { + "location": "/examples/static-ip/README/#assigning-the-ip-to-an-ingress", + "text": "From here on every Ingress created with the ingress.class annotation set to nginx will get the IP allocated in the previous step $ kubectl create -f nginx-ingress.yaml ingress \"nginx-ingress\" created $ kubectl get ing nginx-ingress NAME HOSTS ADDRESS PORTS AGE nginx-ingress * 104.154.109.191 80, 443 13m $ curl 104 .154.109.191 -kL CLIENT VALUES: client_address=10.180.1.25 command=GET real path=/ query=nil request_version=1.1 request_uri=http://104.154.109.191:8080/ ...", + "title": "Assigning the IP to an Ingress" + }, + { + "location": "/examples/static-ip/README/#retaining-the-ip", + "text": "You can test retention by deleting the Ingress $ kubectl delete ing nginx-ingress ingress \"nginx-ingress\" deleted $ kubectl create -f nginx-ingress.yaml ingress \"nginx-ingress\" created $ kubectl get ing nginx-ingress NAME HOSTS ADDRESS PORTS AGE nginx-ingress * 104.154.109.191 80, 443 13m Note that unlike the GCE Ingress, the same loadbalancer IP is shared amongst all\nIngresses, because all requests are proxied through the same set of nginx\ncontrollers.", + "title": "Retaining the IP" + }, + { + "location": "/examples/static-ip/README/#promote-ephemeral-to-static-ip", + "text": "To promote the allocated IP to static, you can update the Service manifest $ kubectl patch svc nginx-ingress-lb -p '{\"spec\": {\"loadBalancerIP\": \"104.154.109.191\"}}' \"nginx-ingress-lb\" patched and promote the IP to static (promotion works differently for cloudproviders,\nprovided example is for GKE/GCE)\n` $ gcloud compute addresses create nginx-ingress-lb --addresses 104 .154.109.191 --region us-central1 Created [https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb]. --- address: 104.154.109.191 creationTimestamp: '2017-01-31T16:34:50.089-08:00' description: '' id: '5208037144487826373' kind: compute#address name: nginx-ingress-lb region: us-central1 selfLink: https://www.googleapis.com/compute/v1/projects/kubernetesdev/regions/us-central1/addresses/nginx-ingress-lb status: IN_USE users: - us-central1/forwardingRules/a09f6913ae80e11e6a8c542010af0000 Now even if the Service is deleted, the IP will persist, so you can recreate the\nService with spec.loadBalancerIP set to 104.154.109.191 .", + "title": "Promote ephemeral to static IP" + }, + { + "location": "/examples/tls-termination/README/", + "text": "TLS termination\n\u00b6\n\n\nThis example demonstrates how to terminate TLS through the nginx Ingress controller.\n\n\nPrerequisites\n\u00b6\n\n\nYou need a \nTLS cert\n and a \ntest HTTP service\n for this example.\n\n\nDeployment\n\u00b6\n\n\nThe following command instructs the controller to terminate traffic using the provided \nTLS cert, and forward un-encrypted HTTP traffic to the test HTTP service.\n\n\nkubectl apply -f ingress.yaml\n\n\n\n\n\n\nValidation\n\u00b6\n\n\nYou can confirm that the Ingress works.\n\n\n$\n kubectl describe ing nginx-test\n\nName: nginx-test\n\n\nNamespace: default\n\n\nAddress: 104.198.183.6\n\n\nDefault backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080)\n\n\nTLS:\n\n\n tls-secret terminates\n\n\nRules:\n\n\n Host Path Backends\n\n\n ---- ---- --------\n\n\n *\n\n\n http-svc:80 ()\n\n\nAnnotations:\n\n\nEvents:\n\n\n FirstSeen LastSeen Count From SubObjectPath Type Reason Message\n\n\n --------- -------- ----- ---- ------------- -------- ------ -------\n\n\n 7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test\n\n\n 7s 7s 1 {nginx-ingress-controller } Normal UPDATE default/nginx-test\n\n\n 7s 7s 1 {nginx-ingress-controller } Normal CREATE ip: 104.198.183.6\n\n\n 7s 7s 1 {nginx-ingress-controller } Warning MAPPING Ingress rule 'default/nginx-test' contains no path definition. Assuming /\n\n\n\n$\n curl \n104\n.198.183.6 -L\n\ncurl: (60) SSL certificate problem: self signed certificate\n\n\nMore details here: http://curl.haxx.se/docs/sslcerts.html\n\n\n\n$\n curl \n104\n.198.183.6 -Lk\n\nCLIENT VALUES:\n\n\nclient_address=10.240.0.4\n\n\ncommand=GET\n\n\nreal path=/\n\n\nquery=nil\n\n\nrequest_version=1.1\n\n\nrequest_uri=http://35.186.221.137:8080/\n\n\n\nSERVER VALUES:\n\n\nserver_version=nginx: 1.9.11 - lua: 10001\n\n\n\nHEADERS RECEIVED:\n\n\naccept=*/*\n\n\nconnection=Keep-Alive\n\n\nhost=35.186.221.137\n\n\nuser-agent=curl/7.46.0\n\n\nvia=1.1 google\n\n\nx-cloud-trace-context=f708ea7e369d4514fc90d51d7e27e91d/13322322294276298106\n\n\nx-forwarded-for=104.132.0.80, 35.186.221.137\n\n\nx-forwarded-proto=https\n\n\nBODY:", + "title": "TLS termination" + }, + { + "location": "/examples/tls-termination/README/#tls-termination", + "text": "This example demonstrates how to terminate TLS through the nginx Ingress controller.", + "title": "TLS termination" + }, + { + "location": "/examples/tls-termination/README/#prerequisites", + "text": "You need a TLS cert and a test HTTP service for this example.", + "title": "Prerequisites" + }, + { + "location": "/examples/tls-termination/README/#deployment", + "text": "The following command instructs the controller to terminate traffic using the provided \nTLS cert, and forward un-encrypted HTTP traffic to the test HTTP service. kubectl apply -f ingress.yaml", + "title": "Deployment" + }, + { + "location": "/examples/tls-termination/README/#validation", + "text": "You can confirm that the Ingress works. $ kubectl describe ing nginx-test Name: nginx-test Namespace: default Address: 104.198.183.6 Default backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080) TLS: tls-secret terminates Rules: Host Path Backends ---- ---- -------- * http-svc:80 () Annotations: Events: FirstSeen LastSeen Count From SubObjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test 7s 7s 1 {nginx-ingress-controller } Normal UPDATE default/nginx-test 7s 7s 1 {nginx-ingress-controller } Normal CREATE ip: 104.198.183.6 7s 7s 1 {nginx-ingress-controller } Warning MAPPING Ingress rule 'default/nginx-test' contains no path definition. Assuming / $ curl 104 .198.183.6 -L curl: (60) SSL certificate problem: self signed certificate More details here: http://curl.haxx.se/docs/sslcerts.html $ curl 104 .198.183.6 -Lk CLIENT VALUES: client_address=10.240.0.4 command=GET real path=/ query=nil request_version=1.1 request_uri=http://35.186.221.137:8080/ SERVER VALUES: server_version=nginx: 1.9.11 - lua: 10001 HEADERS RECEIVED: accept=*/* connection=Keep-Alive host=35.186.221.137 user-agent=curl/7.46.0 via=1.1 google x-cloud-trace-context=f708ea7e369d4514fc90d51d7e27e91d/13322322294276298106 x-forwarded-for=104.132.0.80, 35.186.221.137 x-forwarded-proto=https BODY:", + "title": "Validation" + }, + { + "location": "/development/", + "text": "Developing for NGINX Ingress controller\n\u00b6\n\n\nThis document explains how to get started with developing for NGINX Ingress controller.\nIt includes how to build, test, and release ingress controllers.\n\n\nQuick Start\n\u00b6\n\n\nInitial developer environment build\n\u00b6\n\n\nPrequisites\n: Minikube must be installed; See \nreleases\n for installation instructions. \n\n\nIf you are using \nMacOS\n and deploying to \nminikube\n, the following command will build the local nginx controller container image and deploy the ingress controller onto a minikube cluster with RBAC enabled in the namespace \ningress-nginx\n:\n\n\n$ make dev-env\n\n\n\n\n\nUpdating the deployment\n\u00b6\n\n\nThe nginx controller container image can be rebuilt using:\n\n\n$ \nARCH\n=\namd64 \nTAG\n=\ndev \nREGISTRY\n=\n$USER\n/ingress-controller make build container\n\n\n\n\n\nThe image will only be used by pods created after the rebuild. To delete old pods which will cause new ones to spin up:\n\n\n$ kubectl get pods -n ingress-nginx\n$ kubectl delete pod -n ingress-nginx nginx-ingress-controller-\n\n\n\n\n\nDependencies\n\u00b6\n\n\nThe build uses dependencies in the \nvendor\n directory, which\nmust be installed before building a binary/image. Occasionally, you\nmight need to update the dependencies.\n\n\nThis guide requires you to install the \ndep\n dependency tool.\n\n\nCheck the version of \ndep\n you are using and make sure it is up to date.\n\n\n$\n dep version\n\ndep:\n\n\n version : devel\n\n\n build date : \n\n\n git hash : \n\n\n go version : go1.9\n\n\n go compiler : gc\n\n\n platform : linux/amd64\n\n\n\n\n\n\nIf you have an older version of \ndep\n, you can update it as follows:\n\n\n$\n go get -u github.com/golang/dep\n\n\n\n\n\nThis will automatically save the dependencies to the \nvendor/\n directory.\n\n\n$\n \ncd\n \n$GOPATH\n/src/k8s.io/ingress-nginx\n\n$\n dep ensure\n\n$\n dep ensure -update\n\n$\n dep prune\n\n\n\n\n\nBuilding\n\u00b6\n\n\nAll ingress controllers are built through a Makefile. Depending on your\nrequirements you can build a raw server binary, a local container image,\nor push an image to a remote repository.\n\n\nIn order to use your local Docker, you may need to set the following environment variables:\n\n\n#\n \n\"gcloud docker\"\n \n(\ndefault\n)\n or \n\"docker\"\n\n\n$\n \nexport\n \nDOCKER\n=\n\n\n\n#\n \n\"quay.io/kubernetes-ingress-controller\"\n \n(\ndefault\n)\n, \n\"index.docker.io\"\n, or your own registry\n\n$\n \nexport\n \nREGISTRY\n=\n\n\n\n\n\n\nTo find the registry simply run: \ndocker system info | grep Registry\n\n\nNginx Controller\n\u00b6\n\n\nBuild a raw server binary\n\n\n$\n make build\n\n\n\n\n\nTODO\n: add more specific instructions needed for raw server binary.\n\n\nBuild a local container image\n\n\n$\n \nTAG\n=\n \nREGISTRY\n=\n$USER\n/ingress-controller make docker-build\n\n\n\n\n\nPush the container image to a remote repository\n\n\n$\n \nTAG\n=\n \nREGISTRY\n=\n$USER\n/ingress-controller make docker-push\n\n\n\n\n\nDeploying\n\u00b6\n\n\nThere are several ways to deploy the ingress controller onto a cluster.\nPlease check the \ndeployment guide\n\n\nTesting\n\u00b6\n\n\nTo run unit-tests, just run\n\n\n$\n \ncd\n \n$GOPATH\n/src/k8s.io/ingress-nginx\n\n$\n make \ntest\n\n\n\n\n\n\nIf you have access to a Kubernetes cluster, you can also run e2e tests using ginkgo.\n\n\n$\n \ncd\n \n$GOPATH\n/src/k8s.io/ingress-nginx\n\n$\n make e2e-test\n\n\n\n\n\nTo run unit-tests for lua code locally, run:\n\n\n$\n \ncd\n \n$GOPATH\n/src/k8s.io/ingress-nginx\n\n$\n ./rootfs/etc/nginx/lua/test/up.sh\n\n$\n make lua-test\n\n\n\n\n\nLua tests are located in \n$GOPATH/src/k8s.io/ingress-nginx/rootfs/etc/nginx/lua/test\n. When creating a new test file it must follow the naming convention \n_test.lua\n or it will be ignored. \n\n\nReleasing\n\u00b6\n\n\nAll Makefiles will produce a release binary, as shown above. To publish this\nto a wider Kubernetes user base, push the image to a container registry, like\n\ngcr.io\n. All release images are hosted under \ngcr.io/google_containers\n and\ntagged according to a \nsemver\n scheme.\n\n\nAn example release might look like:\n\n\n$ make release\n\n\n\n\n\nPlease follow these guidelines to cut a release:\n\n\n\n\nUpdate the \nrelease\n\npage with a short description of the major changes that correspond to a given\nimage tag.\n\n\nCut a release branch, if appropriate. Release branches follow the format of\n\ncontroller-release-version\n. Typically, pre-releases are cut from HEAD.\nAll major feature work is done in HEAD. Specific bug fixes are\ncherry-picked into a release branch.\n\n\nIf you're not confident about the stability of the code,\n\ntag\n it as alpha or beta.\nTypically, a release branch should have stable code.", + "title": "Developing for NGINX Ingress controller" + }, + { + "location": "/development/#developing-for-nginx-ingress-controller", + "text": "This document explains how to get started with developing for NGINX Ingress controller.\nIt includes how to build, test, and release ingress controllers.", + "title": "Developing for NGINX Ingress controller" + }, + { + "location": "/development/#quick-start", + "text": "", + "title": "Quick Start" + }, + { + "location": "/development/#initial-developer-environment-build", + "text": "Prequisites : Minikube must be installed; See releases for installation instructions. If you are using MacOS and deploying to minikube , the following command will build the local nginx controller container image and deploy the ingress controller onto a minikube cluster with RBAC enabled in the namespace ingress-nginx : $ make dev-env", + "title": "Initial developer environment build" + }, + { + "location": "/development/#updating-the-deployment", + "text": "The nginx controller container image can be rebuilt using: $ ARCH = amd64 TAG = dev REGISTRY = $USER /ingress-controller make build container The image will only be used by pods created after the rebuild. To delete old pods which will cause new ones to spin up: $ kubectl get pods -n ingress-nginx\n$ kubectl delete pod -n ingress-nginx nginx-ingress-controller-", + "title": "Updating the deployment" + }, + { + "location": "/development/#dependencies", + "text": "The build uses dependencies in the vendor directory, which\nmust be installed before building a binary/image. Occasionally, you\nmight need to update the dependencies. This guide requires you to install the dep dependency tool. Check the version of dep you are using and make sure it is up to date. $ dep version dep: version : devel build date : git hash : go version : go1.9 go compiler : gc platform : linux/amd64 If you have an older version of dep , you can update it as follows: $ go get -u github.com/golang/dep This will automatically save the dependencies to the vendor/ directory. $ cd $GOPATH /src/k8s.io/ingress-nginx $ dep ensure $ dep ensure -update $ dep prune", + "title": "Dependencies" + }, + { + "location": "/development/#building", + "text": "All ingress controllers are built through a Makefile. Depending on your\nrequirements you can build a raw server binary, a local container image,\nor push an image to a remote repository. In order to use your local Docker, you may need to set the following environment variables: # \"gcloud docker\" ( default ) or \"docker\" $ export DOCKER = # \"quay.io/kubernetes-ingress-controller\" ( default ) , \"index.docker.io\" , or your own registry $ export REGISTRY = To find the registry simply run: docker system info | grep Registry", + "title": "Building" + }, + { + "location": "/development/#nginx-controller", + "text": "Build a raw server binary $ make build TODO : add more specific instructions needed for raw server binary. Build a local container image $ TAG = REGISTRY = $USER /ingress-controller make docker-build Push the container image to a remote repository $ TAG = REGISTRY = $USER /ingress-controller make docker-push", + "title": "Nginx Controller" + }, + { + "location": "/development/#deploying", + "text": "There are several ways to deploy the ingress controller onto a cluster.\nPlease check the deployment guide", + "title": "Deploying" + }, + { + "location": "/development/#testing", + "text": "To run unit-tests, just run $ cd $GOPATH /src/k8s.io/ingress-nginx $ make test If you have access to a Kubernetes cluster, you can also run e2e tests using ginkgo. $ cd $GOPATH /src/k8s.io/ingress-nginx $ make e2e-test To run unit-tests for lua code locally, run: $ cd $GOPATH /src/k8s.io/ingress-nginx $ ./rootfs/etc/nginx/lua/test/up.sh $ make lua-test Lua tests are located in $GOPATH/src/k8s.io/ingress-nginx/rootfs/etc/nginx/lua/test . When creating a new test file it must follow the naming convention _test.lua or it will be ignored.", + "title": "Testing" + }, + { + "location": "/development/#releasing", + "text": "All Makefiles will produce a release binary, as shown above. To publish this\nto a wider Kubernetes user base, push the image to a container registry, like gcr.io . All release images are hosted under gcr.io/google_containers and\ntagged according to a semver scheme. An example release might look like: $ make release Please follow these guidelines to cut a release: Update the release \npage with a short description of the major changes that correspond to a given\nimage tag. Cut a release branch, if appropriate. Release branches follow the format of controller-release-version . Typically, pre-releases are cut from HEAD.\nAll major feature work is done in HEAD. Specific bug fixes are\ncherry-picked into a release branch. If you're not confident about the stability of the code, tag it as alpha or beta.\nTypically, a release branch should have stable code.", + "title": "Releasing" + }, + { + "location": "/ingress-controller-catalog/", + "text": "Ingress Controller Catalog\n\u00b6\n\n\nThis is a non-comprehensive list of existing ingress controllers.\n\n\n\n\nDummy controller backend\n\n\nHAProxy Ingress controller\n\n\nLinkerd\n\n\ntraefik\n\n\nAWS Application Load Balancer Ingress Controller\n\n\nkube-ingress-aws-controller\n\n\nVoyager: HAProxy Ingress Controller\n\n\nExternal Nginx Ingress Controller\n\n\nHeptio Contour controller\n\n\nLemonLDAP::NG kubernetes controller\n adds WebSSO, Access Management and Identity Federation to NGINX Ingress Controller", + "title": "Ingress Controller Catalog" + }, + { + "location": "/ingress-controller-catalog/#ingress-controller-catalog", + "text": "This is a non-comprehensive list of existing ingress controllers. Dummy controller backend HAProxy Ingress controller Linkerd traefik AWS Application Load Balancer Ingress Controller kube-ingress-aws-controller Voyager: HAProxy Ingress Controller External Nginx Ingress Controller Heptio Contour controller LemonLDAP::NG kubernetes controller adds WebSSO, Access Management and Identity Federation to NGINX Ingress Controller", + "title": "Ingress Controller Catalog" + }, + { + "location": "/troubleshooting/", + "text": "Debug & Troubleshooting\n\u00b6\n\n\nDebug\n\u00b6\n\n\nUsing the flag \n--v=XX\n it is possible to increase the level of logging.\nIn particular:\n\n\n\n\n--v=2\n shows details using \ndiff\n about the changes in the configuration in nginx\n\n\n\n\nI0316 12:24:37.581267 1 utils.go:148] NGINX configuration diff a//etc/nginx/nginx.conf b//etc/nginx/nginx.conf\n\n\nI0316 12:24:37.581356 1 utils.go:149] --- /tmp/922554809 2016-03-16 12:24:37.000000000 +0000\n\n\n+++ /tmp/079811012 2016-03-16 12:24:37.000000000 +0000\n\n\n@@ -235,7 +235,6 @@\n\n\n\n upstream default-http-svcx {\n\n\n least_conn;\n\n\n- server 10.2.112.124:5000;\n\n\n server 10.2.208.50:5000;\n\n\n\n }\n\n\nI0316 12:24:37.610073 1 command.go:69] change in configuration detected. Reloading...\n\n\n\n\n\n\n\n\n--v=3\n shows details about the service, Ingress rule, endpoint changes and it dumps the nginx configuration in JSON format\n\n\n--v=5\n configures NGINX in \ndebug mode\n\n\n\n\nTroubleshooting\n\u00b6\n\n\nAuthentication to the Kubernetes API Server\n\u00b6\n\n\nA number of components are involved in the authentication process and the first step is to narrow\ndown the source of the problem, namely whether it is a problem with service authentication or with the kubeconfig file.\nBoth authentications must work:\n\n\n+-------------+ service +------------+\n| | authentication | |\n+ apiserver +<-------------------+ ingress |\n| | | controller |\n+-------------+ +------------+\n\n\n\n\n\nService authentication\n\n\nThe Ingress controller needs information from apiserver. Therefore, authentication is required, which can be achieved in two different ways:\n\n\n\n\n\n\nService Account:\n This is recommended, because nothing has to be configured. The Ingress controller will use information provided by the system to communicate with the API server. See 'Service Account' section for details.\n\n\n\n\n\n\nKubeconfig file:\n In some Kubernetes environments service accounts are not available. In this case a manual configuration is required. The Ingress controller binary can be started with the \n--kubeconfig\n flag. The value of the flag is a path to a file specifying how to connect to the API server. Using the \n--kubeconfig\n does not requires the flag \n--apiserver-host\n.\nThe format of the file is identical to \n~/.kube/config\n which is used by kubectl to connect to the API server. See 'kubeconfig' section for details.\n\n\n\n\n\n\nUsing the flag \n--apiserver-host\n:\n Using this flag \n--apiserver-host=http://localhost:8080\n it is possible to specify an unsecured API server or reach a remote kubernetes cluster using \nkubectl proxy\n.\nPlease do not use this approach in production.\n\n\n\n\n\n\nIn the diagram below you can see the full authentication flow with all options, starting with the browser\non the lower left hand side.\n\n\nKubernetes Workstation\n+---------------------------------------------------+ +------------------+\n| | | |\n| +-----------+ apiserver +------------+ | | +------------+ |\n| | | proxy | | | | | | |\n| | apiserver | | ingress | | | | ingress | |\n| | | | controller | | | | controller | |\n| | | | | | | | | |\n| | | | | | | | | |\n| | | service account/ | | | | | | |\n| | | kubeconfig | | | | | | |\n| | +<-------------------+ | | | | | |\n| | | | | | | | | |\n| +------+----+ kubeconfig +------+-----+ | | +------+-----+ |\n| |<--------------------------------------------------------| |\n| | | |\n+---------------------------------------------------+ +------------------+\n\n\n\n\n\nService Account\n\u00b6\n\n\nIf using a service account to connect to the API server, Dashboard expects the file\n\n/var/run/secrets/kubernetes.io/serviceaccount/token\n to be present. It provides a secret\ntoken that is required to authenticate with the API server.\n\n\nVerify with the following commands:\n\n\n# start a container that contains curl\n\n$ kubectl run \ntest\n --image\n=\ntutum/curl -- sleep \n10000\n\n\n\n# check that container is running\n\n$ kubectl get pods\nNAME READY STATUS RESTARTS AGE\ntest-701078429-s5kca \n1\n/1 Running \n0\n 16s\n\n\n# check if secret exists\n\n$ kubectl \nexec\n test-701078429-s5kca ls /var/run/secrets/kubernetes.io/serviceaccount/\nca.crt\nnamespace\ntoken\n\n\n# get service IP of master\n\n$ kubectl get services\nNAME CLUSTER-IP EXTERNAL-IP PORT\n(\nS\n)\n AGE\nkubernetes \n10\n.0.0.1 \n443\n/TCP 1d\n\n\n# check base connectivity from cluster inside\n\n$ kubectl \nexec\n test-701078429-s5kca -- curl -k https://10.0.0.1\nUnauthorized\n\n\n# connect using tokens\n\n$ \nTOKEN_VALUE\n=\n$(\nkubectl \nexec\n test-701078429-s5kca -- cat /var/run/secrets/kubernetes.io/serviceaccount/token\n)\n\n$ \necho\n \n$TOKEN_VALUE\n\neyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3Mi....9A\n$ kubectl \nexec\n test-701078429-s5kca -- curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H \n\"Authorization: Bearer \n$TOKEN_VALUE\n\"\n https://10.0.0.1\n\n{\n\n \n\"paths\"\n: \n[\n\n \n\"/api\"\n,\n \n\"/api/v1\"\n,\n \n\"/apis\"\n,\n \n\"/apis/apps\"\n,\n \n\"/apis/apps/v1alpha1\"\n,\n \n\"/apis/authentication.k8s.io\"\n,\n \n\"/apis/authentication.k8s.io/v1beta1\"\n,\n \n\"/apis/authorization.k8s.io\"\n,\n \n\"/apis/authorization.k8s.io/v1beta1\"\n,\n \n\"/apis/autoscaling\"\n,\n \n\"/apis/autoscaling/v1\"\n,\n \n\"/apis/batch\"\n,\n \n\"/apis/batch/v1\"\n,\n \n\"/apis/batch/v2alpha1\"\n,\n \n\"/apis/certificates.k8s.io\"\n,\n \n\"/apis/certificates.k8s.io/v1alpha1\"\n,\n \n\"/apis/extensions\"\n,\n \n\"/apis/extensions/v1beta1\"\n,\n \n\"/apis/policy\"\n,\n \n\"/apis/policy/v1alpha1\"\n,\n \n\"/apis/rbac.authorization.k8s.io\"\n,\n \n\"/apis/rbac.authorization.k8s.io/v1alpha1\"\n,\n \n\"/apis/storage.k8s.io\"\n,\n \n\"/apis/storage.k8s.io/v1beta1\"\n,\n \n\"/healthz\"\n,\n \n\"/healthz/ping\"\n,\n \n\"/logs\"\n,\n \n\"/metrics\"\n,\n \n\"/swaggerapi/\"\n,\n \n\"/ui/\"\n,\n \n\"/version\"\n\n \n]\n\n\n}\n\n\n\n\n\n\nIf it is not working, there are two possible reasons:\n\n\n\n\n\n\nThe contents of the tokens are invalid. Find the secret name with \nkubectl get secrets | grep service-account\n and\ndelete it with \nkubectl delete secret \n. It will automatically be recreated.\n\n\n\n\n\n\nYou have a non-standard Kubernetes installation and the file containing the token may not be present.\nThe API server will mount a volume containing this file, but only if the API server is configured to use\nthe ServiceAccount admission controller.\nIf you experience this error, verify that your API server is using the ServiceAccount admission controller.\nIf you are configuring the API server by hand, you can set this with the \n--admission-control\n parameter.\nPlease note that you should use other admission controllers as well. Before configuring this option, you should\nread about admission controllers.\n\n\n\n\n\n\nMore information:\n\n\n\n\nUser Guide: Service Accounts\n\n\nCluster Administrator Guide: Managing Service Accounts\n\n\n\n\nKubeconfig\n\u00b6\n\n\nIf you want to use a kubeconfig file for authentication, follow the deploy procedure and \nadd the flag \n--kubeconfig=/etc/kubernetes/kubeconfig.yaml\n to the deployment", + "title": "Debug & Troubleshooting" + }, + { + "location": "/troubleshooting/#debug-troubleshooting", + "text": "", + "title": "Debug & Troubleshooting" + }, + { + "location": "/troubleshooting/#debug", + "text": "Using the flag --v=XX it is possible to increase the level of logging.\nIn particular: --v=2 shows details using diff about the changes in the configuration in nginx I0316 12:24:37.581267 1 utils.go:148] NGINX configuration diff a//etc/nginx/nginx.conf b//etc/nginx/nginx.conf I0316 12:24:37.581356 1 utils.go:149] --- /tmp/922554809 2016-03-16 12:24:37.000000000 +0000 +++ /tmp/079811012 2016-03-16 12:24:37.000000000 +0000 @@ -235,7 +235,6 @@ upstream default-http-svcx { least_conn; - server 10.2.112.124:5000; server 10.2.208.50:5000; } I0316 12:24:37.610073 1 command.go:69] change in configuration detected. Reloading... --v=3 shows details about the service, Ingress rule, endpoint changes and it dumps the nginx configuration in JSON format --v=5 configures NGINX in debug mode", + "title": "Debug" + }, + { + "location": "/troubleshooting/#troubleshooting", + "text": "", + "title": "Troubleshooting" + }, + { + "location": "/troubleshooting/#authentication-to-the-kubernetes-api-server", + "text": "A number of components are involved in the authentication process and the first step is to narrow\ndown the source of the problem, namely whether it is a problem with service authentication or with the kubeconfig file.\nBoth authentications must work: +-------------+ service +------------+\n| | authentication | |\n+ apiserver +<-------------------+ ingress |\n| | | controller |\n+-------------+ +------------+ Service authentication The Ingress controller needs information from apiserver. Therefore, authentication is required, which can be achieved in two different ways: Service Account: This is recommended, because nothing has to be configured. The Ingress controller will use information provided by the system to communicate with the API server. See 'Service Account' section for details. Kubeconfig file: In some Kubernetes environments service accounts are not available. In this case a manual configuration is required. The Ingress controller binary can be started with the --kubeconfig flag. The value of the flag is a path to a file specifying how to connect to the API server. Using the --kubeconfig does not requires the flag --apiserver-host .\nThe format of the file is identical to ~/.kube/config which is used by kubectl to connect to the API server. See 'kubeconfig' section for details. Using the flag --apiserver-host : Using this flag --apiserver-host=http://localhost:8080 it is possible to specify an unsecured API server or reach a remote kubernetes cluster using kubectl proxy .\nPlease do not use this approach in production. In the diagram below you can see the full authentication flow with all options, starting with the browser\non the lower left hand side. Kubernetes Workstation\n+---------------------------------------------------+ +------------------+\n| | | |\n| +-----------+ apiserver +------------+ | | +------------+ |\n| | | proxy | | | | | | |\n| | apiserver | | ingress | | | | ingress | |\n| | | | controller | | | | controller | |\n| | | | | | | | | |\n| | | | | | | | | |\n| | | service account/ | | | | | | |\n| | | kubeconfig | | | | | | |\n| | +<-------------------+ | | | | | |\n| | | | | | | | | |\n| +------+----+ kubeconfig +------+-----+ | | +------+-----+ |\n| |<--------------------------------------------------------| |\n| | | |\n+---------------------------------------------------+ +------------------+", + "title": "Authentication to the Kubernetes API Server" + }, + { + "location": "/troubleshooting/#service-account", + "text": "If using a service account to connect to the API server, Dashboard expects the file /var/run/secrets/kubernetes.io/serviceaccount/token to be present. It provides a secret\ntoken that is required to authenticate with the API server. Verify with the following commands: # start a container that contains curl \n$ kubectl run test --image = tutum/curl -- sleep 10000 # check that container is running \n$ kubectl get pods\nNAME READY STATUS RESTARTS AGE\ntest-701078429-s5kca 1 /1 Running 0 16s # check if secret exists \n$ kubectl exec test-701078429-s5kca ls /var/run/secrets/kubernetes.io/serviceaccount/\nca.crt\nnamespace\ntoken # get service IP of master \n$ kubectl get services\nNAME CLUSTER-IP EXTERNAL-IP PORT ( S ) AGE\nkubernetes 10 .0.0.1 443 /TCP 1d # check base connectivity from cluster inside \n$ kubectl exec test-701078429-s5kca -- curl -k https://10.0.0.1\nUnauthorized # connect using tokens \n$ TOKEN_VALUE = $( kubectl exec test-701078429-s5kca -- cat /var/run/secrets/kubernetes.io/serviceaccount/token ) \n$ echo $TOKEN_VALUE \neyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3Mi....9A\n$ kubectl exec test-701078429-s5kca -- curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H \"Authorization: Bearer $TOKEN_VALUE \" https://10.0.0.1 { \n \"paths\" : [ \n \"/api\" ,\n \"/api/v1\" ,\n \"/apis\" ,\n \"/apis/apps\" ,\n \"/apis/apps/v1alpha1\" ,\n \"/apis/authentication.k8s.io\" ,\n \"/apis/authentication.k8s.io/v1beta1\" ,\n \"/apis/authorization.k8s.io\" ,\n \"/apis/authorization.k8s.io/v1beta1\" ,\n \"/apis/autoscaling\" ,\n \"/apis/autoscaling/v1\" ,\n \"/apis/batch\" ,\n \"/apis/batch/v1\" ,\n \"/apis/batch/v2alpha1\" ,\n \"/apis/certificates.k8s.io\" ,\n \"/apis/certificates.k8s.io/v1alpha1\" ,\n \"/apis/extensions\" ,\n \"/apis/extensions/v1beta1\" ,\n \"/apis/policy\" ,\n \"/apis/policy/v1alpha1\" ,\n \"/apis/rbac.authorization.k8s.io\" ,\n \"/apis/rbac.authorization.k8s.io/v1alpha1\" ,\n \"/apis/storage.k8s.io\" ,\n \"/apis/storage.k8s.io/v1beta1\" ,\n \"/healthz\" ,\n \"/healthz/ping\" ,\n \"/logs\" ,\n \"/metrics\" ,\n \"/swaggerapi/\" ,\n \"/ui/\" ,\n \"/version\" \n ] } If it is not working, there are two possible reasons: The contents of the tokens are invalid. Find the secret name with kubectl get secrets | grep service-account and\ndelete it with kubectl delete secret . It will automatically be recreated. You have a non-standard Kubernetes installation and the file containing the token may not be present.\nThe API server will mount a volume containing this file, but only if the API server is configured to use\nthe ServiceAccount admission controller.\nIf you experience this error, verify that your API server is using the ServiceAccount admission controller.\nIf you are configuring the API server by hand, you can set this with the --admission-control parameter.\nPlease note that you should use other admission controllers as well. Before configuring this option, you should\nread about admission controllers. More information: User Guide: Service Accounts Cluster Administrator Guide: Managing Service Accounts", + "title": "Service Account" + }, + { + "location": "/troubleshooting/#kubeconfig", + "text": "If you want to use a kubeconfig file for authentication, follow the deploy procedure and \nadd the flag --kubeconfig=/etc/kubernetes/kubeconfig.yaml to the deployment", + "title": "Kubeconfig" + } + ] +} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 000000000..48fba364e --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,186 @@ + + + + + + / + 2018-04-27 + daily + + + + + + + /deploy/ + 2018-04-27 + daily + + + + /deploy/rbac/ + 2018-04-27 + daily + + + + + + + + + + daily + + + + /user-guide/cli-arguments/ + 2018-04-27 + daily + + + + /user-guide/custom-errors/ + 2018-04-27 + daily + + + + /user-guide/exposing-tcp-udp-services/ + 2018-04-27 + daily + + + + /user-guide/external-articles/ + 2018-04-27 + daily + + + + /user-guide/miscellaneous/ + 2018-04-27 + daily + + + + /user-guide/multiple-ingress/ + 2018-04-27 + daily + + + + /user-guide/nginx-status-page/ + 2018-04-27 + daily + + + + /user-guide/tls/ + 2018-04-27 + daily + + + + + + daily + + + + + + + + /examples/PREREQUISITES/ + 2018-04-27 + daily + + + + /examples/README/ + 2018-04-27 + daily + + + + /examples/affinity/cookie/README/ + 2018-04-27 + daily + + + + + + daily + + + + + + daily + + + + /examples/docker-registry/README/ + 2018-04-27 + daily + + + + /examples/external-auth/README/ + 2018-04-27 + daily + + + + /examples/multi-tls/README/ + 2018-04-27 + daily + + + + /examples/rewrite/README/ + 2018-04-27 + daily + + + + /examples/static-ip/README/ + 2018-04-27 + daily + + + + /examples/tls-termination/README/ + 2018-04-27 + daily + + + + + + + /development/ + 2018-04-27 + daily + + + + + + /ingress-controller-catalog/ + 2018-04-27 + daily + + + + + + /troubleshooting/ + 2018-04-27 + daily + + + + \ No newline at end of file diff --git a/troubleshooting/index.html b/troubleshooting/index.html new file mode 100644 index 000000000..e6a02e3d9 --- /dev/null +++ b/troubleshooting/index.html @@ -0,0 +1,1373 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Debug & Troubleshooting - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + + + +

Debug & Troubleshooting

+

Debug

+

Using the flag --v=XX it is possible to increase the level of logging. +In particular:

+
    +
  • --v=2 shows details using diff about the changes in the configuration in nginx
  • +
+
I0316 12:24:37.581267       1 utils.go:148] NGINX configuration diff a//etc/nginx/nginx.conf b//etc/nginx/nginx.conf
+I0316 12:24:37.581356       1 utils.go:149] --- /tmp/922554809  2016-03-16 12:24:37.000000000 +0000
++++ /tmp/079811012  2016-03-16 12:24:37.000000000 +0000
+@@ -235,7 +235,6 @@
+
+     upstream default-http-svcx {
+         least_conn;
+-        server 10.2.112.124:5000;
+         server 10.2.208.50:5000;
+
+     }
+I0316 12:24:37.610073       1 command.go:69] change in configuration detected. Reloading...
+
+ + +
    +
  • --v=3 shows details about the service, Ingress rule, endpoint changes and it dumps the nginx configuration in JSON format
  • +
  • --v=5 configures NGINX in debug mode
  • +
+

Troubleshooting

+

Authentication to the Kubernetes API Server

+

A number of components are involved in the authentication process and the first step is to narrow +down the source of the problem, namely whether it is a problem with service authentication or with the kubeconfig file. +Both authentications must work:

+
+-------------+   service          +------------+
+|             |   authentication   |            |
++  apiserver  +<-------------------+  ingress   |
+|             |                    | controller |
++-------------+                    +------------+
+
+ + +

Service authentication

+

The Ingress controller needs information from apiserver. Therefore, authentication is required, which can be achieved in two different ways:

+
    +
  1. +

    Service Account: This is recommended, because nothing has to be configured. The Ingress controller will use information provided by the system to communicate with the API server. See 'Service Account' section for details.

    +
  2. +
  3. +

    Kubeconfig file: In some Kubernetes environments service accounts are not available. In this case a manual configuration is required. The Ingress controller binary can be started with the --kubeconfig flag. The value of the flag is a path to a file specifying how to connect to the API server. Using the --kubeconfig does not requires the flag --apiserver-host. +The format of the file is identical to ~/.kube/config which is used by kubectl to connect to the API server. See 'kubeconfig' section for details.

    +
  4. +
  5. +

    Using the flag --apiserver-host: Using this flag --apiserver-host=http://localhost:8080 it is possible to specify an unsecured API server or reach a remote kubernetes cluster using kubectl proxy. +Please do not use this approach in production.

    +
  6. +
+

In the diagram below you can see the full authentication flow with all options, starting with the browser +on the lower left hand side.

+
Kubernetes                                                  Workstation
++---------------------------------------------------+     +------------------+
+|                                                   |     |                  |
+|  +-----------+   apiserver        +------------+  |     |  +------------+  |
+|  |           |   proxy            |            |  |     |  |            |  |
+|  | apiserver |                    |  ingress   |  |     |  |  ingress   |  |
+|  |           |                    | controller |  |     |  | controller |  |
+|  |           |                    |            |  |     |  |            |  |
+|  |           |                    |            |  |     |  |            |  |
+|  |           |  service account/  |            |  |     |  |            |  |
+|  |           |  kubeconfig        |            |  |     |  |            |  |
+|  |           +<-------------------+            |  |     |  |            |  |
+|  |           |                    |            |  |     |  |            |  |
+|  +------+----+      kubeconfig    +------+-----+  |     |  +------+-----+  |
+|         |<--------------------------------------------------------|        |
+|                                                   |     |                  |
++---------------------------------------------------+     +------------------+
+
+ + +

Service Account

+

If using a service account to connect to the API server, Dashboard expects the file +/var/run/secrets/kubernetes.io/serviceaccount/token to be present. It provides a secret +token that is required to authenticate with the API server.

+

Verify with the following commands:

+
# start a container that contains curl
+$ kubectl run test --image=tutum/curl -- sleep 10000
+
+# check that container is running
+$ kubectl get pods
+NAME                   READY     STATUS    RESTARTS   AGE
+test-701078429-s5kca   1/1       Running   0          16s
+
+# check if secret exists
+$ kubectl exec test-701078429-s5kca ls /var/run/secrets/kubernetes.io/serviceaccount/
+ca.crt
+namespace
+token
+
+# get service IP of master
+$ kubectl get services
+NAME         CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
+kubernetes   10.0.0.1     <none>        443/TCP   1d
+
+# check base connectivity from cluster inside
+$ kubectl exec test-701078429-s5kca -- curl -k https://10.0.0.1
+Unauthorized
+
+# connect using tokens
+$ TOKEN_VALUE=$(kubectl exec test-701078429-s5kca -- cat /var/run/secrets/kubernetes.io/serviceaccount/token)
+$ echo $TOKEN_VALUE
+eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3Mi....9A
+$ kubectl exec test-701078429-s5kca -- curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H  "Authorization: Bearer $TOKEN_VALUE" https://10.0.0.1
+{
+  "paths": [
+    "/api",
+    "/api/v1",
+    "/apis",
+    "/apis/apps",
+    "/apis/apps/v1alpha1",
+    "/apis/authentication.k8s.io",
+    "/apis/authentication.k8s.io/v1beta1",
+    "/apis/authorization.k8s.io",
+    "/apis/authorization.k8s.io/v1beta1",
+    "/apis/autoscaling",
+    "/apis/autoscaling/v1",
+    "/apis/batch",
+    "/apis/batch/v1",
+    "/apis/batch/v2alpha1",
+    "/apis/certificates.k8s.io",
+    "/apis/certificates.k8s.io/v1alpha1",
+    "/apis/extensions",
+    "/apis/extensions/v1beta1",
+    "/apis/policy",
+    "/apis/policy/v1alpha1",
+    "/apis/rbac.authorization.k8s.io",
+    "/apis/rbac.authorization.k8s.io/v1alpha1",
+    "/apis/storage.k8s.io",
+    "/apis/storage.k8s.io/v1beta1",
+    "/healthz",
+    "/healthz/ping",
+    "/logs",
+    "/metrics",
+    "/swaggerapi/",
+    "/ui/",
+    "/version"
+  ]
+}
+
+ + +

If it is not working, there are two possible reasons:

+
    +
  1. +

    The contents of the tokens are invalid. Find the secret name with kubectl get secrets | grep service-account and +delete it with kubectl delete secret <name>. It will automatically be recreated.

    +
  2. +
  3. +

    You have a non-standard Kubernetes installation and the file containing the token may not be present. +The API server will mount a volume containing this file, but only if the API server is configured to use +the ServiceAccount admission controller. +If you experience this error, verify that your API server is using the ServiceAccount admission controller. +If you are configuring the API server by hand, you can set this with the --admission-control parameter. +Please note that you should use other admission controllers as well. Before configuring this option, you should +read about admission controllers.

    +
  4. +
+

More information:

+ +

Kubeconfig

+

If you want to use a kubeconfig file for authentication, follow the deploy procedure and +add the flag --kubeconfig=/etc/kubernetes/kubeconfig.yaml to the deployment

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/cli-arguments/index.html b/user-guide/cli-arguments/index.html new file mode 100644 index 000000000..6e46fcda5 --- /dev/null +++ b/user-guide/cli-arguments/index.html @@ -0,0 +1,1268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Command line arguments - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Command line arguments

+

The following command line arguments are accepted by the main controller executable.

+

They are set in the container spec of the nginx-ingress-controller Deployment object (see deploy/with-rbac.yaml or deploy/without-rbac.yaml).

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
--alsologtostderrlog to standard error as well as files
--annotations-prefix stringPrefix of the ingress annotations. (default "nginx.ingress.kubernetes.io")
--apiserver-host stringThe address of the Kubernetes Apiserver to connect to in the format of protocol://address:port, e.g., http://localhost:8080. If not specified, the assumption is that the binary runs inside a Kubernetes cluster and local discovery is attempted.
--configmap stringName of the ConfigMap that contains the custom configuration to use
--default-backend-service stringService used to serve a 404 page for the default backend. Takes the form namespace/name. The controller uses the first node port of this Service for the default backend.
--default-server-port intDefault port to use for exposing the default server (catch all) (default 8181)
--default-ssl-certificate stringName of the secret that contains a SSL certificate to be used as default for a HTTPS catch-all server. Takes the form /.
--election-id stringElection id to use for status update. (default "ingress-controller-leader")
--enable-dynamic-configurationWhen enabled controller will try to avoid Nginx reloads as much as possible by using Lua. Disabled by default.
--enable-ssl-chain-completionDefines if the nginx ingress controller should check the secrets for missing intermediate CA certificates. If the certificate contain issues chain issues is not possible to enable OCSP. Default is true. (default true)
--enable-ssl-passthroughEnable SSL passthrough feature. Default is disabled
--force-namespace-isolationForce namespace isolation. This flag is required to avoid the reference of secrets or configmaps located in a different namespace than the specified in the flag --watch-namespace.
--health-check-path stringDefines the URL to be used as health check inside in the default server in NGINX. (default "/healthz")
--healthz-port intport for healthz endpoint. (default 10254)
--http-port intIndicates the port to use for HTTP traffic (default 80)
--https-port intIndicates the port to use for HTTPS traffic (default 443)
--ingress-class stringName of the ingress class to route through this controller.
--kubeconfig stringPath to kubeconfig file with authorization and master location information.
--log_backtrace_at traceLocationwhen logging hits line file:N, emit a stack trace (default :0)
--log_dir stringIf non-empty, write log files in this directory
--logtostderrlog to standard error instead of files (default true)
--profilingEnable profiling via web interface host:port/debug/pprof/ (default true)
--publish-service stringService fronting the ingress controllers. Takes the form namespace/name. The controller will set the endpoint records on the ingress objects to reflect those on the service.
--publish-status-address stringUser customized address to be set in the status of ingress resources. The controller will set the endpoint records on the ingress using this address.
--report-node-internal-ip-addressDefines if the nodes IP address to be returned in the ingress status should be the internal instead of the external IP address
--sort-backendsDefines if backends and its endpoints should be sorted
--ssl-passtrough-proxy-port intDefault port to use internally for SSL when SSL Passthgough is enabled (default 442)
--status-port intIndicates the TCP port to use for exposing the nginx status page (default 18080)
--stderrthreshold severitylogs at or above this threshold go to stderr (default 2)
--sync-period durationRelist and confirm cloud resources this often. Default is 10 minutes (default 10m0s)
--sync-rate-limit float32Define the sync frequency upper limit (default 0.3)
--tcp-services-configmap stringName of the ConfigMap that contains the definition of the TCP services to expose. The key in the map indicates the external port to be used. The value is the name of the service with the format namespace/serviceName and the port of the service could be a number of the name of the port. The ports 80 and 443 are not allowed as external ports. This ports are reserved for the backend
--udp-services-configmap stringName of the ConfigMap that contains the definition of the UDP services to expose. The key in the map indicates the external port to be used. The value is the name of the service with the format namespace/serviceName and the port of the service could be a number of the name of the port.
--update-statusIndicates if the ingress controller should update the Ingress status IP/hostname. Default is true (default true)
--update-status-on-shutdownIndicates if the ingress controller should update the Ingress status IP/hostname when the controller is being stopped. Default is true (default true)
-v, --v Levellog level for V logs
--versionShows release information about the NGINX Ingress controller
--vmodule moduleSpeccomma-separated list of pattern=N settings for file-filtered logging
--watch-namespace stringNamespace to watch for Ingress. Default is to watch all namespaces
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/convert_arguments_to_doc.py b/user-guide/convert_arguments_to_doc.py new file mode 100644 index 000000000..9f419672a --- /dev/null +++ b/user-guide/convert_arguments_to_doc.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Copyright 2018 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Convert the output of `nginx-ingress-controller --help` to +a Markdown table. +""" + +import re +import sys + +assert sys.version_info[0] == 3, 'This script requires Python 3' + +data = sys.stdin.read() +data = data.replace('\t', ' ' * 8) # Expand tabs +data = data.replace('\n' + (' ' * 8 * 2), ' ') # Unwrap lines + +print(''' +| Argument | Description | +|----------|-------------| +'''.rstrip()) + +for arg_m in re.finditer('^\s+(-.+?)\s{2,}(.+)$', data, flags=re.MULTILINE): + arg, description = arg_m.groups() + print('| `{arg}` | {description} |'.format( + arg=arg.replace(', ', '`, `'), + description=description, + )) diff --git a/user-guide/custom-errors/index.html b/user-guide/custom-errors/index.html new file mode 100644 index 000000000..1d2aad71c --- /dev/null +++ b/user-guide/custom-errors/index.html @@ -0,0 +1,1115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Custom errors - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Custom errors

+

In case of an error in a request the body of the response is obtained from the default backend. +Each request to the default backend includes two headers:

+
    +
  • X-Code indicates the HTTP code to be returned to the client.
  • +
  • X-Format the value of the Accept header.
  • +
+

Important: the custom backend must return the correct HTTP status code to be returned. NGINX do not changes the response from the custom default backend.

+

Using this two headers is possible to use a custom backend service like this one that inspect each request and returns a custom error page with the format expected by the client. Please check the example custom-errors

+

NGINX sends additional headers that can be used to build custom response:

+
    +
  • X-Original-URI
  • +
  • X-Namespace
  • +
  • X-Ingress-Name
  • +
  • X-Service-Name
  • +
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/exposing-tcp-udp-services/index.html b/user-guide/exposing-tcp-udp-services/index.html new file mode 100644 index 000000000..ba7ad6b8e --- /dev/null +++ b/user-guide/exposing-tcp-udp-services/index.html @@ -0,0 +1,1123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Exposing TCP and UDP services - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Exposing TCP and UDP services

+

Ingress does not support TCP or UDP services. For this reason this Ingress controller uses the flags --tcp-services-configmap and --udp-services-configmap to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format: +<namespace/service name>:<service port>:[PROXY]:[PROXY]

+

It is also possible to use a number or the name of the port. The two last fields are optional. +Adding PROXY in either or both of the two last fields we can use Proxy Protocol decoding (listen) and/or encoding (proxy_pass) in a TCP service (https://www.nginx.com/resources/admin-guide/proxy-protocol/).

+

The next example shows how to expose the service example-go running in the namespace default in the port 8080 using the port 9000

+
apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: tcp-configmap-example
+data:
+  9000: "default/example-go:8080"
+
+ + +

Since 1.9.13 NGINX provides UDP Load Balancing. +The next example shows how to expose the service kube-dns running in the namespace kube-system in the port 53 using the port 53

+

```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: udp-configmap-example +data: + 53: "kube-system/kube-dns:53"

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/external-articles/index.html b/user-guide/external-articles/index.html new file mode 100644 index 000000000..1b5ea89d8 --- /dev/null +++ b/user-guide/external-articles/index.html @@ -0,0 +1,1106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + External Articles - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + + +
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/miscellaneous/index.html b/user-guide/miscellaneous/index.html new file mode 100644 index 000000000..d0b5ec99c --- /dev/null +++ b/user-guide/miscellaneous/index.html @@ -0,0 +1,1296 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Miscellaneous - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + + + + +
+
+ + + + + +

Miscellaneous

+

Conventions

+

Anytime we reference a tls secret, we mean (x509, pem encoded, RSA 2048, etc). You can generate such a certificate with: +openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ${KEY_FILE} -out ${CERT_FILE} -subj "/CN=${HOST}/O=${HOST}" +and create the secret via kubectl create secret tls ${CERT_NAME} --key ${KEY_FILE} --cert ${CERT_FILE}

+

Requirements

+

The default backend is a service which handles all url paths and hosts the nginx controller doesn't understand (i.e., all the requests that are not mapped with an Ingress). +Basically a default backend exposes two URLs:

+
    +
  • /healthz that returns 200
  • +
  • / that returns 404
  • +
+

The sub-directory /images/404-server provides a service which satisfies the requirements for a default backend. The sub-directory /images/custom-error-pages provides an additional service for the purpose of customizing the error pages served via the default backend.

+

Source IP address

+

By default NGINX uses the content of the header X-Forwarded-For as the source of truth to get information about the client IP address. This works without issues in L7 if we configure the setting proxy-real-ip-cidr with the correct information of the IP/network address of trusted external load balancer.

+

If the ingress controller is running in AWS we need to use the VPC IPv4 CIDR.

+

Another option is to enable proxy protocol using use-proxy-protocol: "true".

+

In this mode NGINX does not use the content of the header to get the source IP address of the connection.

+

Proxy Protocol

+

If you are using a L4 proxy to forward the traffic to the NGINX pods and terminate HTTP/HTTPS there, you will lose the remote endpoint's IP address. To prevent this you could use the Proxy Protocol for forwarding traffic, this will send the connection details before forwarding the actual TCP connection itself.

+

Amongst others ELBs in AWS and HAProxy support Proxy Protocol.

+

Websockets

+

Support for websockets is provided by NGINX out of the box. No special configuration required.

+

The only requirement to avoid the close of connections is the increase of the values of proxy-read-timeout and proxy-send-timeout.

+

The default value of this settings is 60 seconds.

+

A more adequate value to support websockets is a value higher than one hour (3600).

+

Important: If the NGINX ingress controller is exposed with a service type=LoadBalancer make sure the protocol between the loadbalancer and NGINX is TCP.

+

Optimizing TLS Time To First Byte (TTTFB)

+

NGINX provides the configuration option ssl_buffer_size to allow the optimization of the TLS record size.

+

This improves the TLS Time To First Byte (TTTFB). +The default value in the Ingress controller is 4k (NGINX default is 16k).

+

Retries in non-idempotent methods

+

Since 1.9.13 NGINX will not retry non-idempotent requests (POST, LOCK, PATCH) in case of an error. +The previous behavior can be restored using retry-non-idempotent=true in the configuration ConfigMap.

+

Limitations

+
    +
  • Ingress rules for TLS require the definition of the field host
  • +
+

Why endpoints and not services

+

The NGINX ingress controller does not use Services to route traffic to the pods. Instead it uses the Endpoints API in order to bypass kube-proxy to allow NGINX features like session affinity and custom load balancing algorithms. It also removes some overhead, such as conntrack entries for iptables DNAT.

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/multiple-ingress/index.html b/user-guide/multiple-ingress/index.html new file mode 100644 index 000000000..005e0d6ff --- /dev/null +++ b/user-guide/multiple-ingress/index.html @@ -0,0 +1,1212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Multiple ingress controllers - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Multiple ingress controllers

+

Running multiple ingress controllers

+

If you're running multiple ingress controllers, or running on a cloud provider that natively handles ingress, you need to specify the annotation kubernetes.io/ingress.class: "nginx" in all ingresses that you would like this controller to claim. This mechanism also provides users the ability to run multiple NGINX ingress controllers (e.g. one which serves public traffic, one which serves "internal" traffic). When utilizing this functionality the option --ingress-class should be changed to a value unique for the cluster within the definition of the replication controller. Here is a partial example:

+
spec:
+  template:
+     spec:
+       containers:
+         - name: nginx-ingress-internal-controller
+           args:
+             - /nginx-ingress-controller
+             - '--default-backend-service=ingress/nginx-ingress-default-backend'
+             - '--election-id=ingress-controller-leader-internal'
+             - '--ingress-class=nginx-internal'
+             - '--configmap=ingress/nginx-ingress-internal-controller'
+
+ + +

Annotation ingress.class

+

If you have multiple Ingress controllers in a single cluster, you can pick one by specifying the ingress.class +annotation, eg creating an Ingress with an annotation like

+
metadata:
+  name: foo
+  annotations:
+    kubernetes.io/ingress.class: "gce"
+
+ + +

will target the GCE controller, forcing the nginx controller to ignore it, while an annotation like

+
metadata:
+  name: foo
+  annotations:
+    kubernetes.io/ingress.class: "nginx"
+
+ + +

will target the nginx controller, forcing the GCE controller to ignore it.

+

Note: Deploying multiple ingress controller and not specifying the annotation will result in both controllers fighting to satisfy the Ingress.

+

Disabling NGINX ingress controller

+

Setting the annotation kubernetes.io/ingress.class to any other value which does not match a valid ingress class will force the NGINX Ingress controller to ignore your Ingress. If you are only running a single NGINX ingress controller, this can be achieved by setting this to any value except "nginx" or an empty string.

+

Do this if you wish to use one of the other Ingress controllers at the same time as the NGINX controller.

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/nginx-configuration/annotations/index.html b/user-guide/nginx-configuration/annotations/index.html new file mode 100644 index 000000000..964bfb94f --- /dev/null +++ b/user-guide/nginx-configuration/annotations/index.html @@ -0,0 +1,2163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Annotations - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + + + + +
+
+ + + + + +

Annotations

+

You can add these Kubernetes annotations to specific Ingress objects to customize their behavior.

+
+

Tip

+

Annotation keys and values can only be strings. +Other types, such as boolean or numeric values must be quoted, +i.e. "true", "false", "100".

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Nametype
nginx.ingress.kubernetes.io/add-base-url"true" or "false"
nginx.ingress.kubernetes.io/app-rootstring
nginx.ingress.kubernetes.io/affinitycookie
nginx.ingress.kubernetes.io/auth-realmstring
nginx.ingress.kubernetes.io/auth-secretstring
nginx.ingress.kubernetes.io/auth-typebasic or digest
nginx.ingress.kubernetes.io/auth-tls-secretstring
nginx.ingress.kubernetes.io/auth-tls-verify-depthnumber
nginx.ingress.kubernetes.io/auth-tls-verify-clientstring
nginx.ingress.kubernetes.io/auth-tls-error-pagestring
nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream"true" or "false"
nginx.ingress.kubernetes.io/auth-urlstring
nginx.ingress.kubernetes.io/base-url-schemestring
nginx.ingress.kubernetes.io/client-body-buffer-sizestring
nginx.ingress.kubernetes.io/configuration-snippetstring
nginx.ingress.kubernetes.io/default-backendstring
nginx.ingress.kubernetes.io/enable-cors"true" or "false"
nginx.ingress.kubernetes.io/cors-allow-originstring
nginx.ingress.kubernetes.io/cors-allow-methodsstring
nginx.ingress.kubernetes.io/cors-allow-headersstring
nginx.ingress.kubernetes.io/cors-allow-credentials"true" or "false"
nginx.ingress.kubernetes.io/cors-max-agenumber
nginx.ingress.kubernetes.io/force-ssl-redirect"true" or "false"
nginx.ingress.kubernetes.io/from-to-www-redirect"true" or "false"
nginx.ingress.kubernetes.io/limit-connectionsnumber
nginx.ingress.kubernetes.io/limit-rpsnumber
nginx.ingress.kubernetes.io/permanent-redirectstring
nginx.ingress.kubernetes.io/proxy-body-sizestring
nginx.ingress.kubernetes.io/proxy-connect-timeoutnumber
nginx.ingress.kubernetes.io/proxy-send-timeoutnumber
nginx.ingress.kubernetes.io/proxy-read-timeoutnumber
nginx.ingress.kubernetes.io/proxy-next-upstreamstring
nginx.ingress.kubernetes.io/proxy-next-upstream-triesnumber
nginx.ingress.kubernetes.io/proxy-request-bufferingstring
nginx.ingress.kubernetes.io/proxy-redirect-fromstring
nginx.ingress.kubernetes.io/proxy-redirect-tostring
nginx.ingress.kubernetes.io/rewrite-targetURI
nginx.ingress.kubernetes.io/secure-backends"true" or "false"
nginx.ingress.kubernetes.io/secure-verify-ca-secretstring
nginx.ingress.kubernetes.io/server-aliasstring
nginx.ingress.kubernetes.io/server-snippetstring
nginx.ingress.kubernetes.io/service-upstream"true" or "false"
nginx.ingress.kubernetes.io/session-cookie-namestring
nginx.ingress.kubernetes.io/session-cookie-hashstring
nginx.ingress.kubernetes.io/ssl-redirect"true" or "false"
nginx.ingress.kubernetes.io/ssl-passthrough"true" or "false"
nginx.ingress.kubernetes.io/upstream-max-failsnumber
nginx.ingress.kubernetes.io/upstream-fail-timeoutnumber
nginx.ingress.kubernetes.io/upstream-hash-bystring
nginx.ingress.kubernetes.io/load-balancestring
nginx.ingress.kubernetes.io/upstream-vhoststring
nginx.ingress.kubernetes.io/whitelist-source-rangeCIDR
nginx.ingress.kubernetes.io/proxy-bufferingstring
nginx.ingress.kubernetes.io/ssl-ciphersstring
nginx.ingress.kubernetes.io/connection-proxy-headerstring
nginx.ingress.kubernetes.io/enable-access-log"true" or "false"
nginx.ingress.kubernetes.io/lua-resty-wafstring
nginx.ingress.kubernetes.io/lua-resty-waf-debug"true" or "false"
nginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesetsstring
nginx.ingress.kubernetes.io/lua-resty-waf-extra-rulesstring
+

Rewrite

+

In some scenarios the exposed URL in the backend service differs from the specified path in the Ingress rule. Without a rewrite any request will return 404. +Set the annotation nginx.ingress.kubernetes.io/rewrite-target to the path expected by the service.

+

If the application contains relative links it is possible to add an additional annotation nginx.ingress.kubernetes.io/add-base-url that will prepend a base tag in the header of the returned HTML from the backend.

+

If the scheme of base tag need to be specific, set the annotation nginx.ingress.kubernetes.io/base-url-scheme to the scheme such as http and https.

+

If the Application Root is exposed in a different path and needs to be redirected, set the annotation nginx.ingress.kubernetes.io/app-root to redirect requests for /.

+

Please check the rewrite example.

+

Session Affinity

+

The annotation nginx.ingress.kubernetes.io/affinity enables and sets the affinity type in all Upstreams of an Ingress. This way, a request will always be directed to the same upstream server. +The only affinity type available for NGINX is cookie.

+

Please check the affinity example.

+

Authentication

+

Is possible to add authentication adding additional annotations in the Ingress rule. The source of the authentication is a secret that contains usernames and passwords inside the key auth.

+

The annotations are:

+
nginx.ingress.kubernetes.io/auth-type: [basic|digest]
+
+ + +

Indicates the HTTP Authentication Type: Basic or Digest Access Authentication.

+
nginx.ingress.kubernetes.io/auth-secret: secretName
+
+ + +

The name of the Secret that contains the usernames and passwords which are granted access to the paths defined in the Ingress rules. +This annotation also accepts the alternative form "namespace/secretName", in which case the Secret lookup is performed in the referenced namespace instead of the Ingress namespace.

+
nginx.ingress.kubernetes.io/auth-realm: "realm string"
+
+ + +

Please check the auth example.

+

Custom NGINX upstream checks

+

NGINX exposes some flags in the upstream configuration that enable the configuration of each server in the upstream. The Ingress controller allows custom max_fails and fail_timeout parameters in a global context using upstream-max-fails and upstream-fail-timeout in the NGINX ConfigMap or in a particular Ingress rule. upstream-max-fails defaults to 0. This means NGINX will respect the container's readinessProbe if it is defined. If there is no probe and no values for upstream-max-fails NGINX will continue to send traffic to the container.

+

With the default configuration NGINX will not health check your backends. Whenever the endpoints controller notices a readiness probe failure, that pod's IP will be removed from the list of endpoints. This will trigger the NGINX controller to also remove it from the upstreams.

+

To use custom values in an Ingress rule define these annotations:

+

nginx.ingress.kubernetes.io/upstream-max-fails: number of unsuccessful attempts to communicate with the server that should occur in the duration set by the upstream-fail-timeout parameter to consider the server unavailable.

+

nginx.ingress.kubernetes.io/upstream-fail-timeout: time in seconds during which the specified number of unsuccessful attempts to communicate with the server should occur to consider the server unavailable. This is also the period of time the server will be considered unavailable.

+

In NGINX, backend server pools are called "upstreams". Each upstream contains the endpoints for a service. An upstream is created for each service that has Ingress rules defined.

+

Important: All Ingress rules using the same service will use the same upstream. Only one of the Ingress rules should define annotations to configure the upstream servers.

+

Please check the custom upstream check example.

+

Custom NGINX upstream hashing

+

NGINX supports load balancing by client-server mapping based on consistent hashing for a given key. The key can contain text, variables or any combination thereof. This feature allows for request stickiness other than client IP or cookies. The ketama consistent hashing method will be used which ensures only a few keys would be remapped to different servers on upstream group changes.

+

To enable consistent hashing for a backend:

+

nginx.ingress.kubernetes.io/upstream-hash-by: the nginx variable, text value or any combination thereof to use for consistent hashing. For example nginx.ingress.kubernetes.io/upstream-hash-by: "$request_uri" to consistently hash upstream requests by the current request URI.

+

Custom NGINX load balancing

+

This is similar to https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/configmap.md#load-balance but configures load balancing algorithm per ingress. +Note that nginx.ingress.kubernetes.io/upstream-hash-by takes preference over this. If this and nginx.ingress.kubernetes.io/upstream-hash-by are not set then we fallback to using globally configured load balancing algorithm.

+

Custom NGINX upstream vhost

+

This configuration setting allows you to control the value for host in the following statement: proxy_set_header Host $host, which forms part of the location block. This is useful if you need to call the upstream server by something other than $host.

+

Client Certificate Authentication

+

It is possible to enable Client Certificate Authentication using additional annotations in Ingress Rule.

+

The annotations are:

+
nginx.ingress.kubernetes.io/auth-tls-secret: secretName
+
+ + +

The name of the Secret that contains the full Certificate Authority chain ca.crt that is enabled to authenticate against this Ingress. +This annotation also accepts the alternative form "namespace/secretName", in which case the Secret lookup is performed in the referenced namespace instead of the Ingress namespace.

+
nginx.ingress.kubernetes.io/auth-tls-verify-depth
+
+ + +

The validation depth between the provided client certificate and the Certification Authority chain.

+
nginx.ingress.kubernetes.io/auth-tls-verify-client
+
+ + +

Enables verification of client certificates.

+
nginx.ingress.kubernetes.io/auth-tls-error-page
+
+ + +

The URL/Page that user should be redirected in case of a Certificate Authentication Error

+
nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream
+
+ + +

Indicates if the received certificates should be passed or not to the upstream server. +By default this is disabled.

+

Please check the client-certs example.

+

Important:

+

TLS with Client Authentication is NOT possible in Cloudflare as is not allowed it and might result in unexpected behavior.

+

Cloudflare only allows Authenticated Origin Pulls and is required to use their own certificate: +https://blog.cloudflare.com/protecting-the-origin-with-tls-authenticated-origin-pulls/

+

Only Authenticated Origin Pulls are allowed and can be configured by following their tutorial: +https://support.cloudflare.com/hc/en-us/articles/204494148-Setting-up-NGINX-to-use-TLS-Authenticated-Origin-Pulls

+

Configuration snippet

+

Using this annotation you can add additional configuration to the NGINX location. For example:

+
nginx.ingress.kubernetes.io/configuration-snippet: |
+  more_set_headers "Request-Id: $req_id";
+
+ + +

Default Backend

+

The ingress controller requires a default backend. This service handles the response when the service in the Ingress rule does not have endpoints. +This is a global configuration for the ingress controller. In some cases could be required to return a custom content or format. In this scenario we can use the annotation nginx.ingress.kubernetes.io/default-backend: <svc name> to specify a custom default backend.

+

Enable CORS

+

To enable Cross-Origin Resource Sharing (CORS) in an Ingress rule add the annotation nginx.ingress.kubernetes.io/enable-cors: "true". This will add a section in the server location enabling this functionality.

+

CORS can be controlled with the following annotations:

+
    +
  • nginx.ingress.kubernetes.io/cors-allow-methods controls which methods are accepted. This is a multi-valued field, separated by ',' and accepts only letters (upper and lower case).
  • +
+

Example: nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS"

+
    +
  • nginx.ingress.kubernetes.io/cors-allow-headers controls which headers are accepted. This is a multi-valued field, separated by ',' and accepts letters, numbers, _ and -.
  • +
+

Example: nginx.ingress.kubernetes.io/cors-allow-headers: "X-Forwarded-For, X-app123-XPTO"

+
    +
  • nginx.ingress.kubernetes.io/cors-allow-origin controls what's the accepted Origin for CORS and defaults to '*'. This is a single field value, with the following format: http(s)://origin-site.com or http(s)://origin-site.com:port
  • +
+

Example: nginx.ingress.kubernetes.io/cors-allow-origin: "https://origin-site.com:4443"

+
    +
  • nginx.ingress.kubernetes.io/cors-allow-credentials controls if credentials can be passed during CORS operations.
  • +
+

Example: nginx.ingress.kubernetes.io/cors-allow-credentials: "true"

+
    +
  • nginx.ingress.kubernetes.io/cors-max-age controls how long preflight requests can be cached.
  • +
+

Example: nginx.ingress.kubernetes.io/cors-max-age: 600

+

For more information please check https://enable-cors.org/server_nginx.html

+

Server Alias

+

To add Server Aliases to an Ingress rule add the annotation nginx.ingress.kubernetes.io/server-alias: "<alias>". +This will create a server with the same configuration, but a different server_name as the provided host.

+

Note: A server-alias name cannot conflict with the hostname of an existing server. If it does the server-alias +annotation will be ignored. If a server-alias is created and later a new server with the same hostname is created +the new server configuration will take place over the alias configuration.

+

For more information please see http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name

+

Server snippet

+

Using the annotation nginx.ingress.kubernetes.io/server-snippet it is possible to add custom configuration in the server configuration block.

+
apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  annotations:
+    nginx.ingress.kubernetes.io/server-snippet: |
+set $agentflag 0;
+
+if ($http_user_agent ~* "(Mobile)" ){
+  set $agentflag 1;
+}
+
+if ( $agentflag = 1 ) {
+  return 301 https://m.example.com;
+}
+
+ + +

Important: This annotation can be used only once per host

+

Client Body Buffer Size

+

Sets buffer size for reading client request body per location. In case the request body is larger than the buffer, +the whole body or only its part is written to a temporary file. By default, buffer size is equal to two memory pages. +This is 8K on x86, other 32-bit platforms, and x86-64. It is usually 16K on other 64-bit platforms. This annotation is +applied to each location provided in the ingress rule.

+

Note: The annotation value must be given in a valid format otherwise the +For example to set the client-body-buffer-size the following can be done:

+
    +
  • nginx.ingress.kubernetes.io/client-body-buffer-size: "1000" # 1000 bytes
  • +
  • nginx.ingress.kubernetes.io/client-body-buffer-size: 1k # 1 kilobyte
  • +
  • nginx.ingress.kubernetes.io/client-body-buffer-size: 1K # 1 kilobyte
  • +
  • nginx.ingress.kubernetes.io/client-body-buffer-size: 1m # 1 megabyte
  • +
  • nginx.ingress.kubernetes.io/client-body-buffer-size: 1M # 1 megabyte
  • +
+

For more information please see http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size

+

External Authentication

+

To use an existing service that provides authentication the Ingress rule can be annotated with nginx.ingress.kubernetes.io/auth-url to indicate the URL where the HTTP request should be sent.

+
nginx.ingress.kubernetes.io/auth-url: "URL to the authentication service"
+
+ + +

Additionally it is possible to set:

+

nginx.ingress.kubernetes.io/auth-method: <Method> to specify the HTTP method to use.

+

nginx.ingress.kubernetes.io/auth-signin: <SignIn_URL> to specify the location of the error page.

+

nginx.ingress.kubernetes.io/auth-response-headers: <Response_Header_1, ..., Response_Header_n> to specify headers to pass to backend once authorization request completes.

+

nginx.ingress.kubernetes.io/auth-request-redirect: <Request_Redirect_URL> to specify the X-Auth-Request-Redirect header value.

+

Please check the external-auth example.

+

Rate limiting

+

The annotations nginx.ingress.kubernetes.io/limit-connections, nginx.ingress.kubernetes.io/limit-rps, and nginx.ingress.kubernetes.io/limit-rpm define a limit on the connections that can be opened by a single client IP address. This can be used to mitigate DDoS Attacks.

+

nginx.ingress.kubernetes.io/limit-connections: number of concurrent connections allowed from a single IP address.

+

nginx.ingress.kubernetes.io/limit-rps: number of connections that may be accepted from a given IP each second.

+

nginx.ingress.kubernetes.io/limit-rpm: number of connections that may be accepted from a given IP each minute.

+

You can specify the client IP source ranges to be excluded from rate-limiting through the nginx.ingress.kubernetes.io/limit-whitelist annotation. The value is a comma separated list of CIDRs.

+

If you specify multiple annotations in a single Ingress rule, limit-rpm, and then limit-rps takes precedence.

+

The annotation nginx.ingress.kubernetes.io/limit-rate, nginx.ingress.kubernetes.io/limit-rate-after define a limit the rate of response transmission to a client. The rate is specified in bytes per second. The zero value disables rate limiting. The limit is set per a request, and so if a client simultaneously opens two connections, the overall rate will be twice as much as the specified limit.

+

nginx.ingress.kubernetes.io/limit-rate-after: sets the initial amount after which the further transmission of a response to a client will be rate limited.

+

nginx.ingress.kubernetes.io/limit-rate: rate of request that accepted from a client each second.

+

To configure this setting globally for all Ingress rules, the limit-rate-after and limit-rate value may be set in the NGINX ConfigMap. if you set the value in ingress annotation will cover global setting.

+

Permanent Redirect

+

This annotation allows to return a permanent redirect instead of sending data to the upstream. For example nginx.ingress.kubernetes.io/permanent-redirect: https://www.google.com would redirect everything to Google.

+

SSL Passthrough

+

The annotation nginx.ingress.kubernetes.io/ssl-passthrough allows to configure TLS termination in the pod and not in NGINX.

+

Important:

+
    +
  • Using the annotation nginx.ingress.kubernetes.io/ssl-passthrough invalidates all the other available annotations. This is because SSL Passthrough works in L4 (TCP).
  • +
  • The use of this annotation requires Proxy Protocol to be enabled in the load-balancer. For example enabling Proxy Protocol for AWS ELB is described here. If you're using ingress-controller without load balancer then the flag --enable-ssl-passthrough is required (by default it is disabled).
  • +
+

Secure backends

+

By default NGINX uses http to reach the services. Adding the annotation nginx.ingress.kubernetes.io/secure-backends: "true" in the Ingress rule changes the protocol to https. +If you want to validate the upstream against a specific certificate, you can create a secret with it and reference the secret with the annotation nginx.ingress.kubernetes.io/secure-verify-ca-secret.

+

Please note that if an invalid or non-existent secret is given, the NGINX ingress controller will ignore the secure-backends annotation.

+

Service Upstream

+

By default the NGINX ingress controller uses a list of all endpoints (Pod IP/port) in the NGINX upstream configuration. This annotation disables that behavior and instead uses a single upstream in NGINX, the service's Cluster IP and port. This can be desirable for things like zero-downtime deployments as it reduces the need to reload NGINX configuration when Pods come up and down. See issue #257.

+

Known Issues

+

If the service-upstream annotation is specified the following things should be taken into consideration:

+
    +
  • Sticky Sessions will not work as only round-robin load balancing is supported.
  • +
  • The proxy_next_upstream directive will not have any effect meaning on error the request will not be dispatched to another upstream.
  • +
+

Server-side HTTPS enforcement through redirect

+

By default the controller redirects (301) to HTTPS if TLS is enabled for that ingress. If you want to disable that behavior globally, you can use ssl-redirect: "false" in the NGINX config map.

+

To configure this feature for specific ingress resources, you can use the nginx.ingress.kubernetes.io/ssl-redirect: "false" annotation in the particular resource.

+

When using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a redirect to HTTPS even when there is not TLS cert available. This can be achieved by using the nginx.ingress.kubernetes.io/force-ssl-redirect: "true" annotation in the particular resource.

+

Redirect from to www

+

In some scenarios is required to redirect from www.domain.com to domain.com or viceversa. +To enable this feature use the annotation nginx.ingress.kubernetes.io/from-to-www-redirect: "true"

+

Important: +If at some point a new Ingress is created with a host equal to one of the options (like domain.com) the annotation will be omitted.

+

Whitelist source range

+

You can specify the allowed client IP source ranges through the nginx.ingress.kubernetes.io/whitelist-source-range annotation. The value is a comma separated list of CIDRs, e.g. 10.0.0.0/24,172.10.0.1.

+

To configure this setting globally for all Ingress rules, the whitelist-source-range value may be set in the NGINX ConfigMap.

+

Note: Adding an annotation to an Ingress rule overrides any global restriction.

+ +

If you use the cookie type you can also specify the name of the cookie that will be used to route the requests with the annotation nginx.ingress.kubernetes.io/session-cookie-name. The default is to create a cookie named 'INGRESSCOOKIE'.

+

In case of NGINX the annotation nginx.ingress.kubernetes.io/session-cookie-hash defines which algorithm will be used to 'hash' the used upstream. Default value is md5 and possible values are md5, sha1 and index. +The index option is not hashed, an in-memory index is used instead, it's quicker and the overhead is shorter Warning: the matching against upstream servers list is inconsistent. So, at reload, if upstreams servers has changed, index values are not guaranteed to correspond to the same server as before! USE IT WITH CAUTION and only if you need to!

+

In NGINX this feature is implemented by the third party module nginx-sticky-module-ng. The workflow used to define which upstream server will be used is explained here

+

Custom timeouts

+

Using the configuration configmap it is possible to set the default global timeout for connections to the upstream servers. +In some scenarios is required to have different values. To allow this we provide annotations that allows this customization:

+
    +
  • nginx.ingress.kubernetes.io/proxy-connect-timeout
  • +
  • nginx.ingress.kubernetes.io/proxy-send-timeout
  • +
  • nginx.ingress.kubernetes.io/proxy-read-timeout
  • +
  • nginx.ingress.kubernetes.io/proxy-next-upstream
  • +
  • nginx.ingress.kubernetes.io/proxy-next-upstream-tries
  • +
  • nginx.ingress.kubernetes.io/proxy-request-buffering
  • +
+

Proxy redirect

+

With the annotations nginx.ingress.kubernetes.io/proxy-redirect-from and nginx.ingress.kubernetes.io/proxy-redirect-to it is possible to set the text that should be changed in the Location and Refresh header fields of a proxied server response (http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect) +Setting "off" or "default" in the annotation nginx.ingress.kubernetes.io/proxy-redirect-from disables nginx.ingress.kubernetes.io/proxy-redirect-to +Both annotations will be used in any other case +By default the value is "off".

+

Custom max body size

+

For NGINX, 413 error will be returned to the client when the size in a request exceeds the maximum allowed size of the client request body. This size can be configured by the parameter client_max_body_size.

+

To configure this setting globally for all Ingress rules, the proxy-body-size value may be set in the NGINX ConfigMap. +To use custom values in an Ingress rule define these annotation:

+
nginx.ingress.kubernetes.io/proxy-body-size: 8m
+
+ + +

Proxy buffering

+

Enable or disable proxy buffering proxy_buffering. +By default proxy buffering is disabled in the nginx config.

+

To configure this setting globally for all Ingress rules, the proxy-buffering value may be set in the NGINX ConfigMap. +To use custom values in an Ingress rule define these annotation:

+
nginx.ingress.kubernetes.io/proxy-buffering: "on"
+
+ + +

SSL ciphers

+

Specifies the enabled ciphers.

+

Using this annotation will set the ssl_ciphers directive at the server level. This configuration is active for all the paths in the host.

+
nginx.ingress.kubernetes.io/ssl-ciphers: "ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"
+
+ + +

Connection proxy header

+

Using this annotation will override the default connection header set by nginx. To use custom values in an Ingress rule, define the annotation:

+
nginx.ingress.kubernetes.io/connection-proxy-header: "keep-alive"
+
+ + +

Enable Access Log

+

In some scenarios could be required to disable NGINX access logs. To enable this feature use the annotation:

+
nginx.ingress.kubernetes.io/enable-access-log: "false"
+
+ + +

Lua Resty WAF

+

Using lua-resty-waf-* annotations we can enable and control lua-resty-waf per location. +Following configuration will enable WAF for the paths defined in the corresponding ingress:

+
nginx.ingress.kubernetes.io/lua-resty-waf: "active"
+
+ + +

In order to run it in debugging mode you can set nginx.ingress.kubernetes.io/lua-resty-waf-debug to "true" in addition to the above configuration. +The other possible values for nginx.ingress.kubernetes.io/lua-resty-waf are inactive and simulate. In inactive mode WAF won't do anything, whereas +in simulate mode it will log a warning message if there's a matching WAF rule for given request. This is useful to debug a rule and eliminate possible false positives before fully deploying it.

+

lua-resty-waf comes with predefined set of rules(https://github.com/p0pr0ck5/lua-resty-waf/tree/84b4f40362500dd0cb98b9e71b5875cb1a40f1ad/rules) that covers ModSecurity CRS. +You can use nginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets to ignore subset of those rulesets. For an example:

+
nginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets: "41000_sqli, 42000_xss"
+
+ + +

will ignore the two mentioned rulesets.

+

It is also possible to configure custom WAF rules per ingress using nginx.ingress.kubernetes.io/lua-resty-waf-extra-rules annotation. For an example the following snippet will +configure a WAF rule to deny requests with query string value that contains word foo:

+
nginx.ingress.kubernetes.io/lua-resty-waf-extra-rules: '[=[ { "access": [ { "actions": { "disrupt" : "DENY" }, "id": 10001, "msg": "my custom rule", "operator": "STR_CONTAINS", "pattern": "foo", "vars": [ { "parse": [ "values", 1 ], "type": "REQUEST_ARGS" } ] } ], "body_filter": [], "header_filter":[] } ]=]'
+
+ + +

For details on how to write WAF rules, please refer to https://github.com/p0pr0ck5/lua-resty-waf.

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/nginx-configuration/configmap/index.html b/user-guide/nginx-configuration/configmap/index.html new file mode 100644 index 000000000..c77463eab --- /dev/null +++ b/user-guide/nginx-configuration/configmap/index.html @@ -0,0 +1,3642 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ConfigMaps - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

ConfigMaps

+

ConfigMaps allow you to decouple configuration artifacts from image content to keep containerized applications portable.

+

The ConfigMap API resource stores configuration data as key-value pairs. The data provides the configurations for system +components for the nginx-controller. Before you can begin using a config-map it must be deployed.

+

In order to overwrite nginx-controller configuration values as seen in config.go, +you can add key-value pairs to the data section of the config-map. For Example:

+
data:
+  map-hash-bucket-size: "128"
+  ssl-protocols: SSLv2
+
+ + +

IMPORTANT:

+

The key and values in a ConfigMap can only be strings. +This means that we want a value with boolean values we need to quote the values, like "true" or "false". +Same for numbers, like "100".

+

"Slice" types (defined below as []string or []int can be provided as a comma-delimited string.

+

Configuration options

+

The following table shows a configuration option's name, type, and the default value:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
nametypedefault
add-headersstring""
allow-backend-server-headerbool"false"
hide-headersstring arrayempty
access-log-pathstring"/var/log/nginx/access.log"
error-log-pathstring"/var/log/nginx/error.log"
enable-dynamic-tls-recordsbool"true"
enable-modsecuritybool"false"
enable-owasp-modsecurity-crsbool"false"
client-header-buffer-sizestring"1k"
client-header-timeoutint60
client-body-buffer-sizestring"8k"
client-body-timeoutint60
disable-access-logboolfalse
disable-ipv6boolfalse
disable-ipv6-dnsboolfalse
enable-underscores-in-headersboolfalse
ignore-invalid-headersbooltrue
enable-vts-statusboolfalse
vts-status-zone-sizestring"10m"
vts-sum-keystring"*"
vts-default-filter-keystring"$geoip_country_code country::*"
retry-non-idempotentbool"false"
error-log-levelstring"notice"
http2-max-field-sizestring"4k"
http2-max-header-sizestring"16k"
hstsbool"true"
hsts-include-subdomainsbool"true"
hsts-max-agestring"15724800"
hsts-preloadbool"false"
keep-aliveint75
keep-alive-requestsint100
large-client-header-buffersstring"4 8k"
log-format-escape-jsonbool"false"
log-format-upstreamstring%v - [$the_real_ip] - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status
log-format-streamstring[$time_local] $protocol $status $bytes_sent $bytes_received $session_time
max-worker-connectionsint16384
map-hash-bucket-sizeint64
nginx-status-ipv4-whitelist[]string"127.0.0.1"
nginx-status-ipv6-whitelist[]string"::1"
proxy-real-ip-cidr[]string"0.0.0.0/0"
proxy-set-headersstring""
server-name-hash-max-sizeint1024
server-name-hash-bucket-sizeint<size of the processor’s cache line>
proxy-headers-hash-max-sizeint512
proxy-headers-hash-bucket-sizeint64
server-tokensbool"true"
ssl-ciphersstring"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"
ssl-ecdh-curvestring"auto"
ssl-dh-paramstring""
ssl-protocolsstring"TLSv1.2"
ssl-session-cachebool"true"
ssl-session-cache-sizestring"10m"
ssl-session-ticketsbool"true"
ssl-session-ticket-keystring<Randomly Generated>
ssl-session-timeoutstring"10m"
ssl-buffer-sizestring"4k"
use-proxy-protocolbool"false"
use-gzipbool"true"
use-geoipbool"true"
enable-brotlibool"true"
brotli-levelint4
brotli-typesstring"application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component"
use-http2bool"true"
gzip-typesstring"application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component"
worker-processesstring<Number of CPUs>
worker-cpu-affinitystring""
worker-shutdown-timeoutstring"10s"
load-balancestring"least_conn"
variables-hash-bucket-sizeint128
variables-hash-max-sizeint2048
upstream-keepalive-connectionsint32
limit-conn-zone-variablestring"$binary_remote_addr"
proxy-stream-timeoutstring"600s"
proxy-stream-responsesint1
bind-address-ipv4[]string""
bind-address-ipv6[]string""
forwarded-for-headerstring"X-Forwarded-For"
compute-full-forwarded-forbool"false"
proxy-add-original-uri-headerbool"true"
enable-opentracingbool"false"
zipkin-collector-hoststring""
zipkin-collector-portint9411
zipkin-service-namestring"nginx"
jaeger-collector-hoststring""
jaeger-collector-portint6831
jaeger-service-namestring"nginx"
jaeger-sampler-typestring"const"
jaeger-sampler-paramstring"1"
http-snippetstring""
server-snippetstring""
location-snippetstring""
custom-http-errors[]int][]int{}
proxy-body-sizestring"1m"
proxy-connect-timeoutint5
proxy-read-timeoutint60
proxy-send-timeoutint60
proxy-buffer-sizestring"4k"
proxy-cookie-pathstring"off"
proxy-cookie-domainstring"off"
proxy-next-upstreamstring"error timeout invalid_header http_502 http_503 http_504"
proxy-next-upstream-triesint0
proxy-redirect-fromstring"off"
proxy-request-bufferingstring"on"
ssl-redirectbool"true"
whitelist-source-range[]string[]string{}
skip-access-log-urls[]string[]string{}
limit-rateint0
limit-rate-afterint0
http-redirect-codeint308
proxy-bufferingstring"off"
limit-req-status-codeint503
no-tls-redirect-locationsstring"/.well-known/acme-challenge"
no-auth-locationsstring"/.well-known/acme-challenge"
+

add-headers

+

Sets custom headers from named configmap before sending traffic to the client. See proxy-set-headers. example

+

allow-backend-server-header

+

Enables the return of the header Server from the backend instead of the generic nginx string. By default this is disabled.

+

hide-headers

+

Sets additional header that will not be passed from the upstream server to the client response. +Default: empty

+

References: +- http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header

+

access-log-path

+

Access log path. Goes to /var/log/nginx/access.log by default.

+

Note: the file /var/log/nginx/access.log is a symlink to /dev/stdout

+

error-log-path

+

Error log path. Goes to /var/log/nginx/error.log by default.

+

Note: the file /var/log/nginx/error.log is a symlink to /dev/stderr

+

References: +- http://nginx.org/en/docs/ngx_core_module.html#error_log

+

enable-dynamic-tls-records

+

Enables dynamically sized TLS records to improve time-to-first-byte. By default this is enabled. See CloudFlare's blog for more information.

+

enable-modsecurity

+

Enables the modsecurity module for NGINX. By default this is disabled.

+

enable-owasp-modsecurity-crs

+

Enables the OWASP ModSecurity Core Rule Set (CRS). By default this is disabled.

+

client-header-buffer-size

+

Allows to configure a custom buffer size for reading client request header.

+

References: +- http://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_buffer_size

+

client-header-timeout

+

Defines a timeout for reading client request header, in seconds.

+

References: +- http://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_timeout

+

client-body-buffer-size

+

Sets buffer size for reading client request body.

+

References: +- http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size

+

client-body-timeout

+

Defines a timeout for reading client request body, in seconds.

+

References: +- http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_timeout

+

disable-access-log

+

Disables the Access Log from the entire Ingress Controller. This is '"false"' by default.

+

References: +- http://nginx.org/en/docs/http/ngx_http_log_module.html#access_log

+

disable-ipv6

+

Disable listening on IPV6. By default this is disabled.

+

disable-ipv6-dns

+

Disable IPV6 for nginx DNS resolver. By default this is disabled.

+

enable-underscores-in-headers

+

Enables underscores in header names. By default this is disabled.

+

ignore-invalid-headers

+

Set if header fields with invalid names should be ignored. +By default this is enabled.

+

enable-vts-status

+

Allows the replacement of the default status page with a third party module named nginx-module-vts. +By default this is disabled.

+

vts-status-zone-size

+

Vts config on http level sets parameters for a shared memory zone that will keep states for various keys. The cache is shared between all worker processes. Default value is 10m

+

References: +- https://github.com/vozlt/nginx-module-vts#vhost_traffic_status_zone

+

vts-default-filter-key

+

Vts config on http level enables the keys by user defined variable. The key is a key string to calculate traffic. The name is a group string to calculate traffic. The key and name can contain variables such as $host, $server_name. The name's group belongs to filterZones if specified. The key's group belongs to serverZones if not specified second argument name. Default value is $geoip_country_code country::*

+

References: +- https://github.com/vozlt/nginx-module-vts#vhost_traffic_status_filter_by_set_key

+

vts-sum-key

+

For metrics keyed (or when using Prometheus, labeled) by server zone, this value is used to indicate metrics for all server zones combined. Default value is *

+

References: +- https://github.com/vozlt/nginx-module-vts#vhost_traffic_status_display_sum_key

+

retry-non-idempotent

+

Since 1.9.13 NGINX will not retry non-idempotent requests (POST, LOCK, PATCH) in case of an error in the upstream server. The previous behavior can be restored using the value "true".

+

error-log-level

+

Configures the logging level of errors. Log levels above are listed in the order of increasing severity.

+

References: +- http://nginx.org/en/docs/ngx_core_module.html#error_log

+

http2-max-field-size

+

Limits the maximum size of an HPACK-compressed request header field.

+

References: +- https://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_field_size

+

http2-max-header-size

+

Limits the maximum size of the entire request header list after HPACK decompression.

+

References: +- https://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_header_size

+

hsts

+

Enables or disables the header HSTS in servers running SSL. +HTTP Strict Transport Security (often abbreviated as HSTS) is a security feature (HTTP header) that tell browsers that it should only be communicated with using HTTPS, instead of using HTTP. It provides protection against protocol downgrade attacks and cookie theft.

+

References: +- https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security +- https://blog.qualys.com/securitylabs/2016/03/28/the-importance-of-a-proper-http-strict-transport-security-implementation-on-your-web-server

+

hsts-include-subdomains

+

Enables or disables the use of HSTS in all the subdomains of the server-name.

+

hsts-max-age

+

Sets the time, in seconds, that the browser should remember that this site is only to be accessed using HTTPS.

+

hsts-preload

+

Enables or disables the preload attribute in the HSTS feature (when it is enabled) dd

+

keep-alive

+

Sets the time during which a keep-alive client connection will stay open on the server side. The zero value disables keep-alive client connections.

+

References: +- http://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout

+

keep-alive-requests

+

Sets the maximum number of requests that can be served through one keep-alive connection.

+

References: +- http://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_requests

+

large-client-header-buffers

+

Sets the maximum number and size of buffers used for reading large client request header. Default: 4 8k.

+

References: +- http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers

+

log-format-escape-json

+

Sets if the escape parameter allows JSON ("true") or default characters escaping in variables ("false") Sets the nginx log format.

+

log-format-upstream

+

Sets the nginx log format. +Example for json output:

+

consolelog-format-upstream: '{ "time": "$time_iso8601", "remote_addr": "$proxy_protocol_addr","x-forward-for": "$proxy_add_x_forwarded_for", "request_id": "$req_id", "remote_user":"$remote_user", "bytes_sent": $bytes_sent, "request_time": $request_time, "status":$status, "vhost": "$host", "request_proto": "$server_protocol", "path": "$uri","request_query": "$args", "request_length": $request_length, "duration": $request_time,"method": "$request_method", "http_referrer": "$http_referer", "http_user_agent":"$http_user_agent" }'

+

Please check log-format for definition of each field.

+

log-format-stream

+

Sets the nginx stream format.

+

max-worker-connections

+

Sets the maximum number of simultaneous connections that can be opened by each worker process

+

map-hash-bucket-size

+

Sets the bucket size for the map variables hash tables. The details of setting up hash tables are provided in a separate document.

+

proxy-real-ip-cidr

+

If use-proxy-protocol is enabled, proxy-real-ip-cidr defines the default the IP/network address of your external load balancer.

+

proxy-set-headers

+

Sets custom headers from named configmap before sending traffic to backends. The value format is namespace/name. See example

+

server-name-hash-max-size

+

Sets the maximum size of the server names hash tables used in server names,map directive’s values, MIME types, names of request header strings, etc.

+

References: +- http://nginx.org/en/docs/hash.html

+

server-name-hash-bucket-size

+

Sets the size of the bucket for the server names hash tables.

+

References: +- http://nginx.org/en/docs/hash.html +- http://nginx.org/en/docs/http/ngx_http_core_module.html#server_names_hash_bucket_size

+

proxy-headers-hash-max-size

+

Sets the maximum size of the proxy headers hash tables.

+

References: +- http://nginx.org/en/docs/hash.html +- https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_max_size

+

proxy-headers-hash-bucket-size

+

Sets the size of the bucket for the proxy headers hash tables.

+

References: +- http://nginx.org/en/docs/hash.html +- https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_bucket_size

+

server-tokens

+

Send NGINX Server header in responses and display NGINX version in error pages. By default this is enabled.

+

ssl-ciphers

+

Sets the ciphers list to enable. The ciphers are specified in the format understood by the OpenSSL library.

+

The default cipher list is: + 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.

+

The ordering of a ciphersuite is very important because it decides which algorithms are going to be selected in priority. The recommendation above prioritizes algorithms that provide perfect forward secrecy.

+

Please check the Mozilla SSL Configuration Generator.

+

ssl-ecdh-curve

+

Specifies a curve for ECDHE ciphers.

+

References: +- http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_ecdh_curve

+

ssl-dh-param

+

Sets the name of the secret that contains Diffie-Hellman key to help with "Perfect Forward Secrecy".

+

References: +- https://wiki.openssl.org/index.php/Manual:Dhparam(1) +- https://wiki.mozilla.org/Security/Server_Side_TLS#DHE_handshake_and_dhparam +- http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_dhparam

+

ssl-protocols

+

Sets the SSL protocols to use. The default is: TLSv1.2.

+

Please check the result of the configuration using https://ssllabs.com/ssltest/analyze.html or https://testssl.sh.

+

ssl-session-cache

+

Enables or disables the use of shared SSL cache among worker processes.

+

ssl-session-cache-size

+

Sets the size of the SSL shared session cache between all worker processes.

+

ssl-session-tickets

+

Enables or disables session resumption through TLS session tickets.

+

ssl-session-ticket-key

+

Sets the secret key used to encrypt and decrypt TLS session tickets. The value must be a valid base64 string.

+

TLS session ticket-key, by default, a randomly generated key is used. To create a ticket: openssl rand 80 | base64 -w0

+

ssl-session-timeout

+

Sets the time during which a client may reuse the session parameters stored in a cache.

+

ssl-buffer-size

+

Sets the size of the SSL buffer used for sending data. The default of 4k helps NGINX to improve TLS Time To First Byte (TTTFB).

+

References: +- https://www.igvita.com/2013/12/16/optimizing-nginx-tls-time-to-first-byte/

+

use-proxy-protocol

+

Enables or disables the PROXY protocol to receive client connection (real IP address) information passed through proxy servers and load balancers such as HAProxy and Amazon Elastic Load Balancer (ELB).

+

use-gzip

+

Enables or disables compression of HTTP responses using the "gzip" module. +The default mime type list to compress is: application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component.

+

use-geoip

+

Enables or disables "geoip" module that creates variables with values depending on the client IP address, using the precompiled MaxMind databases. +The default value is true.

+

enable-brotli

+

Enables or disables compression of HTTP responses using the "brotli" module. +The default mime type list to compress is: application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component. This is disabled by default.

+

Note: Brotli does not works in Safari < 11 https://caniuse.com/#feat=brotli

+

brotli-level

+

Sets the Brotli Compression Level that will be used. Defaults to 4.

+

brotli-types

+

Sets the MIME Types that will be compressed on-the-fly by brotli. +Defaults to application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component.

+

use-http2

+

Enables or disables HTTP/2 support in secure connections.

+

gzip-types

+

Sets the MIME types in addition to "text/html" to compress. The special value "*" matches any MIME type. Responses with the "text/html" type are always compressed if use-gzip is enabled.

+

worker-processes

+

Sets the number of worker processes. +The default of "auto" means number of available CPU cores.

+

worker-cpu-affinity

+

Binds worker processes to the sets of CPUs. worker_cpu_affinity. +By default worker processes are not bound to any specific CPUs. The value can be:

+
    +
  • "": empty string indicate no affinity is applied.
  • +
  • cpumask: e.g. 0001 0010 0100 1000 to bind processes to specific cpus.
  • +
  • auto: binding worker processes automatically to available CPUs.
  • +
+

worker-shutdown-timeout

+

Sets a timeout for Nginx to wait for worker to gracefully shutdown. The default is "10s".

+

load-balance

+

Sets the algorithm to use for load balancing. +The value can either be:

+
    +
  • round_robin: to use the default round robin loadbalancer
  • +
  • least_conn: to use the least connected method
  • +
  • ip_hash: to use a hash of the server for routing.
  • +
  • ewma: to use the peak ewma method for routing (only available with enable-dynamic-configuration flag)
  • +
+

The default is least_conn.

+

References: +- http://nginx.org/en/docs/http/load_balancing.html.

+

variables-hash-bucket-size

+

Sets the bucket size for the variables hash table.

+

References: +- http://nginx.org/en/docs/http/ngx_http_map_module.html#variables_hash_bucket_size

+

variables-hash-max-size

+

Sets the maximum size of the variables hash table.

+

References: +- http://nginx.org/en/docs/http/ngx_http_map_module.html#variables_hash_max_size

+

upstream-keepalive-connections

+

Activates the cache for connections to upstream servers. The connections parameter sets the maximum number of idle keepalive connections to upstream servers that are preserved in the cache of each worker process. When this +number is exceeded, the least recently used connections are closed. Default: 32

+

References: +- http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive

+

limit-conn-zone-variable

+

Sets parameters for a shared memory zone that will keep states for various keys of limit_conn_zone. The default of "$binary_remote_addr" variable’s size is always 4 bytes for IPv4 addresses or 16 bytes for IPv6 addresses.

+

proxy-stream-timeout

+

Sets the timeout between two successive read or write operations on client or proxied server connections. If no data is transmitted within this time, the connection is closed.

+

References: +- http://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_timeout

+

proxy-stream-responses

+

Sets the number of datagrams expected from the proxied server in response to the client request if the UDP protocol is used.

+

References: +- http://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_responses

+

bind-address-ipv4

+

Sets the addresses on which the server will accept requests instead of *. It should be noted that these addresses must exist in the runtime environment or the controller will crash loop.

+

bind-address-ipv6

+

Sets the addresses on which the server will accept requests instead of *. It should be noted that these addresses must exist in the runtime environment or the controller will crash loop.

+

forwarded-for-header

+

Sets the header field for identifying the originating IP address of a client. Default is X-Forwarded-For

+

compute-full-forwarded-for

+

Append the remote address to the X-Forwarded-For header instead of replacing it. When this option is enabled, the upstream application is responsible for extracting the client IP based on its own list of trusted proxies.

+

proxy-add-original-uri-header

+

Adds an X-Original-Uri header with the original request URI to the backend request

+

enable-opentracing

+

Enables the nginx Opentracing extension. By default this is disabled.

+

References: +- https://github.com/opentracing-contrib/nginx-opentracing

+

zipkin-collector-host

+

Specifies the host to use when uploading traces. It must be a valid URL.

+

zipkin-collector-port

+

Specifies the port to use when uploading traces. Default: 9411

+

zipkin-service-name

+

Specifies the service name to use for any traces created. Default: nginx

+

jaeger-collector-host

+

Specifies the host to use when uploading traces. It must be a valid URL.

+

jaeger-collector-port

+

Specifies the port to use when uploading traces. Default: 6831

+

jaeger-service-name

+

Specifies the service name to use for any traces created. Default: nginx

+

jaeger-sampler-type

+

Specifies the sampler to be used when sampling traces. The available samplers are: const, probabilistic, ratelimiting, remote. Default const.

+

jaeger-sampler-param

+

Specifies the argument to be passed to the sampler constructor. Must be a number. +For const this should be 0 to never sample and 1 to always sample. Default: 1

+

http-snippet

+

Adds custom configuration to the http section of the nginx configuration. +Default: ""

+

server-snippet

+

Adds custom configuration to all the servers in the nginx configuration. +Default: ""

+

location-snippet

+

Adds custom configuration to all the locations in the nginx configuration. +Default: ""

+

custom-http-errors

+

Enables which HTTP codes should be passed for processing with the error_page directive

+

Setting at least one code also enables proxy_intercept_errors which are required to process error_page.

+

Example usage: custom-http-errors: 404,415

+

proxy-body-size

+

Sets the maximum allowed size of the client request body. +See NGINX client_max_body_size.

+

proxy-connect-timeout

+

Sets the timeout for establishing a connection with a proxied server. It should be noted that this timeout cannot usually exceed 75 seconds.

+

proxy-read-timeout

+

Sets the timeout in seconds for reading a response from the proxied server. The timeout is set only between two successive read operations, not for the transmission of the whole response.

+

proxy-send-timeout

+

Sets the timeout in seconds for transmitting a request to the proxied server. The timeout is set only between two successive write operations, not for the transmission of the whole request.

+

proxy-buffer-size

+

Sets the size of the buffer used for reading the first part of the response received from the proxied server. This part usually contains a small response header.

+ +

Sets a text that should be changed in the path attribute of the “Set-Cookie” header fields of a proxied server response.

+ +

Sets a text that should be changed in the domain attribute of the “Set-Cookie” header fields of a proxied server response.

+

proxy-next-upstream

+

Specifies in which cases a request should be passed to the next server.

+

proxy-next-upstream-tries

+

Limit the number of possible tries a request should be passed to the next server.

+

proxy-redirect-from

+

Sets the original text that should be changed in the "Location" and "Refresh" header fields of a proxied server response. Default: off.

+

References: +- http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect

+

proxy-request-buffering

+

Enables or disables buffering of a client request body.

+

ssl-redirect

+

Sets the global value of redirects (301) to HTTPS if the server has a TLS certificate (defined in an Ingress rule). +Default is "true".

+

whitelist-source-range

+

Sets the default whitelisted IPs for each server block. This can be overwritten by an annotation on an Ingress rule. +See ngx_http_access_module.

+

skip-access-log-urls

+

Sets a list of URLs that should not appear in the NGINX access log. This is useful with urls like /health or health-check that make "complex" reading the logs. By default this list is empty

+

limit-rate

+

Limits the rate of response transmission to a client. The rate is specified in bytes per second. The zero value disables rate limiting. The limit is set per a request, and so if a client simultaneously opens two connections, the overall rate will be twice as much as the specified limit.

+

References: +- http://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate

+

limit-rate-after

+

Sets the initial amount after which the further transmission of a response to a client will be rate limited.

+

References: +- http://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate_after

+

http-redirect-code

+

Sets the HTTP status code to be used in redirects. +Supported codes are 301,302,307 and 308 +Default code is 308.

+

Why the default code is 308?

+

RFC 7238 was created to define the 308 (Permanent Redirect) status code that is similar to 301 (Moved Permanently) but it keeps the payload in the redirect. This is important if the we send a redirect in methods like POST.

+

proxy-buffering

+

Enables or disables buffering of responses from the proxied server.

+

limit-req-status-code

+

Sets the status code to return in response to rejected requests.Default: 503

+

no-tls-redirect-locations

+

A comma-separated list of locations on which http requests will never get redirected to their https counterpart. +Default: "/.well-known/acme-challenge"

+

no-auth-locations

+

A comma-separated list of locations that should not get authenticated. +Default: "/.well-known/acme-challenge"

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/nginx-configuration/custom-template/index.html b/user-guide/nginx-configuration/custom-template/index.html new file mode 100644 index 000000000..bf566d3dd --- /dev/null +++ b/user-guide/nginx-configuration/custom-template/index.html @@ -0,0 +1,1152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Custom NGINX template - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Custom NGINX template

+

The NGINX template is located in the file /etc/nginx/template/nginx.tmpl.

+

Using a Volume it is possible to use a custom template. +This includes using a Configmap as source of the template

+
        volumeMounts:
+          - mountPath: /etc/nginx/template
+            name: nginx-template-volume
+            readOnly: true
+      volumes:
+        - name: nginx-template-volume
+          configMap:
+            name: nginx-template
+            items:
+            - key: nginx.tmpl
+              path: nginx.tmpl
+
+ + +

Please note the template is tied to the Go code. Do not change names in the variable $cfg.

+

For more information about the template syntax please check the Go template package. +In addition to the built-in functions provided by the Go package the following functions are also available:

+
    +
  • empty: returns true if the specified parameter (string) is empty
  • +
  • contains: strings.Contains
  • +
  • hasPrefix: strings.HasPrefix
  • +
  • hasSuffix: strings.HasSuffix
  • +
  • toUpper: strings.ToUpper
  • +
  • toLower: strings.ToLower
  • +
  • buildLocation: helps to build the NGINX Location section in each server
  • +
  • buildProxyPass: builds the reverse proxy configuration
  • +
  • buildRateLimit: helps to build a limit zone inside a location if contains a rate limit annotation
  • +
+

TODO:

+
    +
  • buildAuthLocation:
  • +
  • buildAuthResponseHeaders:
  • +
  • buildResolvers:
  • +
  • buildLogFormatUpstream:
  • +
  • buildDenyVariable:
  • +
  • buildUpstreamName:
  • +
  • buildForwardedFor:
  • +
  • buildAuthSignURL:
  • +
  • buildNextUpstream:
  • +
  • filterRateLimits:
  • +
  • formatIP:
  • +
  • getenv:
  • +
  • getIngressInformation:
  • +
  • serverConfig:
  • +
  • isLocationAllowed:
  • +
  • isValidClientBodyBufferSize:
  • +
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/nginx-configuration/index.html b/user-guide/nginx-configuration/index.html new file mode 100644 index 000000000..1b21ac6e9 --- /dev/null +++ b/user-guide/nginx-configuration/index.html @@ -0,0 +1,1108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NGINX Configuration - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

NGINX Configuration

+

There are three ways to customize NGINX:

+
    +
  1. ConfigMap: using a Configmap to set global configurations in NGINX.
  2. +
  3. Annotations: use this if you want a specific configuration for a particular Ingress rule.
  4. +
  5. Custom template: when more specific settings are required, like open_file_cache, adjust listen options as rcvbuf or when is not possible to change the configuration through the ConfigMap.
  6. +
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/nginx-configuration/log-format/index.html b/user-guide/nginx-configuration/log-format/index.html new file mode 100644 index 000000000..e7d90bbfe --- /dev/null +++ b/user-guide/nginx-configuration/log-format/index.html @@ -0,0 +1,1134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Log format - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

Log format

+

The default configuration uses a custom logging format to add additional information about upstreams, response time and status

+
    log_format upstreaminfo '{{ if $cfg.useProxyProtocol }}$proxy_protocol_addr{{ else }}$remote_addr{{ end }} - '
+        '[$the_real_ip] - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" '
+        '$request_length $request_time [$proxy_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status';
+
+ + +

Sources:

+ +

Description:

+
    +
  • $proxy_protocol_addr: if PROXY protocol is enabled
  • +
  • $remote_addr: if PROXY protocol is disabled (default)
  • +
  • $the_real_ip: the source IP address of the client
  • +
  • $remote_user: user name supplied with the Basic authentication
  • +
  • $time_local: local time in the Common Log Format
  • +
  • $request: full original request line
  • +
  • $status: response status
  • +
  • $body_bytes_sent: number of bytes sent to a client, not counting the response header
  • +
  • $http_referer: value of the Referer header
  • +
  • $http_user_agent: value of User-Agent header
  • +
  • $request_length: request length (including request line, header, and request body)
  • +
  • $request_time: time elapsed since the first bytes were read from the client
  • +
  • $proxy_upstream_name: name of the upstream. The format is upstream-<namespace>-<service name>-<service port>
  • +
  • $upstream_addr: keeps the IP address and port, or the path to the UNIX-domain socket of the upstream server. If several servers were contacted during request processing, their addresses are separated by commas
  • +
  • $upstream_response_length: keeps the length of the response obtained from the upstream server
  • +
  • $upstream_response_time: keeps time spent on receiving the response from the upstream server; the time is kept in seconds with millisecond resolution
  • +
  • $upstream_status: keeps status code of the response obtained from the upstream server
  • +
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/nginx-status-page/index.html b/user-guide/nginx-status-page/index.html new file mode 100644 index 000000000..f53bf8a6a --- /dev/null +++ b/user-guide/nginx-status-page/index.html @@ -0,0 +1,1106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NGINX status page - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

NGINX status page

+

The ngx_http_stub_status_module module provides access to basic status information. +This is the default module active in the url /nginx_status in the status port (default is 18080).

+

This controller provides an alternative to this module using the nginx-module-vts module. +To use this module just set in the configuration configmap enable-vts-status: "true".

+

nginx-module-vts screenshot

+

To extract the information in JSON format the module provides a custom URL: /nginx_status/format/json

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/third-party-addons/modsecurity/index.html b/user-guide/third-party-addons/modsecurity/index.html new file mode 100644 index 000000000..d40c0b998 --- /dev/null +++ b/user-guide/third-party-addons/modsecurity/index.html @@ -0,0 +1,1111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ModSecurity Web Application Firewall - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

ModSecurity Web Application Firewall

+

ModSecurity is an open source, cross platform web application firewall (WAF) engine for Apache, IIS and Nginx that is developed by Trustwave's SpiderLabs. It has a robust event-based programming language which provides protection from a range of attacks against web applications and allows for HTTP traffic monitoring, logging and real-time analysis - https://www.modsecurity.org

+

The ModSecurity-nginx connector is the connection point between NGINX and libmodsecurity (ModSecurity v3).

+

The default ModSecurity configuration file is located in /etc/nginx/modsecurity/modsecurity.conf. This is the only file located in this directory and contains the default recommended configuration. Using a volume we can replace this file with the desired configuration. +To enable the ModSecurity feature we need to specify enable-modsecurity: "true" in the configuration configmap.

+

NOTE: the default configuration use detection only, because that minimises the chances of post-installation disruption. +The file /var/log/modsec_audit.log contains the log of ModSecurity.

+

The OWASP ModSecurity Core Rule Set (CRS) is a set of generic attack detection rules for use with ModSecurity or compatible web application firewalls. The CRS aims to protect web applications from a wide range of attacks, including the OWASP Top Ten, with a minimum of false alerts. +The directory /etc/nginx/owasp-modsecurity-crs contains the https://github.com/SpiderLabs/owasp-modsecurity-crs repository. +Using enable-owasp-modsecurity-crs: "true" we enable the use of the rules.

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/third-party-addons/opentracing/index.html b/user-guide/third-party-addons/opentracing/index.html new file mode 100644 index 000000000..9dd2043d1 --- /dev/null +++ b/user-guide/third-party-addons/opentracing/index.html @@ -0,0 +1,1136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OpenTracing - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + + +

OpenTracing

+

Using the third party module opentracing-contrib/nginx-opentracing the NGINX ingress controller can configure NGINX to enable OpenTracing instrumentation. +By default this feature is disabled.

+

To enable the instrumentation we just need to enable the instrumentation in the configuration configmap and set the host where we should send the traces.

+

In the rnburn/zipkin-date-server +github repository is an example of a dockerized date service. To install the example and zipkin collector run:

+
kubectl create -f https://raw.githubusercontent.com/rnburn/zipkin-date-server/master/kubernetes/zipkin.yaml
+kubectl create -f https://raw.githubusercontent.com/rnburn/zipkin-date-server/master/kubernetes/deployment.yaml
+
+ + +

Also we need to configure the NGINX controller configmap with the required values:

+
$ echo '
+apiVersion: v1
+kind: ConfigMap
+data:
+  enable-opentracing: "true"
+  zipkin-collector-host: zipkin.default.svc.cluster.local
+metadata:
+  name: nginx-configuration
+  namespace: ingress-nginx
+  labels:
+    app: ingress-nginx
+' | kubectl replace -f -
+
+ + +

Using curl we can generate some traces:

+
$ curl -v http://$(minikube ip)
+$ curl -v http://$(minikube ip)
+
+ + +

In the zipkin interface we can see the details:

+

zipkin screenshot

+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/user-guide/tls/index.html b/user-guide/tls/index.html new file mode 100644 index 000000000..4a34cb50a --- /dev/null +++ b/user-guide/tls/index.html @@ -0,0 +1,1371 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TLS - NGINX Ingress Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content + + + +
+ +
+ +
+ + + + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ + + + + +
+
+ + + + + +

TLS

+ +

Default SSL Certificate

+

NGINX provides the option to configure a server as a catch-all with server_name for requests that do not match any of the configured server names. This configuration works without issues for HTTP traffic. +In case of HTTPS, NGINX requires a certificate. +For this reason the Ingress controller provides the flag --default-ssl-certificate. The secret behind this flag contains the default certificate to be used in the mentioned scenario. If this flag is not provided NGINX will use a self signed certificate.

+

Running without the flag --default-ssl-certificate:

+
$ curl -v https://10.2.78.7:443 -k
+* Rebuilt URL to: https://10.2.78.7:443/
+*   Trying 10.2.78.4...
+* Connected to 10.2.78.7 (10.2.78.7) port 443 (#0)
+* ALPN, offering http/1.1
+* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
+* successfully set certificate verify locations:
+*   CAfile: /etc/ssl/certs/ca-certificates.crt
+  CApath: /etc/ssl/certs
+* TLSv1.2 (OUT), TLS header, Certificate Status (22):
+* TLSv1.2 (OUT), TLS handshake, Client hello (1):
+* TLSv1.2 (IN), TLS handshake, Server hello (2):
+* TLSv1.2 (IN), TLS handshake, Certificate (11):
+* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
+* TLSv1.2 (IN), TLS handshake, Server finished (14):
+* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
+* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
+* TLSv1.2 (OUT), TLS handshake, Finished (20):
+* TLSv1.2 (IN), TLS change cipher, Client hello (1):
+* TLSv1.2 (IN), TLS handshake, Finished (20):
+* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
+* ALPN, server accepted to use http/1.1
+* Server certificate:
+*    subject: CN=foo.bar.com
+*    start date: Apr 13 00:50:56 2016 GMT
+*    expire date: Apr 13 00:50:56 2017 GMT
+*    issuer: CN=foo.bar.com
+*    SSL certificate verify result: self signed certificate (18), continuing anyway.
+> GET / HTTP/1.1
+> Host: 10.2.78.7
+> User-Agent: curl/7.47.1
+> Accept: */*
+>
+< HTTP/1.1 404 Not Found
+< Server: nginx/1.11.1
+< Date: Thu, 21 Jul 2016 15:38:46 GMT
+< Content-Type: text/html
+< Transfer-Encoding: chunked
+< Connection: keep-alive
+< Strict-Transport-Security: max-age=15724800; includeSubDomains; preload
+<
+<span>The page you're looking for could not be found.</span>
+
+* Connection #0 to host 10.2.78.7 left intact
+
+ + +

Specifying --default-ssl-certificate=default/foo-tls:

+
core@localhost ~ $ curl -v https://10.2.78.7:443 -k
+* Rebuilt URL to: https://10.2.78.7:443/
+*   Trying 10.2.78.7...
+* Connected to 10.2.78.7 (10.2.78.7) port 443 (#0)
+* ALPN, offering http/1.1
+* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
+* successfully set certificate verify locations:
+*   CAfile: /etc/ssl/certs/ca-certificates.crt
+  CApath: /etc/ssl/certs
+* TLSv1.2 (OUT), TLS header, Certificate Status (22):
+* TLSv1.2 (OUT), TLS handshake, Client hello (1):
+* TLSv1.2 (IN), TLS handshake, Server hello (2):
+* TLSv1.2 (IN), TLS handshake, Certificate (11):
+* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
+* TLSv1.2 (IN), TLS handshake, Server finished (14):
+* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
+* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
+* TLSv1.2 (OUT), TLS handshake, Finished (20):
+* TLSv1.2 (IN), TLS change cipher, Client hello (1):
+* TLSv1.2 (IN), TLS handshake, Finished (20):
+* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
+* ALPN, server accepted to use http/1.1
+* Server certificate:
+*    subject: CN=foo.bar.com
+*    start date: Apr 13 00:50:56 2016 GMT
+*    expire date: Apr 13 00:50:56 2017 GMT
+*    issuer: CN=foo.bar.com
+*    SSL certificate verify result: self signed certificate (18), continuing anyway.
+> GET / HTTP/1.1
+> Host: 10.2.78.7
+> User-Agent: curl/7.47.1
+> Accept: */*
+>
+< HTTP/1.1 404 Not Found
+< Server: nginx/1.11.1
+< Date: Mon, 18 Jul 2016 21:02:59 GMT
+< Content-Type: text/html
+< Transfer-Encoding: chunked
+< Connection: keep-alive
+< Strict-Transport-Security: max-age=15724800; includeSubDomains; preload
+<
+<span>The page you're looking for could not be found.</span>
+
+* Connection #0 to host 10.2.78.7 left intact
+
+ + +

SSL Passthrough

+

The flag --enable-ssl-passthrough enables SSL passthrough feature. +By default this feature is disabled

+

HTTP Strict Transport Security

+

HTTP Strict Transport Security (HSTS) is an opt-in security enhancement specified through the use of a special response header. Once a supported browser receives this header that browser will prevent any communications from being sent over HTTP to the specified domain and will instead send all communications over HTTPS.

+

By default the controller redirects (301) to HTTPS if there is a TLS Ingress rule.

+

To disable this behavior use hsts: "false" in the configuration ConfigMap.

+

Server-side HTTPS enforcement through redirect

+

By default the controller redirects (301) to HTTPS if TLS is enabled for that ingress. If you want to disable that behavior globally, you can use ssl-redirect: "false" in the NGINX config map.

+

To configure this feature for specific ingress resources, you can use the nginx.ingress.kubernetes.io/ssl-redirect: "false" annotation in the particular resource.

+

When using SSL offloading outside of cluster (e.g. AWS ELB) it may be useful to enforce a redirect to HTTPS even when there is not TLS cert available. This can be achieved by using the nginx.ingress.kubernetes.io/force-ssl-redirect: "true" annotation in the particular resource.

+

Automated Certificate Management with Kube-Lego

+

Kube-Lego automatically requests missing or expired certificates from Let's Encrypt by monitoring ingress resources and their referenced secrets. To enable this for an ingress resource you have to add an annotation:

+
kubectl annotate ing ingress-demo kubernetes.io/tls-acme="true"
+
+ + +

To setup Kube-Lego you can take a look at this full example. The first +version to fully support Kube-Lego is nginx Ingress controller 0.8.

+

Default TLS Version and Ciphers

+

To provide the most secure baseline configuration possible, nginx-ingress defaults to using TLS 1.2 and a secure set of TLS ciphers

+

Legacy TLS

+

The default configuration, though secure, does not support some older browsers and operating systems. For instance, 20% of Android phones in use today are not compatible with nginx-ingress's default configuration. To change this default behavior, use a ConfigMap.

+

A sample ConfigMap to allow these older clients connect could look something like the following:

+
kind: ConfigMap
+apiVersion: v1
+metadata:
+  name: nginx-config
+data:
+  ssl-ciphers: "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
+  ssl-protocols: "TLSv1 TLSv1.1 TLSv1.2"
+
+ + + + + + + + + +
+
+
+
+ + + + +
+ + + + + + + + + + + \ No newline at end of file