diff --git a/docs/_static/css/main.css b/docs/_static/css/main.css index 77653817..7274cea1 100644 --- a/docs/_static/css/main.css +++ b/docs/_static/css/main.css @@ -1 +1 @@ -:root{--blue: #005dab;--primary-blue: #063b67;--secondary-blue: #074e8a;--text-blue: #063b67;--light-blue: #EEF8FF;--light-blue-clear: #F8FCFF;--aqua: #51B3DB;--primary-orange: #FF7101;--hover-orange: #FF8201;--light-orange: #f2a557;--grey: #F5F6F8;--grey-border: #D9E7F3;--light-grey-sidebar: #E5EAF0;--message-success: #4bb52d;--message-success-bg: #E3F6CF;--message-success-text: #0D3D00;--message-danger: #D10000;--message-danger-bg: #FAE5E8;--message-danger-text: #6A0000;--message-warning: #DC7500;--message-warning-bg: #FFF1ED;--message-warning-text: #9C3900;--message-info: #074E8A;--message-info-bg: #E7F2F8;--message-info-text: #063b67;--cc-btn-primary-bg: var(--primary-blue);--cc-btn-secondary-text: var(--primary-blue)}.rst-content section ul{line-height:auto}code,pre,pre span,span.pre,.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:"Ubuntu Mono",monospace}ul.simple li code,code.docutils.literal.notranslate{border:none;width:max-content;font-size:13px;padding:10px;margin:10px 0;border-radius:8px;background:#292d3e}ul.simple li code.literal,code.docutils.literal.notranslate.literal{color:var(--aqua)}code.docutils.literal.notranslate{background:#efefef;padding:2px 6px}code.docutils.literal.notranslate.literal{color:var(--blue)}.rst-content div.notranslate{border:none}.rst-content div.notranslate .highlight{font-family:"Ubuntu Mono",monospace;font-size:16px;padding:10px;line-height:24px;margin:10px 0;border-radius:8px;background-color:#292d3e;color:#d9e7f3}.rst-content div.notranslate .highlight .c1{color:var(--message-warning)}.rst-content div.notranslate .highlight .mi,.rst-content div.notranslate .highlight .o,.rst-content div.notranslate .highlight .mf{color:#e4e4e4}.rst-content div.notranslate .highlight .s,.rst-content div.notranslate .highlight .n,.rst-content div.notranslate .highlight .nb,.rst-content div.notranslate .highlight .na,.rst-content div.notranslate .highlight .s1{color:var(--aqua)}.rst-content div.notranslate .highlight .s1{color:var(--light-orange)}.rst-content div.notranslate .highlight .k,.rst-content div.notranslate .highlight .nv,.rst-content div.notranslate .highlight .m,.rst-content div.notranslate .highlight .vg,.rst-content div.notranslate .highlight .p{color:#d9e7f3}.rst-content div.highlight pre{font-size:14px}.btn,.btn-neutral{background:#fff;background-color:#fff !important;border:1px solid var(--primary-orange);font-weight:600;font-size:12px;max-width:110px;padding:0 15px;color:var(--primary-orange) !important}.btn .fa,.btn-neutral .fa{display:none}.btn:visited,.btn-neutral:visited{color:var(--primary-orange) !important}.btn:hover,.btn-neutral:hover{opacity:1}.btn:active{padding:0 15px}.rst-content .btn:focus{outline:0px solid}.btn-orange{background-color:var(--primary-orange) !important;color:#fff !important}.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning{padding:25px 20px 20px 40px;margin:20px 0;border-radius:4px}.rst-content .note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .warning .admonition-title{background:rgba(0,0,0,0);font-size:16px}.rst-content .note p,.rst-content .note a,.rst-content .attention p,.rst-content .attention a,.rst-content .caution p,.rst-content .caution a,.rst-content .danger p,.rst-content .danger a,.rst-content .error p,.rst-content .error a,.rst-content .hint p,.rst-content .hint a,.rst-content .important p,.rst-content .important a,.rst-content .tip p,.rst-content .tip a,.rst-content .warning p,.rst-content .warning a{font-size:13px}.rst-content .note{background:var(--message-info-bg)}.rst-content .note p{color:var(--message-info-text)}.rst-content .note .admonition-title{color:var(--message-info-text)}.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .important{background:var(--message-warning-bg)}.rst-content .attention p,.rst-content .caution p,.rst-content .warning p,.rst-content .important p{color:var(--message-warning-text)}.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .warning .admonition-title,.rst-content .important .admonition-title{color:var(--message-warning-text)}.rst-content .danger,.rst-content .error{background:var(--message-danger-bg)}.rst-content .danger p,.rst-content .error p{color:var(--message-danger-text)}.rst-content .danger .admonition-title,.rst-content .error .admonition-title{color:var(--message-danger-text)}.rst-content .hint,.rst-content .tip{background:var(--message-success-bg)}.rst-content .hint p,.rst-content .tip p{color:var(--message-success-text)}.rst-content .hint .admonition-title,.rst-content .tip .admonition-title{color:var(--message-success-text)}h1,h2,h3,h4,span{font-family:"Montserrat",sans-serif}span,p,div{color:#404040}@media(max-width: 768px){p{font-size:17px;line-height:26px}}a{text-decoration:none}a:hover:not(.logo-title){opacity:.7}a:visited{color:var(--primary-blue)}a.ahref-blue{text-decoration:underline;color:var(--primary-blue)}a.ahref-orange{text-decoration:underline;color:var(--primary-orange)}h1{font-size:40px;line-height:inherit;margin:40px 0}h2{font-size:32px;line-height:1.2em;margin-top:40px}@media(max-width: 768px){h2{font-size:22px}}section{scroll-margin-top:120px}.wy-side-nav-search a:visited{color:#fff !important}.wy-grid-for-nav{display:grid;grid-template-columns:300px 900px 300px;justify-content:center;position:relative;margin-top:80px}@media(max-width: 1442px){.wy-grid-for-nav{display:grid;grid-template-columns:300px 700px 200px;justify-content:center}}@media(max-width: 1200px){.wy-grid-for-nav{grid-template-columns:300px auto}}@media(max-width: 1024px){.wy-grid-for-nav{display:block}}.wy-nav-content-wrap{background:#fcfcfc}@media(max-width: 1024px){.wy-nav-content-wrap{margin-left:0}}@media(max-width: 1024px){.wy-nav-content-wrap.shift{left:0}}@media(max-width: 768px){.wy-nav-content-wrap.shift{position:inherit;top:inherit}}.wy-nav-top{background:rgba(0,0,0,0);color:var(--primary-blue)}.wy-nav-top i{font-size:20px}.wy-nav-top .menu-hamburger{position:relative;width:20px;height:20px;top:0;left:0;transition-duration:.5s}.wy-nav-top .menu-hamburger .icon{transition-duration:.5s;position:absolute;height:100%;width:100%;top:0;left:0}.wy-nav-top .menu-hamburger .icon:before{transition-duration:.5s;position:absolute;width:20px;height:2px;background-color:var(--primary-blue);content:"";top:0px;left:0}.wy-nav-top .menu-hamburger .icon:after{transition-duration:.5s;position:absolute;width:20px;height:2px;background-color:var(--primary-blue);content:"";top:10px;left:0}@media(max-width: 1024px){.wy-nav-top{display:block;position:fixed;top:72px;left:10px;z-index:100}}@media(max-width: 1024px)and (max-width: 420px){.wy-nav-top{top:102px}}.wy-nav-content-wrap.shift .wy-nav-top .menu-hamburger .icon{transition-duration:.5s}.wy-nav-content-wrap.shift .wy-nav-top .menu-hamburger .icon:before{transform:rotateZ(135deg) scaleX(1.05) translate(4px, -4.5px)}.wy-nav-content-wrap.shift .wy-nav-top .menu-hamburger .icon:after{transform:rotateZ(-135deg) scaleX(1.05) translate(2px, 2.9px)}.wy-nav-content{max-width:1200px;padding:20px;height:auto}.wy-nav-content-wrap{margin-left:0}.wy-side-scroll{height:auto}@media(max-width: 1024px){.wy-side-scroll{width:auto}}.wy-side-nav-search{top:0;width:1500px;height:72px;margin-left:auto;margin-right:auto;margin-bottom:0;background-color:rgba(0,0,0,0);padding:0;display:grid;grid-template-columns:300px 1fr 300px;justify-content:center;align-items:center}.wy-side-nav-search .search-bar-container{width:300px}@media(max-width: 768px){.wy-side-nav-search .search-bar-container{width:200px}}@media(max-width: 420px){.wy-side-nav-search .search-bar-container{width:90%;grid-area:2/span 2;justify-self:center}}.wy-side-nav-search a.icon{display:flex}@media(max-width: 1442px){.wy-side-nav-search{display:grid;grid-template-columns:300px 1fr 300px;justify-content:center}}@media(max-width: 1024px){.wy-side-nav-search{width:100%}}@media(max-width: 1200px){.wy-side-nav-search{grid-template-columns:300px 1fr 300px;justify-content:flex-start}}@media(max-width: 768px){.wy-side-nav-search{grid-template-columns:200px 1fr 100px}}@media(max-width: 420px){.wy-side-nav-search{grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr;height:90px}}.wy-menu-vertical{height:calc(100vh - 60px);overflow-y:scroll;position:fixed;top:122px;padding-bottom:60px;padding-top:5px;background-color:#fff}@media(max-width: 420px){.wy-menu-vertical{top:140px}}.wy-nav-side{position:sticky;top:0;background:inherit;z-index:10}@media(max-width: 1024px){.wy-nav-side{width:300px;left:-300px}}@media(max-width: 1024px){.wy-nav-side .wy-menu-vertical{left:-300px;width:300px;transition:.2s ease-in-out}}@media(max-width: 768px){.wy-nav-side.shift{width:300px;left:-300px}}@media(max-width: 1024px){.wy-nav-side.shift .wy-menu-vertical{transition:.2s ease-in-out;left:0}}.wy-menu-vertical p.caption{color:var(--primary-blue);padding:0 20px}.wy-menu-vertical a{color:var(--text-blue)}.wy-menu-vertical li.current>a{color:var(--primary-orange);scroll-margin-top:10px}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l2.current>a{background:#f5f5f5}.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l3.current>a{background:#ebebeb}.wy-menu-vertical li.toctree-l2.current li.toctree-l3,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#e6e6e6}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#dcdcdc}.wy-menu::-webkit-scrollbar{width:10px;background-color:var(--grey-border)}.wy-menu::-webkit-scrollbar-thumb{background-color:var(--primary-blue);border-radius:5px;background-clip:content-box}.wy-menu li.toctree-l1.current>a{border-bottom:0;border-top:0}.wy-menu li.current,.wy-menu li.toctree-l2,.wy-menu li.toctree-l2 a,.wy-menu li.toctree-l2.current,.wy-menu li.toctree-l2.current li.toctree-l3,.wy-menu li.toctree-l3.current li.toctree-l4,.wy-menu li.toctree-l3.current li.toctree-l4>a,.wy-menu li.toctree-l2.current li.toctree-l3>a{background:inherit}.wy-menu li.current>a,.wy-menu li.toctree-l2.current a,.wy-menu li.toctree-l3.current li.toctree-l4.current>a,.wy-menu li.toctree-l2.current li.toctree-l3.current>a{background:#fff}.wy-menu li.current>a,.wy-menu li.on a{background:#fff}.wy-menu li.current>a button.toctree-expand,.wy-menu li.on a button.toctree-expand,.wy-menu li>a button.toctree-expand,.wy-menu li.on a button.toctree-expand{display:none}.wy-menu a{font-size:13px}@media(max-width: 768px){.wy-menu a{font-size:15px}}.wy-menu li.toctree-l2 li.toctree-l3 a:hover,.wy-menu .toctree-l3 a:hover,.wy-menu li.current a:hover,.wy-menu a:hover{color:var(--blue);background-color:#fff}.wy-menu li.current>a{color:var(--blue)}.wy-menu li.toctree-l2,.wy-menu li.toctree-l3,.wy-menu li.toctree-l4,.wy-menu li.toctree-l5{margin-left:22px;border-left:1px solid #c1d2e1}.wy-menu li.current>a,.wy-menu li.on a,.wy-menu li.toctree-l2.current li.toctree-l3>a,.wy-menu li.toctree-l2.current>a,.wy-menu li.toctree-l2>a,.wy-menu li.toctree-l3.current li.toctree-l4>a{border-right:none;padding:10px}.wy-menu li.current>a,.wy-menu li.on a{padding-left:20px}.aside-tile{display:flex;flex-direction:column;justify-content:center;align-items:center;position:relative;width:100%;height:max-content;padding:10px}.aside-tile__container{border-radius:5px;border:1px solid var(--grey-border);position:fixed;top:150px;background-color:#fff;width:250px;height:max-content;padding:20px 20px 10px 20px}@media(max-width: 1442px){.aside-tile__container{width:179px}}.aside-tile__feedback{top:350px}.aside-tile__content{display:flex;flex-direction:column;align-items:center;text-align:center}.aside-tile__content img{max-width:47px}.aside-tile h4{line-height:30px;margin-bottom:10px}@media(max-width: 1200px){.aside-tile{display:none}}.aside-tile .aside-tile__feedback-list{font-size:12px;color:var(--blue);text-align:left;margin-bottom:5px}.aside-tile .aside-tile__feedback-list li{line-height:25px}.aside-tile .aside-tile__feedback-list li i{margin-right:5px;color:var(--message-success)}body>header{background-color:var(--primary-blue);position:fixed;left:0;right:0;z-index:10}.wy-side-nav-search img{background-color:rgba(0,0,0,0);position:relative;top:0;margin:0;height:auto;width:150px;border-radius:0;padding:0}@media(max-width: 768px){.wy-side-nav-search img{width:130px}}.wy-side-nav-search input[type=text],.wy-body-for-nav input:not([type=checkbox]):not([type=radio]):not([type=submit]){border:none;box-shadow:none}.logo-title{display:flex;justify-content:center;align-items:center}.logo-title:hover{color:#fff}@media(max-width: 420px){.logo-title{grid-area:1/span 1}}.wy-side-nav-search>a{display:flex;margin-bottom:0;font-size:15px;justify-self:flex-start}.wy-side-nav-search>a:hover{background:rgba(0,0,0,0)}.wy-side-nav-search>a.wy-side-nav__login{justify-self:flex-end;position:relative;right:23px;padding:0 15px;max-width:100px;font-size:12px}@media(max-width: 420px){.wy-side-nav-search>a.wy-side-nav__login{grid-area:1/span 1}}.wy-side-nav-search__menu-items{display:flex;column-gap:10px;justify-content:flex-end;align-items:center;height:100%;padding-right:20px}.wy-side-nav-search__menu-items a{font-size:13px}.wy-side-nav-search__menu-items a.wy-side-nav-search__menu-item{color:#fff;height:97%;display:flex;align-items:center;padding:0 10px}.wy-side-nav-search__menu-items a.wy-side-nav-search__menu-item:hover{border-bottom:2px solid var(--primary-orange)}.wy-side-nav-search__menu-items a.wy-side-nav-search__menu-item.current{border-bottom:2px solid var(--primary-orange)}@media(max-width: 768px){.wy-side-nav-search__menu-items a.wy-side-nav-search__menu-item{display:none}}.edit{text-align:center}.copyright p{font-size:11px}.article-meta{display:inline-block;position:relative;top:30px;font-size:11px;font-weight:600;opacity:.35}.article-meta--updated{opacity:.5}.article-meta--updated::after{content:"•";padding-left:5px}@media(max-width: 420px){.article-meta{font-size:12px}}.wy-breadcrumbs{max-width:1500px;padding:0 21px;margin:auto}.wy-breadcrumbs li{padding-top:initial}@media(max-width: 1024px){.wy-breadcrumbs{padding:0 20px 0 60px;overflow:auto;white-space:nowrap}}@media(max-width: 420px){.wy-breadcrumbs{padding:0 20px 0 65px}}.wy-breadcrumbs,.wy-breadcrumbs li a,.wy-breadcrumbs-aside a{font-size:11px}@media(max-width: 768px){.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}.wy-breadcrumbs li a:visited{color:var(--light-orange)}li.wy-breadcrumbs-aside a{padding:10px}.header{height:50px;line-height:50px;width:100%;position:fixed;top:72px;border-bottom:1px solid var(--grey-border);z-index:20;background-color:#fff}@media(max-width: 420px){.header{top:90px}}.DocSearch-Button{background-color:#fff;border-radius:9999px}.DocSearch-Button:hover{background-color:#fff}.main-content a{color:var(--secondary-blue);text-decoration:underline}.main-content a:visited{opacity:.8;color:var(--secondary-blue) !important}#rtd-search-form input.main-search-bar__input{position:relative;top:10px;padding:0 15px 0 30px}@media(max-width: 420px){#rtd-search-form input.main-search-bar__input{top:0}}#rtd-search-form .search-icon{position:relative;width:13px;top:-18px;left:-132px}@media(max-width: 768px){#rtd-search-form .search-icon{left:-83px}}@media(max-width: 420px){#rtd-search-form .search-icon{top:-27px;left:-149px}}.rst-content{max-width:900px;padding:0 50px}@media(max-width: 768px){.rst-content{padding:0}}.rst-content p+ul{margin-top:-14px} +:root{--blue: #005dab;--primary-blue: #063b67;--secondary-blue: #074e8a;--text-blue: #063b67;--light-blue: #EEF8FF;--light-blue-clear: #F8FCFF;--aqua: #51B3DB;--primary-orange: #FF7101;--hover-orange: #FF8201;--light-orange: #f2a557;--grey: #F5F6F8;--grey-border: #D9E7F3;--light-grey-sidebar: #E5EAF0;--message-success: #4bb52d;--message-success-bg: #E3F6CF;--message-success-text: #0D3D00;--message-danger: #D10000;--message-danger-bg: #FAE5E8;--message-danger-text: #6A0000;--message-warning: #DC7500;--message-warning-bg: #FFF1ED;--message-warning-text: #9C3900;--message-info: #074E8A;--message-info-bg: #E7F2F8;--message-info-text: #063b67;--cc-btn-primary-bg: var(--primary-blue);--cc-btn-secondary-text: var(--primary-blue)}.rst-content section ul{line-height:auto}code,pre,pre span,span.pre,.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:"Ubuntu Mono",monospace}ul.simple li code,code.docutils.literal.notranslate{border:none;width:max-content;font-size:13px;padding:10px;margin:10px 0;border-radius:8px;background:#292d3e}ul.simple li code.literal,code.docutils.literal.notranslate.literal{color:var(--aqua)}code.docutils.literal.notranslate{background:#efefef;padding:2px 6px}code.docutils.literal.notranslate.literal{color:var(--blue)}.rst-content div.notranslate{border:none}.rst-content div.notranslate .highlight{font-family:"Ubuntu Mono",monospace;font-size:16px;padding:10px;line-height:24px;margin:10px 0;border-radius:8px;background-color:#292d3e;color:#d9e7f3}.rst-content div.notranslate .highlight .c1{color:var(--message-warning)}.rst-content div.notranslate .highlight .mi,.rst-content div.notranslate .highlight .o,.rst-content div.notranslate .highlight .mf{color:#e4e4e4}.rst-content div.notranslate .highlight .s,.rst-content div.notranslate .highlight .n,.rst-content div.notranslate .highlight .nb,.rst-content div.notranslate .highlight .na,.rst-content div.notranslate .highlight .s1{color:var(--aqua)}.rst-content div.notranslate .highlight .s1{color:var(--light-orange)}.rst-content div.notranslate .highlight .k,.rst-content div.notranslate .highlight .nv,.rst-content div.notranslate .highlight .m,.rst-content div.notranslate .highlight .vg,.rst-content div.notranslate .highlight .p{color:#d9e7f3}.rst-content div.highlight pre{font-size:14px}.btn,.btn-neutral{background:#fff;background-color:#fff !important;border:1px solid var(--primary-orange);font-weight:600;font-size:12px;max-width:110px;padding:0 15px;color:var(--primary-orange) !important}.btn .fa,.btn-neutral .fa{display:none}.btn:visited,.btn-neutral:visited{color:var(--primary-orange) !important}.btn:hover,.btn-neutral:hover{opacity:1}.btn:active{padding:0 15px}.rst-content .btn:focus{outline:0px solid}.btn-orange{background-color:var(--primary-orange) !important;color:#fff !important}.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning{padding:25px 20px 20px 40px;margin:20px 0;border-radius:4px}.rst-content .note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .warning .admonition-title{background:rgba(0,0,0,0);font-size:16px}.rst-content .note p,.rst-content .note a,.rst-content .attention p,.rst-content .attention a,.rst-content .caution p,.rst-content .caution a,.rst-content .danger p,.rst-content .danger a,.rst-content .error p,.rst-content .error a,.rst-content .hint p,.rst-content .hint a,.rst-content .important p,.rst-content .important a,.rst-content .tip p,.rst-content .tip a,.rst-content .warning p,.rst-content .warning a{font-size:13px}.rst-content .note{background:var(--message-info-bg)}.rst-content .note p{color:var(--message-info-text)}.rst-content .note .admonition-title{color:var(--message-info-text)}.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .important{background:var(--message-warning-bg)}.rst-content .attention p,.rst-content .caution p,.rst-content .warning p,.rst-content .important p{color:var(--message-warning-text)}.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .warning .admonition-title,.rst-content .important .admonition-title{color:var(--message-warning-text)}.rst-content .danger,.rst-content .error{background:var(--message-danger-bg)}.rst-content .danger p,.rst-content .error p{color:var(--message-danger-text)}.rst-content .danger .admonition-title,.rst-content .error .admonition-title{color:var(--message-danger-text)}.rst-content .hint,.rst-content .tip{background:var(--message-success-bg)}.rst-content .hint p,.rst-content .tip p{color:var(--message-success-text)}.rst-content .hint .admonition-title,.rst-content .tip .admonition-title{color:var(--message-success-text)}h1,h2,h3,h4,span{font-family:"Montserrat",sans-serif}span,p,div{color:#404040}@media(max-width: 768px){p{font-size:17px;line-height:26px}}.rst-content table.docutils thead th p,.rst-content table.docutils thead th a,.rst-content table.docutils thead td p,.rst-content table.docutils thead td a,.rst-content table.field-list thead th p,.rst-content table.field-list thead th a,.rst-content table.field-list thead td p,.rst-content table.field-list thead td a,.wy-table thead th p,.wy-table thead th a,.wy-table thead td p,.wy-table thead td a{font-size:inherit;font-weight:inherit;line-height:inherit}a{text-decoration:none}a:hover:not(.logo-title){opacity:.7}a:visited{color:var(--primary-blue)}a.ahref-blue{text-decoration:underline;color:var(--primary-blue)}a.ahref-orange{text-decoration:underline;color:var(--primary-orange)}h1{font-size:40px;line-height:inherit;margin:40px 0}h2{font-size:32px;line-height:1.2em;margin-top:40px}@media(max-width: 768px){h2{font-size:22px}}section{scroll-margin-top:120px}.wy-side-nav-search a:visited{color:#fff !important}.wy-grid-for-nav{display:grid;grid-template-columns:300px 900px 300px;justify-content:center;position:relative;margin-top:80px}@media(max-width: 1442px){.wy-grid-for-nav{display:grid;grid-template-columns:300px 700px 200px;justify-content:center}}@media(max-width: 1200px){.wy-grid-for-nav{grid-template-columns:300px auto}}@media(max-width: 1024px){.wy-grid-for-nav{display:block}}.wy-nav-content-wrap{background:#fcfcfc}@media(max-width: 1024px){.wy-nav-content-wrap{margin-left:0}}@media(max-width: 1024px){.wy-nav-content-wrap.shift{left:0}}@media(max-width: 768px){.wy-nav-content-wrap.shift{position:inherit;top:inherit}}.wy-nav-top{background:rgba(0,0,0,0);color:var(--primary-blue)}.wy-nav-top i{font-size:20px}.wy-nav-top .menu-hamburger{position:relative;width:20px;height:20px;top:0;left:0;transition-duration:.5s}.wy-nav-top .menu-hamburger .icon{transition-duration:.5s;position:absolute;height:100%;width:100%;top:0;left:0}.wy-nav-top .menu-hamburger .icon:before{transition-duration:.5s;position:absolute;width:20px;height:2px;background-color:var(--primary-blue);content:"";top:0px;left:0}.wy-nav-top .menu-hamburger .icon:after{transition-duration:.5s;position:absolute;width:20px;height:2px;background-color:var(--primary-blue);content:"";top:10px;left:0}@media(max-width: 1024px){.wy-nav-top{display:block;position:fixed;top:72px;left:10px;z-index:100}}@media(max-width: 1024px)and (max-width: 420px){.wy-nav-top{top:102px}}.wy-nav-content-wrap.shift .wy-nav-top .menu-hamburger .icon{transition-duration:.5s}.wy-nav-content-wrap.shift .wy-nav-top .menu-hamburger .icon:before{transform:rotateZ(135deg) scaleX(1.05) translate(4px, -4.5px)}.wy-nav-content-wrap.shift .wy-nav-top .menu-hamburger .icon:after{transform:rotateZ(-135deg) scaleX(1.05) translate(2px, 2.9px)}.wy-nav-content{max-width:1200px;padding:20px;height:auto}.wy-nav-content-wrap{margin-left:0}.wy-side-scroll{height:auto}@media(max-width: 1024px){.wy-side-scroll{width:auto}}.wy-side-nav-search{top:0;width:1500px;height:72px;margin-left:auto;margin-right:auto;margin-bottom:0;background-color:rgba(0,0,0,0);padding:0;display:grid;grid-template-columns:300px 1fr 300px;justify-content:center;align-items:center}.wy-side-nav-search .search-bar-container{width:300px}@media(max-width: 768px){.wy-side-nav-search .search-bar-container{width:200px}}@media(max-width: 420px){.wy-side-nav-search .search-bar-container{width:90%;grid-area:2/span 2;justify-self:center}}.wy-side-nav-search a.icon{display:flex}@media(max-width: 1442px){.wy-side-nav-search{display:grid;grid-template-columns:300px 1fr 300px;justify-content:center}}@media(max-width: 1024px){.wy-side-nav-search{width:100%}}@media(max-width: 1200px){.wy-side-nav-search{grid-template-columns:300px 1fr 300px;justify-content:flex-start}}@media(max-width: 768px){.wy-side-nav-search{grid-template-columns:200px 1fr 100px}}@media(max-width: 420px){.wy-side-nav-search{grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr;height:90px}}.wy-menu-vertical{height:calc(100vh - 60px);overflow-y:scroll;position:fixed;top:122px;padding-bottom:60px;padding-top:5px;background-color:#fff}@media(max-width: 420px){.wy-menu-vertical{top:140px}}.wy-nav-side{position:sticky;top:0;background:inherit;z-index:10}@media(max-width: 1024px){.wy-nav-side{width:300px;left:-300px}}@media(max-width: 1024px){.wy-nav-side .wy-menu-vertical{left:-300px;width:300px;transition:.2s ease-in-out}}@media(max-width: 768px){.wy-nav-side.shift{width:300px;left:-300px}}@media(max-width: 1024px){.wy-nav-side.shift .wy-menu-vertical{transition:.2s ease-in-out;left:0}}.wy-menu-vertical p.caption{color:var(--primary-blue);padding:0 20px}.wy-menu-vertical a{color:var(--text-blue)}.wy-menu-vertical li.current>a{color:var(--primary-orange);scroll-margin-top:10px}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l2.current>a{background:#f5f5f5}.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l3.current>a{background:#ebebeb}.wy-menu-vertical li.toctree-l2.current li.toctree-l3,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#e6e6e6}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#dcdcdc}.wy-menu::-webkit-scrollbar{width:10px;background-color:var(--grey-border)}.wy-menu::-webkit-scrollbar-thumb{background-color:var(--primary-blue);border-radius:5px;background-clip:content-box}.wy-menu li.toctree-l1.current>a{border-bottom:0;border-top:0}.wy-menu li.current,.wy-menu li.toctree-l2,.wy-menu li.toctree-l2 a,.wy-menu li.toctree-l2.current,.wy-menu li.toctree-l2.current li.toctree-l3,.wy-menu li.toctree-l3.current li.toctree-l4,.wy-menu li.toctree-l3.current li.toctree-l4>a,.wy-menu li.toctree-l2.current li.toctree-l3>a{background:inherit}.wy-menu li.current>a,.wy-menu li.toctree-l2.current a,.wy-menu li.toctree-l3.current li.toctree-l4.current>a,.wy-menu li.toctree-l2.current li.toctree-l3.current>a{background:#fff}.wy-menu li.current>a,.wy-menu li.on a{background:#fff}.wy-menu li.current>a button.toctree-expand,.wy-menu li.on a button.toctree-expand,.wy-menu li>a button.toctree-expand,.wy-menu li.on a button.toctree-expand{display:none}.wy-menu a{font-size:13px}@media(max-width: 768px){.wy-menu a{font-size:15px}}.wy-menu li.toctree-l2 li.toctree-l3 a:hover,.wy-menu .toctree-l3 a:hover,.wy-menu li.current a:hover,.wy-menu a:hover{color:var(--blue);background-color:#fff}.wy-menu li.current>a{color:var(--blue)}.wy-menu li.toctree-l2,.wy-menu li.toctree-l3,.wy-menu li.toctree-l4,.wy-menu li.toctree-l5{margin-left:22px;border-left:1px solid #c1d2e1}.wy-menu li.current>a,.wy-menu li.on a,.wy-menu li.toctree-l2.current li.toctree-l3>a,.wy-menu li.toctree-l2.current>a,.wy-menu li.toctree-l2>a,.wy-menu li.toctree-l3.current li.toctree-l4>a{border-right:none;padding:10px}.wy-menu li.current>a,.wy-menu li.on a{padding-left:20px}.aside-tile{display:flex;flex-direction:column;justify-content:center;align-items:center;position:relative;width:100%;height:max-content;padding:10px}.aside-tile__container{border-radius:5px;border:1px solid var(--grey-border);position:fixed;top:150px;background-color:#fff;width:250px;height:max-content;padding:20px 20px 10px 20px}@media(max-width: 1442px){.aside-tile__container{width:179px}}.aside-tile__feedback{top:350px}.aside-tile__content{display:flex;flex-direction:column;align-items:center;text-align:center}.aside-tile__content img{max-width:47px}.aside-tile h4{line-height:30px;margin-bottom:10px}@media(max-width: 1200px){.aside-tile{display:none}}.aside-tile .aside-tile__feedback-list{font-size:12px;color:var(--blue);text-align:left;margin-bottom:5px}.aside-tile .aside-tile__feedback-list li{line-height:25px}.aside-tile .aside-tile__feedback-list li i{margin-right:5px;color:var(--message-success)}body>header{background-color:var(--primary-blue);position:fixed;left:0;right:0;z-index:10}.wy-side-nav-search img{background-color:rgba(0,0,0,0);position:relative;top:0;margin:0;height:auto;width:150px;border-radius:0;padding:0}@media(max-width: 768px){.wy-side-nav-search img{width:130px}}.wy-side-nav-search input[type=text],.wy-body-for-nav input:not([type=checkbox]):not([type=radio]):not([type=submit]){border:none;box-shadow:none}.logo-title{display:flex;justify-content:center;align-items:center}.logo-title:hover{color:#fff}@media(max-width: 420px){.logo-title{grid-area:1/span 1}}.wy-side-nav-search>a{display:flex;margin-bottom:0;font-size:15px;justify-self:flex-start}.wy-side-nav-search>a:hover{background:rgba(0,0,0,0)}.wy-side-nav-search>a.wy-side-nav__login{justify-self:flex-end;position:relative;right:23px;padding:0 15px;max-width:100px;font-size:12px}@media(max-width: 420px){.wy-side-nav-search>a.wy-side-nav__login{grid-area:1/span 1}}.wy-side-nav-search__menu-items{display:flex;column-gap:10px;justify-content:flex-end;align-items:center;height:100%;padding-right:20px}.wy-side-nav-search__menu-items a{font-size:13px}.wy-side-nav-search__menu-items a.wy-side-nav-search__menu-item{color:#fff;height:97%;display:flex;align-items:center;padding:0 10px}.wy-side-nav-search__menu-items a.wy-side-nav-search__menu-item:hover{border-bottom:2px solid var(--primary-orange)}.wy-side-nav-search__menu-items a.wy-side-nav-search__menu-item.current{border-bottom:2px solid var(--primary-orange)}@media(max-width: 768px){.wy-side-nav-search__menu-items a.wy-side-nav-search__menu-item{display:none}}.edit{text-align:center}.copyright p{font-size:11px}.article-meta{display:inline-block;position:relative;top:30px;font-size:11px;font-weight:600;opacity:.35}.article-meta--updated{opacity:.5}.article-meta--updated::after{content:"•";padding-left:5px}@media(max-width: 420px){.article-meta{font-size:12px}}.wy-breadcrumbs{max-width:1500px;padding:0 21px;margin:auto}.wy-breadcrumbs li{padding-top:initial}@media(max-width: 1024px){.wy-breadcrumbs{padding:0 20px 0 60px;overflow:auto;white-space:nowrap}}@media(max-width: 420px){.wy-breadcrumbs{padding:0 20px 0 65px}}.wy-breadcrumbs,.wy-breadcrumbs li a,.wy-breadcrumbs-aside a{font-size:11px}@media(max-width: 768px){.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}.wy-breadcrumbs li a:visited{color:var(--light-orange)}li.wy-breadcrumbs-aside a{padding:10px}.header{height:50px;line-height:50px;width:100%;position:fixed;top:72px;border-bottom:1px solid var(--grey-border);z-index:20;background-color:#fff}@media(max-width: 420px){.header{top:90px}}.DocSearch-Button{background-color:#fff;border-radius:9999px}.DocSearch-Button:hover{background-color:#fff}.main-content a{color:var(--secondary-blue);text-decoration:underline}.main-content a:visited{opacity:.8;color:var(--secondary-blue) !important}#rtd-search-form input.main-search-bar__input{position:relative;top:10px;padding:0 15px 0 30px}@media(max-width: 420px){#rtd-search-form input.main-search-bar__input{top:0}}#rtd-search-form .search-icon{position:relative;width:13px;top:-18px;left:-132px}@media(max-width: 768px){#rtd-search-form .search-icon{left:-83px}}@media(max-width: 420px){#rtd-search-form .search-icon{top:-27px;left:-149px}}.rst-content{max-width:900px;padding:0 50px}@media(max-width: 768px){.rst-content{padding:0}}.rst-content p+ul{margin-top:-14px} diff --git a/docs/_static/scss/components/defaults/_module.scss b/docs/_static/scss/components/defaults/_module.scss index 1fd21d09..33637d3b 100644 --- a/docs/_static/scss/components/defaults/_module.scss +++ b/docs/_static/scss/components/defaults/_module.scss @@ -25,6 +25,20 @@ p { } } +.rst-content table.docutils thead th, +.rst-content table.docutils thead td, +.rst-content table.field-list thead th, +.rst-content table.field-list thead td, +.wy-table thead th, +.wy-table thead td { + p, + a { + font-size: inherit; + font-weight: inherit; + line-height: inherit; + } +} + a { text-decoration: none; diff --git a/docs/best-practices/firewall/ftp-waf-database-allowlist.md b/docs/best-practices/firewall/ftp-waf-database-allowlist.md index 66aaf177..a95e1d2d 100644 --- a/docs/best-practices/firewall/ftp-waf-database-allowlist.md +++ b/docs/best-practices/firewall/ftp-waf-database-allowlist.md @@ -26,6 +26,8 @@ Follow these steps to whitelist an IP addresses for FTP: The `hypernode-systemctl whitelist` command allows you to manage allowlist entries for different services on your Hypernode. You can use it to add, remove, or list allowlist entries for FTP, WAF, database, and SSH. +When [Botstopper](../../hypernode-platform/botstopper/how-to-use-botstopper.md) is enabled, IP addresses on the WAF allowlist are also allowed by Botstopper before custom and standard Botstopper deny or challenge rules are evaluated. + ### Command structure ``` diff --git a/docs/best-practices/performance/how-to-fix-performance-issues-caused-by-bots-and-crawlers.md b/docs/best-practices/performance/how-to-fix-performance-issues-caused-by-bots-and-crawlers.md index 3fbba469..1783a9f2 100644 --- a/docs/best-practices/performance/how-to-fix-performance-issues-caused-by-bots-and-crawlers.md +++ b/docs/best-practices/performance/how-to-fix-performance-issues-caused-by-bots-and-crawlers.md @@ -20,7 +20,7 @@ Among the thousands of shops on our platform, **excessive bot traffic is the num Layered navigation pages do not require crawling, and in fact, their indexation could **produce a penalty** for your search engine ranking, as it produces a lot of duplicate content. So you are advised to resolve this, both for performance and SEO reasons. -With these four measures, you will resolve this situation completely. +With these four measures, you will resolve this situation completely. If you want Hypernode to challenge, deny, or allow bot traffic before it reaches your shop, see [How to Use Botstopper on Hypernode](../../hypernode-platform/botstopper/how-to-use-botstopper.md). # How to Block Abusive Bots (If Any) @@ -35,7 +35,7 @@ app@abcdef-example-magweb-cmbl:~$ pnl --yesterday --php --bots --fields ua | sor ``` -In this example, there were almost 4K Bingbot pageviews, 2K Google pageviews and almost 13K MegaIndex pageviews. So you could eliminate a large chunk of load by blocking MegaIndex (a shady crawler whose benefits to you are disputable). [Here](../../hypernode-platform/nginx/how-to-block-user-agents-and-referrer-sites.md) are instructions on blocking specific bots on Hypernode. +In this example, there were almost 4K Bingbot pageviews, 2K Google pageviews and almost 13K MegaIndex pageviews. So you could eliminate a large chunk of load by blocking MegaIndex (a shady crawler whose benefits to you are disputable). You can use [Botstopper](../../hypernode-platform/botstopper/how-to-use-botstopper.md) for policy-based bot handling, or use [Nginx rules](../../hypernode-platform/nginx/how-to-block-user-agents-and-referrer-sites.md) to block specific user agents yourself. # How to Block Bot Access to Layered Navigation @@ -89,3 +89,4 @@ Make sure all URLs in the layered navigation have “nofollow” in its links. H - [How to Block Specific Countries From Accessing Your Shop](../../hypernode-platform/nginx/how-to-block-your-webshop-for-specific-countries.md) - [How to Resolve 429 Too Many Requests](../../hypernode-platform/nginx/how-to-resolve-rate-limited-requests-429-too-many-requests.md) +- [How to Use Botstopper on Hypernode](../../hypernode-platform/botstopper/how-to-use-botstopper.md) diff --git a/docs/hypernode-platform/botstopper.md b/docs/hypernode-platform/botstopper.md new file mode 100644 index 00000000..b77a7ceb --- /dev/null +++ b/docs/hypernode-platform/botstopper.md @@ -0,0 +1,18 @@ +--- +myst: + html_meta: + description: This table of contents gives you a summary of all Hypernode platform + knowledge base articles that include information about the botstopper. + title: Botstopper | Hypernode platform +--- + +# Botstopper + +```{toctree} +--- +caption: Table of Contents +maxdepth: 1 +glob: +--- +botstopper/* +``` diff --git a/docs/hypernode-platform/botstopper/how-to-use-botstopper.md b/docs/hypernode-platform/botstopper/how-to-use-botstopper.md new file mode 100644 index 00000000..32a3573c --- /dev/null +++ b/docs/hypernode-platform/botstopper/how-to-use-botstopper.md @@ -0,0 +1,240 @@ +--- +myst: + html_meta: + description: Learn how to enable Botstopper, choose an AI policy, and write custom + Botstopper policies on Hypernode. + title: How to use Botstopper on Hypernode | Hypernode +--- + +# How to Use Botstopper on Hypernode + +Bot traffic has changed. Some bots still identify themselves with clear user agents, but many scrapers now use large sets of user agents or pretend to be a normal Chrome browser. That makes simple user-agent blocking less reliable. + +Botstopper gives you control over this traffic before it reaches Magento, Shopware, or another application. It checks incoming requests and decides whether they should be allowed, blocked, or challenged. Botstopper is the commercial derivative of the open source project [Anubis](https://anubis.techaro.lol/). + +Use Botstopper when bots cause high load, scrape content, crawl expensive layered navigation URLs, or ignore your `robots.txt` file. Botstopper also lets each merchant choose how strict they want to be with AI crawlers and AI clients. + +```{tip} +For more background on bot traffic and Magento performance, see [How to Fix Performance Issues Caused by Bots and Crawlers](../../best-practices/performance/how-to-fix-performance-issues-caused-by-bots-and-crawlers.md). +``` + +## Enable Botstopper + +Botstopper is disabled by default on a Hypernode. Enable it with: + +```bash +hypernode-systemctl settings botstopper_enabled True +``` + +Disable it again with: + +```bash +hypernode-systemctl settings botstopper_enabled False +``` + +## Configure Botstopper Per Vhost + +Botstopper is enabled per vhost by default. This means that when you enable Botstopper on Hypernode level, Botstopper becomes active for all managed vhosts unless you disabled it for a specific vhost. See [Hypernode Managed Vhosts](../nginx/hypernode-managed-vhosts.md) for more information about vhost configuration. + +Disable Botstopper for one vhost with: + +```bash +hypernode-manage-vhosts example.com --disable-botstopper +``` + +Enable it again for that vhost with: + +```bash +hypernode-manage-vhosts example.com --botstopper +``` + +## Choose an AI Policy + +Botstopper has three AI policies. The default policy is `aggressive`. + +```bash +hypernode-systemctl settings botstopper_ai_policy aggressive +hypernode-systemctl settings botstopper_ai_policy moderate +hypernode-systemctl settings botstopper_ai_policy permissive +``` + +| Policy | Behavior | +| ------------ | ---------------------------------------------------------------------------------------------------------------- | +| `aggressive` | Blocks AI training crawlers, AI search crawlers, and AI clients as much as possible. | +| `moderate` | Blocks AI training crawlers and unknown AI bots. Allows documented AI search bots and user-triggered AI clients. | +| `permissive` | Allows documented AI bots. Blocks unknown AI-style bots. | + +Use `aggressive` if you want the strictest AI blocking. Use `moderate` if you want to block AI training while keeping documented AI search and user tools working. Use `permissive` if you only want to block unclear or undocumented AI crawlers. + +Some AI crawlers also require `robots.txt` rules before they respect your opt-out. Botstopper blocks requests at the webserver layer, but `robots.txt` is still useful for crawlers that require policy signals there. See the [Magento 1 robots.txt](../../ecommerce-applications/magento-1/how-to-create-a-robots-txt-for-your-magento-1-shop.md) or [Magento 2 robots.txt](../../ecommerce-applications/magento-2/how-to-create-a-robots-txt-for-magento-2-x.md) articles if you need to configure one. + +## How Botstopper Handles Requests + +Botstopper evaluates policy rules from top to bottom. A rule can allow, deny, challenge, or weigh a request. + +| Action | What happens | +| ----------- | ------------------------------------------------------------ | +| `ALLOW` | The request is sent to your shop immediately. | +| `DENY` | The request is blocked with HTTP `403`. | +| `CHALLENGE` | The visitor receives a browser challenge. | +| `WEIGH` | Suspicion points are added or removed. Evaluation continues. | + +`ALLOW`, `DENY`, and `CHALLENGE` stop evaluation immediately. The first matching rule wins. + +`WEIGH` does not stop evaluation. Multiple `WEIGH` rules can match the same request. After all rules are checked, Botstopper uses the final weight to decide whether the request should be allowed or challenged. + +Challenge responses use HTTP `200`. This is intentional. Many aggressive scraper bots stop retrying once they receive a `200` response. + +## Standard Hypernode Policies + +Hypernode ships Botstopper with a standard policy that keeps important services working and blocks common abusive traffic. + +The standard policy does the following: + +1. Allows Hypernode platform services, payment providers, monitoring tools, and common e-commerce integrations. +1. Allows IP addresses on the Hypernode WAF allowlist. +1. Runs your custom pre-policy from `/data/web/botstopper/pre.policy.yml`. +1. Denies sensitive Magento media paths, such as `/media/customer/`, `/media/import/`, and `/media/downloadable/`. +1. Allows storefront assets, such as `/static/`, normal `/media/` files, etc. +1. Denies or weighs known bad bots, headless browsers, abusive cloud ranges, and suspicious HTTP clients. +1. Applies the configured AI policy. +1. Allows known good search engine crawlers when they are verified by IP ranges or reverse DNS. +1. Allows common public files, such as `robots.txt`, `sitemap.xml`, `favicon.ico`, and `.well-known` paths. +1. Adds suspicion weight for some high-risk countries, networks, and browser-like user agents. +1. Runs your custom post-policy from `/data/web/botstopper/post.policy.yml`. +1. Uses the final suspicion weight to allow or challenge the request. + +The WAF allowlist is shared with the Hypernode firewall allowlist. Botstopper allows these IPs before your custom `pre.policy.yml` and before the standard deny and challenge rules. + +Add a trusted IP to the WAF allowlist with: + +```bash +hypernode-systemctl whitelist add waf 1.2.3.4 --description "Office IP" +``` + +View the WAF allowlist with: + +```bash +hypernode-systemctl whitelist get --type waf +``` + +See [How to allowlist FTP, WAF and database](../../best-practices/firewall/ftp-waf-database-allowlist.md) for more details. + +The order matters. For example, a broad `DENY` rule in `pre.policy.yml` can block a good crawler before the standard verified crawler allow rules are reached. + +## Write Custom Policies + +You can add your own rules in these files: + +| File | When it runs | Use it for | +| -------------------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------- | +| `/data/web/botstopper/pre.policy.yml` | Before most standard deny and challenge rules | Allowing trusted traffic or blocking very specific traffic early. | +| `/data/web/botstopper/post.policy.yml` | After standard rules, before final weight thresholds | Adding suspicion weight or handling fallback cases. | + +Both files contain a YAML list of policy rules. An empty file looks like this: + +```yaml +[] +``` + +Edit the files as the `app` user. For example: + +```bash +sensible-editor /data/web/botstopper/pre.policy.yml +``` + +After changing a policy file, restart Botstopper: + +```bash +hypernode-servicectl restart techaro-botstopper@default.service +``` + +## Policy Conditions + +A policy rule can match on request details, such as the client IP, user agent, path, or headers. + +Common fields are: + +| Field | Checks | +| ------------------ | ----------------------------------------------------- | +| `remote_addresses` | Client IP address against CIDR ranges. | +| `user_agent_regex` | The `User-Agent` header against a regular expression. | +| `path_regex` | The request path against a regular expression. | +| `headers_regex` | Request headers against regular expressions. | +| `expression` | A custom expression for advanced matching. | + +When a rule has multiple conditions, all conditions must match. This is useful for trusted allow rules. For example, you can allow a monitoring tool only when both its user agent and source IP match. + +## Examples + +Allow a trusted monitoring service: + +```yaml +- name: allow-my-monitor + action: ALLOW + user_agent_regex: MyMonitor + remote_addresses: + - 203.0.113.10/32 +``` + +Block a specific bot: + +```yaml +- name: block-bad-bot + action: DENY + user_agent_regex: BadBot +``` + +Challenge traffic to an expensive search page: + +```yaml +- name: challenge-suspicious-search + action: CHALLENGE + path_regex: ^/catalogsearch/result/.* +``` + +Add suspicion weight for bots crawling layered navigation URLs: + +```yaml +- name: weigh-layered-navigation-bots + action: WEIGH + path_regex: ^/.*(color|size|brand)=.* + user_agent_regex: (?i:bot|crawler|spider) + weight: + adjust: 20 +``` + +Protect a trusted integration from a broader custom rule: + +```yaml +- name: allow-partner-feed + action: ALLOW + path_regex: ^/partner/feed/.* + user_agent_regex: PartnerFeedClient + remote_addresses: + - 198.51.100.0/24 +``` + +You usually do not need allow rules for API or webhook traffic. Botstopper allows traffic by default. Use an `ALLOW` rule when you already have, or plan to add, a broader custom rule that could otherwise challenge or block this trusted traffic. + +## Safe Policy Changes + +Use specific rules whenever possible. Broad user-agent rules can block legitimate crawlers or integrations. + +Prefer `WEIGH` when you are not fully sure traffic should be blocked. A `WEIGH` rule lets Botstopper combine multiple signals before it challenges the request. + +Use `ALLOW` with both a user agent and IP range for trusted services when possible. User agents can be spoofed, IP ranges are harder to fake. + +Use the WAF allowlist for trusted source IPs that should always bypass Botstopper checks. This is often better than maintaining your own IP allow rule in `pre.policy.yml`. + +Keep custom `DENY` rules narrow. A broad `DENY` rule in `pre.policy.yml` can override the standard Hypernode allow rules that run later. + +Do not add allow rules for every API endpoint or webhook. Add them when a specific Botstopper rule would otherwise match that traffic. + +## Anubis Documentation + +Because Botstopper is the commercial derivative of Anubis, the Anubis documentation is a useful reference when you want to understand the underlying concepts or write advanced custom policies: + +- [How Anubis works](https://anubis.techaro.lol/docs/design/how-anubis-works) +- [Anubis policies](https://anubis.techaro.lol/docs/admin/policies/) +- [Anubis policy thresholds](https://anubis.techaro.lol/docs/admin/configuration/thresholds) diff --git a/docs/hypernode-platform/nginx/how-to-block-user-agents-and-referrer-sites.md b/docs/hypernode-platform/nginx/how-to-block-user-agents-and-referrer-sites.md index eb88607d..849b4a8a 100644 --- a/docs/hypernode-platform/nginx/how-to-block-user-agents-and-referrer-sites.md +++ b/docs/hypernode-platform/nginx/how-to-block-user-agents-and-referrer-sites.md @@ -15,6 +15,8 @@ redirect_from: **Blocking IP addresses, User Agents or Referres may cause unforseen issues, since it's easy to block more then expected.** +If your goal is to manage bot traffic more broadly, consider [Botstopper](../botstopper/how-to-use-botstopper.md). Botstopper can allow, deny, challenge, or weigh requests before they reach your application. + ## How to Block User Agents First you need to know what User Agent you wish to block. You can retrieve such information from the access logs (`/var/log/nginx/access.log`) diff --git a/docs/hypernode-platform/nginx/how-to-resolve-rate-limited-requests-429-too-many-requests.md b/docs/hypernode-platform/nginx/how-to-resolve-rate-limited-requests-429-too-many-requests.md index c1a46e28..3e2f116d 100644 --- a/docs/hypernode-platform/nginx/how-to-resolve-rate-limited-requests-429-too-many-requests.md +++ b/docs/hypernode-platform/nginx/how-to-resolve-rate-limited-requests-429-too-many-requests.md @@ -14,6 +14,8 @@ redirect_from: To protect your Hypernode from all kinds of attacks, bots, brute forces, and script kiddies causing downtime, we've implemented several layers of rate limiting. +Rate limiting slows down excessive traffic. If you want to challenge, deny, or allow bot traffic before it reaches your application, see [How to Use Botstopper on Hypernode](../botstopper/how-to-use-botstopper.md). + Most of these rate-limit methods only apply to bots. Still, to avoid FPM worker depletion, we [implemented a rate-limiting mechanism per IP](https://changelog.hypernode.com/release-4735-upper-limit-active-php-requests-per-ip/) to prevent one single IP from exhausting the available FPM workers. This article will explain the differences between the different rate-limiting methods and show you how to find which rate-limiting method applies and, if needed, how to override them. diff --git a/docs/hypernode-platform/nginx/hypernode-managed-vhosts.md b/docs/hypernode-platform/nginx/hypernode-managed-vhosts.md index b162afc0..da951363 100644 --- a/docs/hypernode-platform/nginx/hypernode-managed-vhosts.md +++ b/docs/hypernode-platform/nginx/hypernode-managed-vhosts.md @@ -76,6 +76,10 @@ Once the command is processed you could list all the vhosts to check if Varnish To disable Varnish for a vhost, use the following command: `hypernode-manage-vhosts example.com --disable-varnish` +## Botstopper and Hypernode Managed Vhosts + +When [Botstopper](../botstopper/how-to-use-botstopper.md) is enabled on Hypernode level, it is enabled for managed vhosts by default. Disable it for a specific vhost with `hypernode-manage-vhosts example.com --disable-botstopper`. Enable it again with `hypernode-manage-vhosts example.com --botstopper`. + ## Object Storage and Hypernode Managed Vhosts If you're using object storage with Magento 2.x or Shopware 6.x you can use HMV to adjust your nginx config to serve assets directly from your bucket. diff --git a/docs/hypernode-platform/tools/how-to-use-the-hypernode-systemctl-cli-tool.md b/docs/hypernode-platform/tools/how-to-use-the-hypernode-systemctl-cli-tool.md index 2e79ed56..6f72a583 100644 --- a/docs/hypernode-platform/tools/how-to-use-the-hypernode-systemctl-cli-tool.md +++ b/docs/hypernode-platform/tools/how-to-use-the-hypernode-systemctl-cli-tool.md @@ -25,6 +25,8 @@ To see which values you can set and which values they are allowed to have take a | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | **blackfire_enabled**
A great tool to find performance bottlenecks
in Magento
| False | True, False | | **block_bad_ips_enabled**
Blocks abusive IPs with high AbuseIPDB.com confidence scores | True | True, False | +| **botstopper_ai_policy**
Choose how strict Botstopper should be for AI crawlers and AI clients | aggressive | aggressive, moderate, permissive | +| **botstopper_enabled**
Enable Botstopper bot protection | False | True, False | | **composer_version**
Change the Composer version | 2.x | 1.x, 2.2, 2.6, 2.7, 2.8, 2.x | | **disable_optimizer_switch**
Disable the optimizer switch | False | True, False | | **elasticsearch_enabled**
Enable Elasticsearch | False | True, False | @@ -113,6 +115,13 @@ If an invalid value is provided you will be notified of this during the setting - `blackfire_server_token`The BlackFire server token for your Blackfire setup. - `blackfire_server_id` The BlackFire server ID for your Blackfire setup. +### Botstopper + +- `botstopper_enabled`: Enables Botstopper bot protection. +- `botstopper_ai_policy`: Configures the Botstopper AI policy. Possible values are `aggressive`, `moderate`, and `permissive`. + +See [How to Use Botstopper on Hypernode](../botstopper/how-to-use-botstopper.md) for details about enabling Botstopper, configuring it per vhost, and writing custom policies. + ### Disable optimizer switch Indicates whether `use_index_extensions` and `mrr` are turned off. If turned off this can improve performance due to an issue in PHP 5.6 related to Multi-Range Read Optimization. For more information about this setting see this [changelog](https://changelog.hypernode.com/release-5340-block-ftp-access-sftp-used-systems-tweaks/). diff --git a/docs/troubleshooting/performance/how-to-block-bad-bots-via-the-control-panel.md b/docs/troubleshooting/performance/how-to-block-bad-bots-via-the-control-panel.md index 232d5b15..d2e8a25a 100644 --- a/docs/troubleshooting/performance/how-to-block-bad-bots-via-the-control-panel.md +++ b/docs/troubleshooting/performance/how-to-block-bad-bots-via-the-control-panel.md @@ -14,6 +14,8 @@ redirect_from: A lot of bot traffic has a negative impact on the performance of your webshop. Some bots are very useful (e.g. Google), others have no value at all and even have a negative influence on the performance of your shop. We offer you the possibility to block bad user agents with a few mouse clicks, via your Control Panel. +The Control Panel bot blocklist is useful when you know exactly which user agent you want to block. If you want Hypernode to challenge, deny, or allow traffic based on richer Botstopper policies, see [How to Use Botstopper on Hypernode](../../hypernode-platform/botstopper/how-to-use-botstopper.md). + ## Add Bad Bots to the Blocklist If blocking (a part of) the recommended list of bad bots does not have enough positive impact on your webshop, please add unwanted bots to the list yourself.