zacharybillman-hugo/public/posts/my-selfhosting-journey/index.html

368 lines
29 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en" dir="auto">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="robots" content="index, follow">
<title>My selfhosting journey. | Zachary Billman</title>
<meta name="keywords" content="selfhosting, FOSS">
<meta name="description" content="My interest in self-hosting began in my with my interests in internet privacy. Plastered all over the internet are stories about how much Google, Facebook and Amazon know about you. I deleted my Facebook account years ago, and I&rsquo;m too paranoid to go back to the site because there&rsquo;s a real possibility that Facebook has cached my account, ready to spin it back up in case I try to login again. The ads served to me were too accurate for my liking.
This is despite almost never clicking on them!
I have become convinced of the idea that, if you are not paying for the product, you are the product. From this assumption, it follows that anywhere I trust with my data that I am not paying for (like Google Drive, Google Photos, Dropbox, Facebook, Twitter) is using my data to earn money. We know that Google uses the labels you add to Photos to train it&rsquo;s AI, and Facebook uses (at least) Instagram photos to train it&rsquo;s AI. For some, the value proposition of allowing a company to use your data for a useful service in return is an acceptable one. I find this to be a reasonable stance, but I took my growing interest in internet privacy as a chance to learn about how I can take control of my data.">
<meta name="author" content="Zachary Billman">
<link rel="canonical" href="https://www.zacharybillman.com/posts/my-selfhosting-journey/">
<link crossorigin="anonymous" href="/assets/css/stylesheet.2501c2c03e4bf83dbcd5f4c6f8fda43d8c7d579cf54417793281f3c19df525fb.css" integrity="sha256-JQHCwD5L&#43;D281fTG&#43;P2kPYx9V5z1RBd5MoHzwZ31Jfs=" rel="preload stylesheet" as="style">
<link rel="icon" href="https://www.zacharybillman.com/favicon.ico">
<link rel="icon" type="image/png" sizes="16x16" href="https://www.zacharybillman.com/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="https://www.zacharybillman.com/favicon-32x32.png">
<link rel="apple-touch-icon" href="https://www.zacharybillman.com/apple-touch-icon.png">
<link rel="mask-icon" href="https://www.zacharybillman.com/safari-pinned-tab.svg">
<meta name="theme-color" content="#2e2e33">
<meta name="msapplication-TileColor" content="#2e2e33">
<link rel="alternate" hreflang="en" href="https://www.zacharybillman.com/posts/my-selfhosting-journey/">
<noscript>
<style>
#theme-toggle,
.top-link {
display: none;
}
</style>
</noscript><script async defer data-website-id="cfe9001f-a59d-4e57-9df0-10551852558b" src="https://umami.zacharybillman.com/umami.js"></script>
<meta property="og:title" content="My selfhosting journey." />
<meta property="og:description" content="My interest in self-hosting began in my with my interests in internet privacy. Plastered all over the internet are stories about how much Google, Facebook and Amazon know about you. I deleted my Facebook account years ago, and I&rsquo;m too paranoid to go back to the site because there&rsquo;s a real possibility that Facebook has cached my account, ready to spin it back up in case I try to login again. The ads served to me were too accurate for my liking.
This is despite almost never clicking on them!
I have become convinced of the idea that, if you are not paying for the product, you are the product. From this assumption, it follows that anywhere I trust with my data that I am not paying for (like Google Drive, Google Photos, Dropbox, Facebook, Twitter) is using my data to earn money. We know that Google uses the labels you add to Photos to train it&rsquo;s AI, and Facebook uses (at least) Instagram photos to train it&rsquo;s AI. For some, the value proposition of allowing a company to use your data for a useful service in return is an acceptable one. I find this to be a reasonable stance, but I took my growing interest in internet privacy as a chance to learn about how I can take control of my data." />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://www.zacharybillman.com/posts/my-selfhosting-journey/" /><meta property="article:section" content="posts" />
<meta property="article:published_time" content="2022-07-02T00:00:00+00:00" />
<meta property="article:modified_time" content="2022-07-02T00:00:00+00:00" /><meta property="og:site_name" content="Zachary Billman" />
<meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="My selfhosting journey."/>
<meta name="twitter:description" content="My interest in self-hosting began in my with my interests in internet privacy. Plastered all over the internet are stories about how much Google, Facebook and Amazon know about you. I deleted my Facebook account years ago, and I&rsquo;m too paranoid to go back to the site because there&rsquo;s a real possibility that Facebook has cached my account, ready to spin it back up in case I try to login again. The ads served to me were too accurate for my liking.
This is despite almost never clicking on them!
I have become convinced of the idea that, if you are not paying for the product, you are the product. From this assumption, it follows that anywhere I trust with my data that I am not paying for (like Google Drive, Google Photos, Dropbox, Facebook, Twitter) is using my data to earn money. We know that Google uses the labels you add to Photos to train it&rsquo;s AI, and Facebook uses (at least) Instagram photos to train it&rsquo;s AI. For some, the value proposition of allowing a company to use your data for a useful service in return is an acceptable one. I find this to be a reasonable stance, but I took my growing interest in internet privacy as a chance to learn about how I can take control of my data."/>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1 ,
"name": "Posts",
"item": "https://www.zacharybillman.com/posts/"
},
{
"@type": "ListItem",
"position": 2 ,
"name": "My selfhosting journey.",
"item": "https://www.zacharybillman.com/posts/my-selfhosting-journey/"
}
]
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "My selfhosting journey.",
"name": "My selfhosting journey.",
"description": "My interest in self-hosting began in my with my interests in internet privacy. Plastered all over the internet are stories about how much Google, Facebook and Amazon know about you. I deleted my Facebook account years ago, and I\u0026rsquo;m too paranoid to go back to the site because there\u0026rsquo;s a real possibility that Facebook has cached my account, ready to spin it back up in case I try to login again. The ads served to me were too accurate for my liking. This is despite almost never clicking on them! I have become convinced of the idea that, if you are not paying for the product, you are the product. From this assumption, it follows that anywhere I trust with my data that I am not paying for (like Google Drive, Google Photos, Dropbox, Facebook, Twitter) is using my data to earn money. We know that Google uses the labels you add to Photos to train it\u0026rsquo;s AI, and Facebook uses (at least) Instagram photos to train it\u0026rsquo;s AI. For some, the value proposition of allowing a company to use your data for a useful service in return is an acceptable one. I find this to be a reasonable stance, but I took my growing interest in internet privacy as a chance to learn about how I can take control of my data.\n",
"keywords": [
"selfhosting", "FOSS"
],
"articleBody": "My interest in self-hosting began in my with my interests in internet privacy. Plastered all over the internet are stories about how much Google, Facebook and Amazon know about you. I deleted my Facebook account years ago, and Im too paranoid to go back to the site because theres a real possibility that Facebook has cached my account, ready to spin it back up in case I try to login again. The ads served to me were too accurate for my liking. This is despite almost never clicking on them! I have become convinced of the idea that, if you are not paying for the product, you are the product. From this assumption, it follows that anywhere I trust with my data that I am not paying for (like Google Drive, Google Photos, Dropbox, Facebook, Twitter) is using my data to earn money. We know that Google uses the labels you add to Photos to train its AI, and Facebook uses (at least) Instagram photos to train its AI. For some, the value proposition of allowing a company to use your data for a useful service in return is an acceptable one. I find this to be a reasonable stance, but I took my growing interest in internet privacy as a chance to learn about how I can take control of my data.\nInitially, I lurked on forums like /r/privacy to learn what I could do to avoid big-techs watchful eye. There were numerous comments along the lines of: “The only way to be in control of your data is to self-host your services.” I had no idea what this meant! Hard to believe that less than a year later, I learned to use (and love) Linux as my primary OS, and have happily replaced Google Photos, Google Drive and other services with my own self-hosted alternatives. Self-hosting, I have since learned, is when you run useful programs from your own computer. By doing so, you have complete knowledge of where and how your data is stored and how it is being used. It has the additional effect of being a bottomless time sink.\nTo begin, I needed an always-on computer to run these useful programs. I began with a humble Raspberry Pi.\nFigure 1: My humble Raspberry Pi and its hard drive. This dude currently tirelessly runs the excellent Adguard Home and downloads a backup of my data every night.\nThese are tiny, but capable computers that are great for fiddling with. The projects people develop for these are amazing and diverse. With RPi in hand, I began with the ambitious project of replacing Google Drive with Nextcloud. After much frustration with a bare metal installation, I found the NextcloudPi project. Surprisingly, it went pretty okay! At first, I was intimidated by Linux defaults, but over time I grew to appreciate, and indeed, prefer Linux as an operating system. My decision to use Linux over Windows/MacOS is because it is free and open source software (FOSS). This is a topic for a different post, but I think using FOSS when possible is a moral imperative of sorts. I used Nextcloud strictly from my home for a few months, without the ability to connect to it from the internet, to test the self-hosting waters. My first true cloud replacement spun up once I decided to access this lil guy from the internet. To do so, I purchased a domain (not the one this site is hosted on) and pointed it to the IP of my house. I forwarded the appropriate ports of my router to the RPi.\nThis is when the real exploration began. I was able to access my files and images using Nextcloud, but the photo viewing service left something to be desired. No problem, why not spin up an instance of Photoprism? I use RSS feeds to keep on top of the latest science in the journals relevant to my field using Feedly. Why not host my own RSS feed aggregator so I can subscribe to as many feeds as I desire?\nThis cycle continued, and I accrued many cool applications, but in the back of my mind I worried about opening up my home network to the internet. I also struggled to run some programs because the RPi uses the arm64 architecture, and most services are written with amd64 in mind. These two forces eventually convinced me to purchase a server where I could manage all of my services remotely. Some would say that not owning the hardware that is running your own services is not “true” self-hosting. I think this is needlessly exclusive. Let everyone self host, dangit! Someday, when I have more stable internet and a more permanent home, I hope to host everything from my own home, but until then, Im extremely pleased with my current stack. And that is where I am now. I happily host numerous services on my virtual private server that entirely replace Google Photos, Google Drive and GitHub for me. Even better, there are specialized services that fill a need I never realized I had. Whats more, if I ever want to spin up a new service, all I have to do is add it to my to docker-compose file and it will be up within minutes. What a world!\nI thought about making this into a “guide” style post. I nixed that idea because, quite frankly, I feel like I dont know what Im doing. I am really happy with my setup, but I dont feel like I have the authority to tell people how to administer their own services. If you are interested, allow me to point you toward the guide that really got me rolling: Ultimate Traefik Docker Compose Guide.\nFor those of you wondering what I am currently hosting, check out my current list at the link and let me know what you think!\n",
"wordCount" : "980",
"inLanguage": "en",
"datePublished": "2022-07-02T00:00:00Z",
"dateModified": "2022-07-02T00:00:00Z",
"author":[{
"@type": "Person",
"name": "Zachary Billman"
}],
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://www.zacharybillman.com/posts/my-selfhosting-journey/"
},
"publisher": {
"@type": "Organization",
"name": "Zachary Billman",
"logo": {
"@type": "ImageObject",
"url": "https://www.zacharybillman.com/favicon.ico"
}
}
}
</script>
</head>
<body class="" id="top">
<script>
if (localStorage.getItem("pref-theme") === "dark") {
document.body.classList.add('dark');
}
</script>
<header class="header">
<nav class="nav">
<div class="logo">
<a href="https://www.zacharybillman.com/" accesskey="h" title="Zachary Billman (Alt + H)">
<img src="https://www.zacharybillman.com/homepage/flask.svg" alt="" aria-label="logo"
height="35">Zachary Billman</a>
<div class="logo-switches">
<button id="theme-toggle" accesskey="t" title="(Alt + T)">
<svg id="moon" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round">
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
</svg>
<svg id="sun" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</button>
</div>
</div>
<ul id="menu">
<li>
<a href="https://www.zacharybillman.com/categories/" title="categories">
<span>categories</span>
</a>
</li>
<li>
<a href="https://www.zacharybillman.com/tags/" title="tags">
<span>tags</span>
</a>
</li>
<li>
<a href="https://www.zacharybillman.com/posts/" title="posts">
<span>posts</span>
</a>
</li>
<li>
<a href="https://www.zacharybillman.com/search/" title="search (Alt &#43; /)" accesskey=/>
<span>search</span>
</a>
</li>
</ul>
</nav>
</header>
<main class="main">
<article class="post-single">
<header class="post-header">
<div class="breadcrumbs"><a href="https://www.zacharybillman.com/">Home</a>&nbsp;»&nbsp;<a href="https://www.zacharybillman.com/posts/">Posts</a></div>
<h1 class="post-title entry-hint-parent">
My selfhosting journey.
</h1>
<div class="post-meta"><span title='2022-07-02 00:00:00 +0000 UTC'>Saturday, July 2, 2022</span>&nbsp;·&nbsp;5 min&nbsp;·&nbsp;Zachary Billman
</div>
</header>
<div class="post-content"><p>My interest in self-hosting began in my with my interests in internet privacy. Plastered all over the internet are stories about how much Google, Facebook and Amazon know about you. I deleted my Facebook account years ago, and I&rsquo;m too paranoid to go back to the site because there&rsquo;s <a href="https://www.reddit.com/r/privacy/comments/6nmjfh/facebook_account_fully_recovered_3_years_after/">a real possibility that Facebook has cached my account, ready to spin it back up</a> in case I try to login again. The ads served to me were too accurate for my liking.
<span class="sidenote-number"><small class="sidenote">
This is despite almost never clicking on them!
</small></span>
I have become convinced of the idea that, if you are not paying for the product, you are the product. From this assumption, it follows that anywhere I trust with my data that I am not paying for (like Google Drive, Google Photos, Dropbox, Facebook, Twitter) is using my data to earn money. We know that <a href="https://www.theverge.com/2020/11/11/21559930/google-train-ai-photos-image-labelling-app-android-update">Google uses the labels you add to Photos to train it&rsquo;s AI</a>, and <a href="https://ai.facebook.com/blog/seer-the-start-of-a-more-powerful-flexible-and-accessible-era-for-computer-vision/">Facebook uses (at least) Instagram photos to train it&rsquo;s AI</a>. For some, the value proposition of allowing a company to use your data for a useful service in return is an acceptable one. I find this to be a reasonable stance, but I took my growing interest in internet privacy as a chance to learn about how I can take control of my data.</p>
<p>Initially, I lurked on forums like /r/privacy to learn what I could do to avoid big-tech&rsquo;s watchful eye. There were numerous comments along the lines of: &ldquo;The only way to be in control of your data is to self-host your services.&rdquo; I had no idea what this meant!
<span class="sidenote-number"><small class="sidenote">
Hard to believe that less than a year later, I learned to use (and love) Linux as my primary OS, and have happily replaced Google Photos, Google Drive and other services with my own self-hosted alternatives.
</small></span>
Self-hosting, I have since learned, is when you run useful programs from your own computer. By doing so, you have complete knowledge of where and how your data is stored and how it is being used. It has the additional effect of being a bottomless time sink.</p>
<p>To begin, I needed an always-on computer to run these useful programs. I began with a humble Raspberry Pi.</p>
<p><a id="figure--rpi"></a></p>
<figure>
<img loading="lazy" src="./images/rpi.webp"
alt="Figure 1: My humble Raspberry Pi and it&rsquo;s hard drive. This dude currently tirelessly runs the excellent Adguard Home and downloads a backup of my data every night."/> <figcaption>
<p><span class="figure-number">Figure 1: </span>My humble Raspberry Pi and it&rsquo;s hard drive. This dude currently tirelessly runs <a href="https://github.com/AdguardTeam/AdGuardHome">the excellent Adguard Home</a> and downloads a backup of my data every night.</p>
</figcaption>
</figure>
<p>These are tiny, but capable computers that are great for fiddling with. The projects <a href="https://www.reddit.com/r/RASPBERRY_PI_PROJECTS/">people develop for these are amazing and diverse.</a> With RPi in hand, I began with the ambitious project of replacing Google Drive with <a href="https://nextcloud.com/">Nextcloud.</a> After much frustration with a bare metal installation, I found the <a href="https://github.com/nextcloud/nextcloudpi">NextcloudPi project.</a> Surprisingly, it went pretty okay! At first, I was intimidated by Linux defaults, but over time I grew to appreciate, and indeed, prefer Linux as an operating system.
<span class="sidenote-number"><small class="sidenote">
My decision to use Linux over Windows/MacOS is because it is free and open source software (FOSS). This is a topic for a different post, but I think using FOSS when possible is a moral imperative of sorts.
</small></span>
I used Nextcloud strictly from my home for a few months, without the ability to connect to it from the internet, to test the self-hosting waters. My first true cloud replacement spun up once I decided to access this lil&rsquo; guy from the internet. To do so, I purchased a domain (not the one this site is hosted on) and pointed it to the IP of my house. I forwarded the appropriate ports of my router to the RPi.</p>
<p>This is when the real exploration began. I was able to access my files and images using Nextcloud, but the photo viewing service left something to be desired. No problem, why not spin up <a href="https://photoprism.app/">an instance of Photoprism?</a> I use RSS feeds to keep on top of the latest science in the journals relevant to my field using Feedly. Why not host <a href="https://freshrss.org/">my own RSS feed aggregator</a> so I can subscribe to as many feeds as I desire?</p>
<p>This cycle continued, and I accrued many cool applications, but in the back of my mind I worried about opening up my home network to the internet. I also struggled to run some programs because the RPi uses the arm64 architecture, and most services are written with amd64 in mind. These two forces eventually convinced me to purchase a server where I could manage all of my services remotely.
<span class="sidenote-number"><small class="sidenote">
Some would say that not owning the hardware that is running your own services is not &ldquo;true&rdquo; self-hosting. I think this is needlessly exclusive. Let everyone self host, dangit! Someday, when I have more stable internet and a more permanent home, I hope to host everything from my own home, but until then, I&rsquo;m extremely pleased with my current stack.
</small></span>
And that is where I am now. I happily host numerous services on my virtual private server that entirely replace Google Photos, Google Drive and GitHub for me. Even better, there are specialized services that fill a need I never realized I had. What&rsquo;s more, if I ever want to spin up a new service, all I have to do is add it to my to docker-compose file and it will be up within minutes. What a world!</p>
<p>I thought about making this into a &ldquo;guide&rdquo; style post. I nixed that idea because, quite frankly, I feel like I don&rsquo;t know what I&rsquo;m doing. I am really happy with my setup, but I don&rsquo;t feel like I have the authority to tell people how to administer their own services. If you are interested, allow me to point you toward the guide <a href="https://www.smarthomebeginner.com/traefik-docker-compose-guide-2022/">that really got me rolling: Ultimate Traefik Docker Compose Guide.</a></p>
<p>For those of you wondering <a href="https://www.zacharybillman.com/posts/zpb-current-selfhosted/">what I am currently hosting, check out my current list at the link</a> and let me know what you think!</p>
</div>
<footer class="post-footer">
<ul class="post-tags">
<li><a href="https://www.zacharybillman.com/tags/selfhosting/">Selfhosting</a></li>
<li><a href="https://www.zacharybillman.com/tags/foss/">FOSS</a></li>
</ul>
<nav class="paginav">
<a class="prev" href="https://www.zacharybillman.com/posts/rss-feeds-to-find-science-papers/">
<span class="title">« Prev</span>
<br>
<span>Using RSS feeds to keep on top of science.</span>
</a>
<a class="next" href="https://www.zacharybillman.com/posts/zpb-current-selfhosted/">
<span class="title">Next »</span>
<br>
<span>What I&#39;m currently selfhosting.</span>
</a>
</nav>
</footer><script defer src="https://commento.zacharybillman.com/js/commento.js"></script>
<noscript>
Please enable JavaScript to view the
<a href="https://commento.io" rel="nofollow">
comments powered by Commento++.
</a>
</noscript>
<div id="commento"></div>
</article>
</main>
<footer class="footer">
<span>&copy; 2024 <a href="https://www.zacharybillman.com/">Zachary Billman</a></span> ·
<span>
Powered by
<a href="https://gohugo.io/" rel="noopener noreferrer" target="_blank">Hugo</a> &
<a href="https://github.com/adityatelange/hugo-PaperMod/" rel="noopener" target="_blank">PaperMod</a>
</span>
</footer>
<a href="#top" aria-label="go to top" title="Go to Top (Alt + G)" class="top-link" id="top-link" accesskey="g">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 6" fill="currentColor">
<path d="M12 6H0l6-6z" />
</svg>
</a>
<script>
let menu = document.getElementById('menu')
if (menu) {
menu.scrollLeft = localStorage.getItem("menu-scroll-position");
menu.onscroll = function () {
localStorage.setItem("menu-scroll-position", menu.scrollLeft);
}
}
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener("click", function (e) {
e.preventDefault();
var id = this.getAttribute("href").substr(1);
if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView({
behavior: "smooth"
});
} else {
document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView();
}
if (id === "top") {
history.replaceState(null, null, " ");
} else {
history.pushState(null, null, `#${id}`);
}
});
});
</script>
<script>
var mybutton = document.getElementById("top-link");
window.onscroll = function () {
if (document.body.scrollTop > 800 || document.documentElement.scrollTop > 800) {
mybutton.style.visibility = "visible";
mybutton.style.opacity = "1";
} else {
mybutton.style.visibility = "hidden";
mybutton.style.opacity = "0";
}
};
</script>
<script>
document.getElementById("theme-toggle").addEventListener("click", () => {
if (document.body.className.includes("dark")) {
document.body.classList.remove('dark');
localStorage.setItem("pref-theme", 'light');
} else {
document.body.classList.add('dark');
localStorage.setItem("pref-theme", 'dark');
}
})
</script>
<script>
document.querySelectorAll('pre > code').forEach((codeblock) => {
const container = codeblock.parentNode.parentNode;
const copybutton = document.createElement('button');
copybutton.classList.add('copy-code');
copybutton.innerHTML = 'copy';
function copyingDone() {
copybutton.innerHTML = 'copied!';
setTimeout(() => {
copybutton.innerHTML = 'copy';
}, 2000);
}
copybutton.addEventListener('click', (cb) => {
if ('clipboard' in navigator) {
navigator.clipboard.writeText(codeblock.textContent);
copyingDone();
return;
}
const range = document.createRange();
range.selectNodeContents(codeblock);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
try {
document.execCommand('copy');
copyingDone();
} catch (e) { };
selection.removeRange(range);
});
if (container.classList.contains("highlight")) {
container.appendChild(copybutton);
} else if (container.parentNode.firstChild == container) {
} else if (codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName == "TABLE") {
codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.appendChild(copybutton);
} else {
codeblock.parentNode.appendChild(copybutton);
}
});
</script>
</body>
</html>