Goodbye, Twitter

Signed-off-by: David Young <davidy@funkypenguin.co.nz>
This commit is contained in:
David Young committed 2022-11-21 11:20:07 +13:00
1 parent 791c30a294
commit 5177cc01cb
4 files changed
+3 -533

No files matched your search

+2 -2
View File
@@ -64,7 +64,7 @@ I want your [support][github_sponsor], either in the [financial][github_sponsor]
### Get in touch 👋 ### Get in touch 👋
- Come and say hi to me and the friendly geeks in the [Discord][discord] chat or the [Discourse][discourse] forums - say hi, ask a question, or suggest a new recipe! - Come and say hi to me and the friendly geeks in the [Discord][discord] chat or the [Discourse][discourse] forums - say hi, ask a question, or suggest a new recipe!
- Tweet me up, I'm [@funkypenguin][twitter]! 🐦 - Toot me up, I'm [@funkypenguin][mastodon]! 🐦
- [Contact me][contact] by a variety of channels - [Contact me][contact] by a variety of channels
### [Sponsor][github_sponsor] / [Patronize][patreon] me ❤️ ### [Sponsor][github_sponsor] / [Patronize][patreon] me ❤️
@@ -92,5 +92,5 @@ Impulsively **[click here (NOW quick do it!)][github_sponsor]** to [sponsor me][
[patreon]: https://www.patreon.com/bePatron?u=6982506 [patreon]: https://www.patreon.com/bePatron?u=6982506
[github_sponsor]: https://github.com/sponsors/funkypenguin [github_sponsor]: https://github.com/sponsors/funkypenguin
[discourse]: https://forum.funkypenguin.co.nz/ [discourse]: https://forum.funkypenguin.co.nz/
[twitter]: https://twitter.com/funkypenguin
[contact]: https://www.funkypenguin.co.nz [contact]: https://www.funkypenguin.co.nz
[mastodon]: https://so.fnky.nz/@funkypenguin
+1 -1
View File
@@ -98,7 +98,7 @@ I want your [support](https://github.com/sponsors/funkypenguin), either in the [
#### Get in touch 💬 #### Get in touch 💬
- Come and say hi to me and the friendly geeks in the [Discord](http://chat.funkypenguin.co.nz) chat or the [Discourse](https://forum.funkypenguin.co.nz/) forums - say hi, ask a question, or suggest a new recipe! - Come and say hi to me and the friendly geeks in the [Discord](http://chat.funkypenguin.co.nz) chat or the [Discourse](https://forum.funkypenguin.co.nz/) forums - say hi, ask a question, or suggest a new recipe!
- Tweet me up, I'm [@funkypenguin](https://twitter.com/funkypenguin)! 🐦 - Toot me up, I'm [@funkypenguin](https://so.fnky.nz/@funkypengui)! 🐘
- [Contact me](https://www.funkypenguin.co.nz/contact/) by a variety of channels - [Contact me](https://www.funkypenguin.co.nz/contact/) by a variety of channels
#### [Sponsor](https://github.com/sponsors/funkypenguin) me ❤️ #### [Sponsor](https://github.com/sponsors/funkypenguin) me ❤️
-2
View File
@@ -367,8 +367,6 @@ extra:
link: 'https://so.fnky.nz/@funkypenguin' link: 'https://so.fnky.nz/@funkypenguin'
- icon: 'fontawesome/brands/github' - icon: 'fontawesome/brands/github'
link: 'https://github.com/funkypenguin' link: 'https://github.com/funkypenguin'
- icon: 'fontawesome/brands/twitter'
link: 'https://twitter.com/funkypenguin'
- icon: 'fontawesome/brands/stack-overflow' - icon: 'fontawesome/brands/stack-overflow'
link: 'https://stackoverflow.com/cv/funkypenguin' link: 'https://stackoverflow.com/cv/funkypenguin'
- icon: 'material/rss' - icon: 'material/rss'
-528
View File
@@ -1,528 +0,0 @@
<html><head><meta charset="utf-8"/><meta content="width=device-width,initial-scale=1" name="viewport"/><meta content="My collection of how-to guides and tutorials for establishing your own container-based awesome selfhosted platform, using either Docker or Kubernetes." name="description"/><meta content="David Young" name="author"/><link href="https://geek-cookbook.funkypenguin.co.nz/" rel="canonical"/><link href="file:///Users/davidy/Documents/Personal/Projects/geek-cookbook/site/images/site-logo.svg" rel="icon"/><meta content="mkdocs-1.3.0, mkdocs-material-8.3.9" name="generator"/><title>How I do "awesome selfhosted" |・∀・</title><link href="file:///Users/davidy/Documents/Personal/Projects/geek-cookbook/site/assets/stylesheets/main.1d29e8d0.min.css" rel="stylesheet"/><link href="file:///Users/davidy/Documents/Personal/Projects/geek-cookbook/site/assets/stylesheets/palette.cbb835fc.min.css" rel="stylesheet"/><script>__md_scope=new URL(".",location),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script><!-- <script src="https://cdn.jsdelivr.net/npm/@widgetbot/crate@3" async defer></script> --><script src="/js/i-am-groot.js"></script><script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script><!-- RightMessage --><script type="text/javascript">
(function(p, a, n, d, o, b, c) {
o = n.createElement('script'); o.type = 'text/javascript'; o.async = true; o.src = 'https://tb.rightmessage.com/'+p+'.js';
b = n.getElementsByTagName('script')[0]; d = function(h, u, i) { var c = n.createElement('style'); c.id = 'rmcloak'+i;
c.type = 'text/css'; c.appendChild(n.createTextNode('.rmcloak'+h+'{visibility:hidden}.rmcloak'+u+'{display:none}'));
b.parentNode.insertBefore(c, b); return c; }; c = d('', '-hidden', ''); d('-stay-invisible', '-stay-hidden', '-stay');
setTimeout(o.onerror = function() { c.parentNode && c.parentNode.removeChild(c); }, a); b.parentNode.insertBefore(o, b);
})('1802694484', 20000, document);
</script><link href="file:///Users/davidy/Documents/Personal/Projects/geek-cookbook/site/assets/stylesheets/extra-style.w7lhf_wh.min.css" rel="stylesheet"/><style>@charset "UTF-8";
:root {
string-set: author 'David Young', copyright 'Copyright © 2016 - 2021 David Young, Funky Penguin Limited', title 'Funky Penguin\27s Geek Cookbook'; }
h1, h2, h3 {
string-set: chapter content(); }
@page {
size: a4 portrait;
margin: 25mm 10mm 25mm 10mm;
counter-increment: page;
white-space: pre;
color: grey;
@top-right {
font-size: 7pt;
content: string(chapter); }
@bottom-center {
font-size: 8pt;
content: "- " counter(page) "/" counter(pages) " -"; }
@bottom-right {
font-size: 6pt;
content: string(copyright); } }
@media print {
body {
background: none;
background-color: #fff; } }
article,
section + section {
page-break-before: always;
min-height: 100vh;
/* Defining all page breaks */ }
article,
article h1,
article h2,
article h3,
article h4,
article h5,
article h6,
article div.tabbed-content--wrap > .tabbed-content,
section + section,
section + section h1,
section + section h2,
section + section h3,
section + section h4,
section + section h5,
section + section h6,
section + section div.tabbed-content--wrap > .tabbed-content {
clear: both; }
article h1,
article h2,
article h3,
article h4,
article h5,
article h6,
article img,
section + section h1,
section + section h2,
section + section h3,
section + section h4,
section + section h5,
section + section h6,
section + section img {
page-break-after: avoid;
page-break-inside: avoid; }
article a,
article blockquote,
article table,
article ul,
article ol,
section + section a,
section + section blockquote,
section + section table,
section + section ul,
section + section ol {
page-break-before: avoid;
page-break-inside: avoid; }
article pre,
article dt + dd,
section + section pre,
section + section dt + dd {
page-break-before: avoid; }
article h1 + ul,
article h2 + ul,
article h3 + ul,
article h4 + ul,
article h5 + ul,
article h6 + ul,
article h1 + ol,
article h2 + ol,
article h3 + ol,
article h4 + ol,
article h5 + ol,
article h6 + ol,
section + section h1 + ul,
section + section h2 + ul,
section + section h3 + ul,
section + section h4 + ul,
section + section h5 + ul,
section + section h6 + ul,
section + section h1 + ol,
section + section h2 + ol,
section + section h3 + ol,
section + section h4 + ol,
section + section h5 + ol,
section + section h6 + ol {
page-break-inside: auto; }
article div.admonition,
section + section div.admonition {
page-break-inside: avoid; }
article div.tabbed-content--wrap,
section + section div.tabbed-content--wrap {
page-break-inside: avoid; }
article * + div.highlight,
article * + div.tabbed-set,
section + section * + div.highlight,
section + section * + div.tabbed-set {
page-break-before: avoid; }
section.two-columns {
columns: 2;
column-gap: 1cm; }
article h1 {
border-bottom: 2px solid #f00; }
article h2 {
border-bottom: 1px solid #f99; }
article h3 {
border-bottom: 0.5px solid #eee; }
article h1 > .pdf-order,
article h2 > .pdf-order,
article h3 > .pdf-order {
padding-left: 6px; }
article#doc-toc {
margin: 0 .8rem 1.2rem;
padding-top: .6rem;
font-size: 12pt;
line-height: 1.6; }
article#doc-toc > h1 {
margin: 0 0 2rem;
color: rgba(0, 0, 0, 0.54);
font-size: 1.2rem;
font-weight: 300;
letter-spacing: -.01em;
page-break-after: auto;
page-break-inside: auto;
bookmark-level: none; }
article#doc-toc > h1::before {
display: block;
margin-top: -9px;
padding-top: 9px;
content: ""; }
article#doc-toc ul {
list-style: none;
padding-left: 0;
margin-left: 1em;
font-size: 8pt;
page-break-inside: auto !important; }
article#doc-toc li {
list-style: none; }
article#doc-toc li > a {
color: inherit;
text-decoration: none;
padding-top: 0.4rem;
border-bottom: 1px dotted #ddd;
display: inline-block;
width: 100%; }
article#doc-toc li > a > .pdf-order {
padding-right: 0.5em; }
article#doc-toc li > a::after {
float: right;
content: target-counter(attr(href), page); }
@media print {
html {
font-size: 95%;
font-family: 'Kelmscott Roman NF', 'Noto Serif JP', serif; }
body {
font-size: 10.5pt;
font-family: 'Classico URW T OT', 'Noto Serif JP', serif; }
article {
font-size: 0.8rem;
line-height: 1.6; }
h1,
h2,
h3,
h4,
h5,
h6,
label {
font-family: 'Gentium Book Basic', 'Helvetica Neue', Helvetica, Arial, 'Noto Sans JP', 'Roboto', sans-serif; }
pre,
code,
var,
samp,
kbd,
tt {
font-family: 'Noto Sans Mono CJK JP', 'Courier New', monospace, serif;
font-size: 0.8em; }
pre code,
pre var,
pre samp,
pre kbd,
pre tt {
font-size: 100%; } }
@page :first {
@top-right {
content: normal; }
@bottom-center {
content: normal; }
@bottom-right {
content: normal; } }
article#doc-cover {
display: flex;
flex-direction: column;
height: 100vh; }
article#doc-cover > .wrapper {
flex: 1 0 auto;
text-align: center;
padding: 0 3rem; }
article#doc-cover > .wrapper.upper {
flex: 1 1 auto;
max-height: 30vh; }
article#doc-cover > .wrapper.upper > .logo {
width: 100%;
height: 100%;
background-position: center bottom;
background-repeat: no-repeat;
background-size: contain; }
article#doc-cover > .wrapper h1 {
font-size: 36pt;
line-height: 1.4; }
article#doc-cover > .wrapper h2 {
border: none;
bookmark-level: none; }
article#doc-cover > .properties {
flex: 0 0 auto;
text-align: right;
padding: 0 2rem; }
article#doc-cover > .properties p#copyright {
font-size: 80%; }
article#doc-back_cover {
page: back_cover;
height: 100vh;
display: flex;
flex-direction: column;
text-align: center; }
article#doc-back_cover .wrapper {
flex: 1 0 auto;
display: inline-block;
background: #eee; }
article#doc-back_cover .qrcode {
display: inline-block;
flex: 0 0 auto;
background: #eee; }
article#doc-back_cover .qrcode > a {
display: inline-block;
padding: 0.5em 2em;
border-radius: 1em;
background-color: #fff; }
article#doc-back_cover .qrcode > a img {
width: 100%;
height: auto; }
@page back_cover {
background-color: #eee;
@top-right {
content: normal; }
@bottom-center {
content: normal; }
@bottom-left {
font-size: 8pt;
content: string(title); }
@bottom-right {
font-size: 8pt;
content: string(copyright); } }
@media print {
html {
font-size: 95%;
font-family: 'Ubuntu'; }
body {
font-size: 11.5pt;
font-family: 'Ubuntu'; }
article {
font-size: 0.8rem;
line-height: 1.6; }
h1,
h2,
h3,
h4,
h5,
h6,
label {
font-family: 'Gentium Book Basic', 'Helvetica Neue', Helvetica, Arial, 'Noto Sans JP', 'Roboto', sans-serif; }
pre,
code,
var,
samp,
kbd,
tt {
font-family: 'Noto Sans Mono CJK JP', 'Courier New', monospace, serif;
font-size: 0.8em; }
pre code,
pre var,
pre samp,
pre kbd,
pre tt {
font-size: 100%; } }
</style><style>@media print {
.md-typeset .tabbed-set {
display: block; }
.md-typeset .tabbed-set .tabbed-content--wrap {
display: inline-block;
width: 100%;
margin-bottom: 0.25rem; }
.md-typeset .tabbed-set .tabbed-content--wrap > input {
display: none; }
.md-typeset .tabbed-set .tabbed-content--wrap > label {
background-color: rgba(170, 170, 170, 0.2);
padding: 0.2rem 2rem;
margin: 0;
font-weight: 600;
color: #666;
border-radius: 3px 3px 0 0;
border-bottom-color: transparent; }
.md-typeset .tabbed-set .tabbed-content--wrap > .tabbed-content {
display: block;
box-shadow: none; }
.md-typeset .admonition-title + .tabbed-set:last-child,
.md-typeset summary + .tabbed-set:last-child {
margin-top: 0.5rem; }
.md-typeset > details summary::after {
display: none; }
.md-typeset > div, .md-typeset > div.admonition, .md-typeset > details, .md-typeset > div.tabbed-set, .md-typeset > blockquote, .md-typeset > mark, .md-typeset > table, .md-typeset > p {
margin-left: 0.7rem; }
.md-typeset > table.highlighttable {
margin: 0 0 0 0.7rem; }
.md-typeset table.highlighttable,
.md-typeset table.highlighttable > tbody {
width: 100%; }
.md-typeset table.highlighttable {
padding-bottom: 0.5em; }
.md-typeset table.highlighttable .linenos {
padding-bottom: 0; }
.md-typeset > ul {
margin-left: 1.5rem; }
.md-typeset h4,
.md-typeset h5,
.md-typeset h6 {
margin-left: 0.25rem; }
.md-typeset *:not(h3) + h4 {
margin-top: 1.5rem; }
.md-typeset hr {
border-bottom: 1px dotted #999; }
.md-typeset .footnote {
line-height: 1.1; }
.md-typeset table:not([class]) th, .md-typeset table:not([class]) td {
padding: 0.5em 1.25rem 0.4em; }
.md-typeset table:not([class]) td {
border-bottom: 1px solid #eee; }
.md-typeset span.twemoji {
vertical-align: middle;
height: 1.125rem;
display: inline-block; }
.md-typeset span.twemoji > img {
height: 1.125rem;
vertical-align: middle;
display: inline-block; } }
.md-typeset kbd {
vertical-align: middle;
border-color: #b8b8b8;
border-style: outset;
border-width: .05rem .075rem .1rem .075rem;
border-radius: .25rem;
box-shadow: none; }
:root {
--print-md-admonition-icon--note: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23448aff"><path d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z"/></svg>');
--print-md-admonition-icon--abstract: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%2300b0ff"><path d="M4 5h16v2H4V5m0 4h16v2H4V9m0 4h16v2H4v-2m0 4h10v2H4v-2z"/></svg>');
--print-md-admonition-icon--info: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%2300b8d4"><path d="M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 002 12a10 10 0 0010 10 10 10 0 0010-10A10 10 0 0012 2z"/></svg>');
--print-md-admonition-icon--tip: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%2300bfa5"><path d="M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 01-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z"/></svg>');
--print-md-admonition-icon--success: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%2300c853"><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2m-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>');
--print-md-admonition-icon--question: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%2364dd17"><path d="M15.07 11.25l-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 00-2-2 2 2 0 00-2 2H8a4 4 0 014-4 4 4 0 014 4 3.2 3.2 0 01-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 002 12a10 10 0 0010 10 10 10 0 0010-10c0-5.53-4.5-10-10-10z"/></svg>');
--print-md-admonition-icon--warning: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23ff9100"><path d="M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z"/></svg>');
--print-md-admonition-icon--failure: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23ff5252"><path d="M12 2c5.53 0 10 4.47 10 10s-4.47 10-10 10S2 17.53 2 12 6.47 2 12 2m3.59 5L12 10.59 8.41 7 7 8.41 10.59 12 7 15.59 8.41 17 12 13.41 15.59 17 17 15.59 13.41 12 17 8.41 15.59 7z"/></svg>');
--print-md-admonition-icon--danger: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23ff1744"><path d="M11.5 20l4.86-9.73H13V4l-5 9.73h3.5V20M12 2c2.75 0 5.1 1 7.05 2.95C21 6.9 22 9.25 22 12s-1 5.1-2.95 7.05C17.1 21 14.75 22 12 22s-5.1-1-7.05-2.95C3 17.1 2 14.75 2 12s1-5.1 2.95-7.05C6.9 3 9.25 2 12 2z"/></svg>');
--print-md-admonition-icon--bug: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23f50057"><path d="M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 00-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 00-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z"/></svg>');
--print-md-admonition-icon--example: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23651fff"><path d="M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 01.75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z"/></svg>');
--print-md-admonition-icon--quote: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%239e9e9e"><path d="M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z"/></svg>'); }
@media print {
.md-typeset .admonition-title {
padding: .6rem .6rem .4rem 2.2rem; }
.md-typeset .admonition-title::before {
margin-top: -0.15rem;
background-color: transparent;
background-image: var(--print-md-admonition-icon--note); }
.md-typeset .note > .admonition-title, .md-typeset .note > summary {
padding: .6rem .6rem .4rem 2.2rem; }
.md-typeset .note > .admonition-title::before, .md-typeset .note > summary::before {
margin-top: -0.15rem;
background-color: transparent;
background-image: var(--print-md-admonition-icon--note); }
.md-typeset .abstract > .admonition-title, .md-typeset .tldr > .admonition-title, .md-typeset .summary > .admonition-title, .md-typeset .abstract > summary, .md-typeset .tldr > summary, .md-typeset .summary > summary {
padding: .6rem .6rem .4rem 2.2rem; }
.md-typeset .abstract > .admonition-title::before, .md-typeset .tldr > .admonition-title::before, .md-typeset .summary > .admonition-title::before, .md-typeset .abstract > summary::before, .md-typeset .tldr > summary::before, .md-typeset .summary > summary::before {
margin-top: -0.15rem;
background-color: transparent;
background-image: var(--print-md-admonition-icon--abstract); }
.md-typeset .info > .admonition-title, .md-typeset .todo > .admonition-title, .md-typeset .info > summary, .md-typeset .todo > summary {
padding: .6rem .6rem .4rem 2.2rem; }
.md-typeset .info > .admonition-title::before, .md-typeset .todo > .admonition-title::before, .md-typeset .info > summary::before, .md-typeset .todo > summary::before {
margin-top: -0.15rem;
background-color: transparent;
background-image: var(--print-md-admonition-icon--info); }
.md-typeset .tip > .admonition-title, .md-typeset .important > .admonition-title, .md-typeset .hint > .admonition-title, .md-typeset .tip > summary, .md-typeset .important > summary, .md-typeset .hint > summary {
padding: .6rem .6rem .4rem 2.2rem; }
.md-typeset .tip > .admonition-title::before, .md-typeset .important > .admonition-title::before, .md-typeset .hint > .admonition-title::before, .md-typeset .tip > summary::before, .md-typeset .important > summary::before, .md-typeset .hint > summary::before {
margin-top: -0.15rem;
background-color: transparent;
background-image: var(--print-md-admonition-icon--tip); }
.md-typeset .success > .admonition-title, .md-typeset .done > .admonition-title, .md-typeset .check > .admonition-title, .md-typeset .success > summary, .md-typeset .done > summary, .md-typeset .check > summary {
padding: .6rem .6rem .4rem 2.2rem; }
.md-typeset .success > .admonition-title::before, .md-typeset .done > .admonition-title::before, .md-typeset .check > .admonition-title::before, .md-typeset .success > summary::before, .md-typeset .done > summary::before, .md-typeset .check > summary::before {
margin-top: -0.15rem;
background-color: transparent;
background-image: var(--print-md-admonition-icon--success); }
.md-typeset .question > .admonition-title, .md-typeset .faq > .admonition-title, .md-typeset .help > .admonition-title, .md-typeset .question > summary, .md-typeset .faq > summary, .md-typeset .help > summary {
padding: .6rem .6rem .4rem 2.2rem; }
.md-typeset .question > .admonition-title::before, .md-typeset .faq > .admonition-title::before, .md-typeset .help > .admonition-title::before, .md-typeset .question > summary::before, .md-typeset .faq > summary::before, .md-typeset .help > summary::before {
margin-top: -0.15rem;
background-color: transparent;
background-image: var(--print-md-admonition-icon--question); }
.md-typeset .warning > .admonition-title, .md-typeset .attention > .admonition-title, .md-typeset .caution > .admonition-title, .md-typeset .warning > summary, .md-typeset .attention > summary, .md-typeset .caution > summary {
padding: .6rem .6rem .4rem 2.2rem; }
.md-typeset .warning > .admonition-title::before, .md-typeset .attention > .admonition-title::before, .md-typeset .caution > .admonition-title::before, .md-typeset .warning > summary::before, .md-typeset .attention > summary::before, .md-typeset .caution > summary::before {
margin-top: -0.15rem;
background-color: transparent;
background-image: var(--print-md-admonition-icon--warning); }
.md-typeset .failure > .admonition-title, .md-typeset .missing > .admonition-title, .md-typeset .fail > .admonition-title, .md-typeset .failure > summary, .md-typeset .missing > summary, .md-typeset .fail > summary {
padding: .6rem .6rem .4rem 2.2rem; }
.md-typeset .failure > .admonition-title::before, .md-typeset .missing > .admonition-title::before, .md-typeset .fail > .admonition-title::before, .md-typeset .failure > summary::before, .md-typeset .missing > summary::before, .md-typeset .fail > summary::before {
margin-top: -0.15rem;
background-color: transparent;
background-image: var(--print-md-admonition-icon--failure); }
.md-typeset .danger > .admonition-title, .md-typeset .error > .admonition-title, .md-typeset .danger > summary, .md-typeset .error > summary {
padding: .6rem .6rem .4rem 2.2rem; }
.md-typeset .danger > .admonition-title::before, .md-typeset .error > .admonition-title::before, .md-typeset .danger > summary::before, .md-typeset .error > summary::before {
margin-top: -0.15rem;
background-color: transparent;
background-image: var(--print-md-admonition-icon--danger); }
.md-typeset .bug > .admonition-title, .md-typeset .bug > summary {
padding: .6rem .6rem .4rem 2.2rem; }
.md-typeset .bug > .admonition-title::before, .md-typeset .bug > summary::before {
margin-top: -0.15rem;
background-color: transparent;
background-image: var(--print-md-admonition-icon--bug); }
.md-typeset .example > .admonition-title, .md-typeset .example > summary {
padding: .6rem .6rem .4rem 2.2rem; }
.md-typeset .example > .admonition-title::before, .md-typeset .example > summary::before {
margin-top: -0.15rem;
background-color: transparent;
background-image: var(--print-md-admonition-icon--example); }
.md-typeset .quote > .admonition-title, .md-typeset .cite > .admonition-title, .md-typeset .quote > summary, .md-typeset .cite > summary {
padding: .6rem .6rem .4rem 2.2rem; }
.md-typeset .quote > .admonition-title::before, .md-typeset .cite > .admonition-title::before, .md-typeset .quote > summary::before, .md-typeset .cite > summary::before {
margin-top: -0.15rem;
background-color: transparent;
background-image: var(--print-md-admonition-icon--quote); } }
:root {
--print-md-footnotes-icon: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23000000de"><path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.42L5.83 13H21V7h-2z"/></svg>'); }
@media print {
.md-typeset .footnote-backref::before {
background-color: transparent;
background-image: var(--print-md-footnotes-icon); } }
:root {
--print-md-details-icon: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="hsla(0, 0%, 0%, 0.87)"><path d="M8.59 16.58L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42z"/></svg>'); }
@media print {
.md-typeset summary::after {
background-color: transparent;
background-image: var(--print-md-details-icon);
-webkit-mask-image: none;
mask-image: none; } }
:root {
--print-md-tasklist-icon: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23ddd"><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2m-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>');
--print-md-tasklist-icon--checked: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%2300e676"><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2m-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>'); }
@media print {
.md-typeset .task-list-control .task-list-indicator::before {
background-color: transparent;
background-image: var(--print-md-tasklist-icon); }
.md-typeset .task-list-control [type=checkbox]:checked + .task-list-indicator::before {
background-color: transparent;
background-image: var(--print-md-tasklist-icon--checked); } }
/*# sourceMappingURL=material-polyfills.css.map*/
</style></head><body>I am a cover!<article id="doc-toc"><h1>Table of contents</h1><ul><li><a href="#.:lets-build-your-awesome-selfhosted-platform-together">Let's build your awesome selfhosted platform together!</a><ul><li><a href="#.:what-to-expect">What to expect</a></li><li><a href="#.:how-will-this-benefit-me">How will this benefit me?</a></li><li><a href="#.:testimonials">Testimonials</a></li><li><a href="#.:who-made-this">Who made this?</a><ul><li><a href="#.:hi-im-david">👋 Hi, I'm David</a></li><li><a href="#.:what-do-you-want-from-me">What do you want from me?</a></li><li><a href="#.:sponsored-projects">Sponsored Projects</a></li></ul></li></ul></li><li><a href="#IRXWG23FOIQFG53BOJWQ/">Docker Swarm</a><ul><li><a href="#docker-swarm/:highly-available-docker-swarm-design">Highly Available Docker Swarm Design</a><ul><li><a href="#docker-swarm/:design-decisions">Design Decisions</a></li><li><a href="#docker-swarm/:security">Security</a></li><li><a href="#docker-swarm/:high-availability">High availability</a></li></ul></li><li><a href="#IRXWG23FOIQFG53BOJWQ/KBZGK4DBOJQXI2LPNY/">Preparation</a><ul><li><a href="#docker-swarm/design/:highly-available-docker-swarm-design">Highly Available Docker Swarm Design</a></li><li><a href="#docker-swarm/nodes/:nodes">Nodes</a></li></ul></li></ul></li><li><a href="#4KN3IICLOVRGK4TOMV2GK4Y/">⛴ Kubernetes</a><ul><li><a href="#4KN3IICLOVRGK4TOMV2GK4Y/KBZGK4DBOJQXI2LPNY/">Preparation</a><ul><li><a href="#kubernetes/">Introduction</a></li></ul></li></ul></li></ul></article><article class="md-content__inner md-typeset" data-url="/." id=".:"> <h1 id=".:lets-build-your-awesome-selfhosted-platform-together">Let's build your awesome selfhosted platform together!</h1> <p>Welcome, fellow geek <img alt="👋" class="twemoji" src="https://twemoji.maxcdn.com/v/latest/svg/1f44b.svg" title=":wave:"/> If you're impatient, just start here <img alt="👇" class="twemoji" src="https://twemoji.maxcdn.com/v/latest/svg/1f447.svg" title=":point_down:"/></p> <div class="grid cards"> <ul> <li> <p><strong>Dive into <span class="twemoji docker lg middle"><img class="converted-twemoji" src="data:image/svg+xml;charset=utf-8;base64,PHN2ZyBoZWlnaHQ9IjI0IiBzdHlsZT0iZmlsbDogY3VycmVudENvbG9yOyIgdmlld2JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTIxLjgxIDEwLjI1Yy0uMDYtLjA0LS41Ni0uNDMtMS42NC0uNDMtLjI4IDAtLjU2LjAzLS44NC4wOC0uMjEtMS40LTEuMzgtMi4xMS0xLjQzLTIuMTRsLS4yOS0uMTctLjE4LjI3Yy0uMjQuMzYtLjQzLjc3LS41MSAxLjE5LS4yLjgtLjA4IDEuNTYuMzMgMi4yMS0uNDkuMjgtMS4yOS4zNS0xLjQ2LjM1SDIuNjJjLS4zNCAwLS42Mi4yOC0uNjIuNjMgMCAxLjE1LjE4IDIuMy41OCAzLjM4LjQ1IDEuMTkgMS4xMyAyLjA3IDIgMi42MS45OC42IDIuNTkuOTQgNC40Mi45NC43OSAwIDEuNjEtLjA3IDIuNDItLjIyIDEuMTItLjIgMi4yLS41OSAzLjE5LTEuMTZBOC4zIDguMyAwIDAgMCAxNi43OCAxNmMxLjA1LTEuMTcgMS42Ny0yLjUgMi4xMi0zLjY1aC4xOWMxLjE0IDAgMS44NS0uNDYgMi4yNC0uODUuMjYtLjI0LjQ1LS41My41OS0uODdsLjA4LS4yNC0uMTktLjE0bS0xNy45Ni45OWgxLjc2Yy4wOCAwIC4xNi0uMDcuMTYtLjE2VjkuNWMwLS4wOC0uMDctLjE2LS4xNi0uMTZIMy44NWMtLjA5IDAtLjE2LjA3LS4xNi4xNnYxLjU4Yy4wMS4wOS4wNy4xNi4xNi4xNm0yLjQzIDBoMS43NmMuMDggMCAuMTYtLjA3LjE2LS4xNlY5LjVjMC0uMDgtLjA3LS4xNi0uMTYtLjE2SDYuMjhjLS4wOSAwLS4xNi4wNy0uMTYuMTZ2MS41OGMuMDEuMDkuMDcuMTYuMTYuMTZtMi40NyAwaDEuNzVjLjEgMCAuMTctLjA3LjE3LS4xNlY5LjVjMC0uMDgtLjA2LS4xNi0uMTctLjE2SDguNzVjLS4wOCAwLS4xNS4wNy0uMTUuMTZ2MS41OGMwIC4wOS4wNi4xNi4xNS4xNm0yLjQ0IDBoMS43N2MuMDggMCAuMTUtLjA3LjE1LS4xNlY5LjVjMC0uMDgtLjA2LS4xNi0uMTUtLjE2aC0xLjc3Yy0uMDggMC0uMTUuMDctLjE1LjE2djEuNThjMCAuMDkuMDcuMTYuMTUuMTZNNi4yOCA5aDEuNzZjLjA4IDAgLjE2LS4wOS4xNi0uMThWNy4yNWMwLS4wOS0uMDctLjE2LS4xNi0uMTZINi4yOGMtLjA5IDAtLjE2LjA2LS4xNi4xNnYxLjU3Yy4wMS4wOS4wNy4xOC4xNi4xOG0yLjQ3IDBoMS43NWMuMSAwIC4xNy0uMDkuMTctLjE4VjcuMjVjMC0uMDktLjA2LS4xNi0uMTctLjE2SDguNzVjLS4wOCAwLS4xNS4wNi0uMTUuMTZ2MS41N2MwIC4wOS4wNi4xOC4xNS4xOG0yLjQ0IDBoMS43N2MuMDggMCAuMTUtLjA5LjE1LS4xOFY3LjI1YzAtLjA5LS4wNy0uMTYtLjE1LS4xNmgtMS43N2MtLjA4IDAtLjE1LjA2LS4xNS4xNnYxLjU3YzAgLjA5LjA3LjE4LjE1LjE4bTAtMi4yOGgxLjc3Yy4wOCAwIC4xNS0uMDcuMTUtLjE2VjVjMC0uMS0uMDctLjE3LS4xNS0uMTdoLTEuNzdjLS4wOCAwLS4xNS4wNi0uMTUuMTd2MS41NmMwIC4wOC4wNy4xNi4xNS4xNm0yLjQ2IDQuNTJoMS43NmMuMDkgMCAuMTYtLjA3LjE2LS4xNlY5LjVjMC0uMDgtLjA3LS4xNi0uMTYtLjE2aC0xLjc2Yy0uMDggMC0uMTUuMDctLjE1LjE2djEuNThjMCAuMDkuMDcuMTYuMTUuMTYiPjwvcGF0aD48L3N2Zz4="/></span> <a href="/docker-swarm/design/">Docker Swarm</a></strong></p> <hr/> <p>The quickest way to get started, and to get your head around the basics.</p> </li> <li> <p><strong>Kick it with <span class="twemoji kubernetes lg middle"><img class="converted-twemoji" src="data:image/svg+xml;charset=utf-8;base64,PHN2ZyBoZWlnaHQ9IjI0IiBzdHlsZT0iZmlsbDogY3VycmVudENvbG9yOyIgdmlld2JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTEzLjk1IDEzLjVoLS4yM2MtLjE4LjExLS4yNi4zMi0uMTguNWwuODYgMi4xMWMuODMtLjUzIDEuNDYtMS4zMiAxLjc5LTIuMjVsLTIuMjMtLjM2aC0uMDFtLTMuNDUuMjlhLjQxNS40MTUgMCAwIDAtLjM4LS4yOWgtLjA4bC0yLjIyLjM3Yy4zMy45Mi45NiAxLjcgMS43OSAyLjIzbC44NS0yLjA3VjE0Yy4wNC0uMDUuMDQtLjE0LjA0LS4yMW0xLjgzLjgxYS4zNzguMLine truncated
-A INPUT -s <span class="m">192</span>.168.31.0/24 -j ACCEPT
</code></pre></div> <p>And restart iptables with <code>systemctl restart iptables</code></p> <h6 id="docker-swarm/nodes/:ubuntu">Ubuntu</h6> <p>Install the (<em>non-default</em>) persistent iptables tools, by running <code>apt-get install iptables-persistent</code>, establishing some default rules (<em>dkpg will prompt you to save current ruleset</em>), and then add something like this to <code>/etc/iptables/rules.v4</code>:</p> <div class="highlight"><pre><span></span><code><span class="c1"># Allow all inter-node communication</span>
-A INPUT -s <span class="m">192</span>.168.31.0/24 -j ACCEPT
</code></pre></div> <p>And refresh your running iptables rules with <code>iptables-restore &lt; /etc/iptables/rules.v4</code></p> <h5 id="docker-swarm/nodes/:enable-hostname-resolution">Enable hostname resolution</h5> <p>Depending on your hosting environment, you may have DNS automatically setup for your VMs. If not, it's useful to set up static entries in /etc/hosts for the nodes. For example, I setup the following:</p> <ul> <li>192.168.31.11 ds1 ds1.funkypenguin.co.nz</li> <li>192.168.31.12 ds2 ds2.funkypenguin.co.nz</li> <li>192.168.31.13 ds3 ds3.funkypenguin.co.nz</li> </ul> <h5 id="docker-swarm/nodes/:set-timezone">Set timezone</h5> <p>Set your local timezone, by running:</p> <div class="highlight"><pre><span></span><code>ln -sf /usr/share/zoneinfo/&lt;your timezone&gt; /etc/localtime
</code></pre></div> <h4 id="docker-swarm/nodes/:serving">Serving</h4> <p>After completing the above, you should have:</p> <div class="admonition summary"> <p class="admonition-title">Summary</p> <p>Deployed in this recipe:</p> <ul class="task-list"> <li class="task-list-item"><label class="task-list-control"><input checked="" disabled="" type="checkbox"/><span class="task-list-indicator"></span></label> 3 x nodes (<em>bare-metal or VMs</em>), each with:<ul> <li>A mainstream Linux OS (<em>tested on either <a href="https://www.centos.org">CentOS</a> 7+ or <a href="http://releases.ubuntu.com">Ubuntu</a> 16.04+</em>)</li> <li>At least 2GB RAM</li> <li>At least 20GB disk space (<em>but it'll be tight</em>)</li> </ul> </li> <li class="task-list-item"><label class="task-list-control"><input checked="" disabled="" type="checkbox"/><span class="task-list-indicator"></span></label> Connectivity to each other within the same subnet, and on a low-latency link (<em>i.e., no WAN links</em>)</li> </ul> </div> <hr/> <div class="md-source-file"> <small> Last update: <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-date">July 9, 2022</span> </small> </div> </section></section></article><article class="md-content__inner md-typeset" data-url="/4KN3IICLOVRGK4TOMV2GK4Y/" id="4KN3IICLOVRGK4TOMV2GK4Y/:"><h1 id="4KN3IICLOVRGK4TOMV2GK4Y/">⛴ Kubernetes</h1><section class="md-typeset" data-url="/4KN3IICLOVRGK4TOMV2GK4Y/KBZGK4DBOJQXI2LPNY/" id="4KN3IICLOVRGK4TOMV2GK4Y/KBZGK4DBOJQXI2LPNY/:"><h2 id="4KN3IICLOVRGK4TOMV2GK4Y/KBZGK4DBOJQXI2LPNY/">Preparation</h2><section class="md-typeset" data-url="/kubernetes/" id="kubernetes/:"> <h3 id="kubernetes/">Introduction</h3> <p>My first introduction to Kubernetes was a children's story:</p> <!-- markdownlint-disable MD033 --> <iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/R9-SOzep73w" width="560"></iframe> <h4 id="kubernetes/:why-kubernetes">Why Kubernetes?</h4> <p>Why would you want to Kubernetes for your self-hosted recipes, over simple <a href="/docker-swarm/">Docker Swarm</a>? Here's my personal take..</p> <h5 id="kubernetes/:docker-swarm-is-dead">Docker Swarm is dead</h5> <p>Sorry to say, but from where I sit, there's no innovation or development happening in docker swarm.</p> <p>Yes, I know, after Docker Inc <a href="https://www.mirantis.com/blog/mirantis-acquires-docker-enterprise-platform-business/">sold its platform business to Mirantis in Nov 2019</a>, in Feb 2020 Mirantis <a href="https://www.mirantis.com/blog/mirantis-will-continue-to-support-and-develop-docker-swarm/">back-tracked</a> on their original plan to sunset swarm after 2 years, and stated that they'd continue to invest in swarm. But seriously, look around. Nobody is interested in swarm right now...</p> <p>... Not even Mirantis! As of Nov 2021, the Mirantis blog tag "<a href="https://www.mirantis.com/tag/kubernetes/">kubernetes</a>" had 8 posts within the past month. The tag "<a href="https://www.mirantis.com/tag/docker/">docker</a>" has 8 posts in the past <strong>2 years</strong>, the 8<sup>th</sup> being the original announcement of the Docker aquisition. The tag "<a href="https://www.mirantis.com/tag/docker-swarm/">docker swarm</a>" has only 2 posts, <strong>ever</strong>.</p> <p>Dead. <a href="https://youtu.be/NxnZC9L_YXE?t=47">Extinct. Like the doodoo</a>.</p> <h5 id="kubernetes/:once-you-go-kubernetes-you-cant-go-back">Once you go Kubernetes, you can't go back</h5> <p>For years now, <a href="https://www.funkypenguin.co.nz/work-with-me/">I've provided Kubernetes design consulting</a> to small clients and large enterprises. The implementation details in each case vary widely, but there are some primitives which I've come to take for granted, and I wouldn't easily do without. A few examples:</p> <ul> <li><strong>CLI drives API from anywhere</strong>. From my laptop, I can use my credentials to manage any number of Kubernetes clusters, simply by switching kubectl "context". Each interaction is an API call against an HTTPS endpoint. No SSHing to hosts and manually running docker command as root!</li> <li><strong>GitOps is magic</strong>. There are multiple ways to achieve it, but having changes you commit to a repo automatically applied to a cluster, "Just Works™". The process removes so much friction from making changes that it makes you more productive, and a better "gitizen" ;P</li> <li><strong>Controllers are trustworthy</strong>. I've come to trust that when I tell Kubernetes to run 3 replicas on separate hosts, to scale up a set of replicas based on CPU load metrics, or provision a blob of storage for a given workloa, that this will be done in a consistent and visible way. I'll be able to see logs / details for each action taken by the controller, and adjust my own instructions/configuration accordingly if necessary.</li> </ul> <h4 id="kubernetes/:uggh-itLine truncated
<div class="wrapper"></div><div class="qrcode">
<a href="https://geek-cookbook.funkypenguin.co.nz/">
<img src="data:image/svg+xml;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz4KPHN2ZyB3aWR0aD0iMzdtbSIgaGVpZ2h0PSIzN21tIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAzNyAzNyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNIDMwIDI1IEwgMzAgMjYgTCAzMSAyNiBMIDMxIDI1IHogTSAyMyA0IEwgMjMgNSBMIDI0IDUgTCAyNCA0IHogTSAxMiAxMyBMIDEyIDE0IEwgMTMgMTQgTCAxMyAxMyB6IE0gMjMgMTMgTCAyMyAxNCBMIDI0IDE0IEwgMjQgMTMgeiBNIDQgOSBMIDQgMTAgTCA1IDEwIEwgNSA5IHogTSAxNSA5IEwgMTUgMTAgTCAxNiAxMCBMIDE2IDkgeiBNIDQgMjcgTCA0IDI4IEwgNSAyOCBMIDUgMjcgeiBNIDE1IDI3IEwgMTUgMjggTCAxNiAyOCBMIDE2IDI3IHogTSAxNCAzMSBMIDE0IDMyIEwgMTUgMzIgTCAxNSAzMSB6IE0gMjkgMjkgTCAyOSAzMCBMIDMwIDMwIEwgMzAgMjkgeiBNIDggNiBMIDggNyBMIDkgNyBMIDkgNiB6IE0gMjYgMTQgTCAyNiAxNSBMIDI3IDE1IEwgMjcgMTQgeiBNIDcgMTAgTCA3IDExIEwgOCAxMSBMIDggMTAgeiBNIDI2IDIzIEwgMjYgMjQgTCAyNyAyNCBMIDI3IDIzIHogTSAyNiAzMiBMIDI2IDMzIEwgMjcgMzMgTCAyNyAzMiB6IE0gNyAyOCBMIDcgMjkgTCA4IDI5IEwgOCAyOCB6IE0gMTggMjggTCAxOCAyOSBMIDE5IDI5IEwgMTkgMjggeiBNIDMwIDIwIEwgMzAgMjEgTCAzMSAyMSBMIDMxIDIwIHogTSAzMCAyOSBMIDMwIDMwIEwgMzEgMzAgTCAzMSAyOSB6IE0gMTIgOCBMIDEyIDkgTCAxMyA5IEwgMTMgOCB6IE0gMjMgOCBMIDIzIDkgTCAyNCA5IEwgMjQgOCB6IE0gNCA0IEwgNCA1IEwgNSA1IEwgNSA0IHogTSA0IDEzIEwgNCAxNCBMIDUgMTQgTCA1IDEzIHogTSAyOSAxNSBMIDI5IDE2IEwgMzAgMTYgTCAzMCAxNSB6IE0gMjYgOSBMIDI2IDEwIEwgMjcgMTAgTCAyNyA5IHogTSAxOCA1IEwgMTggNiBMIDE5IDYgTCAxOSA1IHogTSA3IDE0IEwgNyAxNSBMIDggMTUgTCA4IDE0IHogTSAxOCAxNCBMIDE4IDE1IEwgMTkgMTUgTCAxOSAxNCB6IE0gNyAyMyBMIDcgMjQgTCA4IDI0IEwgOCAyMyB6IE0gMTggMjMgTCAxOCAyNCBMIDE5IDI0IEwgMTkgMjMgeiBNIDcgMzIgTCA3IDMzIEwgOCAzMyBMIDggMzIgeiBNIDE4IDMyIEwgMTggMzMgTCAxOSAzMyBMIDE5IDMyIHogTSAzMCA2IEwgMzAgNyBMIDMxIDcgTCAzMSA2IHogTSAzMCAyNCBMIDMwIDI1IEwgMzEgMjUgTCAzMSAyNCB6IE0gMTUgOCBMIDE1IDkgTCAxNiA5IEwgMTYgOCB6IE0gMjkgMTAgTCAyOSAxMSBMIDMwIDExIEwgMzAgMTAgeiBNIDE0IDIxIEwgMTQgMjIgTCAxNSAyMiBMIDE1IDIxIHogTSAxNCAzMCBMIDE0IDMxIEwgMTUgMzEgTCAxNSAzMCB6IE0gNiAyNiBMIDYgMjcgTCA3IDI3IEwgNyAyNiB6IE0gMjYgNCBMIDI2IDUgTCAyNyA1IEwgMjcgNCB6IE0gMjYgMTMgTCAyNiAxNCBMIDI3IDE0IEwgMjcgMTMgeiBNIDE4IDkgTCAxOCAxMCBMIDE5IDEwIEwgMTkgOSB6IE0gMjYgMjIgTCAyNiAyMyBMIDI3IDIzIEwgMjcgMjIgeiBNIDcgMTggTCA3IDE5IEwgOCAxOSBMIDggMTggeiBNIDI2IDMxIEwgMjYgMzIgTCAyNyAzMiBMIDI3IDMxIHogTSAzMCAxMCBMIDMwIDExIEwgMzEgMTEgTCAzMSAxMCB6IE0gMzIgMjkgTCAzMiAzMCBMIDMzIDMwIEwgMzMgMjkgeiBNIDIyIDYgTCAyMiA3IEwgMjMgNyBMIDIzIDYgeiBNIDExIDE1IEwgMTEgMTYgTCAxMiAxNiBMIDEyIDE1IHogTSAyMiAxNSBMIDIyIDE2IEwgMjMgMTYgTCAyMyAxNSB6IE0gMjUgMTcgTCAyNSAxOCBMIDI2IDE4IEwgMjYgMTcgeiBNIDEwIDI4IEwgMTAgMjkgTCAxMSAyOSBMIDExIDI4IHogTSAxNCA3IEwgMTQgOCBMIDE1IDggTCAxNSA3IHogTSA2IDEyIEwgNiAxMyBMIDcgMTMgTCA3IDEyIHogTSA2IDMwIEwgNiAzMSBMIDcgMzEgTCA3IDMwIHogTSAyNiA4IEwgMjYgOSBMIDI3IDkgTCAyNyA4IHogTSA3IDQgTCA3IDUgTCA4IDUgTCA4IDQgeiBNIDI2IDE3IEwgMjYgMTggTCAyNyAxOCBMIDI3IDE3IHogTSAxOCAyMiBMIDE4IDIzIEwgMTkgMjMgTCAxOSAyMiB6IE0gMjEgMjQgTCAyMSAyNSBMIDIyIDI1IEwgMjIgMjQgeiBNIDMyIDI0IEwgMzIgMjUgTCAzMyAyNSBMIDMzIDI0IHogTSAxMyAyOSBMIDEzIDMwIEwgMTQgMzAgTCAxNCAyOSB6IE0gMTAgMTQgTCAxMCAxNSBMIDExIDE1IEwgMTEgMTQgeiBNIDI1IDIxIEwgMjUgMjIgTCAyNiAyMiBMIDI2IDIxIHogTSAxMCAzMiBMIDEwIDMzIEwgMTEgMzMgTCAxMSAzMiB6IE0gMjUgMzAgTCAyNSAzMSBMIDI2IDMxIEwgMjYgMzAgeiBNIDE0IDExIEwgMTQgMTIgTCAxNSAxMiBMIDE1IDExIHogTSA2IDcgTCA2IDggTCA3IDggTCA3IDcgeiBNIDYgMTYgTCA2IDE3IEwgNyAxNyBMIDcgMTYgeiBNIDI5IDE4IEwgMjkgMTkgTCAzMCAxOSBMIDMwIDE4IHogTSAyNiAxMiBMIDI2IDEzIEwgMjcgMTMgTCAyNyAxMiB6IE0gMTcgMzEgTCAxNyAzMiBMIDE4IDMyIEwgMTggMzEgeiBNIDcgOCBMIDcgOSBMIDggOSBMIDggOCB6IE0gMzIgMTAgTCAzMiAxMSBMIDMzIDExIEwgMzMgMTAgeiBNIDEzIDE1IEwgMTMgMTYgTCAxNCAxNiBMIDE0IDE1IHogTSA5IDI2IEwgOSAyNyBMIDEwIDI3IEwgMTAgMjYgeiBNIDIxIDI4IEwgMjEgMjkgTCAyMiAyOSBMIDIyIDI4IHogTSAzMiAyOCBMIDMyIDI5IEwgMzMgMjkgTCAzMyAyOCB6IE0gMTAgOSBMIDEwIDEwIEwgMTEgMTAgTCAxMSA5IHogTSAxMCAxOCBMIDEwIDE5IEwgMTEgMTkgTCAxMSAxOCB6IE0gMTAgMjcgTCAxMCAyOCBMIDExIDI4IEwgMTEgMjcgeiBNIDI5IDQgTCAyOSA1IEwgMzAgNSBMIDMwIDQgeiBNIDE0IDE1IEwgMTQgMTYgTCAxNSAxNiBMIDE1IDE1IHogTSAxNyAxNyBMIDE3IDE4IEwgMTggMTggTCAxOCAxNyB6IE0gMjggMTcgTCAyOCAxOCBMIDI5IDE4IEwgMjkgMTcgeiBNIDE3IDI2IEwgMTcgMjcgTCAxOCAyNyBMIDE4IDI2IHogTSAyOCAyNiBMIDI4IDI3IEwgMjkgMjcgTCAyOSAyNiB6IE0gMjAgMjIgTCAyMCAyMyBMIDIxIDIzIEwgMjEgMjIgeiBNIDIwIDMxIEwgMjAgMzIgTCAyMSAzMiBMIDIxIDMxIHogTSAyMSA1IEwgMjEgNiBMIDIyIDYgTCAyMiA1IHogTSAzMiA1IEwgMzIgNiBMIDMzIDYgTCAzMyA1IHogTSA5IDEyIEwgOSAxMyBMIDEwIDEzIEwgMTAgMTIgeiBNIDIxIDE0IEwgMjEgMTUgTCAyMiAxNSBMIDIyIDE0IHogTSA5IDIxIEwgOSAyMiBMIDEwIDIyIEwgMTAgMjEgeiBNIDEzIDE5IEwgMTMgMjAgTCAxNCAyMCBMIDE0IDE5IHogTSAyMSAzMiBMIDIxIDMzIEwgMjIgMzMgTCAyMiAzMiB6IE0gMTAgNCBMIDEwIDUgTCAxMSA1IEwgMTEgNCB6IE0gMTAgMjIgTCAxMCAyMyBMIDExIDIzIEwgMTEgMjIgeiBNIDI0IDI0IEwgMjQgMjUgTCAyNSAyNSBMIDI1IDI0IHogTSAxNCAxMCBMIDE0IDExIEwgMTUgMTEgTCAxNSAxMCB6IE0gMTYgMjkgTCAxNiAzMCBMIDE3IDMwIEwgMTcgMjkgeiBNIDYgNiBMIDYgNyBMIDcgNyBMIDcgNiB6IE0gNiAxNSBMIDYgMTYgTCA3IDE2IEwgNyAxNSB6IE0gMTcgMTIgTCAxNyAxMyBMIDE4IDEzIEwgMTggMTIgeiBNIDI4IDEyIEwgMjggMTMgTCAyOSAxMyBMIDI5IDEyIHogTSA1IDE5IEwgNSAyMCBMIDYgMjAgTCA2IDE5IHogTSAxNyAyMSBMIDE3IDIyIEwgMTggMjIgTCAxOCAyMSB6IE0gMjggMjEgTCAyOCAyMiBMIDI5IDIyIEwgMjkgMjEgeiBNIDIwIDE3IEwgMjAgMTggTCAyMSAxOCBMIDIxIDE3IHogTSAxNyAzMCBMIDE3IDMxIEwgMTggMzEgTCAxOCAzMCB6IE0gMLine truncated
<div>https://geek-cookbook.funkypenguin.co.nz/</div>
</a>
</div> <div class="wrapper"></div>
</article></body></html>