Remove old static files
312
public/404.html
@@ -1,312 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang='en' dir='auto'><head>
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||
<meta name='description' content='personal blog'>
|
||||
<meta name='theme-color' content='#8979b3'>
|
||||
|
||||
<meta property='og:title' content='This page no longer exists, or maybe it never did? Try https://archive.org? • davegallant'>
|
||||
<meta property='og:description' content='personal blog'>
|
||||
<meta property='og:url' content='/404.html'>
|
||||
<meta property='og:site_name' content='davegallant'>
|
||||
<meta property='og:type' content='website'><meta property='og:updated_time' content='2022-12-10T21:46:55-05:00'/><meta name='twitter:card' content='summary'>
|
||||
|
||||
<meta name="generator" content="Hugo 0.108.0">
|
||||
|
||||
<title>This page no longer exists, or maybe it never did? Try https://archive.org? • davegallant</title>
|
||||
<link rel='canonical' href='/404.html'>
|
||||
|
||||
|
||||
<link rel='icon' href='/favicon.ico'>
|
||||
<link rel='stylesheet' href='/assets/css/main.ab98e12b.css'><link rel='stylesheet' href='/css/custom.css'><style>
|
||||
:root{--color-accent:#8979b3;}
|
||||
</style>
|
||||
|
||||
<script type="application/javascript">
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-98710982-2', 'auto');
|
||||
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
<body class='error404 type-page has-sidebar'>
|
||||
|
||||
<div class='site'><div id='sidebar' class='sidebar'>
|
||||
<a class='screen-reader-text' href='#main-menu'>Skip to Main Menu</a>
|
||||
|
||||
<div class='container'><section class='widget widget-about sep-after'>
|
||||
<header>
|
||||
|
||||
<div class='logo'>
|
||||
<a href='/'>
|
||||
<img src='/images/logo.png'>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<h2 class='title site-title '>
|
||||
<a href='/'>
|
||||
davegallant
|
||||
</a>
|
||||
</h2>
|
||||
<div class='desc'>
|
||||
personal blog
|
||||
</div>
|
||||
</header>
|
||||
|
||||
</section>
|
||||
<section class='widget widget-taxonomy_cloud sep-after'>
|
||||
<header>
|
||||
<h4 class='title widget-title'>Tags</h4>
|
||||
</header>
|
||||
|
||||
<div class='container list-container'>
|
||||
<ul class='list taxonomy-cloud'><li>
|
||||
<a href='/tags/adguard/' style='font-size:1em'>adguard</a>
|
||||
</li><li>
|
||||
<a href='/tags/aws/' style='font-size:1em'>aws</a>
|
||||
</li><li>
|
||||
<a href='/tags/aws-vault/' style='font-size:1em'>aws-vault</a>
|
||||
</li><li>
|
||||
<a href='/tags/backup/' style='font-size:1em'>backup</a>
|
||||
</li><li>
|
||||
<a href='/tags/containers/' style='font-size:1em'>containers</a>
|
||||
</li><li>
|
||||
<a href='/tags/degoogle/' style='font-size:2em'>degoogle</a>
|
||||
</li><li>
|
||||
<a href='/tags/docker/' style='font-size:1em'>docker</a>
|
||||
</li><li>
|
||||
<a href='/tags/dotfiles/' style='font-size:1em'>dotfiles</a>
|
||||
</li><li>
|
||||
<a href='/tags/gmail/' style='font-size:1em'>gmail</a>
|
||||
</li><li>
|
||||
<a href='/tags/grafana/' style='font-size:1em'>grafana</a>
|
||||
</li><li>
|
||||
<a href='/tags/home-manager/' style='font-size:1em'>home-manager</a>
|
||||
</li><li>
|
||||
<a href='/tags/homelab/' style='font-size:1em'>homelab</a>
|
||||
</li><li>
|
||||
<a href='/tags/invidious/' style='font-size:1em'>invidious</a>
|
||||
</li><li>
|
||||
<a href='/tags/jellyfin/' style='font-size:1em'>jellyfin</a>
|
||||
</li><li>
|
||||
<a href='/tags/k3s/' style='font-size:1em'>k3s</a>
|
||||
</li><li>
|
||||
<a href='/tags/linux/' style='font-size:1em'>linux</a>
|
||||
</li><li>
|
||||
<a href='/tags/lxc/' style='font-size:1em'>lxc</a>
|
||||
</li><li>
|
||||
<a href='/tags/netdata/' style='font-size:1em'>netdata</a>
|
||||
</li><li>
|
||||
<a href='/tags/nix/' style='font-size:1em'>nix</a>
|
||||
</li><li>
|
||||
<a href='/tags/openwrt/' style='font-size:1em'>openwrt</a>
|
||||
</li><li>
|
||||
<a href='/tags/pfsense/' style='font-size:1em'>pfsense</a>
|
||||
</li><li>
|
||||
<a href='/tags/pihole/' style='font-size:1em'>pihole</a>
|
||||
</li><li>
|
||||
<a href='/tags/plex/' style='font-size:1em'>plex</a>
|
||||
</li><li>
|
||||
<a href='/tags/podman/' style='font-size:1em'>podman</a>
|
||||
</li><li>
|
||||
<a href='/tags/privacy/' style='font-size:1em'>privacy</a>
|
||||
</li><li>
|
||||
<a href='/tags/proxmox/' style='font-size:2em'>proxmox</a>
|
||||
</li><li>
|
||||
<a href='/tags/python/' style='font-size:2em'>python</a>
|
||||
</li><li>
|
||||
<a href='/tags/ransomware/' style='font-size:1em'>ransomware</a>
|
||||
</li><li>
|
||||
<a href='/tags/router/' style='font-size:1em'>router</a>
|
||||
</li><li>
|
||||
<a href='/tags/router-on-a-stick/' style='font-size:1em'>router-on-a-stick</a>
|
||||
</li><li>
|
||||
<a href='/tags/security/' style='font-size:1em'>security</a>
|
||||
</li><li>
|
||||
<a href='/tags/synology/' style='font-size:1em'>synology</a>
|
||||
</li><li>
|
||||
<a href='/tags/tailscale/' style='font-size:2em'>tailscale</a>
|
||||
</li><li>
|
||||
<a href='/tags/virtualization/' style='font-size:1em'>virtualization</a>
|
||||
</li><li>
|
||||
<a href='/tags/vlan/' style='font-size:1em'>vlan</a>
|
||||
</li><li>
|
||||
<a href='/tags/vpn/' style='font-size:1em'>vpn</a>
|
||||
</li><li>
|
||||
<a href='/tags/yewtu.be/' style='font-size:1em'>yewtu.be</a>
|
||||
</li><li>
|
||||
<a href='/tags/youtube/' style='font-size:1em'>youtube</a>
|
||||
</li></ul>
|
||||
</div>
|
||||
|
||||
|
||||
</section>
|
||||
<section class='widget widget-social_menu sep-after'><nav aria-label='Social Menu'>
|
||||
<ul><li>
|
||||
<a href='https://github.com/davegallant' target='_blank' rel='noopener me'>
|
||||
<span class='screen-reader-text'>Open Github account in new tab</span><svg
|
||||
class="icon"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewbox="0 0 24 24"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
aria-hidden="true"
|
||||
><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22" />
|
||||
</svg>
|
||||
</a>
|
||||
</li><li>
|
||||
<a href='https://twitter.com/davega11ant' target='_blank' rel='noopener me'>
|
||||
<span class='screen-reader-text'>Open Twitter account in new tab</span><svg
|
||||
class="icon"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewbox="0 0 24 24"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
aria-hidden="true"
|
||||
><path d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z" />
|
||||
</svg>
|
||||
</a>
|
||||
</li><li>
|
||||
<a href='https://fosstodon.org/@davegallant' target='_blank' rel='noopener me'>
|
||||
<span class='screen-reader-text'>Open Mastodon account in new tab</span><svg
|
||||
class="icon"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewbox="0 0 24 24"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
aria-hidden="true"
|
||||
><path fill="#ccc" d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127C.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611c.118 1.24.325 2.47.62 3.68c.55 2.237 2.777 4.098 4.96 4.857c2.336.792 4.849.923 7.256.38c.265-.061.527-.132.786-.213c.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041a.053.053 0 0 0-.046-.01a20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433a.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546c.376 0 .75 0 1.125-.01c1.57-.044 3.224-.124 4.768-.422c.038-.008.077-.015.11-.024c2.435-.464 4.753-1.92 4.989-5.604c.008-.145.03-1.52.03-1.67c.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976c-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35c-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12c.696-.77 1.608-1.164 2.74-1.164c1.311 0 2.302.5 2.962 1.498l.638 1.06l.638-1.06c.66-.999 1.65-1.498 2.96-1.498c1.13 0 2.043.395 2.74 1.164c.675.77 1.012 1.81 1.012 3.12z"/>
|
||||
</svg>
|
||||
</a>
|
||||
</li><li>
|
||||
<a href='mailto:dave.gallant@gmail.com' target='_blank' rel='noopener me'>
|
||||
<span class='screen-reader-text'>Contact via Email</span><svg
|
||||
class="icon"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewbox="0 0 24 24"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
aria-hidden="true"
|
||||
><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" />
|
||||
<polyline points="22,6 12,13 2,6" />
|
||||
</svg>
|
||||
</a>
|
||||
</li><li>
|
||||
<a href='https://linkedin.com/in/dave-gallant' target='_blank' rel='noopener me'>
|
||||
<span class='screen-reader-text'>Open Linkedin account in new tab</span><svg
|
||||
class="icon"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewbox="0 0 24 24"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
aria-hidden="true"
|
||||
><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z" />
|
||||
<rect x="2" y="9" width="4" height="12" />
|
||||
<circle cx="4" cy="4" r="2" />
|
||||
</svg>
|
||||
</a>
|
||||
</li></ul>
|
||||
</nav>
|
||||
</section></div>
|
||||
|
||||
<div class='sidebar-overlay'></div>
|
||||
</div><div class='main'><nav id='main-menu' class='menu main-menu' aria-label='Main Menu'>
|
||||
<div class='container'>
|
||||
<a class='screen-reader-text' href='#content'>Skip to Content</a>
|
||||
|
||||
<button id='sidebar-toggler' class='sidebar-toggler' aria-controls='sidebar'>
|
||||
<span class='screen-reader-text'>Toggle Sidebar</span>
|
||||
<span class='open'><svg
|
||||
class="icon"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewbox="0 0 24 24"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
aria-hidden="true"
|
||||
><line x1="3" y1="12" x2="21" y2="12" />
|
||||
<line x1="3" y1="6" x2="21" y2="6" />
|
||||
<line x1="3" y1="18" x2="21" y2="18" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class='close'><svg
|
||||
class="icon"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewbox="0 0 24 24"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
aria-hidden="true"
|
||||
><line x1="18" y1="6" x2="6" y2="18" />
|
||||
<line x1="6" y1="6" x2="18" y2="18" />
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<ul><li class='item'>
|
||||
<a href='/'>Home</a>
|
||||
</li><li class='item'>
|
||||
<a href='/about/'>About</a>
|
||||
</li><li class='item'>
|
||||
<a href='/index.xml'>RSS</a>
|
||||
</li></ul>
|
||||
</div>
|
||||
</nav><div class='header-widgets'>
|
||||
<div class='container'></div>
|
||||
</div>
|
||||
|
||||
<header id='header' class='header site-header'>
|
||||
<div class='container sep-after'>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id='content'>
|
||||
|
||||
|
||||
<div class='entry'>
|
||||
<div class='container entry-content'>
|
||||
<span class='screen-reader-text'>This page no longer exists, or maybe it never did? Try https://archive.org?</span>
|
||||
<figure class='gopher'>
|
||||
<a href='/'>
|
||||
<img src='/assets/gopher.png' alt='Gopher'/>
|
||||
<span class='screen-reader-text'>Go Home...</span>
|
||||
</a>
|
||||
<figcaption>
|
||||
<h1 class='title'>
|
||||
<a href='/'>This page no longer exists, or maybe it never did? Try https://archive.org?</a>
|
||||
</h1>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<footer id='footer' class='footer'>
|
||||
<div class='container sep-before'><div class='copyright'>
|
||||
<p> © 2020-2022 Dave Gallant </p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</div><script>window.__assets_js_src="/assets/js/"</script>
|
||||
|
||||
<script src='/assets/js/main.c3bcf2df.js'></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 462 KiB |
Before Width: | Height: | Size: 74 KiB |
@@ -1 +0,0 @@
|
||||
blockquote{padding-left:0;padding-right:1em;border-left:0;border-right:.2em solid #bdbdbd}body{direction:rtl}ol,ul{margin:0 2em 1.5em 0}li>ol,li>ul{padding-left:0;padding-right:1.5em;margin-left:0;margin-right:.5em}caption,td,th{text-align:right}.main-menu li{margin-right:0;margin-left:.625em}.main-menu li:last-child{margin-left:0}.sidebar-menu .sub-menu{padding-right:0}.sidebar-menu .sub-menu .item:not(.has-children){padding-right:0;padding-left:1.2em}.sub-menu-toggler{margin-left:0;margin-right:.2em}.page-link:first-child{padding-left:.625em;padding-right:0}.page-link:last-child{padding-left:0;padding-right:.625em}.page-link.next .icon,.page-link.prev .icon{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.main{transition:margin-right .2s}.sidebar.toggled~.main{margin-left:0;margin-right:300px}@media screen and (min-width:920px){.has-sidebar .main{float:right;margin-left:0;margin-right:300px;padding-left:0;padding-right:2em}}.has-sidebar .container{margin-left:auto;margin-right:0}.sidebar{float:right;left:auto;right:-300px;margin-right:0;margin-left:-100%;transition:right .2s;text-align:left}.sidebar.toggled{right:0}.sidebar .sep-after:after{margin-left:0;margin-right:auto}@media screen and (min-width:920px){.sidebar{left:auto;right:0}}.main .sidebar-toggler{right:auto;left:20px}.main-menu .sidebar-toggler{margin-right:0;margin-left:.75em}.sidebar .sidebar-toggler{left:auto;right:.5em}.header-info .taxonomy-name{margin-right:0;margin-left:.25em}.entry-meta>span{display:inline-block}.entry-meta span{margin-right:0;margin-left:.75em}.entry-meta .icon,.no-details details>summary:before{margin-right:0;margin-left:.25em}.entry-footer .icon{margin-right:0;margin-left:.375em}.comment .avatar{float:right;margin-right:0;margin-left:.75em}.comment .reply{right:auto;left:0}.comment-reply-title small{margin-left:0;margin-right:1em}.comment-submission-feedback a{right:auto;left:1.5em}.list .item .icon{margin-right:0;margin-left:.25em}.taxonomy-cloud li{padding:0 0 .5em 1.5em}img.emoji{margin:0 .1em 0 .05em}.layout-archive .list .item{padding-left:0;padding-right:1em}.sidebar .widget-about .logo{margin-left:0;margin-right:auto}.widget-search .search-submit{right:auto;left:0;border-radius:.2em 0 0 0}.layout-search .widget-search .search-term{padding-right:.875em;padding-left:3em}.widget-social_menu li{margin-right:0;margin-left:.625em}.widget-social_menu li:last-child{margin-left:0}.sidebar .widget-social_menu li{margin-left:0;margin-right:.625em}.sidebar .widget-taxonomy_cloud li{padding:0 .8em .4em 0}.screen-reader-text:focus{left:auto;right:.5em}.convo .sep{padding-left:.5em;padding-right:.75em}
|
Before Width: | Height: | Size: 207 KiB |
@@ -1 +0,0 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[1],{45:function(e,n,t){"use strict";t.r(n),t.d(n,"initComments",function(){return a});var o=document.querySelector(".comment-list"),r=document.querySelector("#respond"),c=r.querySelector("form"),i=r.querySelector("#cancel-comment-reply-link"),l=r.querySelector('[name="fields[parent_id]"]'),u=function(e){if(e){var n=o.querySelector("#comment-".concat(e," article"));return l.value=e,n.parentNode.insertBefore(r,n.nextSibling),i.style.display="",c.querySelector("textarea").focus(),!1}},a=function(){i.style.display="none",i.addEventListener("click",function(e){e.preventDefault(),l.value="",o.parentNode.appendChild(r),i.style.display="none"}),window.moveRespondBlock=u}}}]);
|
@@ -1 +0,0 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{42:function(e,n,t){"use strict";t.r(n),t.d(n,"detailsPolyfill",function(){return i});var o=document.body,i=function(e){(function(){var e=document.createElement("details");if(!("open"in e))return!1;e.innerHTML="<summary>a</summary>b",o.appendChild(e);var n=e.offsetHeight;e.open=!0;var t=n!=e.offsetHeight;return o.removeChild(e),t})()||(o.classList.add("no-details"),e.forEach(function(e){e.querySelector("summary").addEventListener("click",function(){e.getAttribute("open")?(e.open=!1,e.removeAttribute("open")):(e.open=!0,e.setAttribute("open","open"))})}))}}}]);
|
@@ -1 +0,0 @@
|
||||
!function(e){function t(t){for(var n,o,i=t[0],u=t[1],a=0,c=[];a<i.length;a++)o=i[a],r[o]&&c.push(r[o][0]),r[o]=0;for(n in u)Object.prototype.hasOwnProperty.call(u,n)&&(e[n]=u[n]);for(l&&l(t);c.length;)c.shift()()}var n={},r={5:0};function o(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.e=function(e){var t=[],n=r[e];if(0!==n)if(n)t.push(n[2]);else{var i=new Promise(function(t,o){n=r[e]=[t,o]});t.push(n[2]=i);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,o.nc&&a.setAttribute("nonce",o.nc),a.src=function(e){return o.p+""+({1:"comments",2:"details-polyfill",7:"sidebar",8:"twemoji"}[e]||e)+"."+{1:"57223579",2:"45606d79",7:"9ea42a6e",8:"79bd873e"}[e]+".js"}(e);var l=new Error;u=function(t){a.onerror=a.onload=null,clearTimeout(c);var n=r[e];if(0!==n){if(n){var o=t&&("load"===t.type?"missing":t.type),i=t&&t.target&&t.target.src;l.message="Loading chunk "+e+" failed.\n("+o+": "+i+")",l.type=o,l.request=i,n[1](l)}r[e]=void 0}};var c=setTimeout(function(){u({type:"timeout",target:a})},12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(t)},o.m=e,o.c=n,o.d=function(e,t,n){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)o.d(n,r,function(t){return e[t]}.bind(null,r));return n},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o.oe=function(e){throw console.error(e),e};var i=window.webpackJsonp=window.webpackJsonp||[],u=i.push.bind(i);i.push=t,i=i.slice();for(var a=0;a<i.length;a++)t(i[a]);var l=u;o(o.s=41)}({12:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){function t(){document.removeEventListener("DOMContentLoaded",t,!1),window.removeEventListener("load",t,!1),e()}"complete"===document.readyState?setTimeout(e):(document.addEventListener("DOMContentLoaded",t,!1),window.addEventListener("load",t,!1))},e.exports=t.default},16:function(e,t,n){n.p=window.__assets_js_src},17:function(e,t,n){},41:function(e,t,n){"use strict";n.r(t);n(16),n(17);var r=n(12);function o(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t<e.length;t++)n[t]=e[t];return n}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}n.n(r)()(function(){var e=document.body,t=e.querySelectorAll(".taxonomy-cloud:not(.no-shuffle)");t.length&&t.forEach(function(e){(function(e){for(var t,n,r=o(e),i=e.length;i;)n=Math.floor(Math.random()*i),t=r[--i],r[i]=r[n],r[n]=t;return r})(e.querySelectorAll("li")).forEach(function(e){return e.parentElement.appendChild(e)})});var r=e.querySelectorAll("details");if(r.length&&n.e(2).then(n.bind(null,42)).then(function(e){return(0,e.detailsPolyfill)(r)}),e.classList.contains("has-emoji")){var i=e.querySelector(".entry");n.e(8).then(n.t.bind(null,43,7)).then(function(e){return e.parse(i)})}e.classList.contains("has-sidebar")&&n.e(7).then(n.bind(null,44)).then(function(e){return(0,e.initSidebar)()}),e.querySelector("#comment-form")&&n.e(1).then(n.bind(null,45)).then(function(e){return(0,e.initComments)()})})}});
|
@@ -1 +0,0 @@
|
||||
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=40)}({40:function(e,t,r){}});
|
@@ -1 +0,0 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{44:function(t,e,i){"use strict";i.r(e),i.d(e,"initSidebar",function(){return E});var n=document.body,o=n.querySelector("#sidebar"),r=n.querySelector("#sidebar-toggler"),s=n.querySelector(".sidebar-overlay"),c=n.querySelector("#sidebar-menu"),d=r.cloneNode(!0);d.setAttribute("id","#sidebar-collapse");var u,l,a,f,b,p,w=function(t,e){t.forEach(function(t){return t.setAttribute("aria-expanded",e)})},g=function(){o.classList.remove("toggled"),w([o,r,d],!1)},y=function(){o.classList.add("toggled"),w([o,r,d],!0),o.focus()},v=0,h=!1,A=!1,L=0,m=function(){f=window.scrollY,l=n.offsetHeight,a=o.offsetHeight,b=Math.round(f+o.getBoundingClientRect().top),a>u?f>v?h?(h=!1,L=b>0?b:0,o.setAttribute("style","top: ".concat(L,"px;"))):!A&&f+u>a+b&&a<l&&(A=!0,o.setAttribute("style","position: fixed; bottom: 0;")):f<v?A?(A=!1,L=b>0?b:0,o.setAttribute("style","top: ".concat(L,"px;"))):!h&&f<b&&(h=!0,o.setAttribute("style","position: fixed;")):(h=A=!1,L=b||0,o.setAttribute("style","top: ".concat(L,"px;"))):h||(h=!0,o.setAttribute("style","position: fixed;")),v=f},x=function(){window.innerWidth,u=window.innerHeight,m()},E=function(){o.setAttribute("tabindex","-1"),o.insertBefore(d,o.children[1]),w([o,r,d],!1),r.addEventListener("click",y),d.addEventListener("click",g),s.addEventListener("click",g),window.addEventListener("scroll",m),window.addEventListener("resize",function(){clearTimeout(p),p=setTimeout(x,500)}),x(),c&&c.querySelectorAll(".item.has-children").forEach(function(t){var e=t.querySelector("button"),i=t.querySelector(".sub-menu");w([i,e],!1),e.addEventListener("click",function(){var n=t.classList.contains("toggled");t.classList[n?"remove":"add"]("toggled"),w([i,e],!n)})})}}}]);
|
@@ -1,115 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Authors - davegallant</title><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<link rel="alternate" type="application/rss+xml" href="/authors/index.xml" title="davegallant" />
|
||||
<meta property="og:title" content="Authors" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="/authors/" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Authors"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.ac08a4c9714baa859217f92f051deb58df2938ec352b506df655005dcaf98cc0.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css" media="(prefers-color-scheme: dark)" />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<h1 class="page-title">All tags</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="tag-cloud">
|
||||
<ul class="tags">
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
<footer>
|
||||
<div style="display:flex"></div>
|
||||
<div class="footer-info">
|
||||
2023 <a
|
||||
href="https://github.com/athul/archie">Archie Theme</a> | Built with <a href="https://gohugo.io">Hugo</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script type="application/javascript">
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-98710982-2', 'auto');
|
||||
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>Authors on davegallant</title>
|
||||
<link>/authors/</link>
|
||||
<description>Recent content in Authors on davegallant</description>
|
||||
<generator>Hugo -- gohugo.io</generator>
|
||||
<language>en-us</language><atom:link href="/authors/index.xml" rel="self" type="application/rss+xml" />
|
||||
</channel>
|
||||
</rss>
|
@@ -1,13 +0,0 @@
|
||||
.hanchor {
|
||||
visibility: hidden;
|
||||
color: silver;
|
||||
font-size: 100%;
|
||||
transition: 0.2s;
|
||||
padding-left: 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
h2:hover a, h3:hover a, h4:hover a {
|
||||
visibility: visible;
|
||||
text-decoration: none;
|
||||
}
|
@@ -1,159 +0,0 @@
|
||||
body {
|
||||
color: white;
|
||||
background-color: #202124;
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background: blue;
|
||||
color: #fff;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: red;
|
||||
color: #fff;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-top: 3px dotted blue;
|
||||
}
|
||||
code {
|
||||
background-color: lightblue;
|
||||
color: black;
|
||||
text-decoration: bold;
|
||||
padding: 0.1em 0.2em;
|
||||
}
|
||||
pre {
|
||||
background-color: #272822;
|
||||
line-height: 1.4;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
blockquote {
|
||||
border-color: blue;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: #ddd;
|
||||
}
|
||||
h1::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "# ";
|
||||
}
|
||||
h2::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "## ";
|
||||
}
|
||||
h3::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "### ";
|
||||
}
|
||||
h4::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "#### ";
|
||||
}
|
||||
h5::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "##### ";
|
||||
}
|
||||
h6::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "###### ";
|
||||
}
|
||||
|
||||
a {
|
||||
border-bottom: 3px solid var(--darkMaincolor);
|
||||
color: inherit;
|
||||
}
|
||||
a:hover {
|
||||
background-color: var(--darkMaincolor);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.site-description a {
|
||||
color: #ddd;
|
||||
}
|
||||
.site-description a:hover {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.tags a {
|
||||
border-bottom: 3px solid var(--darkMaincolor);
|
||||
}
|
||||
.tags a:hover {
|
||||
background-color: var(--darkMaincolor);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.site-title a {
|
||||
color: white;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.header nav,
|
||||
.footer {
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: #333;
|
||||
}
|
||||
.soc:hover {
|
||||
color: black;
|
||||
}
|
||||
.draft-label {
|
||||
color: var(--darkMaincolor);
|
||||
background-color: blue;
|
||||
}
|
||||
.highlight pre code[class=language-javaScript]::before,
|
||||
.highlight pre code[class="language-js"]::before {
|
||||
content: "js";
|
||||
background: #f7df1e;
|
||||
color: black;
|
||||
}
|
||||
.highlight pre code[class*='language-yml']::before,
|
||||
.highlight pre code[class*='language-yaml']::before {
|
||||
content: 'yaml';
|
||||
background: #f71e6a;
|
||||
color: white;
|
||||
}
|
||||
.highlight pre code[class*='language-shell']::before,
|
||||
.highlight pre code[class*='language-bash']::before,
|
||||
.highlight pre code[class*='language-sh']::before {
|
||||
content: 'shell';
|
||||
background: green;
|
||||
color:white
|
||||
}
|
||||
.highlight pre code[class*='language-json']::before{
|
||||
content: 'json';
|
||||
background: dodgerblue;
|
||||
color: #000000
|
||||
}
|
||||
.highlight pre code[class*='language-python']::before,
|
||||
.highlight pre code[class*='language-py']::before {
|
||||
content: 'py';
|
||||
background: blue;
|
||||
color: yellow ;
|
||||
}
|
||||
.highlight pre code[class*='language-css']::before{
|
||||
content: 'css';
|
||||
background: cyan;
|
||||
color: black ;
|
||||
}
|
||||
.highlight pre code[class*='language-go']::before{
|
||||
content: 'Go';
|
||||
background: cyan;
|
||||
color: royalblue ;
|
||||
}
|
||||
.highlight pre code[class*='language-md']::before,
|
||||
.highlight pre code[class*='language-md']::before{
|
||||
content: 'Markdown';
|
||||
background: royalblue;
|
||||
color: whitesmoke ;
|
||||
}
|
@@ -1,159 +0,0 @@
|
||||
body {
|
||||
color: white;
|
||||
background-color: #202124;
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background: blue;
|
||||
color: #fff;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: rgb(212, 240, 32);
|
||||
color: #000000;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-top: 3px dotted blue;
|
||||
}
|
||||
code {
|
||||
background-color: rgb(184, 189, 190);
|
||||
color: black;
|
||||
text-decoration: bold;
|
||||
padding: 0em 0.1em;
|
||||
}
|
||||
pre {
|
||||
background-color: #272822;
|
||||
line-height: 1.4;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
blockquote {
|
||||
border-color: blue;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: #ddd;
|
||||
}
|
||||
h1::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "# ";
|
||||
}
|
||||
h2::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "## ";
|
||||
}
|
||||
h3::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "### ";
|
||||
}
|
||||
h4::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "#### ";
|
||||
}
|
||||
h5::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "##### ";
|
||||
}
|
||||
h6::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "###### ";
|
||||
}
|
||||
|
||||
a {
|
||||
border-bottom: 3px solid var(--darkMaincolor);
|
||||
color: inherit;
|
||||
}
|
||||
a:hover {
|
||||
background-color: var(--darkMaincolor);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.site-description a {
|
||||
color: #ddd;
|
||||
}
|
||||
.site-description a:hover {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.tags a {
|
||||
border-bottom: 3px solid var(--darkMaincolor);
|
||||
}
|
||||
.tags a:hover {
|
||||
background-color: var(--darkMaincolor);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.site-title a {
|
||||
color: white;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.header nav,
|
||||
.footer {
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: #333;
|
||||
}
|
||||
.soc:hover {
|
||||
color: black;
|
||||
}
|
||||
.draft-label {
|
||||
color: var(--darkMaincolor);
|
||||
background-color: blue;
|
||||
}
|
||||
.highlight pre code[class=language-javaScript]::before,
|
||||
.highlight pre code[class="language-js"]::before {
|
||||
content: "js";
|
||||
background: #f7df1e;
|
||||
color: black;
|
||||
}
|
||||
.highlight pre code[class*='language-yml']::before,
|
||||
.highlight pre code[class*='language-yaml']::before {
|
||||
content: 'yaml';
|
||||
background: #f71e6a;
|
||||
color: white;
|
||||
}
|
||||
.highlight pre code[class*='language-shell']::before,
|
||||
.highlight pre code[class*='language-bash']::before,
|
||||
.highlight pre code[class*='language-sh']::before {
|
||||
content: 'shell';
|
||||
background: green;
|
||||
color:white
|
||||
}
|
||||
.highlight pre code[class*='language-json']::before{
|
||||
content: 'json';
|
||||
background: dodgerblue;
|
||||
color: #000000
|
||||
}
|
||||
.highlight pre code[class*='language-python']::before,
|
||||
.highlight pre code[class*='language-py']::before {
|
||||
content: 'py';
|
||||
background: blue;
|
||||
color: yellow ;
|
||||
}
|
||||
.highlight pre code[class*='language-css']::before{
|
||||
content: 'css';
|
||||
background: cyan;
|
||||
color: black ;
|
||||
}
|
||||
.highlight pre code[class*='language-go']::before{
|
||||
content: 'Go';
|
||||
background: cyan;
|
||||
color: royalblue ;
|
||||
}
|
||||
.highlight pre code[class*='language-md']::before,
|
||||
.highlight pre code[class*='language-md']::before{
|
||||
content: 'Markdown';
|
||||
background: royalblue;
|
||||
color: whitesmoke ;
|
||||
}
|
@@ -1,159 +0,0 @@
|
||||
body {
|
||||
color: white;
|
||||
background-color: #202124;
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background: blue;
|
||||
color: #fff;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: red;
|
||||
color: #fff;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-top: 3px dotted blue;
|
||||
}
|
||||
code {
|
||||
background-color: rgb(184, 189, 190);
|
||||
color: black;
|
||||
text-decoration: bold;
|
||||
padding: 0em 0.1em;
|
||||
}
|
||||
pre {
|
||||
background-color: #272822;
|
||||
line-height: 1.4;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
blockquote {
|
||||
border-color: blue;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: #ddd;
|
||||
}
|
||||
h1::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "# ";
|
||||
}
|
||||
h2::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "## ";
|
||||
}
|
||||
h3::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "### ";
|
||||
}
|
||||
h4::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "#### ";
|
||||
}
|
||||
h5::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "##### ";
|
||||
}
|
||||
h6::before {
|
||||
color: var(--darkMaincolor);
|
||||
content: "###### ";
|
||||
}
|
||||
|
||||
a {
|
||||
border-bottom: 3px solid var(--darkMaincolor);
|
||||
color: inherit;
|
||||
}
|
||||
a:hover {
|
||||
background-color: var(--darkMaincolor);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.site-description a {
|
||||
color: #ddd;
|
||||
}
|
||||
.site-description a:hover {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.tags a {
|
||||
border-bottom: 3px solid var(--darkMaincolor);
|
||||
}
|
||||
.tags a:hover {
|
||||
background-color: var(--darkMaincolor);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.site-title a {
|
||||
color: white;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.header nav,
|
||||
.footer {
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: #333;
|
||||
}
|
||||
.soc:hover {
|
||||
color: black;
|
||||
}
|
||||
.draft-label {
|
||||
color: var(--darkMaincolor);
|
||||
background-color: blue;
|
||||
}
|
||||
.highlight pre code[class=language-javaScript]::before,
|
||||
.highlight pre code[class="language-js"]::before {
|
||||
content: "js";
|
||||
background: #f7df1e;
|
||||
color: black;
|
||||
}
|
||||
.highlight pre code[class*='language-yml']::before,
|
||||
.highlight pre code[class*='language-yaml']::before {
|
||||
content: 'yaml';
|
||||
background: #f71e6a;
|
||||
color: white;
|
||||
}
|
||||
.highlight pre code[class*='language-shell']::before,
|
||||
.highlight pre code[class*='language-bash']::before,
|
||||
.highlight pre code[class*='language-sh']::before {
|
||||
content: 'shell';
|
||||
background: green;
|
||||
color:white
|
||||
}
|
||||
.highlight pre code[class*='language-json']::before{
|
||||
content: 'json';
|
||||
background: dodgerblue;
|
||||
color: #000000
|
||||
}
|
||||
.highlight pre code[class*='language-python']::before,
|
||||
.highlight pre code[class*='language-py']::before {
|
||||
content: 'py';
|
||||
background: blue;
|
||||
color: yellow ;
|
||||
}
|
||||
.highlight pre code[class*='language-css']::before{
|
||||
content: 'css';
|
||||
background: cyan;
|
||||
color: black ;
|
||||
}
|
||||
.highlight pre code[class*='language-go']::before{
|
||||
content: 'Go';
|
||||
background: cyan;
|
||||
color: royalblue ;
|
||||
}
|
||||
.highlight pre code[class*='language-md']::before,
|
||||
.highlight pre code[class*='language-md']::before{
|
||||
content: 'Markdown';
|
||||
background: royalblue;
|
||||
color: whitesmoke ;
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
/* fira-sans-regular - latin */
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Fira Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('../fonts/fira-sans-v10-latin-regular.eot'); /* IE9 Compat Modes */
|
||||
src: local('Fira Sans Regular'), local('FiraSans-Regular'),
|
||||
url('../fonts/fira-sans-v10-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('../fonts/fira-sans-v10-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('../fonts/fira-sans-v10-latin-regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('../fonts/fira-sans-v10-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||
url('../fonts/fira-sans-v10-latin-regular.svg#FiraSans') format('svg'); /* Legacy iOS */
|
||||
}
|
||||
/* roboto-mono-regular - latin */
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('../fonts/roboto-mono-v12-latin-regular.eot'); /* IE9 Compat Modes */
|
||||
src: url('../fonts/roboto-mono-v12-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('../fonts/roboto-mono-v12-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('../fonts/roboto-mono-v12-latin-regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('../fonts/roboto-mono-v12-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||
url('../fonts/roboto-mono-v12-latin-regular.svg#RobotoMono') format('svg'); /* Legacy iOS */
|
||||
}
|
||||
/* ibm-plex-mono-500italic - latin */
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'IBM Plex Mono';
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
src: url('../fonts/ibm-plex-mono-v6-latin-500italic.eot'); /* IE9 Compat Modes */
|
||||
src: local('IBM Plex Mono Medium Italic'), local('IBMPlexMono-MediumItalic'),
|
||||
url('../fonts/ibm-plex-mono-v6-latin-500italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('../fonts/ibm-plex-mono-v6-latin-500italic.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('../fonts/ibm-plex-mono-v6-latin-500italic.woff') format('woff'), /* Modern Browsers */
|
||||
url('../fonts/ibm-plex-mono-v6-latin-500italic.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||
url('../fonts/ibm-plex-mono-v6-latin-500italic.svg#IBMPlexMono') format('svg'); /* Legacy iOS */
|
||||
}
|
@@ -1,333 +0,0 @@
|
||||
/* Markdown */
|
||||
:root{
|
||||
--maincolor: red;
|
||||
--bordercl:rebeccapurple;
|
||||
--callouctcolor:dodgerblue;
|
||||
--hovercolor:navy;
|
||||
--darkMaincolor: #50fa7b;
|
||||
}
|
||||
html {
|
||||
color: #232333;
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
font-size: 15px;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
body{
|
||||
display: block;
|
||||
margin: 8px;
|
||||
}
|
||||
* {
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--maincolor);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: 'Fira Sans', sans-serif;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 3px dotted var(--bordercl);
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--bordercl);
|
||||
color: #737373;
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
background-color: var(--hovercolor);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 2ch;
|
||||
}
|
||||
ul li {
|
||||
text-indent: -2ch;
|
||||
}
|
||||
ul > li::before {
|
||||
content: '* ';
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Images */
|
||||
img {
|
||||
border: 3px solid #ececec;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure img {
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
figure {
|
||||
padding: 0 40px;
|
||||
}
|
||||
}
|
||||
|
||||
figure h4 {
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
figure h4::before {
|
||||
content: '↳ ';
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
code {
|
||||
background-color: #f1f1f1;
|
||||
padding: .1em .2em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #ececec;
|
||||
line-height: 1.4;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.highlight pre ::selection {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
pre code {
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
font-size: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Containers */
|
||||
.content {
|
||||
margin-bottom: 4em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 800px;
|
||||
padding: 0 1ch;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin: 1em 0;
|
||||
line-height: 2.5em;
|
||||
}
|
||||
|
||||
header .main {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-size: 1.2rem;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
h1::before { color: var(--maincolor); content: '# '; }
|
||||
h2::before { color: var(--maincolor); content: '## '; }
|
||||
h3::before { color: var(--maincolor); content: '### '; }
|
||||
h4::before { color: var(--maincolor); content: '#### '; }
|
||||
h5::before { color: var(--maincolor); content: '##### '; }
|
||||
h6::before { color: var(--maincolor); content: '###### '; }
|
||||
|
||||
.meta {
|
||||
color: #999;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-top: 0.4rem dotted var(--bordercl);
|
||||
padding: 2rem 0rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
.soc {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: none;
|
||||
}
|
||||
.border {
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
border: 1px solid;
|
||||
}
|
||||
.footer-info {
|
||||
padding: var(--footer-padding);
|
||||
}
|
||||
|
||||
/* Common */
|
||||
.title h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
time {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
/* Posts */
|
||||
article .title {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
||||
/* Callout */
|
||||
.callout {
|
||||
background-color: var(--callouctcolor);
|
||||
color: #fff;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.callout p {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.callout a {
|
||||
border-bottom: 3px solid #fff;
|
||||
}
|
||||
|
||||
.callout a:hover {
|
||||
background-color: #fff;
|
||||
color: var(--callouctcolor);
|
||||
}
|
||||
|
||||
.site-description {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.tags li::before{
|
||||
content: "🏷 ";
|
||||
}
|
||||
.tags a{
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
}
|
||||
.tags a:hover{
|
||||
color:white;
|
||||
background-color: var(--hovercolor);
|
||||
}
|
||||
svg{
|
||||
max-height: 15px;
|
||||
}
|
||||
.soc:hover{
|
||||
color: white;
|
||||
}
|
||||
.draft-label{
|
||||
color: var(--bordercl);
|
||||
text-decoration: none;
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
margin-left: 6px;
|
||||
background-color: #f9f2f4;
|
||||
}
|
||||
.highlight {
|
||||
position: relative;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"] {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"]::before {
|
||||
background: black;
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.025rem;
|
||||
padding: 0.1rem 0.5rem;
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
text-align: right;
|
||||
text-transform: uppercase;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.highlight pre code[class=language-javaScript]::before,
|
||||
.highlight pre code[class="language-js"]::before {
|
||||
content: "js";
|
||||
background: #f7df1e;
|
||||
color: black;
|
||||
}
|
||||
.highlight pre code[class*='language-yml']::before,
|
||||
.highlight pre code[class*='language-yaml']::before {
|
||||
content: 'yaml';
|
||||
background: #f71e6a;
|
||||
color: white;
|
||||
}
|
||||
.highlight pre code[class*='language-shell']::before,
|
||||
.highlight pre code[class*='language-bash']::before,
|
||||
.highlight pre code[class*='language-sh']::before {
|
||||
content: 'shell';
|
||||
background: green;
|
||||
color:white
|
||||
}
|
||||
.highlight pre code[class*='language-json']::before{
|
||||
content: 'json';
|
||||
background: dodgerblue;
|
||||
color: #000000
|
||||
}
|
||||
.highlight pre code[class*='language-python']::before,
|
||||
.highlight pre code[class*='language-py']::before {
|
||||
content: 'py';
|
||||
background: blue;
|
||||
color: yellow ;
|
||||
}
|
||||
.highlight pre code[class*='language-css']::before{
|
||||
content: 'css';
|
||||
background: cyan;
|
||||
color: black ;
|
||||
}
|
||||
.highlight pre code[class*='language-go']::before{
|
||||
content: 'Go';
|
||||
background: cyan;
|
||||
color: royalblue ;
|
||||
}
|
||||
.highlight pre code[class*='language-md']::before,
|
||||
.highlight pre code[class*='language-md']::before{
|
||||
content: 'Markdown';
|
||||
background: royalblue;
|
||||
color: whitesmoke ;
|
||||
}
|
||||
|
||||
/* table */
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table th{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
table td{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
}
|
@@ -1,333 +0,0 @@
|
||||
/* Markdown */
|
||||
:root{
|
||||
--maincolor: rgb(111, 119, 140);
|
||||
--bordercl:rebeccapurple;
|
||||
--callouctcolor:dodgerblue;
|
||||
--hovercolor:navy;
|
||||
--darkMaincolor: #50fa7b;
|
||||
}
|
||||
html {
|
||||
color: #232333;
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
font-size: 15px;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
body{
|
||||
display: block;
|
||||
margin: 8px;
|
||||
}
|
||||
* {
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--maincolor);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: 'Fira Sans', sans-serif;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 3px dotted var(--bordercl);
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--bordercl);
|
||||
color: #737373;
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
background-color: var(--hovercolor);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 2ch;
|
||||
}
|
||||
ul li {
|
||||
text-indent: -2ch;
|
||||
}
|
||||
ul > li::before {
|
||||
content: '* ';
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Images */
|
||||
img {
|
||||
border: 3px solid #ececec;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure img {
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
figure {
|
||||
padding: 0 40px;
|
||||
}
|
||||
}
|
||||
|
||||
figure h4 {
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
figure h4::before {
|
||||
content: '↳ ';
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
code {
|
||||
background-color: #f1f1f1;
|
||||
padding: 0em .0.1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #ececec;
|
||||
line-height: 1.4;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.highlight pre ::selection {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
pre code {
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
font-size: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Containers */
|
||||
.content {
|
||||
margin-bottom: 4em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 800px;
|
||||
padding: 0 1ch;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin: 1em 0;
|
||||
line-height: 2.5em;
|
||||
}
|
||||
|
||||
header .main {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-size: 1.2rem;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
h1::before { color: var(--maincolor); content: '# '; }
|
||||
h2::before { color: var(--maincolor); content: '## '; }
|
||||
h3::before { color: var(--maincolor); content: '### '; }
|
||||
h4::before { color: var(--maincolor); content: '#### '; }
|
||||
h5::before { color: var(--maincolor); content: '##### '; }
|
||||
h6::before { color: var(--maincolor); content: '###### '; }
|
||||
|
||||
.meta {
|
||||
color: #999;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-top: 0.4rem dotted var(--bordercl);
|
||||
padding: 2rem 0rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
.soc {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: none;
|
||||
}
|
||||
.border {
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
border: 1px solid;
|
||||
}
|
||||
.footer-info {
|
||||
padding: var(--footer-padding);
|
||||
}
|
||||
|
||||
/* Common */
|
||||
.title h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
time {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
/* Posts */
|
||||
article .title {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
||||
/* Callout */
|
||||
.callout {
|
||||
background-color: var(--callouctcolor);
|
||||
color: #fff;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.callout p {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.callout a {
|
||||
border-bottom: 3px solid #fff;
|
||||
}
|
||||
|
||||
.callout a:hover {
|
||||
background-color: #fff;
|
||||
color: var(--callouctcolor);
|
||||
}
|
||||
|
||||
.site-description {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.tags li::before{
|
||||
content: "🏷 ";
|
||||
}
|
||||
.tags a{
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
}
|
||||
.tags a:hover{
|
||||
color:white;
|
||||
background-color: var(--hovercolor);
|
||||
}
|
||||
svg{
|
||||
max-height: 15px;
|
||||
}
|
||||
.soc:hover{
|
||||
color: white;
|
||||
}
|
||||
.draft-label{
|
||||
color: var(--bordercl);
|
||||
text-decoration: none;
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
margin-left: 6px;
|
||||
background-color: #f9f2f4;
|
||||
}
|
||||
.highlight {
|
||||
position: relative;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"] {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"]::before {
|
||||
background: black;
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.025rem;
|
||||
padding: 0.1rem 0.5rem;
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
text-align: right;
|
||||
text-transform: uppercase;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.highlight pre code[class=language-javaScript]::before,
|
||||
.highlight pre code[class="language-js"]::before {
|
||||
content: "js";
|
||||
background: #f7df1e;
|
||||
color: black;
|
||||
}
|
||||
.highlight pre code[class*='language-yml']::before,
|
||||
.highlight pre code[class*='language-yaml']::before {
|
||||
content: 'yaml';
|
||||
background: #f71e6a;
|
||||
color: white;
|
||||
}
|
||||
.highlight pre code[class*='language-shell']::before,
|
||||
.highlight pre code[class*='language-bash']::before,
|
||||
.highlight pre code[class*='language-sh']::before {
|
||||
content: 'shell';
|
||||
background: green;
|
||||
color:white
|
||||
}
|
||||
.highlight pre code[class*='language-json']::before{
|
||||
content: 'json';
|
||||
background: dodgerblue;
|
||||
color: #000000
|
||||
}
|
||||
.highlight pre code[class*='language-python']::before,
|
||||
.highlight pre code[class*='language-py']::before {
|
||||
content: 'py';
|
||||
background: blue;
|
||||
color: yellow ;
|
||||
}
|
||||
.highlight pre code[class*='language-css']::before{
|
||||
content: 'css';
|
||||
background: cyan;
|
||||
color: black ;
|
||||
}
|
||||
.highlight pre code[class*='language-go']::before{
|
||||
content: 'Go';
|
||||
background: cyan;
|
||||
color: royalblue ;
|
||||
}
|
||||
.highlight pre code[class*='language-md']::before,
|
||||
.highlight pre code[class*='language-md']::before{
|
||||
content: 'Markdown';
|
||||
background: royalblue;
|
||||
color: whitesmoke ;
|
||||
}
|
||||
|
||||
/* table */
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table th{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
table td{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
}
|
@@ -1,333 +0,0 @@
|
||||
/* Markdown */
|
||||
:root{
|
||||
--maincolor: rgb(111, 119, 140);
|
||||
--bordercl:rebeccapurple;
|
||||
--callouctcolor:dodgerblue;
|
||||
--hovercolor:navy;
|
||||
--darkMaincolor: #50fa7b;
|
||||
}
|
||||
html {
|
||||
color: #232333;
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
font-size: 15px;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
body{
|
||||
display: block;
|
||||
margin: 8px;
|
||||
}
|
||||
* {
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: #eef35c;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: 'Fira Sans', sans-serif;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 3px dotted var(--bordercl);
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--bordercl);
|
||||
color: #737373;
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
background-color: var(--hovercolor);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 2ch;
|
||||
}
|
||||
ul li {
|
||||
text-indent: -2ch;
|
||||
}
|
||||
ul > li::before {
|
||||
content: '* ';
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Images */
|
||||
img {
|
||||
border: 3px solid #ececec;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure img {
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
figure {
|
||||
padding: 0 40px;
|
||||
}
|
||||
}
|
||||
|
||||
figure h4 {
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
figure h4::before {
|
||||
content: '↳ ';
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
code {
|
||||
background-color: #f1f1f1;
|
||||
padding: 0em .0.1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #ececec;
|
||||
line-height: 1.4;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.highlight pre ::selection {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
pre code {
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
font-size: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Containers */
|
||||
.content {
|
||||
margin-bottom: 4em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 800px;
|
||||
padding: 0 1ch;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin: 1em 0;
|
||||
line-height: 2.5em;
|
||||
}
|
||||
|
||||
header .main {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-size: 1.2rem;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
h1::before { color: var(--maincolor); content: '# '; }
|
||||
h2::before { color: var(--maincolor); content: '## '; }
|
||||
h3::before { color: var(--maincolor); content: '### '; }
|
||||
h4::before { color: var(--maincolor); content: '#### '; }
|
||||
h5::before { color: var(--maincolor); content: '##### '; }
|
||||
h6::before { color: var(--maincolor); content: '###### '; }
|
||||
|
||||
.meta {
|
||||
color: #999;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-top: 0.4rem dotted var(--bordercl);
|
||||
padding: 2rem 0rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
.soc {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: none;
|
||||
}
|
||||
.border {
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
border: 1px solid;
|
||||
}
|
||||
.footer-info {
|
||||
padding: var(--footer-padding);
|
||||
}
|
||||
|
||||
/* Common */
|
||||
.title h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
time {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
/* Posts */
|
||||
article .title {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
||||
/* Callout */
|
||||
.callout {
|
||||
background-color: var(--callouctcolor);
|
||||
color: #fff;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.callout p {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.callout a {
|
||||
border-bottom: 3px solid #fff;
|
||||
}
|
||||
|
||||
.callout a:hover {
|
||||
background-color: #fff;
|
||||
color: var(--callouctcolor);
|
||||
}
|
||||
|
||||
.site-description {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.tags li::before{
|
||||
content: "🏷 ";
|
||||
}
|
||||
.tags a{
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
}
|
||||
.tags a:hover{
|
||||
color:white;
|
||||
background-color: var(--hovercolor);
|
||||
}
|
||||
svg{
|
||||
max-height: 15px;
|
||||
}
|
||||
.soc:hover{
|
||||
color: white;
|
||||
}
|
||||
.draft-label{
|
||||
color: var(--bordercl);
|
||||
text-decoration: none;
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
margin-left: 6px;
|
||||
background-color: #f9f2f4;
|
||||
}
|
||||
.highlight {
|
||||
position: relative;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"] {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"]::before {
|
||||
background: black;
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.025rem;
|
||||
padding: 0.1rem 0.5rem;
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
text-align: right;
|
||||
text-transform: uppercase;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.highlight pre code[class=language-javaScript]::before,
|
||||
.highlight pre code[class="language-js"]::before {
|
||||
content: "js";
|
||||
background: #f7df1e;
|
||||
color: black;
|
||||
}
|
||||
.highlight pre code[class*='language-yml']::before,
|
||||
.highlight pre code[class*='language-yaml']::before {
|
||||
content: 'yaml';
|
||||
background: #f71e6a;
|
||||
color: white;
|
||||
}
|
||||
.highlight pre code[class*='language-shell']::before,
|
||||
.highlight pre code[class*='language-bash']::before,
|
||||
.highlight pre code[class*='language-sh']::before {
|
||||
content: 'shell';
|
||||
background: green;
|
||||
color:white
|
||||
}
|
||||
.highlight pre code[class*='language-json']::before{
|
||||
content: 'json';
|
||||
background: dodgerblue;
|
||||
color: #000000
|
||||
}
|
||||
.highlight pre code[class*='language-python']::before,
|
||||
.highlight pre code[class*='language-py']::before {
|
||||
content: 'py';
|
||||
background: blue;
|
||||
color: yellow ;
|
||||
}
|
||||
.highlight pre code[class*='language-css']::before{
|
||||
content: 'css';
|
||||
background: cyan;
|
||||
color: black ;
|
||||
}
|
||||
.highlight pre code[class*='language-go']::before{
|
||||
content: 'Go';
|
||||
background: cyan;
|
||||
color: royalblue ;
|
||||
}
|
||||
.highlight pre code[class*='language-md']::before,
|
||||
.highlight pre code[class*='language-md']::before{
|
||||
content: 'Markdown';
|
||||
background: royalblue;
|
||||
color: whitesmoke ;
|
||||
}
|
||||
|
||||
/* table */
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table th{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
table td{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
}
|
@@ -1,334 +0,0 @@
|
||||
/* Markdown */
|
||||
:root{
|
||||
--maincolor: #a15bc2;
|
||||
--bordercl: #a15bc2;
|
||||
--callouctcolor:dodgerblue;
|
||||
--hovercolor: #a15bc2;
|
||||
--darkMaincolor: #a15bc2;
|
||||
}
|
||||
html {
|
||||
color: #232333;
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
font-size: 15px;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
body{
|
||||
display: block;
|
||||
background-color: #f8f8f8;
|
||||
margin: 8px;
|
||||
}
|
||||
* {
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: #eef35c;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: 'Fira Sans', sans-serif;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 3px dotted var(--bordercl);
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--bordercl);
|
||||
color: #737373;
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
background-color: var(--hovercolor);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 2ch;
|
||||
}
|
||||
ul li {
|
||||
text-indent: -2ch;
|
||||
}
|
||||
ul > li::before {
|
||||
content: '* ';
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Images */
|
||||
img {
|
||||
border: 3px solid #ececec;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure img {
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
figure {
|
||||
padding: 0 40px;
|
||||
}
|
||||
}
|
||||
|
||||
figure h4 {
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
figure h4::before {
|
||||
content: '↳ ';
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
code {
|
||||
background-color: #f1f1f1;
|
||||
padding: 0em .0.1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #ececec;
|
||||
line-height: 1.4;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.highlight pre ::selection {
|
||||
background: var(--maincolor);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
pre code {
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
font-size: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Containers */
|
||||
.content {
|
||||
margin-bottom: 4em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 800px;
|
||||
padding: 0 1ch;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin: 1em 0;
|
||||
line-height: 2.5em;
|
||||
}
|
||||
|
||||
header .main {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-size: 1.2rem;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
h1::before { color: var(--maincolor); content: '# '; }
|
||||
h2::before { color: var(--maincolor); content: '## '; }
|
||||
h3::before { color: var(--maincolor); content: '### '; }
|
||||
h4::before { color: var(--maincolor); content: '#### '; }
|
||||
h5::before { color: var(--maincolor); content: '##### '; }
|
||||
h6::before { color: var(--maincolor); content: '###### '; }
|
||||
|
||||
.meta {
|
||||
color: #999;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-top: 0.4rem dotted var(--bordercl);
|
||||
padding: 2rem 0rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
.soc {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: none;
|
||||
}
|
||||
.border {
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
border: 1px solid;
|
||||
}
|
||||
.footer-info {
|
||||
padding: var(--footer-padding);
|
||||
}
|
||||
|
||||
/* Common */
|
||||
.title h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
time {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
/* Posts */
|
||||
article .title {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
||||
/* Callout */
|
||||
.callout {
|
||||
background-color: var(--callouctcolor);
|
||||
color: #fff;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.callout p {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.callout a {
|
||||
border-bottom: 3px solid #fff;
|
||||
}
|
||||
|
||||
.callout a:hover {
|
||||
background-color: #fff;
|
||||
color: var(--callouctcolor);
|
||||
}
|
||||
|
||||
.site-description {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.tags li::before{
|
||||
content: "🏷 ";
|
||||
}
|
||||
.tags a{
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
}
|
||||
.tags a:hover{
|
||||
color:white;
|
||||
background-color: var(--hovercolor);
|
||||
}
|
||||
svg{
|
||||
max-height: 15px;
|
||||
}
|
||||
.soc:hover{
|
||||
color: white;
|
||||
}
|
||||
.draft-label{
|
||||
color: var(--bordercl);
|
||||
text-decoration: none;
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
margin-left: 6px;
|
||||
background-color: #f9f2f4;
|
||||
}
|
||||
.highlight {
|
||||
position: relative;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"] {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"]::before {
|
||||
background: black;
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.025rem;
|
||||
padding: 0.1rem 0.5rem;
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
text-align: right;
|
||||
text-transform: uppercase;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.highlight pre code[class=language-javaScript]::before,
|
||||
.highlight pre code[class="language-js"]::before {
|
||||
content: "js";
|
||||
background: #f7df1e;
|
||||
color: black;
|
||||
}
|
||||
.highlight pre code[class*='language-yml']::before,
|
||||
.highlight pre code[class*='language-yaml']::before {
|
||||
content: 'yaml';
|
||||
background: #f71e6a;
|
||||
color: white;
|
||||
}
|
||||
.highlight pre code[class*='language-shell']::before,
|
||||
.highlight pre code[class*='language-bash']::before,
|
||||
.highlight pre code[class*='language-sh']::before {
|
||||
content: 'shell';
|
||||
background: green;
|
||||
color:white
|
||||
}
|
||||
.highlight pre code[class*='language-json']::before{
|
||||
content: 'json';
|
||||
background: dodgerblue;
|
||||
color: #000000
|
||||
}
|
||||
.highlight pre code[class*='language-python']::before,
|
||||
.highlight pre code[class*='language-py']::before {
|
||||
content: 'py';
|
||||
background: blue;
|
||||
color: yellow ;
|
||||
}
|
||||
.highlight pre code[class*='language-css']::before{
|
||||
content: 'css';
|
||||
background: cyan;
|
||||
color: black ;
|
||||
}
|
||||
.highlight pre code[class*='language-go']::before{
|
||||
content: 'Go';
|
||||
background: cyan;
|
||||
color: royalblue ;
|
||||
}
|
||||
.highlight pre code[class*='language-md']::before,
|
||||
.highlight pre code[class*='language-md']::before{
|
||||
content: 'Markdown';
|
||||
background: royalblue;
|
||||
color: whitesmoke ;
|
||||
}
|
||||
|
||||
/* table */
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table th{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
table td{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
}
|
@@ -1,334 +0,0 @@
|
||||
/* Markdown */
|
||||
:root{
|
||||
--maincolor: #a15bc2;
|
||||
--bordercl: #a15bc2;
|
||||
--callouctcolor:dodgerblue;
|
||||
--hovercolor:navy;
|
||||
--darkMaincolor: #a15bc2;
|
||||
}
|
||||
html {
|
||||
color: #232333;
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
font-size: 15px;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
body{
|
||||
display: block;
|
||||
background-color: #f8f8f8;
|
||||
margin: 8px;
|
||||
}
|
||||
* {
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: #eef35c;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: 'Fira Sans', sans-serif;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 3px dotted var(--bordercl);
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--bordercl);
|
||||
color: #737373;
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
background-color: var(--hovercolor);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 2ch;
|
||||
}
|
||||
ul li {
|
||||
text-indent: -2ch;
|
||||
}
|
||||
ul > li::before {
|
||||
content: '* ';
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Images */
|
||||
img {
|
||||
border: 3px solid #ececec;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure img {
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
figure {
|
||||
padding: 0 40px;
|
||||
}
|
||||
}
|
||||
|
||||
figure h4 {
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
figure h4::before {
|
||||
content: '↳ ';
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
code {
|
||||
background-color: #f1f1f1;
|
||||
padding: 0em .0.1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #ececec;
|
||||
line-height: 1.4;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.highlight pre ::selection {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
pre code {
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
font-size: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Containers */
|
||||
.content {
|
||||
margin-bottom: 4em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 800px;
|
||||
padding: 0 1ch;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin: 1em 0;
|
||||
line-height: 2.5em;
|
||||
}
|
||||
|
||||
header .main {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-size: 1.2rem;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
h1::before { color: var(--maincolor); content: '# '; }
|
||||
h2::before { color: var(--maincolor); content: '## '; }
|
||||
h3::before { color: var(--maincolor); content: '### '; }
|
||||
h4::before { color: var(--maincolor); content: '#### '; }
|
||||
h5::before { color: var(--maincolor); content: '##### '; }
|
||||
h6::before { color: var(--maincolor); content: '###### '; }
|
||||
|
||||
.meta {
|
||||
color: #999;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-top: 0.4rem dotted var(--bordercl);
|
||||
padding: 2rem 0rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
.soc {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: none;
|
||||
}
|
||||
.border {
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
border: 1px solid;
|
||||
}
|
||||
.footer-info {
|
||||
padding: var(--footer-padding);
|
||||
}
|
||||
|
||||
/* Common */
|
||||
.title h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
time {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
/* Posts */
|
||||
article .title {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
||||
/* Callout */
|
||||
.callout {
|
||||
background-color: var(--callouctcolor);
|
||||
color: #fff;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.callout p {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.callout a {
|
||||
border-bottom: 3px solid #fff;
|
||||
}
|
||||
|
||||
.callout a:hover {
|
||||
background-color: #fff;
|
||||
color: var(--callouctcolor);
|
||||
}
|
||||
|
||||
.site-description {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.tags li::before{
|
||||
content: "🏷 ";
|
||||
}
|
||||
.tags a{
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
}
|
||||
.tags a:hover{
|
||||
color:white;
|
||||
background-color: var(--hovercolor);
|
||||
}
|
||||
svg{
|
||||
max-height: 15px;
|
||||
}
|
||||
.soc:hover{
|
||||
color: white;
|
||||
}
|
||||
.draft-label{
|
||||
color: var(--bordercl);
|
||||
text-decoration: none;
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
margin-left: 6px;
|
||||
background-color: #f9f2f4;
|
||||
}
|
||||
.highlight {
|
||||
position: relative;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"] {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"]::before {
|
||||
background: black;
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.025rem;
|
||||
padding: 0.1rem 0.5rem;
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
text-align: right;
|
||||
text-transform: uppercase;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.highlight pre code[class=language-javaScript]::before,
|
||||
.highlight pre code[class="language-js"]::before {
|
||||
content: "js";
|
||||
background: #f7df1e;
|
||||
color: black;
|
||||
}
|
||||
.highlight pre code[class*='language-yml']::before,
|
||||
.highlight pre code[class*='language-yaml']::before {
|
||||
content: 'yaml';
|
||||
background: #f71e6a;
|
||||
color: white;
|
||||
}
|
||||
.highlight pre code[class*='language-shell']::before,
|
||||
.highlight pre code[class*='language-bash']::before,
|
||||
.highlight pre code[class*='language-sh']::before {
|
||||
content: 'shell';
|
||||
background: green;
|
||||
color:white
|
||||
}
|
||||
.highlight pre code[class*='language-json']::before{
|
||||
content: 'json';
|
||||
background: dodgerblue;
|
||||
color: #000000
|
||||
}
|
||||
.highlight pre code[class*='language-python']::before,
|
||||
.highlight pre code[class*='language-py']::before {
|
||||
content: 'py';
|
||||
background: blue;
|
||||
color: yellow ;
|
||||
}
|
||||
.highlight pre code[class*='language-css']::before{
|
||||
content: 'css';
|
||||
background: cyan;
|
||||
color: black ;
|
||||
}
|
||||
.highlight pre code[class*='language-go']::before{
|
||||
content: 'Go';
|
||||
background: cyan;
|
||||
color: royalblue ;
|
||||
}
|
||||
.highlight pre code[class*='language-md']::before,
|
||||
.highlight pre code[class*='language-md']::before{
|
||||
content: 'Markdown';
|
||||
background: royalblue;
|
||||
color: whitesmoke ;
|
||||
}
|
||||
|
||||
/* table */
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table th{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
table td{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
}
|
@@ -1,333 +0,0 @@
|
||||
/* Markdown */
|
||||
:root{
|
||||
--maincolor: rgb(111, 119, 140);
|
||||
--bordercl:rebeccapurple;
|
||||
--callouctcolor:dodgerblue;
|
||||
--hovercolor:navy;
|
||||
--darkMaincolor: #50fa7b;
|
||||
}
|
||||
html {
|
||||
color: #232333;
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
font-size: 15px;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
body{
|
||||
display: block;
|
||||
margin: 8px;
|
||||
}
|
||||
* {
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--maincolor);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: 'Fira Sans', sans-serif;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 3px dotted var(--bordercl);
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--bordercl);
|
||||
color: #737373;
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
background-color: var(--hovercolor);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 2ch;
|
||||
}
|
||||
ul li {
|
||||
text-indent: -2ch;
|
||||
}
|
||||
ul > li::before {
|
||||
content: '* ';
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Images */
|
||||
img {
|
||||
border: 3px solid #ececec;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure img {
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
figure {
|
||||
padding: 0 40px;
|
||||
}
|
||||
}
|
||||
|
||||
figure h4 {
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
figure h4::before {
|
||||
content: '↳ ';
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
code {
|
||||
background-color: #f1f1f1;
|
||||
padding: .1em .2em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #ececec;
|
||||
line-height: 1.4;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.highlight pre ::selection {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
pre code {
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
font-size: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Containers */
|
||||
.content {
|
||||
margin-bottom: 4em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 800px;
|
||||
padding: 0 1ch;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin: 1em 0;
|
||||
line-height: 2.5em;
|
||||
}
|
||||
|
||||
header .main {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-size: 1.2rem;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
h1::before { color: var(--maincolor); content: '# '; }
|
||||
h2::before { color: var(--maincolor); content: '## '; }
|
||||
h3::before { color: var(--maincolor); content: '### '; }
|
||||
h4::before { color: var(--maincolor); content: '#### '; }
|
||||
h5::before { color: var(--maincolor); content: '##### '; }
|
||||
h6::before { color: var(--maincolor); content: '###### '; }
|
||||
|
||||
.meta {
|
||||
color: #999;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-top: 0.4rem dotted var(--bordercl);
|
||||
padding: 2rem 0rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
.soc {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: none;
|
||||
}
|
||||
.border {
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
border: 1px solid;
|
||||
}
|
||||
.footer-info {
|
||||
padding: var(--footer-padding);
|
||||
}
|
||||
|
||||
/* Common */
|
||||
.title h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
time {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
/* Posts */
|
||||
article .title {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
||||
/* Callout */
|
||||
.callout {
|
||||
background-color: var(--callouctcolor);
|
||||
color: #fff;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.callout p {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.callout a {
|
||||
border-bottom: 3px solid #fff;
|
||||
}
|
||||
|
||||
.callout a:hover {
|
||||
background-color: #fff;
|
||||
color: var(--callouctcolor);
|
||||
}
|
||||
|
||||
.site-description {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.tags li::before{
|
||||
content: "🏷 ";
|
||||
}
|
||||
.tags a{
|
||||
border-bottom: 3px solid var(--maincolor);
|
||||
}
|
||||
.tags a:hover{
|
||||
color:white;
|
||||
background-color: var(--hovercolor);
|
||||
}
|
||||
svg{
|
||||
max-height: 15px;
|
||||
}
|
||||
.soc:hover{
|
||||
color: white;
|
||||
}
|
||||
.draft-label{
|
||||
color: var(--bordercl);
|
||||
text-decoration: none;
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
margin-left: 6px;
|
||||
background-color: #f9f2f4;
|
||||
}
|
||||
.highlight {
|
||||
position: relative;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"] {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.highlight pre code[class*="language-"]::before {
|
||||
background: black;
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.025rem;
|
||||
padding: 0.1rem 0.5rem;
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
text-align: right;
|
||||
text-transform: uppercase;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.highlight pre code[class=language-javaScript]::before,
|
||||
.highlight pre code[class="language-js"]::before {
|
||||
content: "js";
|
||||
background: #f7df1e;
|
||||
color: black;
|
||||
}
|
||||
.highlight pre code[class*='language-yml']::before,
|
||||
.highlight pre code[class*='language-yaml']::before {
|
||||
content: 'yaml';
|
||||
background: #f71e6a;
|
||||
color: white;
|
||||
}
|
||||
.highlight pre code[class*='language-shell']::before,
|
||||
.highlight pre code[class*='language-bash']::before,
|
||||
.highlight pre code[class*='language-sh']::before {
|
||||
content: 'shell';
|
||||
background: green;
|
||||
color:white
|
||||
}
|
||||
.highlight pre code[class*='language-json']::before{
|
||||
content: 'json';
|
||||
background: dodgerblue;
|
||||
color: #000000
|
||||
}
|
||||
.highlight pre code[class*='language-python']::before,
|
||||
.highlight pre code[class*='language-py']::before {
|
||||
content: 'py';
|
||||
background: blue;
|
||||
color: yellow ;
|
||||
}
|
||||
.highlight pre code[class*='language-css']::before{
|
||||
content: 'css';
|
||||
background: cyan;
|
||||
color: black ;
|
||||
}
|
||||
.highlight pre code[class*='language-go']::before{
|
||||
content: 'Go';
|
||||
background: cyan;
|
||||
color: royalblue ;
|
||||
}
|
||||
.highlight pre code[class*='language-md']::before,
|
||||
.highlight pre code[class*='language-md']::before{
|
||||
content: 'Markdown';
|
||||
background: royalblue;
|
||||
color: whitesmoke ;
|
||||
}
|
||||
|
||||
/* table */
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table th{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
table td{
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
}
|
Before Width: | Height: | Size: 970 B |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 448 B |
Before Width: | Height: | Size: 268 KiB |
@@ -1,180 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="generator" content="Hugo 0.111.3">
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>davegallant | Home </title><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<link rel="alternate" type="application/rss+xml" href="/index.xml" title="davegallant" />
|
||||
<meta property="og:title" content="davegallant" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="/" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="davegallant"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.ac08a4c9714baa859217f92f051deb58df2938ec352b506df655005dcaf98cc0.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css" media="(prefers-color-scheme: dark)" />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="content">
|
||||
<header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/posts">All posts</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
|
||||
<main class="list">
|
||||
<div class="site-description"><p>Personal blog</p></div>
|
||||
|
||||
|
||||
|
||||
<section class="list-item">
|
||||
<h1 class="title"><a href="/post/automatically-rotating-aws-keys/">Automatically Rotating AWS Access Keys</a></h1>
|
||||
<time>Sep 17, 2021</time>
|
||||
<br><div class="description">
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<a class="readmore" href="/post/automatically-rotating-aws-keys/">Read more ⟶</a>
|
||||
</section>
|
||||
|
||||
<section class="list-item">
|
||||
<h1 class="title"><a href="/post/why-i-threw-out-my-dotfiles/">Why I Threw Out My Dotfiles</a></h1>
|
||||
<time>Sep 8, 2021</time>
|
||||
<br><div class="description">
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<a class="readmore" href="/post/why-i-threw-out-my-dotfiles/">Read more ⟶</a>
|
||||
</section>
|
||||
|
||||
<section class="list-item">
|
||||
<h1 class="title"><a href="/post/what-to-do-with-a-homelab/">What To Do With A Homelab</a></h1>
|
||||
<time>Sep 6, 2021</time>
|
||||
<br><div class="description">
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<a class="readmore" href="/post/what-to-do-with-a-homelab/">Read more ⟶</a>
|
||||
</section>
|
||||
|
||||
<section class="list-item">
|
||||
<h1 class="title"><a href="/post/appgate-sdp-on-arch-linux/">AppGate SDP on Arch Linux</a></h1>
|
||||
<time>Mar 16, 2020</time>
|
||||
<br><div class="description">
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<a class="readmore" href="/post/appgate-sdp-on-arch-linux/">Read more ⟶</a>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<ul class="pagination">
|
||||
<span class="page-item page-prev">
|
||||
|
||||
<a href="/" class="page-link" aria-label="Previous"><span aria-hidden="true">← Prev</span></a>
|
||||
|
||||
</span>
|
||||
<span class="page-item page-next">
|
||||
|
||||
</span>
|
||||
</ul>
|
||||
|
||||
|
||||
</main>
|
||||
<footer>
|
||||
<div style="display:flex"></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant | <a
|
||||
href="https://github.com/athul/archie">Archie Theme</a> | Built with <a href="https://gohugo.io">Hugo</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script type="application/javascript">
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-98710982-2', 'auto');
|
||||
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/page/</title>
|
||||
<link rel="canonical" href="/page/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/page/">
|
||||
</head>
|
||||
</html>
|
@@ -1,246 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>AppGate SDP on Arch Linux - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="AppGate SDP provides a Zero Trust network. This post describes how to get AppGate SDP 4.3.2 working on Arch Linux." />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="AppGate SDP on Arch Linux" />
|
||||
<meta property="og:description" content="AppGate SDP provides a Zero Trust network. This post describes how to get AppGate SDP 4.3.2 working on Arch Linux." />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/post/appgate-sdp-on-arch-linux/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2020-03-16T22:00:15-04:00" />
|
||||
<meta property="article:modified_time" content="2020-03-16T22:00:15-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="AppGate SDP on Arch Linux"/>
|
||||
<meta name="twitter:description" content="AppGate SDP provides a Zero Trust network. This post describes how to get AppGate SDP 4.3.2 working on Arch Linux."/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.f7354ef8ed840429a37397307f3d9872782673d6b91d714b3f600b210d91fbaf.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">AppGate SDP on Arch Linux</h1>
|
||||
<div class="meta">Posted on Mar 16, 2020</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>AppGate SDP provides a Zero Trust network. This post describes how to get AppGate SDP <code>4.3.2</code> working on Arch Linux.</p>
|
||||
<p>Depending on the AppGate SDP Server that is running, you may require a client that is more recent than the latest package on <a href="https://aur.archlinux.org/packages/appgate-sdp/">AUR</a>.
|
||||
As of right now, the latest AUR is <code>4.2.2-1</code>.</p>
|
||||
<p>These steps highlight how to get it working with <code>Python3.8</code> by making a 1 line modification to AppGate source code.</p>
|
||||
<h1 id="packaging">Packaging</h1>
|
||||
<p>We already know the community package is currently out of date, so let’s clone it:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>git clone https://aur.archlinux.org/appgate-sdp.git
|
||||
</span></span><span style="display:flex;"><span>cd appgate-sdp
|
||||
</span></span></code></pre></div><p>You’ll likely notice that the version is not what we want, so let’s modify the <code>PKGBUILD</code> to the following:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># Maintainer: Pawel Mosakowski <pawel at mosakowski dot net></span>
|
||||
</span></span><span style="display:flex;"><span>pkgname<span style="color:#f92672">=</span>appgate-sdp
|
||||
</span></span><span style="display:flex;"><span>conflicts<span style="color:#f92672">=(</span><span style="color:#e6db74">'appgate-sdp-headless'</span><span style="color:#f92672">)</span>
|
||||
</span></span><span style="display:flex;"><span>pkgver<span style="color:#f92672">=</span>4.3.2
|
||||
</span></span><span style="display:flex;"><span>_download_pkgver<span style="color:#f92672">=</span>4.3
|
||||
</span></span><span style="display:flex;"><span>pkgrel<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span>
|
||||
</span></span><span style="display:flex;"><span>epoch<span style="color:#f92672">=</span>
|
||||
</span></span><span style="display:flex;"><span>pkgdesc<span style="color:#f92672">=</span><span style="color:#e6db74">"Software Defined Perimeter - GUI client"</span>
|
||||
</span></span><span style="display:flex;"><span>arch<span style="color:#f92672">=(</span><span style="color:#e6db74">'x86_64'</span><span style="color:#f92672">)</span>
|
||||
</span></span><span style="display:flex;"><span>url<span style="color:#f92672">=</span><span style="color:#e6db74">"https://www.cyxtera.com/essential-defense/appgate-sdp/support"</span>
|
||||
</span></span><span style="display:flex;"><span>license<span style="color:#f92672">=(</span><span style="color:#e6db74">'custom'</span><span style="color:#f92672">)</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># dependecies calculated by namcap</span>
|
||||
</span></span><span style="display:flex;"><span>depends<span style="color:#f92672">=(</span><span style="color:#e6db74">'gconf'</span> <span style="color:#e6db74">'libsecret'</span> <span style="color:#e6db74">'gtk3'</span> <span style="color:#e6db74">'python'</span> <span style="color:#e6db74">'nss'</span> <span style="color:#e6db74">'libxss'</span> <span style="color:#e6db74">'nodejs'</span> <span style="color:#e6db74">'dnsmasq'</span><span style="color:#f92672">)</span>
|
||||
</span></span><span style="display:flex;"><span>source<span style="color:#f92672">=(</span><span style="color:#e6db74">"https://sdpdownloads.cyxtera.com/AppGate-SDP-</span><span style="color:#e6db74">${</span>_download_pkgver<span style="color:#e6db74">}</span><span style="color:#e6db74">/clients/</span><span style="color:#e6db74">${</span>pkgname<span style="color:#e6db74">}</span><span style="color:#e6db74">_</span><span style="color:#e6db74">${</span>pkgver<span style="color:#e6db74">}</span><span style="color:#e6db74">_amd64.deb"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"appgatedriver.service"</span><span style="color:#f92672">)</span>
|
||||
</span></span><span style="display:flex;"><span>options<span style="color:#f92672">=(</span>staticlibs<span style="color:#f92672">)</span>
|
||||
</span></span><span style="display:flex;"><span>prepare<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
|
||||
</span></span><span style="display:flex;"><span> tar -xf data.tar.xz
|
||||
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
|
||||
</span></span><span style="display:flex;"><span>package<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
|
||||
</span></span><span style="display:flex;"><span> cp -dpr <span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>srcdir<span style="color:#e6db74">}</span><span style="color:#e6db74">"</span>/<span style="color:#f92672">{</span>etc,lib,opt,usr<span style="color:#f92672">}</span> <span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>pkgdir<span style="color:#e6db74">}</span><span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span> mv -v <span style="color:#e6db74">"</span>$pkgdir<span style="color:#e6db74">/lib/systemd/system"</span> <span style="color:#e6db74">"</span>$pkgdir<span style="color:#e6db74">/usr/lib/systemd/"</span>
|
||||
</span></span><span style="display:flex;"><span> rm -vrf <span style="color:#e6db74">"</span>$pkgdir<span style="color:#e6db74">/lib"</span>
|
||||
</span></span><span style="display:flex;"><span> cp -v <span style="color:#e6db74">"</span>$srcdir<span style="color:#e6db74">/appgatedriver.service"</span> <span style="color:#e6db74">"</span>$pkgdir<span style="color:#e6db74">/usr/lib/systemd/system/appgatedriver.service"</span>
|
||||
</span></span><span style="display:flex;"><span> mkdir -vp <span style="color:#e6db74">"</span>$pkgdir<span style="color:#e6db74">/usr/share/licenses/appgate-sdp"</span>
|
||||
</span></span><span style="display:flex;"><span> cp -v <span style="color:#e6db74">"</span>$pkgdir<span style="color:#e6db74">/usr/share/doc/appgate/copyright"</span> <span style="color:#e6db74">"</span>$pkgdir<span style="color:#e6db74">/usr/share/licenses/appgate-sdp"</span>
|
||||
</span></span><span style="display:flex;"><span> cp -v <span style="color:#e6db74">"</span>$pkgdir<span style="color:#e6db74">/usr/share/doc/appgate/LICENSE.github"</span> <span style="color:#e6db74">"</span>$pkgdir<span style="color:#e6db74">/usr/share/licenses/appgate-sdp"</span>
|
||||
</span></span><span style="display:flex;"><span> cp -v <span style="color:#e6db74">"</span>$pkgdir<span style="color:#e6db74">/usr/share/doc/appgate/LICENSES.chromium.html.bz2"</span> <span style="color:#e6db74">"</span>$pkgdir<span style="color:#e6db74">/usr/share/licenses/appgate-sdp"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
|
||||
</span></span><span style="display:flex;"><span>md5sums<span style="color:#f92672">=(</span><span style="color:#e6db74">'17101aac7623c06d5fbb95f50cf3dbdc'</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'002644116e20b2d79fdb36b7677ab4cf'</span><span style="color:#f92672">)</span>
|
||||
</span></span></code></pre></div><p>Let’s first make sure we have some dependencies. If you do not have <a href="https://github.com/Jguer/yay">yay</a>, check it out.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>yay -S dnsmasq gconf
|
||||
</span></span></code></pre></div><p>Now, let’s install it:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>makepkg -si
|
||||
</span></span></code></pre></div><h1 id="running-the-client">Running the client</h1>
|
||||
<p>Ok, let’s run the client by executing <code>appgate</code>.</p>
|
||||
<p>It complains about not being able to connect.</p>
|
||||
<p>Easy fix:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo systemctl start appgatedriver.service
|
||||
</span></span></code></pre></div><p>Now we should be connected… but DNS is not working?</p>
|
||||
<h1 id="fixing-the-dns">Fixing the DNS</h1>
|
||||
<p>Running <code>resolvectl</code> should display that something is not right.</p>
|
||||
<p>Why is the DNS not being set by appgate?</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ head -3 /opt/appgate/linux/set_dns
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e">#!/usr/bin/env python3</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#e6db74">''</span><span style="color:#960050;background-color:#1e0010">'</span>
|
||||
</span></span><span style="display:flex;"><span>This is used to set and unset the DNS.
|
||||
</span></span></code></pre></div><p>It seems like python3 is required for the DNS setting to happen.
|
||||
Let’s try to run it.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ sudo /opt/appgate/linux/set_dns
|
||||
</span></span><span style="display:flex;"><span>/opt/appgate/linux/set_dns:88: SyntaxWarning: <span style="color:#e6db74">"is"</span> with a literal. Did you mean <span style="color:#e6db74">"=="</span>?
|
||||
</span></span><span style="display:flex;"><span> servers <span style="color:#f92672">=</span> <span style="color:#f92672">[(</span> socket.AF_INET <span style="color:#66d9ef">if</span> x.version is <span style="color:#ae81ff">4</span> <span style="color:#66d9ef">else</span> socket.AF_INET6, map<span style="color:#f92672">(</span>int, x.packed<span style="color:#f92672">))</span> <span style="color:#66d9ef">for</span> x in servers<span style="color:#f92672">]</span>
|
||||
</span></span><span style="display:flex;"><span>Traceback <span style="color:#f92672">(</span>most recent call last<span style="color:#f92672">)</span>:
|
||||
</span></span><span style="display:flex;"><span> File <span style="color:#e6db74">"/opt/appgate/linux/set_dns"</span>, line 30, in <module>
|
||||
</span></span><span style="display:flex;"><span> import dbus
|
||||
</span></span><span style="display:flex;"><span>ModuleNotFoundError: No module named <span style="color:#e6db74">'dbus'</span>
|
||||
</span></span></code></pre></div><p>Ok, let’s install it:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ sudo python3.8 -m pip install dbus-python
|
||||
</span></span></code></pre></div><p>Will it work now? Not yet. There’s another issue:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ sudo /opt/appgate/linux/set_dns
|
||||
</span></span><span style="display:flex;"><span>/opt/appgate/linux/set_dns:88: SyntaxWarning: <span style="color:#e6db74">"is"</span> with a literal. Did you mean <span style="color:#e6db74">"=="</span>?
|
||||
</span></span><span style="display:flex;"><span> servers <span style="color:#f92672">=</span> <span style="color:#f92672">[(</span> socket.AF_INET <span style="color:#66d9ef">if</span> x.version is <span style="color:#ae81ff">4</span> <span style="color:#66d9ef">else</span> socket.AF_INET6, map<span style="color:#f92672">(</span>int, x.packed<span style="color:#f92672">))</span> <span style="color:#66d9ef">for</span> x in servers<span style="color:#f92672">]</span>
|
||||
</span></span><span style="display:flex;"><span>module <span style="color:#e6db74">'platform'</span> has no attribute <span style="color:#e6db74">'linux_distribution'</span>
|
||||
</span></span></code></pre></div><p>This is a breaking change in Python3.8.</p>
|
||||
<p>So what is calling <code>platform.linux_distribution</code>?</p>
|
||||
<p>Let’s search for it:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ sudo grep -r <span style="color:#e6db74">'linux_distribution'</span> /opt/appgate/linux/
|
||||
</span></span><span style="display:flex;"><span>/opt/appgate/linux/nm.py: <span style="color:#66d9ef">if</span> platform.linux_distribution<span style="color:#f92672">()[</span>0<span style="color:#f92672">]</span> !<span style="color:#f92672">=</span> <span style="color:#e6db74">'Fedora'</span>:
|
||||
</span></span></code></pre></div><p>Aha! So this is in the local AppGate source code. This should be an easy fix. Let’s just replace this line with:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">True</span>: <span style="color:#75715e"># Since we are not using Fedora :)</span>
|
||||
</span></span></code></pre></div><h1 id="wrapping-up">Wrapping up</h1>
|
||||
<p>It turns out there are <a href="https://docs.python.org/3.7/library/platform.html#platform.linux_distribution">breaking changes</a> in Python3.8.</p>
|
||||
<p>The docs say <code>Deprecated since version 3.5, will be removed in version 3.8: See alternative like the distro package.</code></p>
|
||||
<p>I suppose this highlights one of the caveats of relying upon the system’s python, rather than having an isolated, dedicated environment for all dependencies.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/linux">linux</a></li>
|
||||
|
||||
<li><a href="/tags/vpn">vpn</a></li>
|
||||
|
||||
<li><a href="/tags/python">python</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments-area'><script src='https://utteranc.es/client.js'
|
||||
repo='davegallant/davegallant.github.io'
|
||||
issue-term='pathname'
|
||||
|
||||
theme='github-light'
|
||||
crossorigin='anonymous' async>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://twitter.com/davega11ant/" rel="me" title="Twitter"><i data-feather="twitter"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://fosstodon.org/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant | Theme based on <a
|
||||
href="https://github.com/athul/archie">Archie</a> | Built with <a href="https://gohugo.io">Hugo</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script type="application/javascript">
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-98710982-2', 'auto');
|
||||
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,166 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Automatically Rotating AWS Access Keys - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Automatically Rotating AWS Access Keys" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/post/automatically-rotating-aws-keys/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2021-09-17T12:48:33-04:00" />
|
||||
<meta property="article:modified_time" content="2021-09-17T12:48:33-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Automatically Rotating AWS Access Keys"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.f7354ef8ed840429a37397307f3d9872782673d6b91d714b3f600b210d91fbaf.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Automatically Rotating AWS Access Keys</h1>
|
||||
<div class="meta">Posted on Sep 17, 2021</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>Rotating credentials is a security best practice. This morning, I read a question about automatically rotating AWS Access Keys without having to go through the hassle of navigating the AWS console. There are some existing solutions already, but I decided to write a <a href="https://gist.github.com/davegallant/2c042686a78684a657fe99e20fa7a924#file-aws_access_key_rotator-py">script</a> since it was incredibly simple. The script could be packed up as a systemd/launchd service to continually rotate access keys in the background.</p>
|
||||
<p>In the longer term, migrating my local workflows to <a href="https://github.com/99designs/aws-vault">aws-vault</a> seems like a more secure solution. This would mean that credentials (even temporary session credentials) never have to be written in plaintext to disk (i.e. where <a href="https://docs.aws.amazon.com/sdkref/latest/guide/file-location.html">AWS suggests</a>). Any existing applications, such as terraform, could be have their credentials passed to them from aws-vault, which retrieves them from the OS’s secure keystore. There is even a <a href="https://github.com/99designs/aws-vault/blob/master/USAGE.md#rotating-credentials">rotate command</a> included.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/aws">aws</a></li>
|
||||
|
||||
<li><a href="/tags/python">python</a></li>
|
||||
|
||||
<li><a href="/tags/security">security</a></li>
|
||||
|
||||
<li><a href="/tags/aws-vault">aws-vault</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments-area'><script src='https://utteranc.es/client.js'
|
||||
repo='davegallant/davegallant.github.io'
|
||||
issue-term='pathname'
|
||||
|
||||
theme='github-light'
|
||||
crossorigin='anonymous' async>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://twitter.com/davega11ant/" rel="me" title="Twitter"><i data-feather="twitter"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://fosstodon.org/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant | Theme based on <a
|
||||
href="https://github.com/athul/archie">Archie</a> | Built with <a href="https://gohugo.io">Hugo</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script type="application/javascript">
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-98710982-2', 'auto');
|
||||
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,186 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Backing Up Gmail With Synology - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Backing Up Gmail With Synology" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/post/backing-up-gmail-with-synology/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2022-03-13T18:49:10-04:00" />
|
||||
<meta property="article:modified_time" content="2022-03-13T18:49:10-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Backing Up Gmail With Synology"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.f7354ef8ed840429a37397307f3d9872782673d6b91d714b3f600b210d91fbaf.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Backing Up Gmail With Synology</h1>
|
||||
<div class="meta">Posted on Mar 13, 2022</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>I’ve used gmail since the beta launched touting a whopping 1GB of storage. I thought this was a massive leap in email technology at the time. I was lucky enough to get an invite fairly quickly. Not suprisingly, I have many years of emails, attachments, and photos. I certainly do not want to lose the content of many of these emails. Despite the redundancy of the data that Google secures, I still feel better retaining a copy of this data on my own physical machines.</p>
|
||||
<p>The thought of completely de-googling has crossed my mind on occassion. Convenience, coupled with my admiration for Google engineering, has prevented me from doing so thus far. Though, I may end up doing so at some point in the future.</p>
|
||||
<h2 id="synology-mailplus-server">Synology MailPlus Server<a href="#synology-mailplus-server" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Synology products are reasonably priced for what you get (essentially a cloud-in-a-box) and there is very little maintenance required. I’ve recently been in interested in syncing and snapshotting my personal data. I’ve setup <a href="https://www.synology.com/en-ca/dsm/feature/cloud_sync">Synology’s Cloud Sync</a> and keep copies of most of my cloud data.</p>
|
||||
<p>I’ve used tools such as <a href="http://www.gmvault.org">gmvault</a> with success in the past. Setting this up on a cron seems like a viable option. However, I don’t really need a lot of the features it offers and do not plan to restore this data to another account.</p>
|
||||
<p>Synology’s MailPlus seems to be a good candidate for backing up this data. By enabling POP3 fetching, it’s possible to fetch all existing emails, as well as periodically fetch all new emails. If a disaster ever did occur, having these emails would be beneficial, as they are an extension of my memory bank.</p>
|
||||
<p>Installing MailPlus can be done from the Package Center:</p>
|
||||
<p><img src="/images/backing-up-gmail-with-synology/install-mailplus-server.png" alt="image"></p>
|
||||
<p>Next, I went into <strong>Synology MailPlus Server</strong> and on the left, clicked on <strong>Account</strong> and ensured my user was marked as active.</p>
|
||||
<p>Afterwords, I followed <a href="https://kb.synology.com/en-in/DSM/tutorial/How_should_I_receive_external_email_messages_via_MailPlus">these instructions</a> in order to start backing up emails.</p>
|
||||
<p>When entering the POP3 credentials, I created an <a href="https://myaccount.google.com/apppasswords">app password</a> solely for authenticating to POP3 from the Synology device. This is required because I have 2-Step verification enabled on my account. There doesn’t seem to be a more secure way to access POP3 at the moment. It does seem like app password access is limited in scope (when MFA is enabled). These app passwords can’t be used to login to the main Google account.</p>
|
||||
<p>I made sure to set the <code>Fetch Range</code> to <code>All</code> in order to get all emails from the beginning of time.</p>
|
||||
<p>After this, mail started coming in.</p>
|
||||
<p><img src="/images/backing-up-gmail-with-synology/mail-plus-incoming-mail.png" alt="image"></p>
|
||||
<p>After fetching 19 years worth of emails, I tried searching for some emails. It only took a few seconds to search through ~50K emails, which is a relief if I ever did have to search for something important.</p>
|
||||
<h2 id="securing-synology">Securing Synology<a href="#securing-synology" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Since Synology devices are not hermetically sealed, it’s best to secure them by <a href="https://kb.synology.com/en-us/DSM/tutorial/How_to_add_extra_security_to_your_Synology_NAS#x_anchor_id8">enabling MFA</a> to help prevent being the <a href="https://www.bleepingcomputer.com/news/security/qlocker-ransomware-returns-to-target-qnap-nas-devices-worldwide/">victim of ransomware</a>. It is also wise to backup your system settings and volumes to the cloud using a tool such as <a href="https://www.synology.com/en-ca/dsm/feature/hyper_backup">Hyper Backup</a>.
|
||||
Encrypting your shared volumes should also be done, since unfortunately <a href="https://community.synology.com/enu/forum/12/post/144665">DSM does not support full disk encryption</a>.</p>
|
||||
<h2 id="summary">Summary<a href="#summary" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Having backups of various forms of cloud data is a good investment, especially in <a href="https://en.wikipedia.org/wiki/2022_Ukraine_cyberattacks">times of war</a>. I certainly feel more at ease for having backed up my emails.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/degoogle">degoogle</a></li>
|
||||
|
||||
<li><a href="/tags/synology">synology</a></li>
|
||||
|
||||
<li><a href="/tags/gmail">gmail</a></li>
|
||||
|
||||
<li><a href="/tags/backup">backup</a></li>
|
||||
|
||||
<li><a href="/tags/ransomware">ransomware</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments-area'><script src='https://utteranc.es/client.js'
|
||||
repo='davegallant/davegallant.github.io'
|
||||
issue-term='pathname'
|
||||
|
||||
theme='github-light'
|
||||
crossorigin='anonymous' async>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://twitter.com/davega11ant/" rel="me" title="Twitter"><i data-feather="twitter"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://fosstodon.org/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant | Theme based on <a
|
||||
href="https://github.com/athul/archie">Archie</a> | Built with <a href="https://gohugo.io">Hugo</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script type="application/javascript">
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-98710982-2', 'auto');
|
||||
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/post/</title>
|
||||
<link rel="canonical" href="/post/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/post/">
|
||||
</head>
|
||||
</html>
|
@@ -1,243 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Replacing docker with podman on macOS (and Linux) - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Replacing docker with podman on macOS (and Linux)" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/post/replacing-docker-with-podman-on-macos/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2021-10-11T10:43:35-04:00" />
|
||||
<meta property="article:modified_time" content="2021-10-11T10:43:35-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Replacing docker with podman on macOS (and Linux)"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.f7354ef8ed840429a37397307f3d9872782673d6b91d714b3f600b210d91fbaf.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Replacing docker with podman on macOS (and Linux)</h1>
|
||||
<div class="meta">Posted on Oct 11, 2021</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>There are a number of reasons why you might want to replace docker, especially on macOS. The following feature bundled in Docker Desktop might have motivated you enough to consider replacing docker:</p>
|
||||
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">...ignoring Docker updates is a paid feature now?? <a href="https://t.co/ZxKW3b9LQM">pic.twitter.com/ZxKW3b9LQM</a></p>— Brendan Dolan-Gavitt (@moyix) <a href="https://twitter.com/moyix/status/1388586550682861568?ref_src=twsrc%5Etfw">May 1, 2021</a></blockquote>
|
||||
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
<p>Docker has been one of the larger influencers in the container world, helping to standardize the <a href="https://github.com/opencontainers/image-spec/blob/main/spec.md">OCI Image Format Specification</a>. For many developers, containers have become synonymous with terms like <code>docker</code> and <code>Dockerfile</code> (a file containing build instructions for a container image). Docker has certainly made it very convenient to build and run containers, but it is not the only solution for doing so.</p>
|
||||
<p>This post briefly describes my experience swapping out docker for podman on macOS.</p>
|
||||
<h3 id="what-is-a-container">What is a container?<a href="#what-is-a-container" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>A container is a standard unit of software that packages up all application dependencies within it. Multiple containers can be run on a host machine all sharing the same kernel as the host. Linux namespaces help provide an isolated view of the system, including mnt, pid, net, ipc, uid, cgroup, and time. There is an <a href="https://www.youtube.com/watch?v=sK5i-N34im8">in-depth video</a> that discusses what containers are made from, and <a href="https://youtu.be/sK5i-N34im8?t=2468">near the end</a> there is a demonstration on how to build your own containers from the command line.</p>
|
||||
<p>By easily allowing the necessary dependencies to live alongside the application code, containers make the “works on my machine” problem less of a problem.</p>
|
||||
<h3 id="benefits-of-podman">Benefits of Podman<a href="#benefits-of-podman" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>One of the most interesting features of Podman is that it is daemonless. There isn’t a process running on your system managing your containers. In contrast, the docker client is reliant upon the docker daemon (often running as root) to be able to build and run containers.</p>
|
||||
<p>Podman is rootless by default. It is now possible to <a href="https://docs.docker.com/engine/security/rootless/">run the docker daemon rootless</a> as well, but it’s still not the default behaviour.</p>
|
||||
<p>I’ve also observed that so far my 2019 16" Macbook Pro hasn’t sounded like a jet engine, although I haven’t performed any disk-intensive operations yet.</p>
|
||||
<h3 id="installing-podman">Installing Podman<a href="#installing-podman" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>Running Podman on macOS is more involved than on Linux, because the podman-machine must run Linux inside of a virtual machine. Fortunately, the installation is made simple with <a href="https://formulae.brew.sh/formula/podman">brew</a> (read <a href="https://podman.io/getting-started/installation#linux-distributions">this</a> if you’re installing Podman on Linux):</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>brew install podman
|
||||
</span></span></code></pre></div><p>The podman-machine must be started:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#75715e"># This is not necessary on Linux</span>
|
||||
</span></span><span style="display:flex;"><span>podman machine init
|
||||
</span></span><span style="display:flex;"><span>podman machine start
|
||||
</span></span></code></pre></div><h3 id="running-a-container">Running a container<a href="#running-a-container" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>Let’s try to pull an image:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>$ podman pull alpine
|
||||
</span></span><span style="display:flex;"><span>Trying to pull docker.io/library/alpine:latest...
|
||||
</span></span><span style="display:flex;"><span>Getting image source signatures
|
||||
</span></span><span style="display:flex;"><span>Copying blob sha256:a0d0a0d46f8b52473982a3c466318f479767577551a53ffc9074c9fa7035982e
|
||||
</span></span><span style="display:flex;"><span>Copying config sha256:14119a10abf4669e8cdbdff324a9f9605d99697215a0d21c360fe8dfa8471bab
|
||||
</span></span><span style="display:flex;"><span>Writing manifest to image destination
|
||||
</span></span><span style="display:flex;"><span>Storing signatures
|
||||
</span></span><span style="display:flex;"><span>14119a10abf4669e8cdbdff324a9f9605d99697215a0d21c360fe8dfa8471bab
|
||||
</span></span></code></pre></div><blockquote>
|
||||
<p>If you’re having an issue pulling images, you may need to remove <code>~/.docker/config.json</code> or remove the set of auths in the configuration as mentioned <a href="https://stackoverflow.com/a/69121873/1191286">here</a>.</p>
|
||||
</blockquote>
|
||||
<p>and then run and exec into the container:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>$ podman run --rm -ti alpine
|
||||
</span></span><span style="display:flex;"><span>Error: error preparing container 99ace1ef8a78118e178372d91fd182e8166c399fbebe0f676af59fbf32ce205b for attach: error configuring network namespace for container 99ace1ef8a78118e178372d91fd182e8166c399fbebe0f676af59fbf32ce205b: error adding pod unruffled_bohr_unruffled_bohr to CNI network "podman": unexpected end of JSON input
|
||||
</span></span></code></pre></div><p>What does this error mean? A bit of searching lead to <a href="https://github.com/containers/podman/issues/11837">this github issue</a>.</p>
|
||||
<p>Until the fix is released, a workaround is to just specify a port (even when it’s not needed):</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>podman run -p <span style="color:#ae81ff">4242</span> --rm -ti alpine
|
||||
</span></span></code></pre></div><p>If you’re reading this from the future, there is a good chance specifying a port won’t be needed.</p>
|
||||
<p>Another example of running a container with Podman can be found in the <a href="https://jellyfin.org/docs/general/administration/installing.html#podman">Jellyfin Documentation</a>.</p>
|
||||
<h3 id="aliasing-docker-with-podman">Aliasing docker with podman<a href="#aliasing-docker-with-podman" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>Force of habit (or other scripts) may have you calling <code>docker</code>. To work around this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>alias docker<span style="color:#f92672">=</span>podman
|
||||
</span></span></code></pre></div><h3 id="podman-compose">podman-compose<a href="#podman-compose" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>You may be wondering: what about docker-compose? Well, there <em>claims</em> to be a drop-in replacement for it: <a href="https://github.com/containers/podman-compose">podman-compose</a>.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>pip3 install --user podman-compose
|
||||
</span></span></code></pre></div><p>Now let’s create a <code>docker-compose.yml</code> file to test:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>cat <span style="color:#e6db74"><< EOF >> docker-compose.yml
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">version: '2'
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">services:
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> hello_world:
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> image: ubuntu
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> command: [/bin/echo, 'Hello world']
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">EOF</span>
|
||||
</span></span></code></pre></div><p>Now run:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>$ podman-compose up
|
||||
</span></span><span style="display:flex;"><span>podman pod create --name=davegallant.github.io --share net
|
||||
</span></span><span style="display:flex;"><span>40d61dc6e95216c07d2b21cea6dcb30205bfcaf1260501fe652f05bddf7e595e
|
||||
</span></span><span style="display:flex;"><span>0
|
||||
</span></span><span style="display:flex;"><span>podman create --name=davegallant.github.io_hello_world_1 --pod=davegallant.github.io -l io.podman.compose.config-hash=123 -l io.podman.compose.project=davegallant.github.io -l io.podman.compose.version=0.0.1 -l com.docker.compose.container-number=1 -l com.docker.compose.service=hello_world --add-host hello_world:127.0.0.1 --add-host davegallant.github.io_hello_world_1:127.0.0.1 ubuntu /bin/echo Hello world
|
||||
</span></span><span style="display:flex;"><span>Resolved "ubuntu" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
|
||||
</span></span><span style="display:flex;"><span>Trying to pull docker.io/library/ubuntu:latest...
|
||||
</span></span><span style="display:flex;"><span>Getting image source signatures
|
||||
</span></span><span style="display:flex;"><span>Copying blob sha256:f3ef4ff62e0da0ef761ec1c8a578f3035bef51043e53ae1b13a20b3e03726d17
|
||||
</span></span><span style="display:flex;"><span>Copying blob sha256:f3ef4ff62e0da0ef761ec1c8a578f3035bef51043e53ae1b13a20b3e03726d17
|
||||
</span></span><span style="display:flex;"><span>Copying config sha256:597ce1600cf4ac5f449b66e75e840657bb53864434d6bd82f00b172544c32ee2
|
||||
</span></span><span style="display:flex;"><span>Writing manifest to image destination
|
||||
</span></span><span style="display:flex;"><span>Storing signatures
|
||||
</span></span><span style="display:flex;"><span>1a68b2fed3fdf2037b7aef16d770f22929eec1d799219ce30541df7876918576
|
||||
</span></span><span style="display:flex;"><span>0
|
||||
</span></span><span style="display:flex;"><span>podman start -a davegallant.github.io_hello_world_1
|
||||
</span></span><span style="display:flex;"><span>Hello world
|
||||
</span></span></code></pre></div><p>This should more or less provide the same results you would come to expect with docker. The README does clearly state that podman-compose is under development.</p>
|
||||
<h3 id="summary">Summary<a href="#summary" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>Installing Podman on macOS was not seamless, but it was manageable well within 30 minutes. I would recommend giving Podman a try to anyone who is unhappy with experiencing forced docker updates, or who is interested in using a more modern technology for running containers.</p>
|
||||
<p>One caveat to mention is that there isn’t an official graphical user interface for Podman, but there is an <a href="https://github.com/containers/podman/issues/11494">open issue</a> considering one. If you rely heavily on Docker Desktop’s UI, you may not be as interested in using podman yet.</p>
|
||||
<blockquote>
|
||||
<p>Update: After further usage, bind mounts do not seem to work out of the box when the client and host are on different machines. A rather involved solution using <a href="https://en.wikipedia.org/wiki/SSHFS">sshfs</a> was shared <a href="https://github.com/containers/podman/issues/8016#issuecomment-920015800">here</a>.</p>
|
||||
</blockquote>
|
||||
<p>I had been experimenting with Podman on Linux before writing this, but after listening to this <a href="https://kubernetespodcast.com/episode/164-podman/">podcast episode</a>, I was inspired to give Podman a try on macOS.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/docker">docker</a></li>
|
||||
|
||||
<li><a href="/tags/podman">podman</a></li>
|
||||
|
||||
<li><a href="/tags/containers">containers</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments-area'><script src='https://utteranc.es/client.js'
|
||||
repo='davegallant/davegallant.github.io'
|
||||
issue-term='pathname'
|
||||
|
||||
theme='github-light'
|
||||
crossorigin='anonymous' async>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://twitter.com/davega11ant/" rel="me" title="Twitter"><i data-feather="twitter"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://fosstodon.org/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant | Theme based on <a
|
||||
href="https://github.com/athul/archie">Archie</a> | Built with <a href="https://gohugo.io">Hugo</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script type="application/javascript">
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-98710982-2', 'auto');
|
||||
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,241 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Running K3s in LXC on Proxmox - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Running K3s in LXC on Proxmox" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/post/running-k3s-in-lxc-on-proxmox/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2021-11-14T10:07:03-05:00" />
|
||||
<meta property="article:modified_time" content="2021-11-14T10:07:03-05:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Running K3s in LXC on Proxmox"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.f7354ef8ed840429a37397307f3d9872782673d6b91d714b3f600b210d91fbaf.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Running K3s in LXC on Proxmox</h1>
|
||||
<div class="meta">Posted on Nov 14, 2021</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>It has been a while since I’ve actively used Kubernetes and wanted to explore the evolution of tools such as <a href="https://helm.sh">Helm</a> and <a href="https://tekton.dev">Tekton</a>. I decided to deploy <a href="https://k3s.io">K3s</a>, since I’ve had success with deploying it on resource-contrained Raspberry Pis in the past. I thought that this time it’d be convenient to have K3s running in a LXC container on Proxmox. This would allow for easy snapshotting of the entire Kubernetes deployment. LXC containers also provide an efficient way to use a machine’s resources.</p>
|
||||
<h2 id="what-is-k3s">What is K3s?<a href="#what-is-k3s" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>K3s is a Kubernetes distro that advertises itself as a lightweight binary with a much smaller memory-footprint than traditional k8s. K3s is not a fork of k8s as it seeks to remain as close to upstream as it possibly can.</p>
|
||||
<h2 id="configure-proxmox">Configure Proxmox<a href="#configure-proxmox" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>This <a href="https://gist.github.com/triangletodd/02f595cd4c0dc9aac5f7763ca2264185">gist</a> contains snippets and discussion on how to deploy K3s in LXC on Proxmox. It mentions that <code>bridge-nf-call-iptables</code> should be loaded, but I did not understand the benefit of doing this.</p>
|
||||
<h2 id="disable-swap">Disable swap<a href="#disable-swap" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>There is an issue on Kubernetes regarding swap <a href="https://github.com/kubernetes/kubernetes/issues/53533">here</a>. There claims to be support for swap in 1.22, but for now let’s disable it:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>sysctl vm.swappiness=0
|
||||
</span></span><span style="display:flex;"><span>swapoff -a
|
||||
</span></span></code></pre></div><p>It might be worth experimenting with swap enabled in the future to see how that might affect performance.</p>
|
||||
<h3 id="enable-ip-forwarding">Enable IP Forwarding<a href="#enable-ip-forwarding" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>To avoid IP Forwarding issues with Traefik, run the following on the host:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>sudo sysctl net.ipv4.ip_forward<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span>
|
||||
</span></span><span style="display:flex;"><span>sudo sysctl net.ipv6.conf.all.forwarding<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span>
|
||||
</span></span><span style="display:flex;"><span>sudo sed -i <span style="color:#e6db74">'s/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g'</span> /etc/sysctl.conf
|
||||
</span></span><span style="display:flex;"><span>sudo sed -i <span style="color:#e6db74">'s/#net.ipv6.conf.all.forwarding=1/net.ipv6.conf.all.forwarding=1/g'</span> /etc/sysctl.conf
|
||||
</span></span></code></pre></div><h2 id="create-lxc-container">Create LXC container<a href="#create-lxc-container" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Create an LXC container in the Proxmox interface as you normally would. Remember to:</p>
|
||||
<ul>
|
||||
<li>Uncheck <code>unprivileged container</code></li>
|
||||
<li>Use a LXC template (I chose a debian 11 template downloaded with <a href="https://pve.proxmox.com/wiki/Linux_Container#Create_container">pveam</a>)</li>
|
||||
<li>In memory, set swap to 0</li>
|
||||
<li>Create and start the container</li>
|
||||
</ul>
|
||||
<h3 id="modify-container-config">Modify container config<a href="#modify-container-config" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>Now back on the host run <code>pct list</code> to determine what VMID it was given.</p>
|
||||
<p>Open <code>/etc/pve/lxc/$VMID.conf</code> and append:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>lxc.apparmor.profile: unconfined
|
||||
</span></span><span style="display:flex;"><span>lxc.cap.drop:
|
||||
</span></span><span style="display:flex;"><span>lxc.mount.auto: <span style="color:#e6db74">"proc:rw sys:rw"</span>
|
||||
</span></span><span style="display:flex;"><span>lxc.cgroup2.devices.allow: c 10:200 rwm
|
||||
</span></span></code></pre></div><p>All of the above configurations are described in the <a href="https://linuxcontainers.org/lxc/manpages/man5/lxc.container.conf.5.html">manpages</a>.
|
||||
Notice that <code>cgroup2</code> is used since Proxmox VE 7.0 has switched to a <a href="https://pve.proxmox.com/pve-docs/chapter-pct.html#pct_cgroup">pure cgroupv2 environment</a>.</p>
|
||||
<p>Thankfully cgroup v2 support has been supported in k3s with these contributions:</p>
|
||||
<ul>
|
||||
<li><a href="https://github.com/k3s-io/k3s/pull/2584">https://github.com/k3s-io/k3s/pull/2584</a></li>
|
||||
<li><a href="https://github.com/k3s-io/k3s/pull/2844">https://github.com/k3s-io/k3s/pull/2844</a></li>
|
||||
</ul>
|
||||
<h2 id="enable-shared-host-mounts">Enable shared host mounts<a href="#enable-shared-host-mounts" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>From within the container, run:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>echo <span style="color:#e6db74">'#!/bin/sh -e
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">ln -s /dev/console /dev/kmsg
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">mount --make-rshared /'</span> > /etc/rc.local
|
||||
</span></span><span style="display:flex;"><span>chmod +x /etc/rc.local
|
||||
</span></span><span style="display:flex;"><span>reboot
|
||||
</span></span></code></pre></div><h2 id="install-k3s">Install K3s<a href="#install-k3s" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>One of the simplest ways to install K3s on a remote host is to use <a href="https://github.com/alexellis/k3sup">k3sup</a>.
|
||||
Ensure that you supply a valid <code>CONTAINER_IP</code> and choose the <code>k3s-version</code> you prefer.
|
||||
As of 2021/11, it is still defaulting to the 1.19 channel, so I overrode it to 1.22 for cgroup v2 support. See the published releases <a href="https://github.com/k3s-io/k3s/releases">here</a>.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ssh-copy-id root@$CONTAINER_IP
|
||||
</span></span><span style="display:flex;"><span>k3sup install --ip $CONTAINER_IP --user root --k3s-version v1.22.3+k3s1
|
||||
</span></span></code></pre></div><p>If all goes well, you should see a path to the <code>kubeconfig</code> generated. I moved this into <code>~/.kube/config</code> so that kubectl would read this by default.</p>
|
||||
<h2 id="wrapping-up">Wrapping up<a href="#wrapping-up" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Installing K3s in LXC on Proxmox works with a few tweaks to the default configuration. I later followed the Tekton’s <a href="https://tekton.dev/docs/getting-started/">Getting Started</a> guide and was able to deploy it in a few commands.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>$ kubectl get all --namespace tekton-pipelines
|
||||
</span></span><span style="display:flex;"><span>NAME READY STATUS RESTARTS AGE
|
||||
</span></span><span style="display:flex;"><span>pod/tekton-pipelines-webhook-8566ff9b6b-6rnh8 1/1 Running 1 (50m ago) 12h
|
||||
</span></span><span style="display:flex;"><span>pod/tekton-dashboard-6bf858f977-qt4hr 1/1 Running 1 (50m ago) 11h
|
||||
</span></span><span style="display:flex;"><span>pod/tekton-pipelines-controller-69fd7498d8-f57m4 1/1 Running 1 (50m ago) 12h
|
||||
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
</span></span><span style="display:flex;"><span>service/tekton-pipelines-controller ClusterIP 10.43.44.245 <none> 9090/TCP,8080/TCP 12h
|
||||
</span></span><span style="display:flex;"><span>service/tekton-pipelines-webhook ClusterIP 10.43.183.242 <none> 9090/TCP,8008/TCP,443/TCP,8080/TCP 12h
|
||||
</span></span><span style="display:flex;"><span>service/tekton-dashboard ClusterIP 10.43.87.97 <none> 9097/TCP 11h
|
||||
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
</span></span><span style="display:flex;"><span>deployment.apps/tekton-pipelines-webhook 1/1 1 1 12h
|
||||
</span></span><span style="display:flex;"><span>deployment.apps/tekton-dashboard 1/1 1 1 11h
|
||||
</span></span><span style="display:flex;"><span>deployment.apps/tekton-pipelines-controller 1/1 1 1 12h
|
||||
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>NAME DESIRED CURRENT READY AGE
|
||||
</span></span><span style="display:flex;"><span>replicaset.apps/tekton-pipelines-webhook-8566ff9b6b 1 1 1 12h
|
||||
</span></span><span style="display:flex;"><span>replicaset.apps/tekton-dashboard-6bf858f977 1 1 1 11h
|
||||
</span></span><span style="display:flex;"><span>replicaset.apps/tekton-pipelines-controller-69fd7498d8 1 1 1 12h
|
||||
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
|
||||
</span></span><span style="display:flex;"><span>horizontalpodautoscaler.autoscaling/tekton-pipelines-webhook Deployment/tekton-pipelines-webhook 9%/100% 1 5 1 12h
|
||||
</span></span></code></pre></div><p>I made sure to install Tailscale in the container so that I can easily access K3s from anywhere.</p>
|
||||
<p>If I’m feeling adventurous, I might experiment with <a href="https://rancher.com/docs/k3s/latest/en/advanced/#running-k3s-with-rootless-mode-experimental">K3s rootless</a>.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/k3s">k3s</a></li>
|
||||
|
||||
<li><a href="/tags/proxmox">proxmox</a></li>
|
||||
|
||||
<li><a href="/tags/lxc">lxc</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments-area'><script src='https://utteranc.es/client.js'
|
||||
repo='davegallant/davegallant.github.io'
|
||||
issue-term='pathname'
|
||||
|
||||
theme='github-light'
|
||||
crossorigin='anonymous' async>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://twitter.com/davega11ant/" rel="me" title="Twitter"><i data-feather="twitter"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://fosstodon.org/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant | Theme based on <a
|
||||
href="https://github.com/athul/archie">Archie</a> | Built with <a href="https://gohugo.io">Hugo</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script type="application/javascript">
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-98710982-2', 'auto');
|
||||
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,206 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Virtualizing My Router With pfSense - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Virtualizing My Router With pfSense" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/post/virtualizing-a-router-with-pfsense/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2022-04-02T18:50:09-04:00" />
|
||||
<meta property="article:modified_time" content="2022-04-02T18:50:09-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Virtualizing My Router With pfSense"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.f7354ef8ed840429a37397307f3d9872782673d6b91d714b3f600b210d91fbaf.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Virtualizing My Router With pfSense</h1>
|
||||
<div class="meta">Posted on Apr 2, 2022</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><h2 id="the-problem">The problem<a href="#the-problem" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>My aging router has been running <a href="https://en.wikipedia.org/wiki/OpenWrt">OpenWrt</a> for years and for the most part has been quite reliable. OpenWrt is an open-source project used on embedded devices to route network traffic. It supports many different configurations and there exists a <a href="https://openwrt.org/packages/index/start">large index of packages</a>. Ever since I’ve connected some standalone wireless access points, I’ve had less of a need for an off-the-shelf all-in-one wireless router combo. I’ve also recently been experiencing instability with my router (likely the result of a combination of configuration tweaking and firmware updating). OpenWrt has served me well, but it is time to move on!</p>
|
||||
<h2 id="pfsense">pfSense<a href="#pfsense" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>I figured this would be a good opportunity to try <a href="https://en.wikipedia.org/wiki/PfSense">pfSense</a>. I’ve heard nothing but positive things about pfSense and the fact it’s been around since 2004, based on FreeBSD, and written in PHP gave me the impression that it would be relatively stable (and I’d expect nothing less because it has an important job to do!). pfSense can be run on many different machines, and there are even some <a href="https://www.netgate.com/appliances">officially supported appliances</a>. Since I already have a machine running Proxmox, why not just run it in a VM? It’d allow for automatic snapshotting of the machine. There is a good <a href="https://www.youtube.com/watch?v=hdoBQNI_Ab8">video</a> on this by Techno Tim. Tim has a lot of good videos, and this one is about virtualizing pfSense.</p>
|
||||
<h2 id="router-on-a-stick">Router on a stick<a href="#router-on-a-stick" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>I had initially made the assumption that in order to build a router, you would need more than a single NIC (or a dual-port NIC) in order to support both WAN and LAN. This is simply <a href="https://en.wikipedia.org/wiki/Router_on_a_stick">not the case</a>, because VLANs are awesome! In order to create a router, all you need is a single port NIC and a network switch that supports VLANs (also marketed as a managed switch). I picked up the Netgear GS308E because it has both a sufficient amount of ports for my needs, and it supports VLANs. It also has a nice sturdy metal frame which was a pleasant surprise.</p>
|
||||
<p>After setting up this Netgear switch, it shoud be possible to access the web interface at <a href="http://192.168.0.239">http://192.168.0.239</a>. It may be at a different address. To find the address, try checking your DHCP leases in your router interface (if you plugged it into an existing router). I realized I was unable to access this interface because I was on a different subnet, so I set my machine’s address to <code>192.168.0.22</code> in order to temporarily setup this switch. I assigned a static ip address to the switch (in <code>System > Switch Information</code>) so that it was in the same subnet as the rest of my network.</p>
|
||||
<p>The web interface is nothing spectactular, but it allows for managing VLANs.</p>
|
||||
<p>The following configuration will:</p>
|
||||
<ul>
|
||||
<li>assign port 1 to be the LAN (connected to the Proxmox machine)</li>
|
||||
<li>assign port 8 to be the WAN (connected to my ISP’s modem)</li>
|
||||
</ul>
|
||||
<p>In the switch’s web interface, I went to <code>VLAN</code> and then <code>802.1Q</code>, and then clicked on <code>VLAN Configuration</code>. I configured the ports to look like this:</p>
|
||||
<p><img src="/images/virtualizing-a-router-with-pfsense/netgear-vlan-configuration.png" alt="vlan-config"></p>
|
||||
<p>Note that the <code>VLAN Identifier Setting</code> has been setup already with two VLANs (1 and 10). More VLANs can be created (i.e. to isolate IoT devices), but 2 VLANs is all we need for the initial setup of a router.</p>
|
||||
<p>To replicate the above configuration, add a new VLAN ID 10 (1 should exist by default).</p>
|
||||
<p>Next, go into <code>VLAN Membership</code> and configure VLAN 1’s port membership to be the following:</p>
|
||||
<p><img src="/images/virtualizing-a-router-with-pfsense/netgear-vlan-membership-1.png" alt="vlan-membership-1"></p>
|
||||
<p>and then configure VLAN 10’s port membership to be the following:</p>
|
||||
<p><img src="/images/virtualizing-a-router-with-pfsense/netgear-vlan-membership-10.png" alt="vlan-membership-10"></p>
|
||||
<p>Now, go into <code>Port PVID</code> and ensure that port 8 is set to PVID 10.</p>
|
||||
<p><img src="/images/virtualizing-a-router-with-pfsense/netgear-port-pvid.png" alt="vlan-port-pvid"></p>
|
||||
<p>This above configuration will dedicate two of the eight ports to WAN and LAN. This will allow the internet to flow into the pfSense from the modem.</p>
|
||||
<h2 id="setting-up-pfsense">Setting up pfSense<a href="#setting-up-pfsense" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>pfSense is fairly easy to setup. Just <a href="https://www.pfsense.org/download/">download the latest ISO</a> and boot up the virtual machine.
|
||||
When setting up the machine, I mostly went with all of the defaults. Configuration can be changed later in the web interface, which is quite a bit simpler.</p>
|
||||
<p>Since VLANs are going to be leveraged, when you go to <code>Assign Interfaces</code>, VLANs should be setup now like the following:</p>
|
||||
<ul>
|
||||
<li><code>WAN</code> should be <code>vtnet0.10</code></li>
|
||||
<li><code>LAN</code> should be <code>vtnet0</code></li>
|
||||
</ul>
|
||||
<p>After going through the rest of the installation, if everything is connected correctly it should display both WAN and LAN addresses.</p>
|
||||
<p>If all goes well, the web interface should be running at <a href="https://192.168.1.1">https://192.168.1.1</a>.</p>
|
||||
<p><img src="/images/virtualizing-a-router-with-pfsense/pfsense-dashboard.png" alt="pfsense-dashboard"></p>
|
||||
<p>And this is where the fun begins. There are many tutorials and blogs about how to setup pfSense and various services and packages that can be installed. I’ve already installed <a href="https://docs.netgate.com/pfsense/en/latest/packages/pfblocker.html">pfBlocker-NG</a>.</p>
|
||||
<h2 id="summary">Summary<a href="#summary" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>It is fairly simple to setup a router with pfSense from within a virtual machine. A physical dedicated routing machine is not necessary and often does not perform as well as software running on faster and more reliable hardware. So far, pfSense has been running for over a week without a single hiccup. pfSense is a mature piece of software that is incredibly powerful and flexible. To avoid some of the instability I had experienced with OpenWrt, I enabled <a href="https://docs.netgate.com/pfsense/en/latest/backup/autoconfigbackup.html">AutoConfigBackup</a>, which is capable of automatically backing up configuration upon every change. I plan to explore and experiment with more services and configuration in the future, so the ability to track all of these changes gives me the peace of mind that experimentation is safe.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/pfsense">pfsense</a></li>
|
||||
|
||||
<li><a href="/tags/router">router</a></li>
|
||||
|
||||
<li><a href="/tags/openwrt">openwrt</a></li>
|
||||
|
||||
<li><a href="/tags/router-on-a-stick">router-on-a-stick</a></li>
|
||||
|
||||
<li><a href="/tags/proxmox">proxmox</a></li>
|
||||
|
||||
<li><a href="/tags/vlan">vlan</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments-area'><script src='https://utteranc.es/client.js'
|
||||
repo='davegallant/davegallant.github.io'
|
||||
issue-term='pathname'
|
||||
|
||||
theme='github-light'
|
||||
crossorigin='anonymous' async>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://twitter.com/davega11ant/" rel="me" title="Twitter"><i data-feather="twitter"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://fosstodon.org/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant | Theme based on <a
|
||||
href="https://github.com/athul/archie">Archie</a> | Built with <a href="https://gohugo.io">Hugo</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script type="application/javascript">
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-98710982-2', 'auto');
|
||||
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,224 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Watching YouTube in Private - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Watching YouTube in Private" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/post/watching-youtube-in-private/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2022-12-10T21:46:55-05:00" />
|
||||
<meta property="article:modified_time" content="2022-12-10T21:46:55-05:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Watching YouTube in Private"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.f7354ef8ed840429a37397307f3d9872782673d6b91d714b3f600b210d91fbaf.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Watching YouTube in Private</h1>
|
||||
<div class="meta">Posted on Dec 10, 2022</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>I recently stumbled upon <a href="https://yewtu.be">yewtu.be</a> and found it intriguing. It not only allows you to watch YouTube without <em>being on YouTube</em>, but it also allows you to create an account and subscribe to channels without a Google account. What sort of wizardry is going on under the hood? It turns out that it’s a hosted instance of <a href="https://invidious.io/">invidious</a>.</p>
|
||||
<p><img src="/images/watching-youtube-in-private/computerphile.png" alt="requestly"></p>
|
||||
<p>This layout is simple, and <strong>JavaScript is not required</strong>.</p>
|
||||
<p>I started using <a href="https://yewtu.be">yewtu.be</a> as my primary client for watching videos. I subscribe to several YouTube channels and I prefer the interface invidiuous provides due to its simplicity. It’s also nice to be in control of my search and watch history.</p>
|
||||
<p>A few days ago, yewtu.be went down briefly, and that motivated me enough to self-host invidious. There are several other hosted instances listed <a href="https://docs.invidious.io/instances/">here</a>, but being able to easily backup my own instance (including subscriptions and watch history) is more compelling in my case.</p>
|
||||
<h3 id="hosting-invidious">Hosting invidious<a href="#hosting-invidious" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>The quickest way to get invidious up is with docker-compose as mentioned in the <a href="https://docs.invidious.io/installation/">docs</a>.</p>
|
||||
<p>I made a few modifications (such as pinning the container’s tag), and ended up with:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">version</span>: <span style="color:#e6db74">"3"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#f92672">services</span>:
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">invidious</span>:
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">quay.io/invidious/invidious:5160d8bae39dc5cc5d51abee90571a03c08d0f2b</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">unless-stopped</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">ports</span>:
|
||||
</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">"0.0.0.0:3000:3000"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">environment</span>:
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">INVIDIOUS_CONFIG</span>: |<span style="color:#e6db74">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> db:
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> dbname: invidious
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> user: kemal
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> password: kemal
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> host: invidious-db
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> port: 5432
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> check_tables: true</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">healthcheck</span>:
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">test</span>: <span style="color:#ae81ff">wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/comments/jNQXAC9IVRw || exit 1</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">interval</span>: <span style="color:#ae81ff">30s</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeout</span>: <span style="color:#ae81ff">5s</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">retries</span>: <span style="color:#ae81ff">2</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">depends_on</span>:
|
||||
</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">invidious-db</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">invidious-db</span>:
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">docker.io/library/postgres:14</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">unless-stopped</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>:
|
||||
</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">postgresdata:/var/lib/postgresql/data</span>
|
||||
</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">./config/sql:/config/sql</span>
|
||||
</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">./docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">environment</span>:
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">POSTGRES_DB</span>: <span style="color:#ae81ff">invidious</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">POSTGRES_USER</span>: <span style="color:#ae81ff">kemal</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">POSTGRES_PASSWORD</span>: <span style="color:#ae81ff">kemal</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">healthcheck</span>:
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">test</span>: [<span style="color:#e6db74">"CMD-SHELL"</span>, <span style="color:#e6db74">"pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"</span>]
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#f92672">volumes</span>:
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">postgresdata</span>:
|
||||
</span></span></code></pre></div><p>After invidious was up and running, I installed <a href="https://tailscale.com/">Tailscale</a> on it to leverage its MagicDNS, and I’m now able to access this instance from anywhere at <a href="http://invidious:3000/feed/subscriptions">http://invidious:3000/feed/subscriptions</a>.</p>
|
||||
<h3 id="redirecting-youtube-links">Redirecting YouTube links<a href="#redirecting-youtube-links" class="hanchor" ariaLabel="Anchor">#</a></h3>
|
||||
<p>I figured it would be nice to redirect existing YouTube links that others send me, so that I could seamlessly watch the videos using invidious.</p>
|
||||
<p>I went looking for a way to redirect paths at the browser level. I found the lightweight proxy <a href="https://requestly.io/">requestly</a>, which can be used to modify http requests in my browser. I created the following rules:</p>
|
||||
<p><img src="/images/watching-youtube-in-private/requestly-rules.png" alt="requestly"></p>
|
||||
<p>Now the link <a href="https://www.youtube.com/watch?v=-lz30by8-sU">https://www.youtube.com/watch?v=-lz30by8-sU</a> will redirect to <a href="http://invidious:3000/watch?v=-lz30by8-sU">http://invidious:3000/watch?v=-lz30by8-sU</a></p>
|
||||
<p>I’m still looking for ways to improve this invidious setup. There doesn’t appear to be a way to stream in 4K yet.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/invidious">invidious</a></li>
|
||||
|
||||
<li><a href="/tags/degoogle">degoogle</a></li>
|
||||
|
||||
<li><a href="/tags/youtube">youtube</a></li>
|
||||
|
||||
<li><a href="/tags/yewtu.be">yewtu.be</a></li>
|
||||
|
||||
<li><a href="/tags/tailscale">tailscale</a></li>
|
||||
|
||||
<li><a href="/tags/privacy">privacy</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments-area'><script src='https://utteranc.es/client.js'
|
||||
repo='davegallant/davegallant.github.io'
|
||||
issue-term='pathname'
|
||||
|
||||
theme='github-light'
|
||||
crossorigin='anonymous' async>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://twitter.com/davega11ant/" rel="me" title="Twitter"><i data-feather="twitter"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://fosstodon.org/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant | Theme based on <a
|
||||
href="https://github.com/athul/archie">Archie</a> | Built with <a href="https://gohugo.io">Hugo</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script type="application/javascript">
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-98710982-2', 'auto');
|
||||
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,206 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>What To Do With A Homelab - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="A homelab can be an inexpensive way to host a multitude of internal/external services and learn a lot in the process." />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="What To Do With A Homelab" />
|
||||
<meta property="og:description" content="A homelab can be an inexpensive way to host a multitude of internal/external services and learn a lot in the process." />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/post/what-to-do-with-a-homelab/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2021-09-06T01:12:54-04:00" />
|
||||
<meta property="article:modified_time" content="2021-09-06T01:12:54-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="What To Do With A Homelab"/>
|
||||
<meta name="twitter:description" content="A homelab can be an inexpensive way to host a multitude of internal/external services and learn a lot in the process."/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.f7354ef8ed840429a37397307f3d9872782673d6b91d714b3f600b210d91fbaf.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">What To Do With A Homelab</h1>
|
||||
<div class="meta">Posted on Sep 6, 2021</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>A homelab can be an inexpensive way to host a multitude of internal/external services and learn <em>a lot</em> in the process.</p>
|
||||
<p>Do you want host your own Media server? Ad blocker? Web server?
|
||||
Are you interested in learning more about Linux? Virtualization? Networking? Security?
|
||||
Building a homelab can be an entertaining playground to enhance your computer skills.</p>
|
||||
<p>One of the best parts about building a homelab is that it doesn’t have to be a large investment in terms of hardware. One of the simplest ways to build a homelab is out of a <a href="https://ca.refurb.io/products/hp-800-g1-usff-intel-core-i5-4570s-16gb-ram-512gb-ssd-wifi-windows-10-pro?variant=33049503825943">refurbished computer</a>.
|
||||
Having multiple machines/nodes provides the advantage of increased redundancy, but starting out with a single node is enough to reap many of the benefits of having a homelab.</p>
|
||||
<h2 id="virtualization">Virtualization<a href="#virtualization" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Virtualizing your hardware is an organized way of dividing up your machine’s resources. This can be done with something such as a <em>Virtual Machine</em> or something lighter like a container using <em>LXC</em> or <em>runC</em>.
|
||||
Containers have much less overhead in terms of boot time and storage allocation. This <a href="https://stackoverflow.com/questions/16047306/how-is-docker-different-from-a-virtual-machine">Stack Overflow answer</a> sums it up nicely.</p>
|
||||
<p><img src="/images/proxmox.png" alt="image"></p>
|
||||
<p>A hypervisor such as <a href="https://www.proxmox.com/en/proxmox-ve/get-started">Proxmox</a> can be installed in minutes on a new machine. It provides a web interface and a straight-forward way to spin up new VMs and containers. Even if your plan is to run mostly docker containers, Proxmox can be a useful abstraction for managing VMs, disks and running scheduled backups. You can even run docker within an LXC container by enabling nested virtualization. You’ll want to ensure that VT-d and VT-x are enabled in the BIOS if you decide to install a hypervisor to manage your virtualization.</p>
|
||||
<h2 id="services">Services<a href="#services" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>So what are some useful services to deploy?</p>
|
||||
<ul>
|
||||
<li><a href="https://jellyfin.org/">Jellyfin</a> or <a href="https://www.plex.tv/">Plex</a> - basically a self-hosted Netflix that can be used to stream from multiple devices, and the best part is that you manage the content! Unlike Plex, Jellyfin is open source and can be found <a href="https://github.com/jellyfin/jellyfin">here</a>.</li>
|
||||
<li><a href="https://github.com/dgtlmoon/changedetection.io">changedetection</a> - is a self-hosted equivalent to something like <a href="https://visualping.io/">visualping.io</a> that will notify you when a webpage changes and keep track of the diffs</li>
|
||||
<li><a href="https://github.com/AdguardTeam/AdGuardHome">Adguard</a> or <a href="https://pi-hole.net/">Pihole</a> - can block a list of known trackers for all clients on your local network. I’ve used pihole for a long time, but have recently switched to Adguard since the UI is more modern and it has the ability to toggle on/off a pre-defined list of services, including Netflix (this is useful if you have stealthy young kids). Either of these will speed up your internet experience, simply because you won’t need to download all of the extra tracking bloat.</li>
|
||||
<li><a href="https://gitea.io/">Gitea</a> - A lightweight git server. I use this to mirror git repos from GitHub, GitLab, etc.</li>
|
||||
<li><a href="https://github.com/bastienwirtz/homer">Homer</a> - A customizable landing page for services you need to access (including the ability to quickly search).</li>
|
||||
<li><a href="https://github.com/louislam/uptime-kuma">Uptime Kuma</a> - A fancy tool for monitoring the uptime of services.</li>
|
||||
</ul>
|
||||
<p>There is a large number of services you can self-host, including your own applications that you might be developing. <a href="https://github.com/awesome-selfhosted/awesome-selfhosted">awesome-self-hosted</a> provides a curated list of services that might be of interest to you.</p>
|
||||
<h2 id="vpn">VPN<a href="#vpn" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>You could certainly setup and manage your own VPN by using something like <a href="https://openvpn.net/community-downloads/">OpenVPN</a>, but there is also something else you can try: <a href="https://tailscale.com/">tailscale</a>. It is a very quick way to create fully-encrypted connections between clients. With its <a href="https://tailscale.com/kb/1081/magicdns/">MagicDNS</a>, your can reference the names of machines like <code>homer</code> rather than using an IP address. By using this mesh-like VPN, you can easily create a secure tunnel to your homelab from anywhere.</p>
|
||||
<h2 id="monitoring">Monitoring<a href="#monitoring" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p><img src="/images/netdata.png" alt="dashboard"></p>
|
||||
<p>Monitoring can become an important aspect of your homelab after it starts to become something that is relied upon. One of the simplest ways to setup some monitoring is using <a href="https://www.netdata.cloud/">netdata</a>. It can be installed on individual containers, VMs, and also a hypervisor (such as Proxmox). All of the monitoring works out of the box by detecting disks, memory, network interfaces, etc.</p>
|
||||
<p>Additionally, agents installed on different machines can all be centrally viewed in netdata, and it can alert you when some of your infrastructure is down or in a degraded state. Adding additional nodes to netdata is as simple as a 1-line shell command.</p>
|
||||
<p>As mentioned above, <a href="https://github.com/louislam/uptime-kuma">Uptime Kuma</a> is a convenient way to track uptime and monitor the availability of your services.</p>
|
||||
<p><img src="/images/uptime-kuma.png" alt="uptime-kuma"></p>
|
||||
<h2 id="in-summary">In Summary<a href="#in-summary" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Building out a homelab can be a rewarding experience and it doesn’t require buying a rack full of expensive servers to get a significant amount of utility. There are many services that you can run that require very minimal setup, making it possible to get a server up and running in a short period of time, with monitoring, and that can be securely connected to remotely.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/tailscale">tailscale</a></li>
|
||||
|
||||
<li><a href="/tags/homelab">homelab</a></li>
|
||||
|
||||
<li><a href="/tags/netdata">netdata</a></li>
|
||||
|
||||
<li><a href="/tags/jellyfin">jellyfin</a></li>
|
||||
|
||||
<li><a href="/tags/plex">plex</a></li>
|
||||
|
||||
<li><a href="/tags/pihole">pihole</a></li>
|
||||
|
||||
<li><a href="/tags/virtualization">virtualization</a></li>
|
||||
|
||||
<li><a href="/tags/adguard">adguard</a></li>
|
||||
|
||||
<li><a href="/tags/grafana">grafana</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments-area'><script src='https://utteranc.es/client.js'
|
||||
repo='davegallant/davegallant.github.io'
|
||||
issue-term='pathname'
|
||||
|
||||
theme='github-light'
|
||||
crossorigin='anonymous' async>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://twitter.com/davega11ant/" rel="me" title="Twitter"><i data-feather="twitter"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://fosstodon.org/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant | Theme based on <a
|
||||
href="https://github.com/athul/archie">Archie</a> | Built with <a href="https://gohugo.io">Hugo</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script type="application/javascript">
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-98710982-2', 'auto');
|
||||
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1,297 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Why I Threw Out My Dotfiles - davegallant</title><link rel="icon" type="image/png" href=https://davegallant.ca/favicon.ico /><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta property="og:image" content=""/>
|
||||
<meta property="og:title" content="Why I Threw Out My Dotfiles" />
|
||||
<meta property="og:description" content="" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="/post/why-i-threw-out-my-dotfiles/" /><meta property="article:section" content="post" />
|
||||
<meta property="article:published_time" content="2021-09-08T00:42:33-04:00" />
|
||||
<meta property="article:modified_time" content="2021-09-08T00:42:33-04:00" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Why I Threw Out My Dotfiles"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@1,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.f7354ef8ed840429a37397307f3d9872782673d6b91d714b3f600b210d91fbaf.css" />
|
||||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css" disabled />
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({
|
||||
tex2jax: {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
displayMath: [['$$','$$'], ['\[','\]']],
|
||||
processEscapes: true,
|
||||
processEnvironments: true,
|
||||
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" },
|
||||
extensions: ["AMSmath.js", "AMSsymbols.js"] }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "$", right: "$", display: false}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/custom.2e59ff60a2d9c7e42e3c1af2aff0ba627da46f910a234867e98d178eb05c87dc.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"><header>
|
||||
<div class="main">
|
||||
<a href="/">davegallant</a>
|
||||
</div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Home</a>
|
||||
|
||||
<a href="/post">All posts</a>
|
||||
|
||||
<a href="/about">About</a>
|
||||
|
||||
<a href="/tags">Tags</a>
|
||||
|
||||
| <span id="dark-mode-toggle" onclick="toggleTheme()"></span>
|
||||
<script src="/js/themetoggle.js"></script>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<div class="title">
|
||||
<h1 class="title">Why I Threw Out My Dotfiles</h1>
|
||||
<div class="meta">Posted on Sep 8, 2021</div>
|
||||
</div>
|
||||
|
||||
|
||||
<section class="body"><p>Over the years I have collected a number of dotfiles that I have shared across both Linux and macOS machines (<code>~/.zshrc</code>, <code>~/.config/git/config</code>, <code>~/.config/tmux/tmux.conf</code>, etc). I have tried several different ways to manage them, including <a href="https://www.atlassian.com/git/tutorials/dotfiles">bare git repos</a> and utilities such as <a href="https://www.gnu.org/software/stow/">GNU Stow</a>. These solutions work well enough, but I have since found what I would consider a much better solution for organizing user configuration: <a href="https://github.com/nix-community/home-manager">home-manager</a>.</p>
|
||||
<h2 id="what-is-home-manager">What is home-manager?<a href="#what-is-home-manager" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>Before understanding home-manager, it is worth briefly discussing what nix is. <a href="https://nixos.org/">nix</a> is a package manager that originally spawned from a <a href="https://edolstra.github.io/pubs/phd-thesis.pdf">PhD thesis</a>. Unlike other package managers, it uses symbolic links to keep track of the currently installed packages, keeping around the old ones in case you may want to rollback.</p>
|
||||
<p>For example, I have used nix to install the package <a href="https://search.nixos.org/packages?channel=unstable&show=bind&from=0&size=50&sort=relevance&type=packages&query=bind">bind</a> which includes <code>dig</code>. You can see that it is available on multiple platforms. The absolute path of <code>dig</code> can be found by running:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>$ ls -lh <span style="color:#66d9ef">$(</span>which dig<span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span>lrwxr-xr-x 73 root 31 Dec 1969 /run/current-system/sw/bin/dig -> /nix/store/0r4qdyprljd3dki57jn6c6a8dh2rbg9g-bind-9.16.16-dnsutils/bin/dig
|
||||
</span></span></code></pre></div><p>Notice that there is a hash included in the file path? This is a nix store path and is computed by the nix package manager. This <a href="https://nixos.org/guides/nix-pills/nix-store-paths.html">nix pill</a> does a good job explaining how this hash is computed. All of the nix pills are worth a read, if you are interested in learning more about nix itself. However, using home-manager does not require extensive knowledge of nix.</p>
|
||||
<p>Part of the nix ecosystem includes <a href="https://github.com/NixOS/nixpkgs">nixpkgs</a>. Many popular tools can be found already packaged in this repository. As you can see with these <a href="https://repology.org/repositories/statistics/total">stats</a>, there is a large number of existing packages that are being maintained by the community. Contributing a new package is easy, and anyone can do it!</p>
|
||||
<p>home-manager leverages the nix package manager (and nixpkgs), as well the nix language so that you can declaratively define your system configuration. I store my <a href="https://github.com/davegallant/nix-config">nix-config</a> in git so that I can keep track of my packages and configurations, and retain a clean and informative git commit history so that I can understand what changed and why.</p>
|
||||
<h2 id="setting-up-home-manager">Setting up home-manager<a href="#setting-up-home-manager" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<blockquote>
|
||||
<p>⚠️ If you run this on your main machine, make sure you backup your configuration files first. home-manager is pretty good about not overwriting existing configuration, but it is better to have a backup! Alternatively, you could test this out on a VM or cloud instance.</p>
|
||||
</blockquote>
|
||||
<p>The first thing you should do is <a href="https://nixos.org/guides/install-nix.html">install nix</a>:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>curl -L https://nixos.org/nix/install | sh
|
||||
</span></span></code></pre></div><p>It’s generally not a good idea to curl and execute files from the internet (without verifying integrity), so you might want to download the install script first and take a look before executing it!</p>
|
||||
<p>Open up a new shell in your terminal and running <code>nix</code> <em>should</em> work. If not, run <code>. ~/.nix-profile/etc/profile.d/nix.sh</code></p>
|
||||
<p>Now, <a href="https://github.com/nix-community/home-manager#installation">install home-manager</a>:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>nix-channel --add https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager
|
||||
</span></span><span style="display:flex;"><span>nix-channel --update
|
||||
</span></span><span style="display:flex;"><span>nix-shell <span style="color:#e6db74">'<home-manager>'</span> -A install
|
||||
</span></span></code></pre></div><p>You should see a wave of <code>/nix/store/*</code> paths being displayed on your screen.</p>
|
||||
<p>Now, to start off with a basic configuration, open up <code>~/.config/nixpkgs/home.nix</code> in the editor of your choice and paste this in (you will want to change <code>userName</code> and <code>homeDirectory</code>):</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-nix" data-lang="nix"><span style="display:flex;"><span>{ config<span style="color:#f92672">,</span> pkgs<span style="color:#f92672">,</span> <span style="color:#f92672">...</span> }:
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>{
|
||||
</span></span><span style="display:flex;"><span> programs<span style="color:#f92672">.</span>home-manager<span style="color:#f92672">.</span>enable <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> home <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span> username <span style="color:#f92672">=</span> <span style="color:#e6db74">"dave"</span>;
|
||||
</span></span><span style="display:flex;"><span> homeDirectory <span style="color:#f92672">=</span> <span style="color:#e6db74">"/home/dave"</span>;
|
||||
</span></span><span style="display:flex;"><span> stateVersion <span style="color:#f92672">=</span> <span style="color:#e6db74">"21.11"</span>;
|
||||
</span></span><span style="display:flex;"><span> packages <span style="color:#f92672">=</span> <span style="color:#66d9ef">with</span> pkgs; [
|
||||
</span></span><span style="display:flex;"><span> bind
|
||||
</span></span><span style="display:flex;"><span> exa
|
||||
</span></span><span style="display:flex;"><span> fd
|
||||
</span></span><span style="display:flex;"><span> ripgrep
|
||||
</span></span><span style="display:flex;"><span> ];
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> programs <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> git <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span> enable <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
|
||||
</span></span><span style="display:flex;"><span> aliases <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span> aa <span style="color:#f92672">=</span> <span style="color:#e6db74">"add -A ."</span>;
|
||||
</span></span><span style="display:flex;"><span> br <span style="color:#f92672">=</span> <span style="color:#e6db74">"branch"</span>;
|
||||
</span></span><span style="display:flex;"><span> c <span style="color:#f92672">=</span> <span style="color:#e6db74">"commit -S"</span>;
|
||||
</span></span><span style="display:flex;"><span> ca <span style="color:#f92672">=</span> <span style="color:#e6db74">"commit -S --amend"</span>;
|
||||
</span></span><span style="display:flex;"><span> cb <span style="color:#f92672">=</span> <span style="color:#e6db74">"checkout -b"</span>;
|
||||
</span></span><span style="display:flex;"><span> co <span style="color:#f92672">=</span> <span style="color:#e6db74">"checkout"</span>;
|
||||
</span></span><span style="display:flex;"><span> d <span style="color:#f92672">=</span> <span style="color:#e6db74">"diff"</span>;
|
||||
</span></span><span style="display:flex;"><span> l <span style="color:#f92672">=</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"</span>;
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> delta <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span> enable <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> options <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span> features <span style="color:#f92672">=</span> <span style="color:#e6db74">"line-numbers decorations"</span>;
|
||||
</span></span><span style="display:flex;"><span> whitespace-error-style <span style="color:#f92672">=</span> <span style="color:#e6db74">"22 reverse"</span>;
|
||||
</span></span><span style="display:flex;"><span> plus-style <span style="color:#f92672">=</span> <span style="color:#e6db74">"green bold ul '#198214'"</span>;
|
||||
</span></span><span style="display:flex;"><span> decorations <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span> commit-decoration-style <span style="color:#f92672">=</span> <span style="color:#e6db74">"bold yellow box ul"</span>;
|
||||
</span></span><span style="display:flex;"><span> file-style <span style="color:#f92672">=</span> <span style="color:#e6db74">"bold yellow ul"</span>;
|
||||
</span></span><span style="display:flex;"><span> file-decoration-style <span style="color:#f92672">=</span> <span style="color:#e6db74">"none"</span>;
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> extraConfig <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span> push <span style="color:#f92672">=</span> { default <span style="color:#f92672">=</span> <span style="color:#e6db74">"current"</span>; };
|
||||
</span></span><span style="display:flex;"><span> pull <span style="color:#f92672">=</span> { rebase <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>; };
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> starship <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span> enable <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
|
||||
</span></span><span style="display:flex;"><span> enableZshIntegration <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> settings <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span> add_newline <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>;
|
||||
</span></span><span style="display:flex;"><span> scan_timeout <span style="color:#f92672">=</span> <span style="color:#ae81ff">10</span>;
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> zsh <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span> enable <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
|
||||
</span></span><span style="display:flex;"><span> enableAutosuggestions <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
|
||||
</span></span><span style="display:flex;"><span> enableSyntaxHighlighting <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
|
||||
</span></span><span style="display:flex;"><span> history<span style="color:#f92672">.</span>size <span style="color:#f92672">=</span> <span style="color:#ae81ff">1000000</span>;
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> localVariables <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span> CASE_SENSITIVE <span style="color:#f92672">=</span> <span style="color:#e6db74">"true"</span>;
|
||||
</span></span><span style="display:flex;"><span> DISABLE_UNTRACKED_FILES_DIRTY <span style="color:#f92672">=</span> <span style="color:#e6db74">"true"</span>;
|
||||
</span></span><span style="display:flex;"><span> RPROMPT <span style="color:#f92672">=</span> <span style="color:#e6db74">""</span>; <span style="color:#75715e"># override because macOS defaults to filepath</span>
|
||||
</span></span><span style="display:flex;"><span> ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE <span style="color:#f92672">=</span> <span style="color:#e6db74">"fg=#838383,underline"</span>;
|
||||
</span></span><span style="display:flex;"><span> ZSH_DISABLE_COMPFIX <span style="color:#f92672">=</span> <span style="color:#e6db74">"true"</span>;
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> initExtra <span style="color:#f92672">=</span> <span style="color:#e6db74">''
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> export PAGER=less
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> ''</span>;
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> shellAliases <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">".."</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">"cd .."</span>;
|
||||
</span></span><span style="display:flex;"><span> grep <span style="color:#f92672">=</span> <span style="color:#e6db74">"rg --smart-case"</span>;
|
||||
</span></span><span style="display:flex;"><span> ls <span style="color:#f92672">=</span> <span style="color:#e6db74">"exa -la --git"</span>;
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"oh-my-zsh"</span> <span style="color:#f92672">=</span> {
|
||||
</span></span><span style="display:flex;"><span> enable <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
|
||||
</span></span><span style="display:flex;"><span> plugins <span style="color:#f92672">=</span> [
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"gitfast"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"last-working-dir"</span>
|
||||
</span></span><span style="display:flex;"><span> ];
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> };
|
||||
</span></span><span style="display:flex;"><span>}
|
||||
</span></span></code></pre></div><p>Save the file and run:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>home-manager switch
|
||||
</span></span></code></pre></div><p>You should see another wave of <code>/nix/store/*</code> paths. The new configuration should now be active.</p>
|
||||
<p>If you run <code>zsh</code>, you should see that you have <a href="https://starship.rs/">starship</a> and access to several other utils such as <code>rg</code>, <code>fd</code>, and <code>exa</code>.</p>
|
||||
<p>This basic configuration above is also defining your <code>~/.config/git/config</code> and <code>.zshrc</code>. If you already have either of these files, home-manager will complain about them already existing.</p>
|
||||
<p>If you run <code>cat ~/.zshrc</code>, you will see the way these configuration files are generated.</p>
|
||||
<p>You can extend this configuration for programs such as (neo)vim, emacs, alacritty, ssh, etc. To see other programs, take a look at <a href="https://github.com/nix-community/home-manager/tree/master/modules/programs">home-manager/modules/programs</a>.</p>
|
||||
<h2 id="gateway-to-nix">Gateway To Nix<a href="#gateway-to-nix" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>In ways, home-manager can be seen as a gateway to the nix ecosystem. If you have enjoyed the way you can declare user configuration with home-manager, you may be interested in expanding your configuration to include other system dependencies and configuration. For example, in Linux you can define your entire system’s configuration (including the kernel, kernel modules, networking, filesystems, etc) in nix. For macOS, there is <a href="https://github.com/LnL7/nix-darwin">nix-darwin</a> that includes nix modules for configuring launchd, dock, and other preferences and services. You may also want to check out <a href="https://nixos.wiki/wiki/Flakes">Nix Flakes</a>: a more recent feature that allows you declare dependencies, and have them automatically pinned and hashed in <code>flake.lock</code>, similar to that of many modern package managers.</p>
|
||||
<h2 id="wrapping-up">Wrapping up<a href="#wrapping-up" class="hanchor" ariaLabel="Anchor">#</a></h2>
|
||||
<p>The title of this post is slightly misleading, since it’s possible to retain some of your dotfiles and have them intermingle with home-manager by including them alongside nix. The idea of defining user configuration using nix can provide a clean way to maintain your configuration, and allow it to be portable across platforms. Is it worth the effort to migrate away from shell scripts and dotfiles? I’d say so.</p></section>
|
||||
|
||||
<div class="post-tags">
|
||||
|
||||
|
||||
<nav class="nav tags">
|
||||
<ul class="tags">
|
||||
|
||||
<li><a href="/tags/nix">nix</a></li>
|
||||
|
||||
<li><a href="/tags/dotfiles">dotfiles</a></li>
|
||||
|
||||
<li><a href="/tags/home-manager">home-manager</a></li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<section id='comments' class='comments'>
|
||||
<div class='container sep-before'>
|
||||
<div class='comments-area'><script src='https://utteranc.es/client.js'
|
||||
repo='davegallant/davegallant.github.io'
|
||||
issue-term='pathname'
|
||||
|
||||
theme='github-light'
|
||||
crossorigin='anonymous' async>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</section><footer>
|
||||
<div style="display:flex"><a class="soc" href="https://github.com/davegallant" rel="me" title="GitHub"><i data-feather="github"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://twitter.com/davega11ant/" rel="me" title="Twitter"><i data-feather="twitter"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://fosstodon.org/@davegallant" rel="me" title="Mastodon"><i data-feather="speaker"></i></a>
|
||||
<a class="border"></a><a class="soc" href="https://www.linkedin.com/in/dave-gallant/" rel="me" title="LinkedIn"><i data-feather="linkedin"></i></a>
|
||||
<a class="border"></a></div>
|
||||
<div class="footer-info">
|
||||
2023 Dave Gallant | Theme based on <a
|
||||
href="https://github.com/athul/archie">Archie</a> | Built with <a href="https://gohugo.io">Hugo</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script type="application/javascript">
|
||||
var doNotTrack = false;
|
||||
if (!doNotTrack) {
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-98710982-2', 'auto');
|
||||
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||
|
||||
<script>
|
||||
feather.replace()
|
||||
</script></div>
|
||||
</body>
|
||||
</html>
|
@@ -1 +0,0 @@
|
||||
User-agent: *
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/adguard/</title>
|
||||
<link rel="canonical" href="/tags/adguard/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/adguard/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/aws-vault/</title>
|
||||
<link rel="canonical" href="/tags/aws-vault/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/aws-vault/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/aws/</title>
|
||||
<link rel="canonical" href="/tags/aws/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/aws/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/backup/</title>
|
||||
<link rel="canonical" href="/tags/backup/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/backup/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/containers/</title>
|
||||
<link rel="canonical" href="/tags/containers/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/containers/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/degoogle/</title>
|
||||
<link rel="canonical" href="/tags/degoogle/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/degoogle/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/docker/</title>
|
||||
<link rel="canonical" href="/tags/docker/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/docker/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/dotfiles/</title>
|
||||
<link rel="canonical" href="/tags/dotfiles/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/dotfiles/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/gmail/</title>
|
||||
<link rel="canonical" href="/tags/gmail/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/gmail/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/grafana/</title>
|
||||
<link rel="canonical" href="/tags/grafana/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/grafana/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/home-manager/</title>
|
||||
<link rel="canonical" href="/tags/home-manager/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/home-manager/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/homelab/</title>
|
||||
<link rel="canonical" href="/tags/homelab/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/homelab/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/invidious/</title>
|
||||
<link rel="canonical" href="/tags/invidious/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/invidious/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/jellyfin/</title>
|
||||
<link rel="canonical" href="/tags/jellyfin/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/jellyfin/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/k3s/</title>
|
||||
<link rel="canonical" href="/tags/k3s/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/k3s/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/linux/</title>
|
||||
<link rel="canonical" href="/tags/linux/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/linux/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/lxc/</title>
|
||||
<link rel="canonical" href="/tags/lxc/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/lxc/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/netdata/</title>
|
||||
<link rel="canonical" href="/tags/netdata/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/netdata/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/nix/</title>
|
||||
<link rel="canonical" href="/tags/nix/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/nix/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/openwrt/</title>
|
||||
<link rel="canonical" href="/tags/openwrt/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/openwrt/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/pfsense/</title>
|
||||
<link rel="canonical" href="/tags/pfsense/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/pfsense/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/pihole/</title>
|
||||
<link rel="canonical" href="/tags/pihole/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/pihole/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/plex/</title>
|
||||
<link rel="canonical" href="/tags/plex/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/plex/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/podman/</title>
|
||||
<link rel="canonical" href="/tags/podman/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/podman/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/privacy/</title>
|
||||
<link rel="canonical" href="/tags/privacy/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/privacy/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/proxmox/</title>
|
||||
<link rel="canonical" href="/tags/proxmox/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/proxmox/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/python/</title>
|
||||
<link rel="canonical" href="/tags/python/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/python/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/ransomware/</title>
|
||||
<link rel="canonical" href="/tags/ransomware/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/ransomware/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/router-on-a-stick/</title>
|
||||
<link rel="canonical" href="/tags/router-on-a-stick/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/router-on-a-stick/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/router/</title>
|
||||
<link rel="canonical" href="/tags/router/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/router/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/security/</title>
|
||||
<link rel="canonical" href="/tags/security/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/security/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/synology/</title>
|
||||
<link rel="canonical" href="/tags/synology/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/synology/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/tailscale/</title>
|
||||
<link rel="canonical" href="/tags/tailscale/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/tailscale/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/virtualization/</title>
|
||||
<link rel="canonical" href="/tags/virtualization/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/virtualization/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/vlan/</title>
|
||||
<link rel="canonical" href="/tags/vlan/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/vlan/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/vpn/</title>
|
||||
<link rel="canonical" href="/tags/vpn/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/vpn/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/yewtu.be/</title>
|
||||
<link rel="canonical" href="/tags/yewtu.be/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/yewtu.be/">
|
||||
</head>
|
||||
</html>
|
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>/tags/youtube/</title>
|
||||
<link rel="canonical" href="/tags/youtube/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=/tags/youtube/">
|
||||
</head>
|
||||
</html>
|