1<!DOCTYPE html> 2<html lang="en-US"> 3<head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1" /> 6<meta name='robots' content='max-image-preview:large' /> 7<title>KO4BEP :: Blog – nonsense.</title> 8<link rel="alternate" type="application/rss+xml" title="KO4BEP :: Blog » Feed" href="https://ko4bep.net/blog/index.php/feed/" /> 9<link rel="alternate" type="application/rss+xml" title="KO4BEP :: Blog » Comments Feed" href="https://ko4bep.net/blog/index.php/comments/feed/" /> 10<style id="wp-img-auto-sizes-contain-inline-css"> 11img:is([sizes=auto i],[sizes^="auto," i]){contain-intrinsic-size:3000px 1500px} 12/*# sourceURL=wp-img-auto-sizes-contain-inline-css */ 13</style> 14<style id="wp-block-site-title-inline-css"> 15.wp-block-site-title{box-sizing:border-box}.wp-block-site-title :where(a){color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;text-decoration:inherit} 16/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/site-title/style.min.css */ 17</style> 18<style id="wp-block-navigation-inline-css"> 19.wp-block-navigation{position:relative}.wp-block-navigation ul{margin-bottom:0;margin-left:0;margin-top:0;padding-left:0}.wp-block-navigation ul,.wp-block-navigation ul li{list-style:none}.wp-block-navigation .wp-block-navigation-item{align-items:center;background-color:inherit;display:flex;position:relative}.wp-block-navigation .wp-block-navigation-item .wp-block-navigation__submenu-container:empty{display:none}.wp-block-navigation .wp-block-navigation-item__content{display:block;z-index:1}.wp-block-navigation .wp-block-navigation-item__content.wp-block-navigation-item__content{color:inherit}.wp-block-navigation.has-text-decoration-underline .wp-block-navigation-item__content,.wp-block-navigation.has-text-decoration-underline .wp-block-navigation-item__content:active,.wp-block-navigation.has-text-decoration-underline .wp-block-navigation-item__content:focus{text-decoration:underline}.wp-block-navigation.has-text-decoration-line-through .wp-block-navigation-item__content,.wp-block-navigation.has-text-decoration-line-through .wp-block-navigation-item__content:active,.wp-block-navigation.has-text-decoration-line-through .wp-block-navigation-item__content:focus{text-decoration:line-through}.wp-block-navigation :where(a),.wp-block-navigation :where(a:active),.wp-block-navigation :where(a:focus){text-decoration:none}.wp-block-navigation .wp-block-navigation__submenu-icon{align-self:center;background-color:inherit;border:none;color:currentColor;display:inline-block;font-size:inherit;height:.6em;line-height:0;margin-left:.25em;padding:0;width:.6em}.wp-block-navigation .wp-block-navigation__submenu-icon svg{stroke:currentColor;display:inline-block;height:inherit;margin-top:.075em;width:inherit}.wp-block-navigation{--navigation-layout-justification-setting:flex-start;--navigation-layout-direction:row;--navigation-layout-wrap:wrap;--navigation-layout-justify:flex-start;--navigation-layout-align:center}.wp-block-navigation.is-vertical{--navigation-layout-direction:column;--navigation-layout-justify:initial;--navigation-layout-align:flex-start}.wp-block-navigation.no-wrap{--navigation-layout-wrap:nowrap}.wp-block-navigation.items-justified-center{--navigation-layout-justification-setting:center;--navigation-layout-justify:center}.wp-block-navigation.items-justified-center.is-vertical{--navigation-layout-align:center}.wp-block-navigation.items-justified-right{--navigation-layout-justification-setting:flex-end;--navigation-layout-justify:flex-end}.wp-block-navigation.items-justified-right.is-vertical{--navigation-layout-align:flex-end}.wp-block-navigation.items-justified-space-between{--navigation-layout-justification-setting:space-between;--navigation-layout-justify:space-between}:where(.wp-block-navigation) ul li{padding:0}.wp-block-navigation .has-child .wp-block-navigation__submenu-container{align-items:normal;background-color:inherit;color:inherit;display:flex;flex-direction:column;opacity:0;position:absolute;z-index:2}@media not (prefers-reduced-motion){.wp-block-navigation .has-child .wp-block-navigation__submenu-container{transition:opacity .1s linear}}.wp-block-navigation .has-child .wp-block-navigation__submenu-container{height:0;overflow:hidden;visibility:hidden;width:0}.wp-block-navigation .has-child .wp-block-navigation__submenu-container>.wp-block-navigation-item>.wp-block-navigation-item__content{display:flex;flex-grow:1;padding:.5em 1em}.wp-block-navigation .has-child .wp-block-navigation__submenu-container>.wp-block-navigation-item>.wp-block-navigation-item__content .wp-block-navigation__submenu-icon{margin-left:auto;margin-right:0}.wp-block-navigation .has-child .wp-block-navigation__submenu-container .wp-block-navigation-item__content{margin:0}.wp-block-navigation .has-child .wp-block-navigation__submenu-container{left:-1px;top:100%}@media (min-width:782px){.wp-block-navigation .has-child .wp-block-navigation__submenu-container .wp-block-navigation__submenu-container{left:100%;top:-1px}.wp-block-navigation .has-child .wp-block-navigation__submenu-container .wp-block-navigation__submenu-container:before{background:transparent;content:"";display:block;height:100%;position:absolute;right:100%;width:.5em}.wp-block-navigation .has-child .wp-block-navigation__submenu-container .wp-block-navigation__submenu-icon{margin-right:.25em}.wp-block-navigation .has-child .wp-block-navigation__submenu-container .wp-block-navigation__submenu-icon svg{transform:rotate(-90deg)}}@media (hover:hover){.wp-block-navigation .has-child:not(.open-on-click):hover>.wp-block-navigation__submenu-container{height:auto;
19min-width:200px;opacity:1;overflow:visible;visibility:visible;width:auto}}.wp-block-navigation .has-child .wp-block-navigation-submenu__toggle[aria-expanded=true]~.wp-block-navigation__submenu-container,.wp-block-navigation .has-child:not(.open-on-click):not(.open-on-hover-click):focus-within>.wp-block-navigation__submenu-container{height:auto;min-width:200px;opacity:1;overflow:visible;visibility:visible;width:auto}.wp-block-navigation .has-child.open-always{align-items:var(--navigation-layout-align,initial);flex-direction:var(--navigation-layout-direction,initial);flex-wrap:var(--navigation-layout-wrap,wrap);gap:var(--wp--style--block-gap,2em)}.wp-block-navigation .has-child.open-always,.wp-block-navigation .has-child.open-always .wp-block-navigation-item{justify-content:var(--navigation-layout-justify,initial)}.wp-block-navigation .has-child.open-always .wp-block-navigation__submenu-container,.wp-block-navigation .has-child.open-always.wp-block-navigation-submenu{gap:var(--wp--style--block-gap,2em)}.wp-block-navigation .has-child.open-always .wp-block-navigation-item,.wp-block-navigation .has-child.open-always .wp-block-navigation__submenu-container,.wp-block-navigation .has-child.open-always.wp-block-navigation-submenu{padding-bottom:0;padding-top:0}.wp-block-navigation .has-child.open-always .wp-block-navigation__submenu-container{padding-left:var(--wp--style--block-gap,2em);padding-right:var(--wp--style--block-gap,2em)}.wp-block-navigation .has-child.open-always .wp-block-navigation__submenu-container .wp-block-navigation-item__content{padding:0}.wp-block-navigation .has-child.open-always .wp-block-navigation__submenu-container>.wp-block-navigation-item>.wp-block-navigation-item__content,.wp-block-navigation .has-child.open-always>.wp-block-navigation-item__content{flex-grow:0}.wp-block-navigation .has-child.open-always>.wp-block-navigation__submenu-container{background-color:transparent;border:none;color:inherit;flex-basis:100%;height:auto;opacity:1;overflow:visible;position:static;visibility:visible;width:auto}.wp-block-navigation.has-background .has-child .wp-block-navigation__submenu-container{left:0;top:100%}@media (min-width:782px){.wp-block-navigation.has-background .has-child .wp-block-navigation__submenu-container .wp-block-navigation__submenu-container{left:100%;top:0}}.wp-block-navigation-submenu{display:flex;position:relative}.wp-block-navigation-submenu .wp-block-navigation__submenu-icon svg{stroke:currentColor}button.wp-block-navigation-item__content{background-color:transparent;border:none;color:currentColor;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;text-align:left;text-transform:inherit}.wp-block-navigation-submenu__toggle{cursor:pointer}.wp-block-navigation-submenu__toggle[aria-expanded=true]+.wp-block-navigation__submenu-icon>svg,.wp-block-navigation-submenu__toggle[aria-expanded=true]>svg{transform:rotate(180deg)}.wp-block-navigation-item.open-on-click .wp-block-navigation-submenu__toggle{padding-left:0;padding-right:.85em}.wp-block-navigation-item.open-on-click .wp-block-navigation-submenu__toggle+.wp-block-navigation__submenu-icon{margin-left:-.6em;pointer-events:none}.wp-block-navigation-item.open-on-click button.wp-block-navigation-item__content:not(.wp-block-navigation-submenu__toggle){padding:0}.wp-block-navigation .wp-block-page-list,.wp-block-navigation__container,.wp-block-navigation__responsive-close,.wp-block-navigation__responsive-container,.wp-block-navigation__responsive-container-content,.wp-block-navigation__responsive-dialog{gap:inherit}:where(.wp-block-navigation.has-background .wp-block-navigation-item a:not(.wp-element-button)),:where(.wp-block-navigation.has-background .wp-block-navigation-submenu a:not(.wp-element-button)){padding:.5em 1em}:where(.wp-block-navigation .wp-block-navigation__submenu-container .wp-block-navigation-item a:not(.wp-element-button)),:where(.wp-block-navigation .wp-block-navigation__submenu-container .wp-block-navigation-submenu a:not(.wp-element-button)),:where(.wp-block-navigation .wp-block-navigation__submenu-container .wp-block-navigation-submenu button.wp-block-navigation-item__content),:where(.wp-block-navigation .wp-block-navigation__submenu-container .wp-block-pages-list__item button.wp-block-navigation-item__content){padding:.5em 1em}.wp-block-navigation.items-justified-right .wp-block-navigation__container .has-child .wp-block-navigation__submenu-container,.wp-block-navigation.items-justified-right .wp-block-page-list>.has-child .wp-block-navigation__submenu-container,.wp-block-navigation.items-justified-space-between .wp-block-page-list>.has-child:last-child .wp-block-navigation__submenu-container,.wp-block-navigation.items-justified-space-between>.wp-block-navigation__container>.has-child:last-child .wp-block-navigation__submenu-container{left:auto;right:0}.wp-block-navigation.items-justified-right .wp-block-navigation__container .has-child .wp-block-navigation__submenu-container .wp-block-navigation__submenu-container,.wp-block-navigation.items-justified-right .wp-block-page-list>.has-child .wp-block-navigation__submenu-container .wp-block-navigation__submenu-container,.wp-block-navigation.items-justified-space-between .wp-block-page-list>.has-child:last-child .wp-block-navigation__submenu-container .wp-block-navigation__submenu-container,.wp-block-navigation.items-justified-space-between>.wp-block-navigation__container>.has-child:last-child .wp-block-navigation__submenu-container .wp-block-navigation__submenu-container{left:-1px;right:-1px}@media (min-width:782px){.wp-block-navigation.items-justified-right .wp-block-navigation__container .has-child .wp-block-navigation__submenu-container .wp-block-navigation__submenu-container,.wp-block-navigation.items-justified-right .wp-block-page-list>.has-child .wp-block-navigation__submenu-container .wp-block-navigation__submenu-container,.wp-block-navigation.items-justified-space-between .wp-block-page-list>.has-child:last-child .wp-block-navigation__submenu-container .wp-block-navigation__submenu-container,.wp-block-navigation.items-justified-space-between>.wp-block-navigation__container>.has-child:last-child .wp-block-navigation__submenu-container .wp-block-navigation__submenu-container{left:auto;right:100%}}.wp-block-navigation:not(.has-background) .wp-block-navigation__submenu-container{background-color:#fff;border:1px solid rgba(0,0,0,.15)}.wp-block-navigation.has-background .wp-block-navigation__submenu-container{background-color:inherit}.wp-block-navigation:not(.has-text-color) .wp-block-navigation__submenu-container{c
19olor:#000}.wp-block-navigation__container{align-items:var(--navigation-layout-align,initial);display:flex;flex-direction:var(--navigation-layout-direction,initial);flex-wrap:var(--navigation-layout-wrap,wrap);justify-content:var(--navigation-layout-justify,initial);list-style:none;margin:0;padding-left:0}.wp-block-navigation__container .is-responsive{display:none}.wp-block-navigation__container:only-child,.wp-block-page-list:only-child{flex-grow:1}@keyframes overlay-menu__fade-in-animation{0%{opacity:0;transform:translateY(.5em)}to{opacity:1;transform:translateY(0)}}.wp-block-navigation__responsive-container{bottom:0;display:none;left:0;position:fixed;right:0;top:0}.wp-block-navigation__responsive-container :where(.wp-block-navigation-item a){color:inherit}.wp-block-navigation__responsive-container .wp-block-navigation__responsive-container-content{align-items:var(--navigation-layout-align,initial);display:flex;flex-direction:var(--navigation-layout-direction,initial);flex-wrap:var(--navigation-layout-wrap,wrap);justify-content:var(--navigation-layout-justify,initial)}.wp-block-navigation__responsive-container:not(.is-menu-open.is-menu-open){background-color:inherit!important;color:inherit!important}.wp-block-navigation__responsive-container.is-menu-open{background-color:inherit;display:flex;flex-direction:column}@media not (prefers-reduced-motion){.wp-block-navigation__responsive-container.is-menu-open{animation:overlay-menu__fade-in-animation .1s ease-out;animation-fill-mode:forwards}}.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay){padding:clamp(1rem,var(--wp--style--root--padding-top),20rem) clamp(1rem,var(--wp--style--root--padding-right),20rem) clamp(1rem,var(--wp--style--root--padding-bottom),20rem) clamp(1rem,var(--wp--style--root--padding-left),20rem)}.wp-block-navigation__responsive-container.is-menu-open{overflow:auto;z-index:100000}.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) .wp-block-navigation__responsive-container-content{padding-top:calc(2rem
19+ 24px)}.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-container-content{align-items:var(--navigation-layout-justification-setting,inherit);display:flex;flex-direction:column;flex-wrap:nowrap;overflow:visible}.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-container-content,.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-container-content .wp-block-navigation__container,.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-container-content .wp-block-page-list{justify-content:flex-start}.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-container-content .wp-block-navigation__submenu-icon{display:none}.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-container-content .has-child .wp-block-navigation__submenu-container{border:none;height:auto;
19min-width:200px;opacity:1;overflow:initial;padding-left:2rem;padding-right:2rem;position:static;visibility:visible;width:auto}.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-container-content .wp-block-navigation__container,.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-container-content .wp-block-navigation__submenu-container{gap:inherit}.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-container-content .wp-block-navigation__submenu-container{padding-top:var(--wp--style--block-gap,2em)}.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-container-content .wp-block-navigation-item__content{padding:0}.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-container-content .wp-block-navigation-item,.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-container-content .wp-block-navigation__container,.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-container-content .wp-block-page-list{align-items:var(--navigation-layout-justification-setting,initial);display:flex;flex-direction:column}.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation-item,.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation-item .wp-block-navigation__submenu-container,.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__container,.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-page-list{background:transparent!important;color:inherit!important}.wp-block-navigation__responsive-container.is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__submenu-container.wp-block-navigation__submenu-container.wp-block-navigation__submenu-container.wp-block-navigation__submenu-container{left:auto;right:auto}.wp-block-navigation__responsive-container.disable-default-overlay .wp-block-navigation__overlay-container{display:none;width:100%}.wp-block-navigation__responsive-container.disable-default-overlay .wp-block-navigation__responsive-close{max-width:none}.wp-block-navigation__responsive-container.disable-default-overlay.is-menu-open .wp-block-navigation__responsive-container-content>:not(.wp-block-navigation__overlay-container){display:none}.wp-block-navigation__responsive-container.disable-default-overlay.is-menu-open .wp-block-navigation__responsive-container-content .wp-block-navigation__overlay-container{display:block}.wp-block-navigation__responsive-container.disable-default-overlay.is-menu-open .wp-block-navigation__responsive-container-content .wp-block-navigation__overlay-container .wp-block-navigation__submenu-container{left:0;right:auto}@media (min-width:600px){.wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open){background-color:inherit;display:block;position:relative;width:100%;z-index:auto}.wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) .wp-block-navigation__responsive-container-close{display:none}.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container.wp-block-navigation__submenu-container.wp-block-navigation__submenu-container.wp-block-navigation__submenu-container{left:0}}.wp-block-navigation:not(.has-background) .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay){background-color:#fff}.wp-block-navigation:not(.has-text-color) .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay){color:#000}.wp-block-navigation__toggle_button_label{font-size:1rem;font-weight:700}.wp-block-navigation__responsive-container-close,.wp-block-navigation__responsive-container-open{background:transparent;border:none;color:currentColor;cursor:pointer;margin:0;padding:0;text-transform:inherit;vertical-align:middle}.wp-block-navigation__responsive-container-close svg,.wp-block-navigation__responsive-container-open svg{fill:currentColor;display:block;height:24px;pointer-events:none;width:24px}.wp-block-navigation__responsive-container-open{display:flex}.wp-block-navigation__responsive-container-open.wp-block-navigation__responsive-container-open.wp-block-navigation__responsive-container-open{font-family:inherit;font-size:inherit;font-weight:inherit}@media (min-width:600px){.wp-block-navigation__responsive-container-open:not(.always-shown){display:none}}.wp-block-navigation__responsive-container-close{position:absolute;right:0;top:0;z-index:2}.wp-block-navigation__responsive-container-close.wp-block-navigation__responsive-container-close.wp-block-navigation__responsive-container-close{font-family:inherit;font-size:inherit;font-weight:inherit}.disable-default-overlay .wp-block-navigation__responsive-container-close{right:clamp(1rem,var(--wp--style--root--padding-left),20rem);top:clamp(1rem,var(--wp--style--root--padding-left),20rem)}.wp-block-navigation__responsive-close{width:100%}.has-modal-open .wp-block-navigation__responsive-close{margin-left:auto;margin-right:auto;max-width:var(--wp--style--global--wide-size,100%)}.wp-block-navigation__responsive-close:focus{outline:none}.is-menu-open .wp-block-navigation__responsive-close,.is-menu-open .wp-block-navigation__responsive-container-content,.is-menu-open .wp-block-navigation__responsive-dialog{box-sizing:border-box}.wp-block-navigation__responsive-dialog{position:relative}
19.has-modal-open .admin-bar .is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-dialog{margin-top:46px}@media (min-width:782px){.has-modal-open .admin-bar .is-menu-open:where(:not(.disable-default-overlay)) .wp-block-navigation__responsive-dialog{margin-top:32px}}html.has-modal-open{overflow:hidden} 20/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/navigation/style.min.css */ 21</style> 22<style id="wp-block-group-inline-css"> 23.wp-block-group{box-sizing:border-box}:where(.wp-block-group.wp-block-group-is-layout-constrained){position:relative} 24/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/group/style.min.css */ 25</style> 26<style id="wp-block-heading-inline-css"> 27h1:where(.wp-block-heading).has-background,h2:where(.wp-block-heading).has-background,h3:where(.wp-block-heading).has-background,h4:where(.wp-block-heading).has-background,h5:where(.wp-block-heading).has-background,h6:where(.wp-block-heading).has-background{padding:1.25em 2.375em}h1.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h1.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h2.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h2.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h3.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h3.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h4.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h4.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h5.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h5.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h6.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h6.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]){rotate:180deg} 28/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/heading/style.min.css */ 29</style> 30<style id="wp-block-post-title-inline-css"> 31.wp-block-post-title{box-sizing:border-box;word-break:break-word}.wp-block-post-title :where(a){display:inline-block;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;text-decoration:inherit} 32/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/post-title/style.min.css */ 33</style> 34<style id="wp-block-paragraph-inline-css"> 35.is-small-text{font-size:.875em}.is-regular-text{font-size:1em}.is-large-text{font-size:2.25em}.is-larger-text{font-size:3em}.has-drop-cap:not(:focus):first-letter{float:left;font-size:8.4em;font-style:normal;font-weight:100;line-height:.68;margin:.05em .1em 0 0;text-transform:uppercase}body.rtl .has-drop-cap:not(:focus):first-letter{float:none;margin-left:.1em}p.has-drop-cap.has-background{overflow:hidden}:root :where(p.has-background){padding:1.25em 2.375em}:where(p.has-text-color:not(.has-link-color)) a{color:inherit}p.has-text-align-left[style*="writing-mode:vertical-lr"],p.has-text-align-right[style*="writing-mode:vertical-rl"]{rotate:180deg} 36/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/paragraph/style.min.css */ 37</style> 38<style id="wp-block-list-inline-css"> 39ol,ul{box-sizing:border-box}:root :where(.wp-block-list.has-background){padding:1.25em 2.375em} 40 41 ul.is-style-checkmark-list { 42 list-style-type: "\2713"; 43 } 44 45 ul.is-style-checkmark-list li { 46 padding-inline-start: 1ch; 47 } 48/*# sourceURL=wp-block-list-inline-css */ 49</style> 50<style id="wp-block-code-inline-css"> 51.wp-block-code{box-sizing:border-box}.wp-block-code code{direction:ltr;display:block;font-family:inherit;overflow-wrap:break-word;text-align:initial;white-space:break-spaces} 52/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/code/style.min.css */ 53</style> 54<style id="wp-block-post-content-inline-css"> 55.wp-block-post-content{display:flow-root} 56/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/post-content/style.min.css */ 57</style> 58<style id="wp-block-post-date-inline-css"> 59.wp-block-post-date{box-sizing:border-box} 60/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/post-date/style.min.css */ 61</style> 62<style id="wp-block-separator-inline-css"> 63@charset "UTF-8";.wp-block-separator{border:none;border-top:2px solid}:root :where(.wp-block-separator.is-style-dots){height:auto;line-height:1;text-align:center}:root :where(.wp-block-separator.is-style-dots):before{color:currentColor;content:"···";font-family:serif;font-size:1.5em;letter-spacing:2em;padding-left:2em}.wp-block-separator.is-style-dots{background:none!important;border:none!important}
64/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/separator/style.min.css */ 65</style> 66<style id="wp-block-quote-inline-css"> 67.wp-block-quote{box-sizing:border-box;overflow-wrap:break-word}.wp-block-quote.is-large:where(:not(.is-style-plain)),.wp-block-quote.is-style-large:where(:not(.is-style-plain)){margin-bottom:1em;padding:0 1em}.wp-block-quote.is-large:where(:not(.is-style-plain)) p,.wp-block-quote.is-style-large:where(:not(.is-style-plain)) p{font-size:1.5em;font-style:italic;line-height:1.6}.wp-block-quote.is-large:where(:not(.is-style-plain)) cite,.wp-block-quote.is-large:where(:not(.is-style-plain)) footer,.wp-block-quote.is-style-large:where(:not(.is-style-plain)) cite,.wp-block-quote.is-style-large:where(:not(.is-style-plain)) footer{font-size:1.125em;text-align:right}.wp-block-quote>cite{display:block} 68/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/quote/style.min.css */ 69</style> 70<style id="wp-block-post-template-inline-css"> 71.wp-block-post-template{box-sizing:border-box;list-style:none;margin-bottom:0;margin-top:0;max-width:100%;padding:0}.wp-block-post-template.is-flex-container{display:flex;flex-direction:row;flex-wrap:wrap;gap:1.25em}.wp-block-post-template.is-flex-container>li{margin:0;width:100%}@media (min-width:600px){.wp-block-post-template.is-flex-container.is-flex-container.columns-2>li{width:calc(50% - .625em)}.wp-block-post-template.is-flex-container.is-flex-container.columns-3>li{width:calc(33.33333% - .83333em)}.wp-block-post-template.is-flex-container.is-flex-container.columns-4>li{width:calc(25% - .9375em)}.wp-block-post-template.is-flex-container.is-flex-container.columns-5>li{width:calc(20% - 1em)}.wp-block-post-template.is-flex-container.is-flex-container.columns-6>li{width:calc(16.66667% - 1.04167em)}}@media (max-width:600px){.wp-block-post-template-is-layout-grid[class*=columns-]:not(.has-native-responsive-grid){grid-template-columns:1fr}}.wp-block-post-template-is-layout-constrained>li>.alignright,.wp-block-post-template-is-layout-flow>li>.alignright{float:right;margin-inline-end:0;margin-inline-start:2em}.wp-block-post-template-is-layout-constrained>li>.alignleft,.wp-block-post-template-is-layout-flow>li>.alignleft{float:left;margin-inline-end:2em;margin-inline-start:0}.wp-block-post-template-is-layout-constrained>li>.aligncenter,.wp-block-post-template-is-layout-flow>li>.aligncenter{margin-inline-end:auto;margin-inline-start:auto} 72/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/post-template/style.min.css */ 73</style> 74<style id="wp-block-site-tagline-inline-css"> 75.wp-block-site-tagline{box-sizing:border-box} 76/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/site-tagline/style.min.css */ 77</style> 78<style id="wp-block-spacer-inline-css"> 79.wp-block-spacer{clear:both} 80/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/spacer/style.min.css */ 81</style> 82<style id="wp-block-columns-inline-css"> 83.wp-block-columns{box-sizing:border-box;display:flex;flex-wrap:wrap!important}@media (min-width:782px){.wp-block-columns{flex-wrap:nowrap!important}}.wp-block-columns{align-items:normal!important}.wp-block-columns.are-vertically-aligned-top{align-items:flex-start}.wp-block-columns.are-vertically-aligned-center{align-items:center}.wp-block-columns.are-vertically-aligned-bottom{align-items:flex-end}@media (max-width:781px){.wp-block-columns:not(.is-not-stacked-on-mobile)>.wp-block-column{flex-basis:100%!important}}@media (min-width:782px){.wp-block-columns:not(.is-not-stacked-on-mobile)>.wp-block-column{flex-basis:0;flex-grow:1}.wp-block-columns:not(.is-not-stacked-on-mobile)>.wp-block-column[style*=flex-basis]{flex-grow:0}}.wp-block-columns.is-not-stacked-on-mobile{flex-wrap:nowrap!important}.wp-block-columns.is-not-stacked-on-mobile>.wp-block-column{flex-basis:0;flex-grow:1}.wp-block-columns.is-not-stacked-on-mobile>.wp-block-column[style*=flex-basis]{flex-grow:0}:where(.wp-block-columns){margin-bottom:1.75em}:where(.wp-block-columns.has-background){padding:1.25em 2.375em}.wp-block-column{flex-grow:1;min-width:0;overflow-wrap:break-word;word-break:break-word}.wp-block-column.is-vertically-aligned-top{align-self:flex-start}.wp-block-column.is-vertically-aligned-center{align-self:center}.wp-block-column.is-vertically-aligned-bottom{align-self:flex-end}.wp-block-column.is-vertically-aligned-stretch{align-self:stretch}.wp-block-column.is-vertically-aligned-bottom,.wp-block-column.is-vertically-aligned-center,.wp-block-column.is-vertically-aligned-top{width:100%} 84/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/columns/style.min.css */ 85</style> 86<style id="wp-block-navigation-link-inline-css"> 87.wp-block-navigation .wp-block-navigation-item__label{overflow-wrap:break-word}
87.wp-block-navigation .wp-block-navigation-item__description{display:none}.link-ui-tools{outline:1px solid #f0f0f0;padding:8px}.link-ui-block-inserter{padding-top:8px}.link-ui-block-inserter__back{margin-left:8px;text-transform:uppercase} 88/*# sourceURL=https://ko4bep.net/blog/wp-includes/blocks/navigation-link/style.min.css */ 89</style> 90<style id="wp-emoji-styles-inline-css"> 91 92 img.wp-smiley, img.emoji { 93 display: inline !important; 94 border: none !important; 95 box-shadow: none !important; 96 height: 1em !important; 97 width: 1em !important; 98 margin: 0 0.07em !important; 99 vertical-align: -0.1em !important; 100 background: none !important; 101 padding: 0 !important; 102 } 103/*# sourceURL=wp-emoji-styles-inline-css */ 104</style> 105<style id="wp-block-library-inline-css"> 106:root{--wp-block-synced-color:#7a00df;--wp-block-synced-color--rgb:122,0,223;--wp-bound-block-color:var(--wp-block-synced-color);--wp-editor-canvas-background:#ddd;--wp-admin-theme-color:#007cba;--wp-admin-theme-color--rgb:0,124,186;--wp-admin-theme-color-darker-10:#006ba1;--wp-admin-theme-color-darker-10--rgb:0,107,160.5;--wp-admin-theme-color-darker-20:#005a87;--wp-admin-theme-color-darker-20--rgb:0,90,135;--wp-admin-border-width-focus:2px}@media (min-resolution:192dpi){:root{--wp-admin-border-width-focus:1.5px}}.wp-element-button{cursor:pointer}:root .has-very-light-gray-background-color{background-color:#eee}:root .has-very-dark-gray-background-color{background-color:#313131}:root .has-very-light-gray-color{color:#eee}:root .has-very-dark-gray-color{color:#313131}:root .has-vivid-green-cyan-to-vivid-cyan-blue-gradient-background{background:linear-gradient(135deg,#00d084,#0693e3)}:root .has-purple-crush-gradient-background{background:linear-gradient(135deg,#34e2e4,#4721fb 50%,#ab1dfe)}:root .has-hazy-dawn-gradient-background{background:linear-gradient(135deg,#faaca8,#dad0ec)}:root .has-subdued-olive-gradient-background{background:linear-gradient(135deg,#fafae1,#67a671)}:root .has-atomic-cream-gradient-background{background:linear-gradient(135deg,#fdd79a,#004a59)}:root .has-nightshade-gradient-background{background:linear-gradient(135deg,#330968,#31cdcf)}:root .has-midnight-gradient-background{background:linear-gradient(135deg,#020381,#2874fc)}:root{--wp--preset--font-size--normal:16px;
106--wp--preset--font-size--huge:42px}.has-regular-font-size{font-size:1em}.has-larger-font-size{font-size:2.625em}.has-normal-font-size{font-size:var(--wp--preset--font-size--normal)}.has-huge-font-size{font-size:var(--wp--preset--font-size--huge)}:root .has-text-align-center{text-align:center}:root .has-text-align-left{text-align:left}:root .has-text-align-right{text-align:right}.has-fit-text{white-space:nowrap!important}#end-resizable-editor-section{display:none}.aligncenter{clear:both}.items-justified-left{justify-content:flex-start}.items-justified-center{justify-content:center}.items-justified-right{justify-content:flex-end}.items-justified-space-between{justify-content:space-between}.screen-reader-text{word-wrap:normal!important;border:0;clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-break:normal!important}.screen-reader-text:focus{background-color:#ddd;clip-path:none;color:#444;display:block;font-size:1em;height:auto;left:5px;line-height:normal;padding:15px 23px 14px;text-decoration:none;top:5px;width:auto;z-index:100000}html :where(.has-border-color){border-style:solid}html :where([style^=border-color],[style*=";border-color"],[style*="; border-color"]){border-style:solid}html :where([style^=border-top-color],[style*=";border-top-color"],[style*="; border-top-color"]){border-top-style:solid}html :where([style^=border-right-color],[style*=";border-right-color"],[style*="; border-right-color"]){border-right-style:solid}html :where([style^=border-bottom-color],[style*=";border-bottom-color"],[style*="; border-bottom-color"]){border-bottom-style:solid}html :where([style^=border-left-color],[style*=";border-left-color"],[style*="; border-left-color"]){border-left-style:solid}html :where([style^=border-width],[style*=";border-width"],[style*="; border-width"]){border-style:solid}html :where([style^=border-top-width],[style*=";border-top-width"],[style*="; border-top-width"]){border-top-style:solid}html :where([style^=border-right-width],[style*=";border-right-width"],[style*="; border-right-width"]){border-right-style:solid}html :where([style^=border-bottom-width],[style*=";border-bottom-width"],[style*="; border-bottom-width"]){border-bottom-style:solid}html :where([style^=border-left-width],[style*=";border-left-width"],[style*="; border-left-width"]){border-left-style:solid}html :where(img[class*=wp-image-]){height:auto;max-width:100%}:where(figure){margin:0 0 1em}html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:var(--wp-admin--admin-bar--height,0px)}@media screen and (max-width:600px){html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:0px}} 107/*# sourceURL=/wp-includes/css/dist/block-library/common.min.css */ 108</style> 109<style id="global-styles-inline-css"> 110:root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--color--base: #131313;--wp--preset--color--contrast: #FFFFFF;--wp--preset--color--accent-1: #4B52FF;--wp--preset--color--accent-2: #FF7A5C;--wp--preset--color--accent-3: #252525;--wp--preset--color--accent-4: #FFFFFF;--wp--preset--color--accent-5: #252525;--wp--preset--color--accent-6: #FFFFFF33;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgb(6,147,227) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgb(252,185,
1100) 0%,rgb(255,105,0) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgb(255,105,0) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 0.875rem;--wp--preset--font-size--medium: clamp(1rem, 1rem + ((1vw - 0.2rem) * 0.196), 1.125rem);--wp--preset--font-size--large: clamp(1.125rem, 1.125rem + ((1vw - 0.2rem) * 0.392), 1.375rem);--wp--preset--font-size--x-large: clamp(1.75rem, 1.75rem + ((1vw - 0.2rem) * 0.392), 2rem);--wp--preset--font-size--xx-large: clamp(1.4rem, 1.4rem + ((1vw - 0.2rem) * 1.882), 2.6rem);--wp--preset--font-family--ysabeau-office: "Ysabeau Office", sans-serif;--wp--preset--font-family--manrope: Manrope, sans-serif;--wp--preset--spacing--20: 10px;--wp--preset--spacing--30: 20px;--wp--preset--spacing--40: 30px;--wp--preset--spacing--50: clamp(30px, 5vw, 50px);--wp--preset--spacing--60: clamp(30px, 7vw, 70px);--wp--preset--spacing--70: clamp(50px, 7vw, 90px);--wp--preset--spacing--80: clamp(70px, 10vw, 140px);--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgb(255, 255, 255), 6px 6px rgb(0, 0, 0);--wp--preset--shadow--crisp: 6px 6px 0px rgb(0, 0, 0);}.wp-block-button{--wp--preset--dimension--25: 25%;--wp--preset--dimension--50: 50%;--wp--preset--dimension--75: 75%;--wp--preset--dimension--100: 100%;}:root { --wp--style--global--content-size: 645px;--wp--style--global--wide-size: 1340px; }:where(body) { margin: 0; }.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }.has-global-padding :where(:not(.alignfull.is-layout-flow) > .has-global-padding:not(.wp-block-block, .alignfull)) { padding-right: 0; padding-left: 0; }.has-global-padding :where(:not(.alignfull.is-layout-flow) > .has-global-padding:not(.wp-block-block, .alignfull)) > .alignfull { margin-left: 0; margin-right: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: 1.2rem; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: 1.2rem; }:root :where(.is-layout-flow) > :first-child{margin-block-start: 0;}:root :where(.is-layout-flow) > :last-child{margin-block-end: 0;}:root :where(.is-layout-flow) > *{margin-block-start: 1.2rem;margin-block-end: 0;}:root :where(.is-layout-constrained) > :first-child{margin-block-start: 0;}:root :where(.is-layout-constrained) > :last-child{margin-block-end: 0;}:root :where(.is-layout-constrained) > *{margin-block-start: 1.2rem;margin-block-end: 0;}:root :where(.is-layout-flex){gap: 1.2rem;}:root :where(.is-layout-grid){gap: 1.2rem;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained >
110 :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}body{background-color: var(--wp--preset--color--base);color: var(--wp--preset--color--contrast);font-family: var(--wp--preset--font-family--ysabeau-office);font-size: var(--wp--preset--font-size--large);font-weight: 300;letter-spacing: -0.24px;line-height: 1.4;--wp--style--root--padding-top: 0px;--wp--style--root--padding-right: var(--wp--preset--spacing--50);--wp--style--root--padding-bottom: 0px;--wp--style--root--padding-left: var(--wp--preset--spacing--50);}a:where(:not(.wp-element-button)){color: currentColor;}:root :where(a:where(:not(.wp-element-button)):hover){text-decoration: none;}h1, h2, h3, h4, h5, h6{font-family: var(--wp--preset--font-family--literata);font-weight: 900;letter-spacing: -0.1px;line-height: 1.2;}h1{font-size: var(--wp--preset--font-size--xx-large);}h2{font-size: var(--wp--preset--font-size--x-large);}h3{font-size: var(--wp--preset--font-size--large);}h4{font-size: var(--wp--preset--font-size--medium);}h5{font-size: var(--wp--preset--font-size--small);letter-spacing: 0px;}h6{font-size: var(--wp--preset--font-size--small);font-weight: 900;letter-spacing: 0px;text-transform: uppercase;}:root :where(.wp-element-button, .wp-block-button__link){background-color: var(--wp--preset--color--contrast);border-radius: 0px;border-width: 0;color: var(--wp--preset--color--base);font-family: var(--wp--preset--font-family--literata);font-size: var(--wp--preset--font-size--medium);font-style: inherit;font-weight: 900;letter-spacing: -0.36px;line-height: inherit;padding-top: 1rem;padding-right: 2.25rem;padding-bottom: 1rem;padding-left: 2.25rem;text-decoration: none;text-transform: inherit;}:root :where(.wp-element-button:hover, .wp-block-button__link:hover){background-color: color-mix(in srgb, var(--wp--preset--color--contrast) 85%, transparent);border-color: transparent;color: var(--wp--preset--color--base);}:root :where(.wp-element-button:focus, .wp-block-button__link:focus){outline-color: var(--wp--preset--color--accent-4);outline-offset: 2px;}:root :where(.wp-element-caption, .wp-block-audio figcaption, .wp-block-embed figcaption, .wp-block-gallery figcaption, .wp-block-image figcaption, .wp-block-table figcaption, .wp-block-video figcaption){font-size: var(--wp--preset--font-size--small);line-height: 1.4;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-base-color{color: var(--wp--preset--color--base) !important;}.has-contrast-color{color: var(--wp--preset--color--contrast) !important;}.has-accent-1-color{color: var(--wp--preset--color--accent-1) !important;}.has-accent-2-color{color: var(--wp--preset--color--accent-2) !important;}.has-accent-3-color{color: var(--wp--preset--color--accent-3) !important;}.has-accent-4-color{color: var(--wp--preset--color--accent-4) !important;}.has-accent-5-color{color: var(--wp--preset--color--accent-5) !important;}.has-accent-6-color{color: var(--wp--preset--color--accent-6) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-base-background-color{background-color: var(--wp--preset--color--base) !important;}.has-contrast-background-color{background-color: var(--wp--preset--color--contrast) !important;}.has-accent-1-background-color{background-color: var(--wp--preset--color--accent-1) !important;}.has-accent-2-background-color{background-color: var(--wp--preset--color--accent-2) !important;}.has-accent-3-background-color{background-color: var(--wp--preset--color--accent-3) !important;}.has-accent-4-background-color{background-color: var(--wp--preset--color--accent-4) !important;}.has-accent-5-background-color{background-color: var(--wp--preset--color--accent-5) !important;}.has-accent-6-background-color{background-color: var(--wp--preset--color--accent-6) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-base-border-color{border-color: var(--wp--preset--color--base) !important;}.has-contrast-border-color{border-color: var(--wp--preset--color--contrast) !important;}.has-accent-1-border-color{border-color: var(--wp--preset--color--accent-1) !important;}.has-accent-2-border-color{border-color: var(--wp--preset--color--accent-2) !important;}.has-accent-3-border-color{border-color: var(--wp--preset--color--accent-3) !important;}.has-accent-4-border-color{border-color: var(--wp--preset--color--accent-4) !important;}.has-accent-5-border-color{border-color: var(--wp--preset--color--accent-5) !important;}.has-accent-6-border-color{border-color: var(--wp--preset--color--accent-6) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}
110.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}.has-xx-large-font-size{font-size: var(--wp--preset--font-size--xx-large) !important;}.has-ysabeau-office-font-family{font-family: var(--wp--preset--font-family--ysabeau-office) !important;}.has-manrope-font-family{font-family: var(--wp--preset--font-family--manrope) !important;} 111:root :where(.wp-block-columns-is-layout-flow) > :first-child{margin-block-start: 0;}:root :where(.wp-block-columns-is-layout-flow) > :last-child{margin-block-end: 0;}:root :where(.wp-block-columns-is-layout-flow) > *{margin-block-start: var(--wp--preset--spacing--50);margin-block-end: 0;}:root :where(.wp-block-columns-is-layout-constrained) > :first-child{margin-block-start: 0;}:root :where(.wp-block-columns-is-layout-constrained) > :last-child{margin-block-end: 0;}:root :where(.wp-block-columns-is-layout-constrained) > *{margin-block-start: var(--wp--preset--spacing--50);margin-block-end: 0;}:root :where(.wp-block-columns-is-layout-flex){gap: var(--wp--preset--spacing--50);}:root :where(.wp-block-columns-is-layout-grid){gap: var(--wp--preset--spacing--50);} 112:root :where(.wp-block-code){background-color: var(--wp--preset--color--accent-5);color: var(--wp--preset--color--contrast);font-family: var(--wp--preset--font-family--fira-code);font-size: var(--wp--preset--font-size--medium);font-weight: 300;padding-top: var(--wp--preset--spacing--40);padding-right: var(--wp--preset--spacing--40);padding-bottom: var(--wp--preset--spacing--40);padding-left: var(--wp--preset--spacing--40);} 113:root :where(.wp-block-post-date){color: var(--wp--preset--color--accent-4);font-size: var(--wp--preset--font-size--small);} 114:root :where(.wp-block-post-date a:where(:not(.wp-element-button))){color: var(--wp--preset--color--accent-4);text-decoration: none;} 115:root :where(.wp-block-post-date a:where(:not(.wp-element-button)):hover){text-decoration: underline;} 116:root :where(.wp-block-post-title){font-weight: 900;letter-spacing: -0.96px;} 117:root :where(.wp-block-post-title a:where(:not(.wp-element-button))){text-decoration: none;} 118:root :where(.wp-block-post-title a:where(:not(.wp-element-button)):hover){text-decoration: underline;} 119:root :where(.wp-block-quote){border-color: currentColor;border-width: 0 0 0 2px;border-style: solid;font-size: var(--wp--preset--font-size--large);font-weight: 300;margin-right: 0;margin-left: 0;padding-top: var(--wp--preset--spacing--30);padding-right: var(--wp--preset--spacing--40);padding-bottom: var(--wp--preset--spacing--30);padding-left: var(--wp--preset--spacing--40);}:root :where(.wp-block-quote-is-layout-flow) > :first-child{margin-block-start: 0;}:root :where(.wp-block-quote-is-layout-flow) > :last-child{margin-block-end: 0;}:root :where(.wp-block-quote-is-layout-flow) > *{margin-block-start: var(--wp--preset--spacing--30);margin-block-end: 0;}:root :where(.wp-block-quote-is-layout-constrained) > :first-child{margin-block-start: 0;}:root :where(.wp-block-quote-is-layout-constrained) > :last-child{margin-block-end: 0;}:root :where(.wp-block-quote-is-layout-constrained) > *{margin-block-start: var(--wp--preset--spacing--30);margin-block-end: 0;}:root :where(.wp-block-quote-is-layout-flex){gap: var(--wp--preset--spacing--30);}:root :where(.wp-block-quote-is-layout-grid){gap: var(--wp--preset--spacing--30);}:root :where(.wp-block-quote.has-text-align-right ){border-width: 0 2px 0 0;}:root :where(.wp-block-quote.has-text-align-center ){border-width: 0;border-inline: 0; padding-inline: 0;} 120:root :where(.wp-block-quote cite){font-size: var(--wp--preset--font-size--medium);font-style: normal;font-weight: 300;letter-spacing: -0.14px;}:root :where(.wp-block-quote cite sub){font-size: 0.65em} 121:root :where(.wp-block-separator){border-color: currentColor;border-width: 0 0 1px 0;border-style: solid;color: var(--wp--preset--color--accent-6);} 122:root :where(.wp-block-site-tagline){font-size: var(--wp--preset--font-size--medium);} 123:root :where(.wp-block-site-title){font-family: var(--wp--preset--font-family--ysabeau-office);font-weight: 700;letter-spacing: 1.6px;text-transform: uppercase;}
124:root :where(.wp-block-site-title a:where(:not(.wp-element-button))){text-decoration: none;} 125:root :where(.wp-block-site-title a:where(:not(.wp-element-button)):hover){text-decoration: underline;} 126:root :where(.wp-block-navigation){font-size: clamp(0.875rem, 0.875rem + ((1vw - 0.2rem) * 0.588), 1.25rem);} 127:root :where(.wp-block-navigation a:where(:not(.wp-element-button))){text-decoration: none;} 128:root :where(.wp-block-navigation a:where(:not(.wp-element-button)):hover){text-decoration: underline;} 129:root :where(.wp-block-list li){margin-top: 0.5rem;} 130/*# sourceURL=global-styles-inline-css */ 131</style> 132<style id="core-block-supports-inline-css"> 133.wp-container-core-navigation-is-layout-6e943505{justify-content:flex-end;}.wp-container-core-group-is-layout-fbffc046{flex-wrap:nowrap;gap:var(--wp--preset--spacing--10);justify-content:flex-end;}.wp-container-core-group-is-layout-ec1e7a1e{flex-wrap:nowrap;justify-content:space-between;}.wp-container-core-columns-is-layout-794e3cfa{flex-wrap:nowrap;}.wp-container-core-navigation-is-layout-831b2db5{flex-direction:column;align-items:flex-start;}.wp-container-core-group-is-layout-bf19e0b3{gap:var(--wp--preset--spacing--80);justify-content:space-between;align-items:flex-start;}.wp-container-core-group-is-layout-cf54d0a6{justify-content:space-between;align-items:flex-start;}.wp-container-core-group-is-layout-2ab8c7fb{gap:var(--wp--preset--spacing--20);justify-content:space-between;} 134/*# sourceURL=core-block-supports-inline-css */ 135</style> 136<style id="wp-block-template-skip-link-inline-css"> 137/*! This file is auto-generated */ 138.skip-link.screen-reader-text{border:0;clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute!important;width:1px;word-wrap:normal!important;word-break:normal!important}.skip-link.screen-reader-text:focus{background-color:#eee;clip-path:none;color:#444;display:block;font-size:1em;height:auto;left:5px;line-height:normal;padding:15px 23px 14px;text-decoration:none;top:5px;width:auto;z-index:100000} 139/*# sourceURL=/wp-includes/css/wp-block-template-skip-link.min.css */ 140</style> 141<style id="twentytwentyfive-style-inline-css"> 142a{text-decoration-thickness:1px!important;text-underline-offset:.1em}:where(.wp-site-blocks :focus){outline-style:solid;outline-width:2px}.wp-block-navigation .wp-block-navigation-submenu .wp-block-navigation-item:not(:last-child){margin-bottom:3px}.wp-block-navigation .wp-block-navigation-item .wp-block-navigation-item__content{outline-offset:4px}.wp-block-navigation .wp-block-navigation-item ul.wp-block-navigation__submenu-container .wp-block-navigation-item__content{outline-offset:0}blockquote,caption,figcaption,h1,h2,h3,h4,h5,h6,p{text-wrap:pretty}.more-link{display:block}:where(pre){overflow-x:auto} 143/*# sourceURL=https://ko4bep.net/blog/wp-content/themes/twentytwentyfive/style.min.css */ 144</style> 145<link rel="https://api.w.org/" href="https://ko4bep.net/blog/index.php/wp-json/" /><link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://ko4bep.net/blog/xmlrpc.php?rsd" /> 146<meta name="generator" content="WordPress 7.1" />
147<script id="wp-importmap" type="importmap"> 148{"imports":{"@wordpress/interactivity":"https://ko4bep.net/blog/wp-includes/js/dist/script-modules/interactivity/index.min.js?ver=efaa5193bbad9c60ffd1"}} 149</script>
149 150<link rel="modulepreload" href="https://ko4bep.net/blog/wp-includes/js/dist/script-modules/interactivity/index.min.js?ver=efaa5193bbad9c60ffd1" id="@wordpress/interactivity-js-modulepreload" fetchpriority="low"> 151<style class="wp-fonts-local"> 152@font-face{font-family:"Ysabeau Office";font-style:normal;font-weight:100 900;font-display:fallback;src:url('https://ko4bep.net/blog/wp-content/themes/twentytwentyfive/assets/fonts/ysabeau-office/YsabeauOffice-VariableFont_wght.woff2') format('woff2');} 153@font-face{font-family:"Ysabeau Office";font-style:italic;font-weight:100 900;font-display:fallback;src:url('https://ko4bep.net/blog/wp-content/themes/twentytwentyfive/assets/fonts/ysabeau-office/YsabeauOffice-Italic-VariableFont_wght.woff2') format('woff2');} 154@font-face{font-family:Manrope;font-style:normal;font-weight:200 800;font-display:fallback;src:url('https://ko4bep.net/blog/wp-content/themes/twentytwentyfive/assets/fonts/manrope/Manrope-VariableFont_wght.woff2') format('woff2');} 155</style> 156</head> 157 158<body class="home blog wp-embed-responsive wp-theme-twentytwentyfive"> 159 160<a class="skip-link screen-reader-text" id="wp-skip-link" href="#wp--skip-link--target">Skip to content</a><div class="wp-site-blocks"><header class="wp-block-template-part"> 161<div class="wp-block-group alignfull is-layout-flow wp-block-group-is-layout-flow"> 162 163 <div class="wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained"> 164 165 <div class="wp-block-group alignwide is-content-justification-space-between is-nowrap is-layout-flex wp-container-core-group-is-layout-ec1e7a1e wp-block-group-is-layout-flex" style="padding-top:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30)"> 166 <p class="wp-block-site-title"><a href="https://ko4bep.net/blog" target="_self" rel="home" aria-current="page">KO4BEP :: Blog</a></p> 167 168 <div class="wp-block-group is-content-justification-right is-nowrap is-layout-flex wp-container-core-group-is-layout-fbffc046 wp-block-group-is-layout-flex"> 169 <nav class="is-responsive items-justified-right wp-block-navigation is-content-justification-right is-layout-flex wp-container-core-navigation-is-layout-6e943505 wp-block-navigation-is-layout-flex" 170 data-wp-interactive="core/navigation" data-wp-context='{"overlayOpenedBy":{"click":false,"hover":false,"focus":false},"type":"overlay","roleAttribute":"","ariaLabel":"Menu"}'><button aria-haspopup="dialog" aria-label="Open menu" class="wp-block-navigation__responsive-container-open" 171 data-wp-on--click="actions.openMenuOnClick" 172 data-wp-on--keydown="actions.handleMenuKeydown" 173 ><svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M4 7.5h16v1.5H4z"></path><path d="M4 15h16v1.5H4z"></path></svg></button> 174 <div class="wp-block-navigation__responsive-container has-text-color has-contrast-color has-background has-base-background-color" id="modal-1" 175 data-wp-class--has-modal-open="state.isMenuOpen" 176 data-wp-class--is-menu-open="state.isMenuOpen" 177 data-wp-watch="callbacks.initMenu" 178 data-wp-on--keydown="actions.handleMenuKeydown" 179 data-wp-on--focusout="actions.handleMenuFocusout" 180 tabindex="-1" 181 > 182 <div class="wp-block-navigation__responsive-close" tabindex="-1"> 183 <div class="wp-block-navigation__responsive-dialog" 184 data-wp-bind--aria-modal="state.ariaModal" 185 data-wp-bind--aria-label="state.ariaLabel" 186 data-wp-bind--role="state.roleAttribute" 187 > 188 <button aria-label="Close menu" class="wp-block-navigation__responsive-container-close" 189 data-wp-on--click="actions.closeMenuOnClick" 190 ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false"><path d="m13.06 12 6.47-6.47-1.06-1.06L12 10.94 5.53 4.47 4.47 5.53 10.94 12l-6.47 6.47 1.06 1.06L12 13.06l6.47 6.47 1.06-1.06L13.06 12Z"></path></svg></button> 191 <div class="wp-block-navigation__responsive-container-content" 192 data-wp-watch="callbacks.focusFirstElement" 193 id="modal-1-content"> 194 195 196 </div> 197 </div> 198 </div>
199 </div></nav> 200 </div> 201 202 </div> 203 204 </div> 205 206</div> 207 208 209</header> 210 211 212<main id="wp--skip-link--target" class="wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained" style="margin-top:var(--wp--preset--spacing--60)"> 213 214<h1 class="wp-block-heading has-text-align-left">Blog</h1> 215 216 217 218<div class="wp-block-query alignfull is-layout-flow wp-block-query-is-layout-flow"> 219 <ul class="alignfull wp-block-post-template is-layout-flow wp-block-post-template-is-layout-flow"><li class="wp-block-post post-26 post type-post status-publish format-standard hentry category-uncategorized tag-ai tag-it tag-privacy tag-search tag-selfhosted"> 220 221 <div class="wp-block-group alignfull has-global-padding is-layout-constrained wp-block-group-is-layout-constrained" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--60)"> 222 223 <h2 class="wp-block-post-title has-x-large-font-size"><a href="https://ko4bep.net/blog/index.php/2026/04/27/building-a-local-ai-search-page-with-searxng-and-ollama/" target="_self" >Building a Local AI Search Page with SearXNG and Ollama</a></h2> 224 <div class="entry-content alignfull wp-block-post-content has-medium-font-size has-global-padding is-layout-constrained wp-block-post-content-is-layout-constrained"> 225<h1 class="wp-block-heading"></h1> 226 227 228 229<p class="wp-block-paragraph">Most search engines now bolt an AI answer box onto the top of the results page. That can be useful, but it also means your query and whatever the model does with it are happening on somebody elseâs infrastructure.</p> 230 231 232 233<p class="wp-block-paragraph">This project builds the same basic workflow locally:</p> 234 235 236 237<ul class="wp-block-list"> 238<li>SearXNG handles normal web search.</li> 239 240 241 242<li>Ollama runs a local model.</li> 243 244 245 246<li>A tiny Flask wrapper shows search results immediately.</li> 247 248 249 250<li>AI answers are optional. You check a box when you want them.</li> 251 252 253 254<li>Apache or other reverse proxy can publish the whole thing under <code>/search/</code> on an existing site.</li> 255</ul> 256 257 258 259<h2 class="wp-block-heading">What the final setup looks like</h2> 260 261 262 263<p class="wp-block-paragraph">The public page is:</p> 264 265 266 267<pre class="wp-block-code"><code>https://YOUR_DOMAIN/search/</code></pre> 268 269 270 271<p class="wp-block-paragraph">The local services are:</p> 272 273 274 275<pre class="wp-block-code"><code>SearXNG: http://127.0.0.1:8080 276Ollama: http://127.0.0.1:11434 277AI search: http://0.0.0.0:5001</code></pre> 278 279 280 281<p class="wp-block-paragraph">Of course, you can also use subdomains instead of directory based; I started using directories ages ago and have too much momentum to care about changing now.</p> 282 283 284 285<p class="wp-block-paragraph">Not every search needs a summary. Sometimes you just want results. The browser hits the AI search wrapper which loads normal SearXNG results and only calls Ollama when the user requests it.</p> 286 287 288 289<h2 class="wp-block-heading">Assumptions</h2> 290 291 292 293<p class="wp-block-paragraph">This guide is based on my experience setting this up on my own rig. It should apply broadly to current Ubuntu and derivatives, possibly with some tinkering:</p> 294 295 296 297<ul class="wp-block-list"> 298<li>Ubuntu 25.10 or close enough.</li> 299 300 301 302<li>Docker Engine and Compose v2.</li> 303 304 305 306<li>Apache 2.4 as the reverse proxy (used in this doc, can be easily adapted for other RPs)</li> 307 308 309 310<li>A machine that can run Ollama locally (my machine for reference: Ryzen9 3900X, 128GiB RAM, NVIDIA 4060Ti 16GiB VRAM).</li> 311 312 313 314<li>A reverse proxy path of <code>/search/</code>.</li> 315</ul> 316 317 318 319<p class="wp-block-paragraph">The commands use <code>/opt/ai-search</code>. Change that path if you want, but donât scatter the files around. Future-you will hate present-you.</p> 320 321 322 323<h2 class="wp-block-heading">Install Docker from the Docker repository</h2> 324 325 326 327<p class="wp-block-paragraph">Ubuntuâs Docker packages and Dockerâs official packages can conflict. Pick one lane. I use Dockerâs repository here.</p> 328 329 330 331<pre class="wp-block-code"><code>sudo apt update 332sudo apt install -y ca-certificates curl gnupg apache2 333 334sudo install -m 0755 -d /etc/apt/keyrings 335sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ 336 -o /etc/apt/keyrings/docker.asc 337sudo chmod a+r /etc/apt/keyrings/docker.asc 338 339echo \ 340"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \ 341https://download.docker.com/linux/ubuntu \ 342$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ 343sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 344 345sudo apt update 346sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 347sudo systemctl enable --now docker</code></pre> 348 349 350 351<p class="wp-block-paragraph">Check it:</p> 352 353 354 355<pre class="wp-block-code"><code>sudo docker version 356docker compose version</code></pre> 357 358 359 360<h2 class="wp-block-heading">Create the project directory</h2> 361 362 363 364<pre class="wp-block-code"><code>sudo mkdir -p /opt/ai-search/{searxng,ollama} 365sudo chown -R "$USER:$USER" /opt/ai-search 366cd /opt/ai-search</code></pre> 367 368 369 370<h2 class="wp-block-heading">Docker Compose: SearXNG and Ollama</h2> 371 372 373 374<p class="wp-block-paragraph">This setup uses Docker host networking. That is deliberate.</p> 375 376 377 378<p class="wp-block-paragraph">I use a userspace VPN and systemwide TailScale on the same rig (getting my money’s worth out of a gaming machine when I’m not gaming). Docker bridge networking and Dockerâs embedded DNS can get weird and create frustrating, time wasting conflicts. Host networking removes that whole layer for this project. The tradeoff is that ports bind directly on the host, so do not run this blindly on a
378shared machine.</p> 379 380 381 382<p class="wp-block-paragraph">Create <code>/opt/ai-search/docker-compose.yml</code>:</p> 383 384 385 386<pre class="wp-block-code"><code>services: 387 searxng: 388 image: docker.io/searxng/searxng:latest 389 container_name: searxng 390 restart: unless-stopped 391 network_mode: host 392 volumes: 393 - ./searxng:/etc/searxng 394 395 ollama: 396 image: docker.io/ollama/ollama:latest 397 container_name: ollama 398 restart: unless-stopped 399 network_mode: host 400 volumes: 401 - ./ollama:/root/.ollama</code></pre> 402 403 404 405<p class="wp-block-paragraph">Start it:</p> 406 407 408 409<pre class="wp-block-code"><code>cd /opt/ai-search 410sudo docker compose up -d</code></pre> 411 412 413 414<h2 class="wp-block-heading">SearXNG settings</h2> 415 416 417 418<p class="wp-block-paragraph">Create <code>/opt/ai-search/searxng/settings.yml</code>:</p> 419 420 421 422<pre class="wp-block-code"><code>use_default_settings: true 423 424general: 425 debug: false 426 instance_name: "Search" 427 428search: 429 safe_search: 0 430 autocomplete: duckduckgo 431 default_lang: en-US 432 formats: 433 - html 434 - json 435 436server: 437 secret_key: "CHANGE_THIS_TO_A_LONG_RANDOM_VALUE" 438 base_url: http://127.0.0.1:8080/ 439 limiter: false 440 image_proxy: false 441 method: GET 442 443ui: 444 infinite_scroll: false 445 query_in_title: true 446 results_on_new_tab: true 447 448plugins: 449 searx.plugins.hostnames.SXNGPlugin: 450 active: true 451 searx.plugins.tracker_url_remover.SXNGPlugin: 452 active: true 453 searx.plugins.calculator.SXNGPlugin: 454 active: true 455 456engines: 457 - name: brave 458 disabled: true 459 - name: karmasearch 460 disabled: true 461 - name: karmasearch videos 462 disabled: true 463 - name: mojeek 464 disabled: true 465 - name: yahoo 466 disabled: true</code></pre> 467 468 469 470<p class="wp-block-paragraph">Generate a real secret key:</p> 471 472 473 474<pre class="wp-block-code"><code>python3 - <<'PY' 475import secrets 476print(secrets.token_hex(32)) 477PY</code></pre> 478 479 480 481<p class="wp-block-paragraph">Replace <code>CHANGE_THIS_TO_A_LONG_RANDOM_VALUE</code> with the generated value.</p> 482 483 484 485<p class="wp-block-paragraph">Restart SearXNG:</p> 486 487 488 489<pre class="wp-block-code"><code>cd /opt/ai-search 490sudo docker compose restart searxng 491curl -I http://127.0.0.1:8080</code></pre> 492 493 494 495<p class="wp-block-paragraph">SearXNG must have JSON enabled because the AI wrapper reads search results through <code>/search?q=...&format=json</code>.</p> 496 497 498 499<h2 class="wp-block-heading">Pull a local model with Ollama</h2> 500 501 502 503<p class="wp-block-paragraph">This uses Qwen 2.5 7B because it is small enough for normal local hardware and good enough for short search summaries.<br>f you use a</p> 504 505 506 507<pre class="wp-block-code"><code>curl http://127.0.0.1:11434/api/pull \ 508 -d '{"model":"qwen2.5:7b","stream":false}' 509 510curl http://127.0.0.1:11434/api/tags</code></pre> 511 512 513 514<p class="wp-block-paragraph">Test generation:</p> 515 516 517 518<pre class="wp-block-code"><code>curl http://127.0.0.1:11434/api/generate \ 519 -d '{"model":"qwen2.5:7b","prompt":"Reply with exactly: model working","stream":false}'</code></pre> 520 521 522 523<h2 class="wp-block-heading">Install Python dependencies</h2> 524 525 526 527<p class="wp-block-paragraph">The wrapper is a small Flask app. For the service, use Gunicorn instead of Flaskâs development server.</p> 528 529 530 531<pre class="wp-block-code"><code>sudo apt update 532sudo apt install -y python3-flask python3-requests gunicorn</code></pre> 533 534 535 536<h2 class="wp-block-heading">The AI search wrapper</h2> 537 538 539 540<p class="wp-block-paragraph">Create <code>/opt/ai-search/ai_search_app.py</code>:</p> 541 542 543 544<pre class="wp-block-code"><code>from flask import Flask, request 545import html 546import requests 547 548app = Flask(__name__) 549 550SEARX_UI = "http://127.0.0.1:8080" 551SEARX_API = "http://127.0.0.1:8080/search" 552OLLAMA_API = "http://127.0.0.1:11434/api/generate" 553MODEL = "qwen2.5:7b" 554 555STYLE = """ 556body { 557 margin: 0; 558 font-family: system-ui, sans-serif; 559 background: #111; 560 color: #eee; 561} 562.topbar { 563 padding: 12px; 564 background: #181818; 565 border-bottom: 1px solid #333; 566} 567form { 568 display: flex; 569 gap: 8px; 570} 571input[type="text"] { 572 flex: 1; 573 padding: 10px; 574 font-size: 16px; 575} 576button { 577 padding: 10px 16px; 578 font-size: 16px; 579} 580.ai-box { 581 padding: 14px; 582 margin: 12px; 583 border: 1px solid #444; 584 border-radius: 8px;
585 background: #1b1b1b; 586} 587.ai-loading { 588 opacity: 0.75; 589} 590#raw-results { 591 background: #fff; 592 color: #111; 593 padding: 12px; 594} 595#raw-results a { 596 color: #0645ad; 597} 598""" 599 600SEARX_CSS = '<link rel="stylesheet" href="/search/raw/static/themes/simple/sxng-ltr.min.css" type="text/css">' 601 602@app.route("/") 603def index(): 604 q = request.args.get("q", "").strip() 605 ai_enabled = request.args.get("ai") == "1" 606 q_html = html.escape(q) 607 checked = "checked" if ai_enabled else "" 608 609 if not q: 610 return f""" 611<html> 612<head><title>AI Search</title>{SEARX_CSS}<style>{STYLE}</style></head> 613<body> 614 <div class="topbar"> 615 <form action="/search/" method="get"> 616 <input type="text" name="q" autofocus placeholder="Search..." /> 617 <label style="display:flex;align-items:center;gap:6px"> 618 <input type="checkbox" name="ai" value="1"> 619 include AI 620 </label> 621 <button type="submit">Search</button> 622 </form> 623 </div> 624</body> 625</html> 626""" 627 628 quoted_q = requests.utils.quote(q) 629 raw_url = "/search/raw/search?q=" + quoted_q 630 631 if ai_enabled: 632 ai_block = """ 633 <div id="ai" class="ai-box ai-loading"> 634 <b>AI Answer</b><br><br> 635 Working... 636 </div> 637""" 638 ai_script = f""" 639 <script> 640 fetch("/search/answer?q=" + encodeURIComponent({q!r})) 641 .then(r => r.text()) 642 .then(t => {{ 643 document.getElementById("ai").classList.remove("ai-loading"); 644 document.getElementById("ai").innerHTML = t; 645 }}) 646 .catch(() => {{ 647 document.getElementById("ai").innerHTML = "<b>AI Answer</b><br><br>Unavailable."; 648 }}); 649 </script> 650""" 651 else: 652 ai_block = f""" 653 <div class="ai-box"> 654 <b>AI Answer</b><br><br> 655 <a style="color:#9cf" href="/search/?q={quoted_q}&ai=1">Generate AI summary</a> 656 </div> 657""" 658 ai_script = "" 659 660 return f""" 661<html> 662<head><title>{q_html} - AI Search</title>{SEARX_CSS}<style>{STYLE}</style></head> 663<body> 664 <div class="topbar"> 665 <form action="/search/" method="get"> 666 <input type="text" name="q" value="{q_html}" /> 667 <label style="display:flex;align-items:center;gap:6px"> 668 <input type="checkbox" name="ai" value="1" {checked}> 669 include AI 670 </label> 671 <button type="submit">Search</button> 672 <a style="color:#9cf;padding:10px" href="{raw_url}" target="_blank">Open raw SearXNG</a> 673 </form> 674 </div> 675 676{ai_block} 677 678 <div id="raw-results">Loading search results...</div> 679 680 <script> 681 fetch("/search/raw-html?q=" + encodeURIComponent({q!r})) 682 .then(r => r.text()) 683 .then(t => {{ 684 document.getElementById("raw-results").innerHTML = t; 685 }}) 686 .catch(() => {{ 687 document.getElementById("raw-results").innerHTML = "Search results unavailable."; 688 }}); 689 </script> 690 691{ai_script} 692</body> 693</html> 694""" 695 696@app.route("/raw-html") 697def raw_html(): 698 q = request.args.get("q", "").strip() 699 if not q: 700 return "" 701 702 r = requests.get(SEARX_UI + "/search", params={"q": q}, timeout=45) 703 r.raise_for_status() 704 page = r.text 705 706 start = page.find('<main id="main_results"') 707 if start == -1: 708 return page 709 710 end = page.rfind("</main>") 711 if end == -1: 712 return page[start:] 713 714 return page[start:end + len("</main>")] 715 716@app.route("/answer") 717def answer(): 718 q = request.args.get("q", "").strip() 719 if not q: 720 return "" 721 722 try: 723 sx = requests.get(SEARX_API, params={"q": q, "format": "json"}, timeout=30) 724 sx.raise_for_status() 725 data = sx.json() 726 727 lines = [] 728 for r in data.get("results", [])[:6]: 729 title = r.get("title", "") 730 content = r.get("content", "") 731 url = r.get("url", "") 732 if title or content: 733 lines.append(f"{title}\n{content}\n{url}") 734 735 prompt = ( 736 "User query:\n" + q +
737 "\n\nSearch results:\n" + "\n\n".join(lines) + 738 "\n\nWrite a concise answer in 3 bullet points. " 739 "Use only the provided search results. " 740 "If the results are weak or unrelated, say so." 741 ) 742 743 ol = requests.post( 744 OLLAMA_API, 745 json={"model": MODEL, "prompt": prompt, "stream": False}, 746 timeout=120, 747 ) 748 ol.raise_for_status() 749 750 text = ol.json().get("response", "").strip() 751 safe = html.escape(text).replace("\n", "<br>") 752 return "<b>AI Answer</b><br><br>" + safe 753 754 except Exception as e: 755 return "<b>AI Answer</b><br><br>Unavailable: " + html.escape(str(e)) 756 757if __name__ == "__main__": 758 app.run(host="0.0.0.0", port=5001)</code></pre> 759 760 761 762<p class="wp-block-paragraph">Two small design choices are doing a lot of work here:</p> 763 764 765 766<ul class="wp-block-list"> 767<li>The search results load first.</li> 768 769 770 771<li>AI only runs when <code>ai=1</code> is present.</li> 772</ul> 773 774 775 776<p class="wp-block-paragraph">That keeps normal searches quick.</p> 777 778 779 780<h2 class="wp-block-heading">Run it as a service</h2> 781 782 783 784<p class="wp-block-paragraph">Create <code>/etc/systemd/system/ai-search.service</code>:</p> 785 786 787 788<pre class="wp-block-code"><code>[Unit] 789Description=Local AI Search Wrapper 790After=network.target docker.service 791Wants=docker.service 792 793[Service] 794Type=simple 795User=YOUR_LOCAL_USER 796WorkingDirectory=/opt/ai-search 797ExecStart=/usr/bin/gunicorn -w 2 -b 0.0.0.0:5001 ai_search_app:app 798Restart=always 799RestartSec=3 800 801[Install] 802WantedBy=multi-user.target</code></pre> 803 804 805 806<p class="wp-block-paragraph">Set your local username:</p> 807 808 809 810<pre class="wp-block-code"><code>sudo sed -i "s/User=YOUR_LOCAL_USER/User=$USER/" /etc/systemd/system/ai-search.service 811sudo systemctl daemon-reload 812sudo systemctl enable --now ai-search.service</code></pre> 813 814 815 816<p class="wp-block-paragraph">Test locally:</p> 817 818 819 820<pre class="wp-block-code"><code>curl -I http://127.0.0.1:5001 821curl -L "http://127.0.0.1:5001/?q=linux%20firewall" | head 822curl -L "http://127.0.0.1:5001/?q=linux%20firewall&ai=1" | head</code></pre> 823 824 825 826<h2 class="wp-block-heading">Apache reverse proxy</h2> 827 828 829 830<p class="wp-block-paragraph">This example publishes the wrapper at <code>/search/</code> and raw SearXNG at <code>/search/raw/</code>.</p> 831 832 833 834<p class="wp-block-paragraph">Set the backend IP before using the config:</p> 835 836 837 838<pre class="wp-block-code"><code>AI_SEARCH_HOST="192.168.1.50"</code></pre> 839 840 841 842<p class="wp-block-paragraph">Use the actual LAN or VPN IP of the machine running the AI search service.</p> 843 844 845 846<p class="wp-block-paragraph">Put this inside your existing Apache TLS vhost:</p> 847 848 849 850<pre class="wp-block-code"><code># Local AI Search 851# Public paths: 852# /search/ -> AI wrapper 853# /search/raw/ -> raw SearXNG assets and search page 854 855RedirectMatch 308 ^/search$ /search/ 856 857ProxyPreserveHost On 858ProxyRequests Off 859 860# RAW SEARXNG MUST COME FIRST 861ProxyPass /search/raw/ http://AI_SEARCH_HOST:8080/ 862ProxyPassReverse /search/raw/ http://AI_SEARCH_HOST:8080/ 863 864# AI WRAPPER SECOND 865ProxyPass /search/ http://AI_SEARCH_HOST:5001/ 866ProxyPassReverse /search/ http://AI_SEARCH_HOST:5001/ 867 868<Location /search/raw/> 869 Require all granted 870 871 RequestHeader set X-Forwarded-Proto "https" 872 RequestHeader set X-Forwarded-Host "YOUR_DOMAIN" 873 RequestHeader set X-Forwarded-Prefix "/search/raw" 874 RequestHeader set X-Scheme "https" 875 RequestHeader set X-Script-Name "/search/raw" 876 877 RequestHeader set X-Real-IP %{REMOTE_ADDR}s 878 RequestHeader append X-Forwarded-For %{REMOTE_ADDR}s 879</Location> 880 881<Location /search/> 882 Require all granted 883 884 RequestHeader set X-Forwarded-Proto "https" 885 RequestHeader set X-Forwarded-Host "YOUR_DOMAIN" 886 RequestHeader set X-Forwarded-Prefix "/search" 887 RequestHeader set X-Scheme "https" 888 RequestHeader set X-Script-Name "/search" 889 890 RequestHeader set X-Real-IP %{REMOTE_ADDR}s 891 RequestHeader append X-Forwarded-For %{REMOTE_ADDR}s 892 893 SetEnvIf Request_URI "^/search/" dontlog 894</Location></code></pre> 895 896 897 898<p class="wp-block-paragraph">Replace <code>AI_SEARCH_HOST</code> and <code>YOUR_DOMAIN</code> before reloading Apache.</p> 899 900 901 902<p class="wp-block-paragraph">The order matters. <code>/search/raw/</code> must come before <code>/search/</code>, or Apache will send raw SearXNG requests to the wrapper.</p> 903 904 905 906<p class="wp-block-paragraph">Enable modules and reload:</p> 907 908 909 910<pre class="wp-block-code"><code>sudo a2enmod proxy proxy_http headers rewrite ssl 911sudo apache2ctl configtest 912sudo systemctl reload apache2</code></pre> 913 914 915 916<h2 class="wp-block-heading">Test the final page</h2> 917 918 919 920<p class="wp-block-paragraph">Open:</p> 921 922 923 924<pre class="wp-block-code"><code>https://YOUR_DOMAIN/search/</code></pre> 925 926 927 928<p class="wp-block-paragraph">Search normally. Results should load without calling the model.</p> 929 930 931 932<p class="wp-block-paragraph">Then check <code>include AI</code> and search again. Results should still load first, and the AI answer should appear after a few seconds.</p> 933 934 935 936<h2 class="wp-block-heading">Notes from the build</h2> 937 938 939 940<p class="wp-block-paragraph">Do not start by hacking SearXNG plugins. That sounds cleaner than
940it is. The current SearXNG plugin system expects proper importable Python modules and fully qualified plugin class names. A wrapper avoids tying your project to SearXNG internals.</p> 941 942 943 944<p class="wp-block-paragraph">Do not put <code>127.0.0.1</code> URLs in HTML that will be loaded by another machine. The userâs browser interprets <code>127.0.0.1</code> as the userâs own computer, not your server. Use public paths like <code>/search/raw/search?...</code> and let Apache proxy them.</p> 945 946 947 948<p class="wp-block-paragraph">Do not run AI on every query unless you really want the latency (or you’re keeping warm in winter).</p> 949 950 951 952<p class="wp-block-paragraph">If you use a VPN and Docker networking explodes, try host networking for this stack. It is blunt, but it avoids a lot of route and DNS drama.</p> 953 954 955 956<h2 class="wp-block-heading">Useful references</h2> 957 958 959 960<ul class="wp-block-list"> 961<li>SearXNG Search API: https://docs.searxng.org/dev/search_api.html</li> 962 963 964 965<li>SearXNG JSON formats need to be enabled in <code>settings.yml</code>: https://docs.searxng.org/dev/search_api.html</li> 966 967 968 969<li>Ollama generate API: https://ollama.readthedocs.io/en/api/</li> 970 971 972 973<li>Ollama pull API: https://docs.ollama.com/api/pull</li> 974 975 976 977<li>Docker host networking: https://docs.docker.com/engine/network/drivers/host/</li> 978 979 980 981<li>Apache reverse proxy guide: https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html</li> 982 983 984 985<li>Apache mod_proxy docs: https://httpd.apache.org/docs/current/mod/mod_proxy.html</li> 986</ul> 987</div> 988 <div style="margin-top:var(--wp--preset--spacing--40)" class="wp-block-post-date has-small-font-size"><a href="https://ko4bep.net/blog/index.php/2026/04/27/building-a-local-ai-search-page-with-searxng-and-ollama/"><time datetime="2026-04-27T18:53:02+00:00">April 27, 2026</time></a></div> 989 </div> 990 991 </li><li class="wp-block-post post-10 post type-post status-publish format-standard hentry category-uncategorized tag-docker tag-it tag-rants tag-security"> 992 993 <div class="wp-block-group alignfull has-global-padding is-layout-constrained wp-block-group-is-layout-constrained" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--60)"> 994 995 <h2 class="wp-block-post-title has-x-large-font-size"><a href="https://ko4bep.net/blog/index.php/2025/11/22/why-docker-is-a-pain-in-the-ass/" target="_self" >Why Docker Is a Pain-in-the-Ass</a></h2> 996 <div class="entry-content alignfull wp-block-post-content has-medium-font-size has-global-padding is-layout-constrained wp-block-post-content-is-layout-constrained"> 997<h2 class="wp-block-heading">(And Why Youâre Totally Right to Hate It)</h2> 998 999 1000 1001<p class="wp-block-paragraph">If youâre dealing with containers and still have a shred of sanity, hereâs the brutal truth: Docker is less of a magical âsafe sandboxâ and more of a <strong>convenience-bait with a liability tag</strong>. Letâs tear down the hype and get real about what this thing really brings â so you (and your users) can make an informed decision instead of blindly following the âcontainerize everythingâ evangelists.</p> 1002 1003 1004 1005<hr class="wp-block-separator has-alpha-channel-opacity"/> 1006 1007 1008 1009<h2 class="wp-block-heading">1. The Broken Promise of âIsolationâ</h2> 1010 1011 1012 1013<p class="wp-block-paragraph">Docker likes to sell containers like theyâre neat little self-contained sandboxes. Reality? They share the host kernel.<br>For instance: the âLeaky Vesselsâ vulnerabilities demonstrate how a container could break out and compromise the host. :contentReference[oaicite:1]{index=1}<br>One recent critical bug, CVE-2025-9074 (CVSS 9.3), allowed a container on Docker Desktop to access the Engine API and launch new containersâ<em>without requiring the Docker socket to be mounted</em>. Thatâs full host compromise by design failure. :contentReference[oaicite:2]{index=2}<br>If youâre relying on âcontainers = safeâ youâre working on sand.</p> 1014 1015 1016 1017<hr class="wp-block-separator has-alpha-channel-opacity"/> 1018 1019 1020 1021<h2 class="wp-block-heading">2. Defaults Built for Convenience, Not Security</h2> 1022 1023 1024 1025<p class="wp-block-paragraph">
1025Running as root inside the container? Host volumes mounted indiscriminately? Docker socket (<code>/var/run/docker.sock</code>) handed to untrusted containers? These are not fringe casesâtheyâre default modes of operation for many users.<br>When you deploy tools for novice-to-intermediate users, deploying them inside Docker <em>without</em> being explicit about this is asking for trouble.<br>Simply put: if you skip the hardening, you inherited a risk.<br>See the âAttackerâs Tactics and Techniques in Unsecured Docker Daemonsâ paper: unsecured daemons = bad times. :contentReference[oaicite:3]{index=3}</p> 1026 1027 1028 1029<hr class="wp-block-separator has-alpha-channel-opacity"/> 1030 1031 1032 1033<h2 class="wp-block-heading">3. The API That Acts Like Itâs Open Season</h2> 1034 1035 1036 1037<p class="wp-block-paragraph">One of Dockerâs biggest sins: remote Docker API (especially on port 2375) exposed without authentication. Attackers have used this to spin up containers, mount host directories, drop cryptominers.<br>A new campaign cited by Akamai (Aug/2025) shows this in action: malicious containers created via exposed API, mounting host filesystem at will. :contentReference[oaicite:5]{index=5}<br>If your deployment gives users âpull-run-goâ with no API audit, youâre handing them an open door with a welcome mat.</p> 1038 1039 1040 1041<hr class="wp-block-separator has-alpha-channel-opacity"/> 1042 1043 1044 1045<h2 class="wp-block-heading">4. The Supply-Chain Sucker-Punch</h2> 1046 1047 1048 1049<p class="wp-block-paragraph">You pull an image from Docker Hub and think âcool, containerized, done.â Wrong.<br>A study on base-image vulnerabilities found that many images inherit flawed foundations: âWell Begun is Half Done: An Empirical Study of Exploitability & Impact of Base-Image Vulnerabilitiesâ. :contentReference[oaicite:6]{index=6}<br>Even worse: âgh0stEditâ research shows you can tamper with a signed image without invalidating the signatureâundetected malicious layers. :contentReference[oaicite:7]{index=7}<br>âTrust but verifyâ should be your mantra. With Docker, you might not even be getting that.</p> 1050 1051 1052 1053<hr class="wp-block-separator has-alpha-channel-opacity"/> 1054 1055 1056 1057<h2 class="wp-block-heading">5. Bloat & Time-Bomb of Maintenance</h2> 1058 1059 1060 1061<p class="wp-block-paragraph">Because many Dockerfiles are written for speed and convenience (just throw everything in), images inflate in size, dependencies pile up, attack surface grows.<br>If youâre building a security tool, you donât want a 1 GB monster image filled with unnecessary libs-and-bins. One paper categorised bad base image practices as major exploit enablers. :contentReference[oaicite:8]{index=8}<br>Also: more tooling = more attack surface (engine, desktop, compose, orchestrator). If you arenât vigilant, you inherit the overhead.</p> 1062 1063 1064 1065<hr class="wp-block-separator has-alpha-channel-opacity"/> 1066 1067 1068 1069<h2 class="wp-block-heading">6. Vulnerabilities Keep Piling Up</h2> 1070 1071 1072 1073<p class="wp-block-paragraph">Containers are not invulnerable. They carry their own risks.<br>Dockerâs own security advisory shows a string of critical vulnerabilities: e.g., CVE-2025-9074 (Docker Desktop host compromise), CVE-2025-9164 (DLL hijack in installer) ⦠:contentReference[oaicite:9]{index=9}<br>And the runtime level: new runC vulnerabilities allow container escape toward host via symlink or race conditions. :contentReference[oaicite:10]{index=10}<br>When your stack says âcontainers = safe by defaultâ â misleading is a nice word.</p> 1074 1075 1076 1077<hr class="wp-block-separator has-alpha-channel-opacity"/> 1078 1079 1080 1081<h2 class="wp-block-heading">7. Shared Kernel + Lazy Admins = Disaster Potential</h2> 1082 1083 1084 1085<p class="wp-block-paragraph">The fundamental architectural issue: containers share the host OS kernel. A host-kernel exploit or privileged container â host takeover.<br>From French Wikipedia (yay) on Docker security:</p> 1086 1087 1088 1089<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"> 1090<p class="wp-block-paragraph">âLes conteneurs Linux nâont pas été conçus comme un mécanisme de sécurité permettant dâisoler les conteneurs non fiables ⦠un exploit donnant des privilèges root complets à un conteneur peut permettre à un attaquant de percer ce conteneur et de compromettre lâhôte.â :contentReference[oaicite:11]{index=11}<br>If your user base isnât firmly disciplined, youâre basically trusting that âeverything goes rightâ instead of designing for âwhat happens when someone screws upâ.</p> 1091</blockquote> 1092 1093 1094 1095<hr class="wp-block-separator has-alpha-channel-opacity"/> 1096 1097 1098 1099<h2 class="wp-block-heading">8. Real Incidents: People <em>Got Hurt</em></h2> 1100 1101 1102 1103<ul class="wp-block-list"> 1104<li>A campaign by Akamai (Sep 2025) targeted exposed Docker APIs and installed cryptominers/backdoors. :contentReference[oaicite:12]{index=12}</li> 1105 1106 1107 1108<li>Another research (Datadog, Jun 2024) observed containers spun on exposed Docker daemons for cryptojacking. :contentReference[oaicite:13]{index=13}</li> 1109 1110 1111 1112<li>
1112Older but relevant: Trend Micro (2019) found images on Docker Hub used for mining via exposed APIs. :contentReference[oaicite:14]{index=14}<br>These arenât âmaybe could happenâ â they did happen. Your users should know that.</li> 1113</ul> 1114 1115 1116 1117<hr class="wp-block-separator has-alpha-channel-opacity"/> 1118 1119 1120 1121<h2 class="wp-block-heading">9. Tooling Complexity Hides Risk, Not Reduces It</h2> 1122 1123 1124 1125<p class="wp-block-paragraph">Using Docker often means: engine, desktop GUI, CLI, compose files, registries, networks, volumes, metadata. Each layer invites misconfiguration.<br>If you target novice-to-intermediate users and deploy via Docker without providing <em>explicit training</em> or guardrails, youâre stacking the odds toward error.<br>Again: convenience â safety.</p> 1126 1127 1128 1129<hr class="wp-block-separator has-alpha-channel-opacity"/> 1130 1131 1132 1133<h2 class="wp-block-heading">10. The âEasyâ Narrative Is Misleading</h2> 1134 1135 1136 1137<p class="wp-block-paragraph">Marketing says: âBuild once, run anywhere, container magicâ. Reality:<br>You still need to secure the daemon, lock down APIs, verify images, limit capabilities, monitor runtime, isolate networks, patch base images.<br>When you skip these, your âsafe containerâ becomes your weakest link.</p> 1138 1139 1140 1141<hr class="wp-block-separator has-alpha-channel-opacity"/> 1142 1143 1144 1145<h2 class="wp-block-heading">Final Word</h2> 1146 1147 1148 1149<p class="wp-block-paragraph">Docker: convenience-bait with a hidden price-tag.<br>Isolation? weaker than you think.<br>Defaults? optimized for âworks fastâ, not âsecures tightâ.<br>Image ecosystem? messy.<br>Infrastructure burden? real.<br>If youâre sharing applications with the world, </p> 1150 1151 1152 1153<hr class="wp-block-separator has-alpha-channel-opacity"/> 1154 1155 1156 1157<h2 class="wp-block-heading">References</h2> 1158 1159 1160 1161<ol class="wp-block-list"> 1162<li>Docker Desktop 4.44.3: Important Container Escape Vuln. LinuxSecurity. (Aug 26 2025). <a href="https://linuxsecurity.com/news/security-vulnerabilities/docker-desktop-4-44-3-security-update">https://linuxsecurity.com/news/security-vulnerabilities/docker-desktop-4-44-3-security-update</a> :contentReference[oaicite:15]{index=15}</li> 1163 1164 1165 1166<li>Off Your Docker: Exposed APIs Are Targeted in New Malware Strain. Akamai Hunt Team. (Sep 8 2025). <a href="https://www.akamai.com/blog/security-research/new-malware-targeting-docker-apis-akamai-hunt">https://www.akamai.com/blog/security-research/new-malware-targeting-docker-apis-akamai-hunt</a> :contentReference[oaicite:16]{index=16}</li> 1167 1168 1169 1170<li>Docker Fixes CVE-2025-9074, Critical Container Escape Vulnerability (CVSS 9.3). The Hacker News. (Aug 25 2025). <a href="https://thehackernews.com/2025/08/docker-fixes-cve-2025-9074-critical.html">https://thehackernews.com/2025/08/docker-fixes-cve-2025-9074-critical.html</a> :contentReference[oaicite:17]{index=17}</li> 1171 1172 1173 1174<li>Attackers deploying new tactics in campaign targeting exposed Docker APIs. Datadog Security Labs. (Jun 13 2024). <a href="https://securitylabs.datadoghq.com/articles/attackers-deploying-new-tactics-in-campaign-targeting-exposed-docker-apis/">https://securitylabs.datadoghq.com/articles/attackers-deploying-new-tactics-in-campaign-targeting-exposed-docker-apis/</a> :contentReference[oaicite:18]{index=18}</li> 1175 1176 1177 1178<li>Container Escape: New Vulnerabilities Affecting Docker. Palo-Alto Networks blog. (Feb 5 2024). <a href="https://www.paloaltonetworks.com/blog/cloud-security/leaky-vessels-vulnerabilities-container-escape/">https://www.paloaltonetworks.com/blog/cloud-security/leaky-vessels-vulnerabilities-container-escape/</a> :contentReference[oaicite:19]{index=19}</li> 1179 1180 1181 1182<li>Infected Containers Target Docker via Exposed APIs. Trend Micro. (May 30 2019). <a href="https://www.trendmicro.com/en_us/research/19/e/infected-cryptocurrency-mining-containers-target-docker-hosts-with-exposed-apis-use-shodan-to-find-additional-victims.html">https://www.trendmicro.com/en_us/research/19/e/infected-cryptocurrency-mining-containers-target-docker-hosts-with-exposed-apis-use-shodan-to-find-additional-victims.html</a> :contentReference[oaicite:20]{index=20}</li> 1183 1184 1185 1186<li>Well Begun Is Half Done: An Empirical Study of Exploitability & Impact of Base-Image Vulnerabilities. Ul Haque et al. (Dec 21 2021). <a href="https://arxiv.org/abs/2112.12597">https://arxiv.org/abs/2112.12597</a> :contentReference[oaicite:21]{index=21}</li> 1187 1188 1189 1190<li>gh0stEdit: Exploiting Layer-Based Access Vulnerability Within Docker Container Images. Mills et al. (Jun 9 2025). <a href="https://arxiv.org/abs/2506.08218">https://arxiv.org/abs/2506.08218</a> :contentReference[oaicite:22]{index=22}</li> 1191 1192 1193 1194<li>Docker security announcements. Docker official docs. <a href="https://docs.docker.com/security/security-announcements/">https://docs.docker.com/security/security-announcements/</a> :contentReference[oaicite:23]{index=23}</li> 1195 1196 1197 1198<li>New runC Vulnerabilities Expose Docker and Kubernetes to Container Escape Attacks. ORCA/orca.security blog. (Nov 10 2025). <a href="https://orca.security/resources/blog/new-runc-vulnerabilities-allow-container-escape/">
1198https://orca.security/resources/blog/new-runc-vulnerabilities-allow-container-escape/</a> :contentReference[oaicite:24]{index=24}</li> 1199 1200 1201 1202<li>Vulnerable Docker Installations: Malware Attack Playground. Uptycs Threat Research. (May 2 2022). <a href="https://www.uptycs.com/blog/threat-research-report-team/vulnerable-docker-installations-are-a-playhouse-for-malware-attacks">https://www.uptycs.com/blog/threat-research-report-team/vulnerable-docker-installations-are-a-playhouse-for-malware-attacks</a> :contentReference[oaicite:25]{index=25}</li> 1203 1204 1205 1206<li>Attackerâs Tactics and Techniques in Unsecured Docker Daemons Revealed. Unit 42, Palo Alto Networks. (Jan 29 2020). <a href="https://unit42.paloaltonetworks.com/attackers-tactics-and-techniques-in-unsecured-docker-daemons-revealed/">https://unit42.paloaltonetworks.com/attackers-tactics-and-techniques-in-unsecured-docker-daemons-revealed/</a> :contentReference[oaicite:26]{index=26}</li> 1207</ol> 1208</div> 1209 <div style="margin-top:var(--wp--preset--spacing--40)" class="wp-block-post-date has-small-font-size"><a href="https://ko4bep.net/blog/index.php/2025/11/22/why-docker-is-a-pain-in-the-ass/"><time datetime="2025-11-22T16:16:02+00:00">November 22, 2025</time></a></div> 1210 </div> 1211 1212 </li></ul> 1213 1214 <div class="wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--60)"> 1215 1216 </div> 1217 1218 1219 <div class="wp-block-group alignwide has-global-padding is-layout-constrained wp-block-group-is-layout-constrained"> 1220 1221 </div> 1222 1223</div> 1224 1225 1226</main> 1227 1228 1229<footer class="wp-block-template-part"> 1230<div class="wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained" style="padding-top:var(--wp--preset--spacing--60);padding-bottom:var(--wp--preset--spacing--50)"> 1231 1232 <div class="wp-block-group alignwide is-layout-flow wp-block-group-is-layout-flow"> 1233 1234 1235 1236 <div class="wp-block-group alignfull is-content-justification-space-between is-layout-flex wp-container-core-group-is-layout-cf54d0a6 wp-block-group-is-layout-flex"> 1237 1238 <div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-794e3cfa wp-block-columns-is-layout-flex"> 1239 1240 <div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%"><h2 class="wp-block-site-title"><a href="https://ko4bep.net/blog" target="_self" rel="home" aria-current="page">KO4BEP :: Blog</a></h2> 1241 1242 <p class="wp-block-site-tagline">nonsense.</p> 1243 </div> 1244 1245 1246 1247 <div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"> 1248 1249 <div style="height:var(--wp--preset--spacing--40);width:0px" aria-hidden="true" class="wp-block-spacer"></div> 1250 1251 </div> 1252 1253 </div> 1254 1255 1256 1257 <div class="wp-block-group is-content-justification-space-between is-layout-flex wp-container-core-group-is-layout-bf19e0b3 wp-block-group-is-layout-flex"> 1258 <nav class="is-vertical wp-block-navigation is-layout-flex wp-container-core-navigation-is-layout-831b2db5 wp-block-navigation-is-layout-flex" aria-label=" 2"><ul class="wp-block-navigation__container is-vertical wp-block-navigation"><li class="wp-block-navigation-item wp-block-navigation-link"><a class="wp-block-navigation-item__content" href="#"><span class="wp-block-navigation-item__label">Blog</span></a></li><li class="wp-block-navigation-item wp-block-navigation-link"><a class="wp-block-navigation-item__content" href="#"><span class="wp-block-navigation-item__label">About</span></a></li><li class="wp-block-navigation-item wp-block-navigation-link"><a class="wp-block-navigation-item__content" href="#"><span class="wp-block-navigation-item__label">FAQs</span></a></li><li class="wp-block-navigation-item wp-block-navigation-link"><a class="wp-block-navigation-item__content" href="#"><span class="wp-block-navigation-item__label">Authors</span></a></li></ul></nav> 1259 1260 <nav class="is-vertical wp-block-navigation is-layout-flex wp-container-core-navigation-is-layout-831b2db5 wp-block-navigation-is-layout-flex" aria-label=" 3"><ul class="wp-block-navigation__container is-vertical wp-block-navigation"><li class="wp-block-navigation-item wp-block-navigation-link"><a class="wp-block-navigation-item__content" href="#"><span class="wp-block-navigation-item__label">Events</span></a></li><li class="wp-block-navigation-item wp-block-navigation-link"><a class="wp-block-navigation-item__content" href="#"><span class="wp-block-navigation-item__label">Shop</span></a></li><li class="wp-block-navigation-item wp-block-navigation-link"><a class="wp-block-navigation-item__content" href="#"><span class="wp-block-navigation-item__label">Patterns</span></a></li><li class="wp-block-navigation-item wp-block-navigation-link"><a class="wp-block-navigation-item__content" href="#"><span class="wp-block-navigation-item__label">Themes</span></a></li></ul></nav> 1261 </div> 1262 1263 </div> 1264 1265 1266 1267 <div style="height:var(--wp--preset--spacing--70)" aria-hidden="true" class="wp-block-spacer"></div> 1268 1269 1270 1271 <div class="wp-block-group alignfull is-content-justification-space-between is-layout-flex wp-container-core-group-is-layout-2ab8c7fb wp-block-group-is-layout-flex"> 1272 1273 <p class="has-small-font-size wp-block-paragraph">Twenty Twenty-Five</p> 1274 1275 1276 <p class="has-small-font-size wp-block-paragraph"> 1277 Designed with <a href="https://wordpress.org" rel="nofollow">WordPress</a> </p> 1278 1279 </div> 1280 1281 </div> 1282 1283</div> 1284 1285 1286</footer> 1287</div>
1288<script type="speculationrules"> 1289{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/blog/*"},{"not":{"href_matches":["/blog/wp-*.php","/blog/wp-admin/*","/blog/wp-content/uploads/*","/blog/wp-content/*","/blog/wp-content/plugins/*","/blog/wp-content/themes/twentytwentyfive/*","/blog/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]} 1290</script>
vendor: 1 bytes, line 1290
1290
1291<script data-wp-router-options="{"loadOnClientNavigation":true}" fetchpriority="low" id="@wordpress/block-library/navigation/view-js-module" src="https://ko4bep.net/blog/wp-includes/js/dist/script-modules/block-library/navigation/view.min.js?ver=1bf28ded04f9f188bdcb" type="module"></script>
vendor: 1 bytes, line 1291
1291
1292<script id="wp-emoji-settings" type="application/json"> 1293{"baseUrl":"https://s.w.org/images/core/emoji/17.0.2/72x72/","ext":".png","svgUrl":"https://s.w.org/images/core/emoji/17.0.2/svg/","svgExt":".svg","source":{"concatemoji":"https://ko4bep.net/blog/wp-includes/js/wp-emoji-release.min.js?ver=7.1"}} 1294</script>
vendor: 1 bytes, line 1294
1294
1295<script type="module"> 1296/*! This file is auto-generated */ 1297var e="script#wp-emoji-settings",t=document.querySelector(e);if(!(t instanceof HTMLScriptElement))throw new Error("Element missing: "+e);const r=JSON.parse(t.text),s=(window._wpemojiSettings=r,"wpEmojiSettingsSupports"),o=["flag","emoji"];function i(e){try{var t={supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(s,JSON.stringify(t))}catch(e){}}function c(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);t=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0);const r=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);return t.every((e,t)=>e===r[t])}function p(e,t){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var n=e.getImageData(16,16,1,1);for(let e=0;e<n.data.length;e++)if(0!==n.data[e])return!1;return!0}function u(e,t,n,r){switch(t){case"flag":return n(e,"\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f","\ud83c\udff3\ufe0f\u200b\u26a7\ufe0f")?!1:!n(e,"\ud83c\udde8\ud83c\uddf6","\ud83c\udde8\u200b\ud83c\uddf6")&&!n(e,"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f","\ud83c\udff4\u200b\udb40\udc67\u200b\udb40\udc62\u200b\udb40\udc65\u200b\udb40\udc6e\u200b\udb40\udc67\u200b\udb40\udc7f");case"emoji":return!r(e,"\ud83e\u1fac8")}return!1}function f(e,t,n,r){let a;const s=(a="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):document.createElement("canvas")).getContext("2d",{willReadFrequently:!0}),o=(s.textBaseline="top",s.font="600 32px Arial",{});return e.forEach(e=>{o[e]=t(s,e,n,r)}),o}function a(e){var t=document.createElement("script");t.src=e,t.defer=!0,document.head.appendChild(t)}r.supports={everything:!0,everythingExceptFlag:!0},new Promise(t=>{let n=function(){try{var e=JSON.parse(sessionStorage.getItem(s));if("object"==typeof e&&"number"==typeof e.timestamp&&(new Date).valueOf()<e.timestamp+604800&&"object"==typeof e.supportTests)return e.supportTests}catch(e){}return null}();if(!n){if("undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas&&"undefined"!=typeof URL&&URL.createObjectURL&&"undefined"!=typeof Blob)try{var e="postMessage("+f.toString()+"("+[JSON.stringify(o),u.toString(),c.toString(),p.toString()].join(",")+"));",r=new Blob([e],{type:"text/javascript"});const a=new Worker(URL.createObjectURL(r),{name:"wpTestEmojiSupports"});return void(a.onmessage=e=>{i(n=e.data),a.terminate(),t(n)})}catch(e){}i(n=f(o,u,c,p))}t(n)}).then(e=>{for(const n in e)r.supports[n]=e[n],r.supports.everything=r.supports.everything&&r.supports[n],"flag"!==n&&(r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&&r.supports[n]);var t;r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&&!r.supports.flag,r.supports.everything||((t=r.source||{}).concatemoji?a(t.concatemoji):t.wpemoji&&t.twemoji&&(a(t.twemoji),a(t.wpemoji)))}); 1298//# sourceURL=https://ko4bep.net/blog/wp-includes/js/wp-emoji-loader.min.js 1299</script>
1299 1300</body> 1301</html> 1302 1303<!-- Dynamic page generated in 0.174 seconds. --> 1304<!-- Cached page generated by WP-Super-Cache on 2026-10-07 14:24:12 --> 1305 1306<!-- super cache -->
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.