<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kyle Schwartz</title>
    <description>The latest articles on DEV Community by Kyle Schwartz (@kylejschwartz).</description>
    <link>https://dev.to/kylejschwartz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F280419%2F0793371f-3a8d-4eee-8bbd-f8e189da2d4a.jpg</url>
      <title>DEV Community: Kyle Schwartz</title>
      <link>https://dev.to/kylejschwartz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kylejschwartz"/>
    <language>en</language>
    <item>
      <title>Migrate a JS Project to Yarn Berry</title>
      <dc:creator>Kyle Schwartz</dc:creator>
      <pubDate>Tue, 28 Dec 2021 14:56:46 +0000</pubDate>
      <link>https://dev.to/kylejschwartz/migrate-a-js-project-to-yarn-berry-l90</link>
      <guid>https://dev.to/kylejschwartz/migrate-a-js-project-to-yarn-berry-l90</guid>
      <description>&lt;p&gt;For this tutorial, you will need a starting project. The assumption is that there is no lock file and the project is not installed (i.e. no &lt;code&gt;node_modules&lt;/code&gt; folder). I will be starting with a blank &lt;a href="https://vitejs.dev" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; project. You can create one by running the command below and following the prompts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn create vite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't have Yarn berry installed, run one of the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Node &amp;gt;=16.10 - May have to run as admin&lt;/span&gt;
corepack &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Node &amp;lt;16.10&lt;/span&gt;
npm i &lt;span class="nt"&gt;-g&lt;/span&gt; corepack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once completed, open the project. Now, run the following commands in sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn &lt;span class="nb"&gt;set &lt;/span&gt;version berry
yarn
yarn dlx @yarnpkg/sdks vscode &lt;span class="c"&gt;# If using vscode/vscodium&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All done!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>yarn</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Shuffle JavaScript Array in 1 Line</title>
      <dc:creator>Kyle Schwartz</dc:creator>
      <pubDate>Mon, 06 Dec 2021 21:22:01 +0000</pubDate>
      <link>https://dev.to/kylejschwartz/shuffle-javascript-array-in-1-line-43a3</link>
      <guid>https://dev.to/kylejschwartz/shuffle-javascript-array-in-1-line-43a3</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shuffle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;arr&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although slightly longer than other implementations, it maintains an even distribution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;shuffle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// { '3,2,1': 16647,&lt;/span&gt;
&lt;span class="c1"&gt;//   '1,3,2': 16877,&lt;/span&gt;
&lt;span class="c1"&gt;//   '2,1,3': 16781,&lt;/span&gt;
&lt;span class="c1"&gt;//   '1,2,3': 16510,&lt;/span&gt;
&lt;span class="c1"&gt;//   '3,1,2': 16856,&lt;/span&gt;
&lt;span class="c1"&gt;//   '2,3,1': 16329 }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>array</category>
    </item>
    <item>
      <title>Installing Jellyfin on LG webOS</title>
      <dc:creator>Kyle Schwartz</dc:creator>
      <pubDate>Sat, 06 Nov 2021 13:49:10 +0000</pubDate>
      <link>https://dev.to/kylejschwartz/installing-jellyfin-on-lg-webos-2d7b</link>
      <guid>https://dev.to/kylejschwartz/installing-jellyfin-on-lg-webos-2d7b</guid>
      <description>&lt;p&gt;&lt;strong&gt;UPDATE 2022-11-29&lt;/strong&gt;: Jellyfin has added their app to LG's WebOS store for newer TVs (2021+). For older ones (WebOS &amp;lt; 6), the following instructions should still apply.&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;Clone &lt;a href="https://github.com/jellyfin/jellyfin-webos" rel="noopener noreferrer"&gt;https://github.com/jellyfin/jellyfin-webos&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Open WebOS TV SDK&lt;/li&gt;
&lt;li&gt;cd into directory&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;ares-package org.jellyfin.webos&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Open the Developer Mode app on the TV and login

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://webostv.developer.lge.com/develop/app-test/using-devmode-app/#installDevModeApp" rel="noopener noreferrer"&gt;Get the Developer Mode app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://webostv.developer.lge.com/develop/app-test/preparing-account/" rel="noopener noreferrer"&gt;Get a developer account&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Turn on Dev Mode, TV will reboot&lt;/li&gt;
&lt;li&gt;Re-open the Developer Mode app&lt;/li&gt;
&lt;li&gt;Turn on Key Server&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;ares-novacom --device tv --getkey&lt;/code&gt;, passphrase is found on screen&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;ares-install --device tv --list&lt;/code&gt;, a blank line means everything works&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;ares-install --device tv ./org.jellyfin.webos_X.X.X_all.ipk&lt;/code&gt; replacing the Xs with the requisite version number&lt;/li&gt;
&lt;li&gt;Done!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  If you need to re-add tv to the device list
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;ares-setup-device&lt;/code&gt; and remove tv&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;ares-setup-device&lt;/code&gt; and choose add&lt;/li&gt;
&lt;li&gt;Use the following settings:

&lt;ul&gt;
&lt;li&gt;Device Name: tv&lt;/li&gt;
&lt;li&gt;Device IP address: IP found on screen&lt;/li&gt;
&lt;li&gt;Device Port: 9922&lt;/li&gt;
&lt;li&gt;SSH user: prisoner&lt;/li&gt;
&lt;li&gt;Description: optional&lt;/li&gt;
&lt;li&gt;Select authentication: password&lt;/li&gt;
&lt;li&gt;Password: leave blank&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>jellyfin</category>
      <category>webos</category>
      <category>lg</category>
    </item>
    <item>
      <title>Using Packetriot to Access OctoPrint Remotely</title>
      <dc:creator>Kyle Schwartz</dc:creator>
      <pubDate>Wed, 12 May 2021 15:25:50 +0000</pubDate>
      <link>https://dev.to/kylejschwartz/using-packetriot-to-access-octoprint-remotely-2n8i</link>
      <guid>https://dev.to/kylejschwartz/using-packetriot-to-access-octoprint-remotely-2n8i</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome! This is a pretty straight-forward tutorial on setting up Packetriot. Although intended for OctoPrint, this is pretty software-agnostic, and thus, can be followed for pretty much any local service. I will be doing this on an Orange Pi PC+ running Armbian (Debian) Buster. This should work for any Debian-like OS such as PopOS and Ubuntu.&lt;/p&gt;

&lt;p&gt;For this tutorial, you'll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Domain&lt;/li&gt;
&lt;li&gt;Basic Linux knowledge&lt;/li&gt;
&lt;li&gt;A Packetriot Account (&lt;a href="https://packetriot.com" rel="noopener noreferrer"&gt;Get one here&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're not running a Debian-like OS, additional download instructions are available &lt;a href="https://packetriot.com/downloads" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If at any point you get stuck, check out Packetriot's incredibly extensive documentation &lt;a href="https://docs.packetriot.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, let's get into it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Packetriot
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Install the GPG key and make sure apt can work with GPG signed packages and HTTPS sources.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;apt-transport-https gnupg &lt;span class="nt"&gt;-y&lt;/span&gt;

wget &lt;span class="nt"&gt;-qO&lt;/span&gt; - https://download.packetriot.com/linux/debian/pubkey.gpg | &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-key add -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Setup the Packetriot source in the apt sources directory.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"
deb [arch=amd64] https://download.packetriot.com/linux/debian/buster/stable/non-free/binary-amd64 / 
deb [arch=i386]  https://download.packetriot.com/linux/debian/buster/stable/non-free/binary-i386  / 
deb [arch=armhf] https://download.packetriot.com/linux/debian/buster/stable/non-free/binary-armhf / 
deb [arch=arm64] https://download.packetriot.com/linux/debian/buster/stable/non-free/binary-arm64 / 
"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/packetriot.list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Update the apt sources and install the client.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update

&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;pktriot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add a Domain
&lt;/h2&gt;

&lt;p&gt;In order to have a static domain, you'll either need to have a paid plan or provide your own domain. In this tutorial, we'll opt for the latter.&lt;/p&gt;

&lt;p&gt;On the Packetriot site: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;code&gt;Domains&lt;/code&gt; -&amp;gt; &lt;code&gt;Custom&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;Verify Domain&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enter your domain name.&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;Submit&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, Packetriot will show you a long string of text that you need to copy. In your DNS config in your domain registrar, you will have to create a new &lt;code&gt;TXT&lt;/code&gt; record. Paste in the &lt;code&gt;TXT Record&lt;/code&gt; from Packetriot and wait a few minutes. Once the domain is verified, continue to the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable Packetriot
&lt;/h2&gt;

&lt;p&gt;Now that our domain is setup, we will actually create the tunnel. First, we enable the Packetriot service so it'll start on the server's startup. Then we will login and create the tunnel. When you run configure, make sure you choose option &lt;code&gt;1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;pktriot
&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; pktriot pktriot configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the configuration has been run, you'll be provided with an IPv4. Take this and create a new &lt;code&gt;A&lt;/code&gt; record in your domain registrar's DNS, same as before with the &lt;code&gt;TXT&lt;/code&gt; record. This must be the same domain as registered earlier.&lt;/p&gt;

&lt;p&gt;Next, we will run the following command to tell the tunnel where to connect. The first part is not a typo; it is telling the server to run the command as the &lt;code&gt;pktriot&lt;/code&gt; user, and then running the &lt;code&gt;pktriot&lt;/code&gt; command. Change &lt;code&gt;example.com&lt;/code&gt; and &lt;code&gt;80&lt;/code&gt; to the relevant fields. I.e. your domain and port, respectively. For OctoPrint, this will be 5000 if no reverse proxy has been setup. Additionally, change &lt;code&gt;127.0.0.1&lt;/code&gt; to the appropriate IP if not being run on the same server as the server you are tunneling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; pktriot pktriot tunnel http add &lt;span class="nt"&gt;--domain&lt;/span&gt; example.com &lt;span class="nt"&gt;--destination&lt;/span&gt; 127.0.0.1 &lt;span class="nt"&gt;--http&lt;/span&gt; 80 &lt;span class="nt"&gt;--letsencrypt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, start the Packetriot service. This may take a few minutes to get the SSL certificates. Once it is done, you can go to your URL and access your server from anywhere!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start pktriot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thank you so much for following allong with this tutorial! If you liked it, had any problems, or found any errors, let me know in the comments down below!&lt;/p&gt;

&lt;p&gt;Have a great day!&lt;/p&gt;

</description>
      <category>octoprint</category>
      <category>packetriot</category>
      <category>tunneling</category>
      <category>remote</category>
    </item>
    <item>
      <title>Setting Variables Using Switch Statements In JavaScript</title>
      <dc:creator>Kyle Schwartz</dc:creator>
      <pubDate>Tue, 19 Jan 2021 17:01:32 +0000</pubDate>
      <link>https://dev.to/kylejschwartz/setting-variables-using-switch-statements-in-javascript-4g6h</link>
      <guid>https://dev.to/kylejschwartz/setting-variables-using-switch-statements-in-javascript-4g6h</guid>
      <description>&lt;p&gt;Here is a snippet showing an example of how this would be done. Each animal has a favorite color which we will determine using a switch statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yellow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;green&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "blue"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a similar example with parameter passing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yellow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;green&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "green"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just to show how much cleaner the above version is, here is an example using an if/else statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yellow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animal&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;green&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "green"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While, yes, the if/else version is technically shorter, you repeat yourself, it is less readable (subjectively), and it is inherently slower (at scale). With switch statements, the expression is only evaluated once, but with our if/else it is evaluated 3 times. Although, this example is short, so it may not affect performance. GeeksforGeeks has a great article comparing the two: &lt;a href="https://www.geeksforgeeks.org/switch-vs-else/" rel="noopener noreferrer"&gt;https://www.geeksforgeeks.org/switch-vs-else/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tricks</category>
    </item>
    <item>
      <title>Install Docker (Compose) on Oracle Linux 8</title>
      <dc:creator>Kyle Schwartz</dc:creator>
      <pubDate>Tue, 22 Dec 2020 01:05:12 +0000</pubDate>
      <link>https://dev.to/kylejschwartz/install-docker-compose-on-oracle-linux-8-1kb0</link>
      <guid>https://dev.to/kylejschwartz/install-docker-compose-on-oracle-linux-8-1kb0</guid>
      <description>&lt;p&gt;Welcome! I couldn't find a simple, straightforward tutorial on how to do this. Everything written here is a summation of the &lt;a href="https://docs.docker.com/engine/install/centos/" rel="noopener noreferrer"&gt;Docker documentation&lt;/a&gt; on CentOS, as that is what OL is built upon. I will be using Oracle Linux 8 build 2020.12.17-0, for reference. Now, on to the tutorial!&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Docker Engine
&lt;/h2&gt;

&lt;p&gt;First, install yum-utils&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;yum &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; yum-utils
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we add the Docker repository&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;yum-config-manager &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--add-repo&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    https://download.docker.com/linux/centos/docker-ce.repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can install Docker. Answer &lt;code&gt;y&lt;/code&gt; for all prompts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;yum &lt;span class="nb"&gt;install &lt;/span&gt;docker-ce docker-ce-cli containerd.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, start Docker&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optionally, run the &lt;code&gt;hello-world&lt;/code&gt; image to make sure everything works&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker run hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing Docker Compose
&lt;/h2&gt;

&lt;p&gt;First, download Docker Compose&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="s2"&gt;"https://github.com/docker/compose/releases/download/1.27.4/docker-compose-&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /usr/local/bin/docker-compose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add execution perms to the download&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; +x /usr/local/bin/docker-compose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we need to link to the &lt;code&gt;docker-compose&lt;/code&gt; command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /usr/local/bin/docker-compose /usr/bin/docker-compose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, everything should work. Run &lt;code&gt;docker-compose --version&lt;/code&gt; to confirm.&lt;/p&gt;




&lt;p&gt;And that's it! Easy, right?&lt;/p&gt;

&lt;p&gt;Thank you for joining me on this adventure and I hope this was some help!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>linux</category>
      <category>oracle</category>
      <category>compose</category>
    </item>
    <item>
      <title>My Unnecessary Adventure in (Re)Building a Media Sever</title>
      <dc:creator>Kyle Schwartz</dc:creator>
      <pubDate>Fri, 30 Oct 2020 22:13:50 +0000</pubDate>
      <link>https://dev.to/kylejschwartz/my-unnecessary-adventure-in-re-building-a-media-sever-3b9d</link>
      <guid>https://dev.to/kylejschwartz/my-unnecessary-adventure-in-re-building-a-media-sever-3b9d</guid>
      <description>&lt;p&gt;Welcome! Strap in because this is gonna be a long ride.&lt;/p&gt;

&lt;p&gt;To preface, I had an existing media server that I broke some permissions and reinstalling was the only option. I had an existing RAID 0 setup with lots of data I did not want to lose, plus a standalone SSD. So, without further adieu, here we go!&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Ubuntu Server
&lt;/h2&gt;

&lt;p&gt;I chose Ubuntu Server because Ubuntu has a great deal of community support and I have no need for a desktop GUI.&lt;/p&gt;

&lt;p&gt;Download the ISO from &lt;a href="https://ubuntu.com/download/server" rel="noopener noreferrer"&gt;here&lt;/a&gt;. You may have to choose 'Option 3' to actually get a download. At the time of writing, I'm using 20.04.1, so take that into account.&lt;/p&gt;

&lt;p&gt;My tool of choice for burning ISOs is &lt;a href="https://www.balena.io/etcher/" rel="noopener noreferrer"&gt;balenaEtcher&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Plug in the USB, boot to it, and follow setup. Make sure you enable the SSH server AND NO LVM ON THE SSD. Check to make sure the full capacity of the SSD is mounted to &lt;code&gt;/&lt;/code&gt; and then you're good to go. Finish the setup, remove the USB, and reboot. Now we'll switch to SSH.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring SSH
&lt;/h2&gt;

&lt;p&gt;Port 22 sucks, but we need to login with it. Connect to the server on port 22 with the credentials you added during install.&lt;/p&gt;

&lt;p&gt;Open the port in the firewall&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ufw allow 8364/tcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the SSH config file and change the port used&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/ssh/sshd_config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Find the line containing &lt;code&gt;Port 22&lt;/code&gt;, uncomment, and change to &lt;code&gt;Port 8364&lt;/code&gt;. Save (&lt;code&gt;ctrl x&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;Restart the SSH server and then reconnect on your client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl restart ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Drive Mounting
&lt;/h2&gt;

&lt;p&gt;Find the UUID of the drive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo blkid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your drive to &lt;code&gt;/etc/fstab&lt;/code&gt; (BE CAREFUL, THIS CAN BRICK STUFF):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/fstab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E.g:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UUID=ccc56606-385e-4a16-89c4-7f1513ab1641 /home ext4 defaults 0 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reboot the system and your drive your be properly mounted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker
&lt;/h2&gt;

&lt;p&gt;First, update your system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update
sudo apt upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of repeating things, go follow the official Docker tutorial &lt;a href="https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Just follow the 'Install using the repository' and 'Install Docker Engine' sections.&lt;/p&gt;

&lt;p&gt;Then, install Docker Compose by following the tutorial &lt;a href="https://docs.docker.com/compose/install/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The next part is taken mostly from &lt;a href="https://www.smarthomebeginner.com/docker-home-media-server-2018-basic/#Add_Linux_User_to_Docker_Group" rel="noopener noreferrer"&gt;Smart Home Beginner&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;We will add the current user to the docker group to simplify some things in the future.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo gpasswd -a $USER docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Activate the changes using the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;newgrp docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Portainer
&lt;/h2&gt;

&lt;p&gt;Portainer is our docker management solution. Yes, I have serious issues with it but currently don't have an alternative. Maybe this will change in the future, but here we are.&lt;/p&gt;

&lt;p&gt;Run the following commands to get Portainer up and running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker volume create portainer_data
docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
docker run -d -p 9001:9001 --name portainer_agent --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/docker/volumes:/var/lib/docker/volumes portainer/agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open a browser and go to your computer's IP with the port 9000. For me, that's &lt;code&gt;http://192.168.1.50:9000&lt;/code&gt;. Chose a username and password, then create user.&lt;/p&gt;

&lt;p&gt;Choose "Docker" and press "Connect".&lt;/p&gt;

&lt;p&gt;Now that you are in the web panel, click on 'local' in the middle, and then the 'Stacks' tab on the left. Click 'Add stack' and give it a name such as "main_stack". Paste in the following config and adjust it to fit your needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2.3"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;organizr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linuxserver/organizr&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;organizr&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PUID=${PUID}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PGID=${PGID}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TZ=${TZ}&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${USERDIR}/organizr:/config&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;9983:80&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;watchtower&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;watchtower&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;containrrr/watchtower&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--schedule "0 0 4 * * *" --cleanup&lt;/span&gt;

  &lt;span class="na"&gt;radarr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linuxserver/radarr&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;radarr&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PUID=${PUID}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PGID=${PGID}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TZ=${TZ}&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${USERDIR}/radarr:/config&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${USERDIR}/media/movies:/movies&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${USERDIR}/downloads:/downloads&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;7878:7878&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;sonarr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linuxserver/sonarr&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonarr&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PUID=${PUID}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PGID=${PGID}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TZ=${TZ}&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${USERDIR}/sonarr:/config&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${USERDIR}/media/tv:/tv&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${USERDIR}/downloads:/downloads&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8989:8989&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;duckdns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linuxserver/duckdns&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;duckdns&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TZ=${TZ}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SUBDOMAINS=kyleserver&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TOKEN=326ab158-e842-4d0e-aa20-233e0f7e51e3&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;minecraft-creative&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-creative&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/minecraft-server&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;EULA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
      &lt;span class="na"&gt;TYPE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PAPER&lt;/span&gt;
      &lt;span class="na"&gt;VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.16.2&lt;/span&gt;
      &lt;span class="na"&gt;CONSOLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&lt;/span&gt;
      &lt;span class="na"&gt;LEVEL_TYPE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flat"&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;25566:25565&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${USERDIR}/minecraft-creative:/data&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;minecraft-survival&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-survival&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/minecraft-server&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;EULA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
      &lt;span class="na"&gt;TYPE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PAPER&lt;/span&gt;
      &lt;span class="na"&gt;VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.16.2&lt;/span&gt;
      &lt;span class="na"&gt;CONSOLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&lt;/span&gt;
      &lt;span class="na"&gt;MEMORY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2G&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;25565:25565&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${USERDIR}/minecraft-survival:/data&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;qbittorrent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linuxserver/qbittorrent:14.2.5.99202004250119-7015-2c65b79ubuntu18.04.1-ls93&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;qbittorrent&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;service:gluetun"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${USERDIR}/docker/qbittorrent:/config&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${USERDIR}/downloads:/downloads&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PUID=${PUID}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PGID=${PGID}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TZ=${TZ}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;UMASK_SET=002&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WEBUI_PORT=4545&lt;/span&gt;

  &lt;span class="na"&gt;gluetun&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;qmcgaw/private-internet-access&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gluetun&lt;/span&gt;
    &lt;span class="na"&gt;cap_add&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NET_ADMIN&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8888:8888&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8388:8388&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8388:8388/udp&lt;/span&gt; &lt;span class="c1"&gt;# Shadowsocks&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8001:8001&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;4545:4545&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;6881:6881&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;6881:6881/udp&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${USERDIR}/gluetun:/gluetun&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;VPNSP=surfshark&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TZ=${TZ}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;USER=USERNAME&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PASSWORD=PASSWORD&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;REGION=Canada Toronto&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, run &lt;code&gt;id&lt;/code&gt; and note your uid and pid. We will input these as PUID and PGID in the "Environment" section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PUID=1000
PGID=1000
TZ="America/Toronto"
USERDIR="/home/user"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add any environment variables that you need NOW as I don't believe these can be changed in the future.&lt;/p&gt;

&lt;p&gt;Click 'Deploy the stack'.&lt;/p&gt;

&lt;p&gt;Currently, qbittorrent has an issue with mismatched torrent names, that's why it's using a custom image version. If it gets resolved in the future, remove everything after the colon.&lt;/p&gt;

&lt;p&gt;These are simply the containers I use for everything I do. The 'gluetun' container connects to Surfshark VPN and routes the qbittorrent container's traffic through, allowing a normal container to connect to a VPN. This can be done with any container by moving its ports to gluetun and setting its &lt;code&gt;network_mode&lt;/code&gt; to "service:gluetun". After that, go and check each container to make sure it's working.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jellyfin
&lt;/h2&gt;

&lt;p&gt;Welp, this is gonna be a fun one. If you don't want to do hardware transcoding with a GPU, simply add a standard container to the above compose file. Otherwise, come along for this hell of a ride. There is no guarantee that some of these steps aren't redundant as I have no clue how any of this works. But, ideally, everything will work by the end of this.&lt;/p&gt;

&lt;p&gt;Firstly, we need to install the NVIDIA drivers. I'm using a GTX 1050ti but it should work for any NVIDIA card 10-series or newer.&lt;/p&gt;

&lt;p&gt;Run these commands first to disable Nouveau:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo bash -c "echo blacklist nouveau &amp;gt; /etc/modprobe.d/blacklist-nvidia-nouveau.conf"
sudo bash -c "echo blacklist nouveau &amp;gt; /etc/modprobe.d/blacklist-nvidia-nouveau.conf"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is Nouveau and why are we disabling it? How dare you ask! Subsequently, I have no clue but it's what we gotta do.&lt;/p&gt;

&lt;p&gt;Reboot.&lt;/p&gt;

&lt;p&gt;Install DMKS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install dkms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the instructions &lt;a href="https://github.com/keylase/nvidia-patch" rel="noopener noreferrer"&gt;here&lt;/a&gt; to install the drivers.&lt;br&gt;
Additional Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update the version number in the other commands&lt;/li&gt;
&lt;li&gt;Each command needs the be run with &lt;code&gt;sudo&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click 'Yes' for everything, and after exiting the GUI, reboot, then run the test commands.&lt;/p&gt;

&lt;p&gt;Install ffmpeg:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install ffmpeg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to setup the NVIDIA Container Toolkit. Follow the official instructions &lt;a href="https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#setting-up-nvidia-container-toolkit" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now the GPU should be good to go! Next, we need to actually setup Jellyfin. Going back to SSH, go to your home dir (&lt;code&gt;cd&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Create a new docker compose file called &lt;code&gt;docker-compose.yml&lt;/code&gt; and fill it with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2.3"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;jellyfin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linuxserver/jellyfin&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jellyfin&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host"&lt;/span&gt;
    &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nvidia&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PUID=1000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PGID=1000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TZ=America/Toronto&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NVIDIA_VISIBLE_DEVICES=all&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/home/user/jellyfin:/config&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/home/user/media/tv:/data/tvshows&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/home/user/media/movies:/data/movies&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8080:8096&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;7359:7359/udp&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;docker-compose up -d&lt;/code&gt; and Jellyfin will be running. Counterintuitvly, go to port 8096 on your server's IP and login. &lt;/p&gt;

&lt;h3&gt;
  
  
  Change Jellyfin Settings
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to Settings &amp;gt; Advanced &amp;gt; Networking. Change "Local HTTP port number" and "Public HTTP port number" to 8080. &lt;/li&gt;
&lt;li&gt;Go to Server &amp;gt; Playback and under "Hardware acceleration" choose 'Nvidia NVENC'. Select which files you want to decode.&lt;/li&gt;
&lt;li&gt;Change 'ffmpeg path' to &lt;code&gt;/usr/bin&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Restart Jellyfin from Portainer, and you're good to go!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It was a lot of work, but hopefully everything works. Remember, DuckDuckGo and StackOverflow are your friends. If something doesn't work, let me know below and I'll do my best to help.&lt;/p&gt;

&lt;p&gt;Good luck and stay curious!&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://linuxize.com/post/how-to-change-ssh-port-in-linux/" rel="noopener noreferrer"&gt;https://linuxize.com/post/how-to-change-ssh-port-in-linux/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fossbytes.com/how-to-auto-mount-partitions-on-boot-in-linux-easily/" rel="noopener noreferrer"&gt;https://fossbytes.com/how-to-auto-mount-partitions-on-boot-in-linux-easily/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.smarthomebeginner.com/docker-home-media-server-2018-basic/#Add_Linux_User_to_Docker_Group" rel="noopener noreferrer"&gt;https://www.smarthomebeginner.com/docker-home-media-server-2018-basic/#Add_Linux_User_to_Docker_Group&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://askubuntu.com/questions/477551/how-can-i-use-docker-without-sudo" rel="noopener noreferrer"&gt;https://askubuntu.com/questions/477551/how-can-i-use-docker-without-sudo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linuxconfig.org/how-to-disable-blacklist-nouveau-nvidia-driver-on-ubuntu-20-04-focal-fossa-linux" rel="noopener noreferrer"&gt;https://linuxconfig.org/how-to-disable-blacklist-nouveau-nvidia-driver-on-ubuntu-20-04-focal-fossa-linux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>mediaserver</category>
      <category>ubuntu</category>
      <category>jellyfin</category>
    </item>
    <item>
      <title>Gitea + Drone CI + Vercel = Gitea Pages</title>
      <dc:creator>Kyle Schwartz</dc:creator>
      <pubDate>Sun, 17 May 2020 22:57:05 +0000</pubDate>
      <link>https://dev.to/kylejschwartz/gitea-drone-ci-vercel-gitea-pages-3mgb</link>
      <guid>https://dev.to/kylejschwartz/gitea-drone-ci-vercel-gitea-pages-3mgb</guid>
      <description>&lt;h1&gt;
  
  
  Gitea + Drone CI + Vercel = Gitea Pages
&lt;/h1&gt;

&lt;p&gt;Welcome! So this article comes after a year of being annoyed, but lazy, about the lack of functionality within Gitea to produce something similar to GitHub Pages. About a week ago, I finally got fed up and decided to figure it out and put this knowledge online since no one else has written about this and that’s frustrating. After following the steps below, you’ll be able to deploy your static-generated websites from any framework of your choosing (Vue, React, Svelte, Hugo, …) by simply pushing your code to Gitea.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;This tutorial assumes a couple of things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You have basic computer literacy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You have both a working Gitea server as well as a Drone CI server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You have a repository on your Gitea server that has all of your code ready to be deployed&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don’t have a Gitea or Drone CI server, check out my other post on how to host these for free. Or click the links below because no one likes extra work.&lt;br&gt;
&lt;a href="https://dev.to/kylejschwartz/hosting-gitea-on-google-cloud-platform-384f"&gt;&lt;strong&gt;Hosting Gitea on Google Cloud Platform&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/kylejschwartz/how-to-install-drone-ci-for-gitea-4h29"&gt;&lt;strong&gt;How to Install Drone CI for Gitea&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Vercel Setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Make an account at &lt;a href="https://vercel.com" rel="noopener noreferrer"&gt;https://vercel.com&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to &lt;a href="https://vercel.com/account/tokens" rel="noopener noreferrer"&gt;https://vercel.com/account/tokens&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on the &lt;code&gt;Create&lt;/code&gt; button, then enter “Drone” as the token name&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Create Token&lt;/code&gt; and save the code that is given to you. We will need this for later and Vercel will not show it again.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Done&lt;/code&gt; and continue on.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Drone CI Setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open Drone and open the repository you want to use&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Activate Repository&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Settings&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to the &lt;code&gt;Secrets&lt;/code&gt; section and add a new secret. Name it “NOW_TOKEN”, and give it the value of the token we got from the Vercel setup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;ADD A SECRET&lt;/code&gt; to save it&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Gitea Setup
&lt;/h2&gt;

&lt;p&gt;In the root of your project, create a file called &lt;strong&gt;“.drone.yml”&lt;/strong&gt;. The contents of which should be as follows:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Deployment Settings
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;secret&lt;/code&gt;: required. Don’t touch this either&lt;br&gt;
&lt;code&gt;deploy_name&lt;/code&gt;: Change to what you want your Vercel project name to be&lt;br&gt;
&lt;code&gt;prod&lt;/code&gt;: Leave this if you want a production build. If you want development builds, remove this line&lt;br&gt;
&lt;code&gt;directory&lt;/code&gt;: Only use this if you pre-compiled your code. If not, remove this line&lt;/p&gt;

&lt;p&gt;Push the changes to your repository.&lt;/p&gt;
&lt;h2&gt;
  
  
  Fixing Vercel
&lt;/h2&gt;

&lt;p&gt;Now that you’ve pushed your code, a Drone runner should have pushed your code to Vercel! Fantastic!&lt;/p&gt;

&lt;p&gt;Next comes fixing the issues. Vercel may or may not detect your framework correctly. If you go to your dashboard and your project is there, check the link to see if everything worked correctly. If it did, fantastic! You’ve done everything correctly and there is nothing left to setup. Either check out the Extras section below for some cool stuff or continue writing your code! Enjoy!&lt;/p&gt;

&lt;p&gt;If Vercel did not detect your framework, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open your project in Vercel by clicking its name&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Settings&lt;/code&gt; in the top left&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under &lt;code&gt;Build &amp;amp; Development Settings&lt;/code&gt;, chose your framework preset. If it’s not listed, chose &lt;code&gt;Other&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the build, output, or development commands listed aren’t correct, click the &lt;code&gt;Override&lt;/code&gt; toggle and manually edit the command&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Save&lt;/code&gt; and push your code to Gitea once more. This should fix the issues&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Extras
&lt;/h2&gt;

&lt;p&gt;If you want to only update production when you push to master, check out the gist below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Every branch that isn’t master will push to dev builds and master will now push to production!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Install Drone CI for Gitea</title>
      <dc:creator>Kyle Schwartz</dc:creator>
      <pubDate>Sun, 17 May 2020 22:51:18 +0000</pubDate>
      <link>https://dev.to/kylejschwartz/how-to-install-drone-ci-for-gitea-4h29</link>
      <guid>https://dev.to/kylejschwartz/how-to-install-drone-ci-for-gitea-4h29</guid>
      <description>&lt;h1&gt;
  
  
  How to Install Drone CI for Gitea
&lt;/h1&gt;

&lt;p&gt;Welcome! This is a simple tutorial that is heavily based on Drone’s documentation with a minor focus on Oracle Cloud. Without further ado, let’s get into it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Basic computer literacy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An &lt;a href="https://www.oracle.com/cloud/free/" rel="noopener noreferrer"&gt;Oracle Cloud&lt;/a&gt; account (Any provider such as AWS or GCP with work just as well), since that’s what we’ll be using here&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An existing Gitea server&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A domain name and access to your DNS records&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you chose to use GCP, you can follow my Gitea tutorial for the networking bits found &lt;a href="https://dev.to/kylejschwartz/hosting-gitea-on-google-cloud-platform-384f"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you don’t have a Gitea sever, you can follow the aforementioned tutorial to get one setup.&lt;/p&gt;

&lt;p&gt;It is important to run this on a &lt;strong&gt;DIFFERENT&lt;/strong&gt; server than your Gitea instance. Thankfully, Oracle offers 2 VMs for free so that shouldn’t be a problem!&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate SSH Keys
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24zbc1xvz4y41qwyrd20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24zbc1xvz4y41qwyrd20.png" width="800" height="93"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Login to your Oracle Cloud&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open the Cloud Shell by pressing the console icon in the top right corner&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Wait a few moments and then run the following command in the console at the bottom of the page:&lt;br&gt;
&lt;code&gt;ssh-keygen -t rsa -b 4096 -C "*your_email@example.com*"&lt;/code&gt;&lt;br&gt;
replacing &lt;a href="mailto:your_email@example.com"&gt;your_email@example.com&lt;/a&gt; with your real email. Leave the quotation marks!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The console will ask you where you want to save the key. Just press enter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When prompted to enter a password, simply leave it blank and just press enter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now that your keys are generated, we need to view our public key by entering the following command into the console:&lt;br&gt;
&lt;code&gt;cat .ssh/id_rsa.pub&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This will display our public key in the console. It will begin with ssh-rsa and end with you email. Select the entire block of text, around 3 lines, including ssh_rsa and your email. Copy this, as we will need it to setup our VM and Console Connection.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  VM Setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Click on the hamburger menu (☰) &amp;gt; Compute &amp;gt; Instances&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Create Instance&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Name your instance as you choose, I prefer “Drone”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Change Image&lt;/code&gt; and select &lt;code&gt;Canonical Ubuntu 18.04&lt;/code&gt;. Scroll to the bottom and click &lt;code&gt;Select Image&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Paste SSH Keys&lt;/code&gt; and paste the key you copied from the previous section.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Create&lt;/code&gt; and wait for your instance to be fully setup (The icon will turn green)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now, write down the public IP address under &lt;code&gt;Instance Access&lt;/code&gt;. We will need this down the line.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Networking
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Console Connections
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Scroll to the bottom of your instance page, and click &lt;code&gt;Console Connections&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Create Console Connection&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Paste SSH Key&lt;/code&gt; and paste in the same key from the last section.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Create Console Connection&lt;/code&gt; and wait a few seconds&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Virtual Cloud Network
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;At the top of the instance page, below the &lt;code&gt;Instance Details&lt;/code&gt; section, click on the blue link similar to &lt;code&gt;VirtualCloudNetwork-00000000–0000&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the left side, below the green hexagon, click on &lt;code&gt;Security Lists (1)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on &lt;code&gt;Default Security List for VirtualCloudNetwork-00000000–0000&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Add Ingress Rule&lt;/code&gt; and add the two rules below one at a time:&lt;br&gt;
— — — — &lt;br&gt;
Rule 1:&lt;br&gt;
Source CIDR: 0.0.0.0/0&lt;br&gt;
Destination Port Range: 80 &lt;br&gt;
— — — — &lt;br&gt;
Rule 2:&lt;br&gt;
Source CIDR: 0.0.0.0/0&lt;br&gt;
Destination Port Range: 443&lt;br&gt;
— — — — &lt;br&gt;
Leave all other fields as-is&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Connecting to the VM
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Using the Cloud Console once more, we need to edit the permissions of our Private SSH Key by entering the following into the console:&lt;br&gt;
&lt;code&gt;chmod 400 .ssh/id_rsa&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now, using the public IP address from awhile ago, enter the following command, substituting “address” for the VMs IP address:&lt;br&gt;
&lt;code&gt;ssh –i .ssh/id_rsa ubuntu@address&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Random Config Note
&lt;/h2&gt;

&lt;p&gt;Before going to the next step, I HIGHLY recommend going into the DNS of your domain and configuring drone.yourwebsite.com to the public IP of your VM. If you’re using cloudflare, DON’T PROXY, use DNS ONLY. Thank you, you may continue now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Drone CI
&lt;/h2&gt;

&lt;p&gt;First, you need to install docker. Follow &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04" rel="noopener noreferrer"&gt;this&lt;/a&gt; tutorial from DigitalOcean. You only need to follow everything in step 1.&lt;/p&gt;

&lt;p&gt;Once you have docker installed, we are going to open a new tab and go to our Gitea website. You might need an admin account for this part.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Click on the profile icon in the top right and click &lt;code&gt;Settings&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on the “Applications” tab and scroll down to the &lt;code&gt;Manage OAuth2 Applications&lt;/code&gt; section&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enter “Drone” as your Application Name, and “&lt;a href="http://drone.yourwebsite.com/login%E2%80%9D" rel="noopener noreferrer"&gt;http://drone.yourwebsite.com/login”&lt;/a&gt; as the Redirect URI, then click &lt;code&gt;Create Application&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You will now we shown your Client ID and your Client Secret. Write down or copy the Client Secret as it won’t be shown again. Client ID will always be viewable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now, head back to your Cloud Console (You should still be logged into the VM) and we are going to generate a shared secret by running the following command:&lt;br&gt;
&lt;code&gt;openssl rand -hex 16&lt;/code&gt;&lt;br&gt;
Save the output of this command as we will need it later&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now we will download drone itself by running this command:&lt;br&gt;
docker pull drone/drone:1&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The easiest way to do this next step is to copy the code below into Notepad or TextEdit and edit all of the options there. Below each of the options will be listed. Just paste the value after the equal sign on that line.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_GITEA_SERVER&lt;/code&gt;: The address of your Gitea server. &lt;br&gt;
Eg. &lt;a href="https://git.example.com" rel="noopener noreferrer"&gt;https://git.example.com&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_GITEA_CLIENT_ID&lt;/code&gt;: The Client ID from step 4&lt;br&gt;
Eg. f8cd8dfe-29f6–48f7–9c87–8b1bcec79dbe&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_GITEA_CLIENT_SECRET&lt;/code&gt;: The Client Secret from step 4&lt;br&gt;
Eg. xpV0v74hKmDm5tulfR932TRZTVmkHWqCcZVJXG5CK4A=&lt;br&gt;
P.s. Yes, it will end in an equal sign. No, this is not a mistake&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_RPC_SECRET&lt;/code&gt;: The shared secret generated in step 5&lt;br&gt;
Eg. 2d2c5fc55c5991a8cc90f75e313d5670&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_SERVER_HOST&lt;/code&gt;: The domain of your drone server&lt;br&gt;
Eg. drone.yourwebsite.com&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_SERVER_PROTO&lt;/code&gt;: Leave as http&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you’ve edited all of the values, copy the command and paste it into your cloud console. Now you have a Drone CI server up and running!&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Runner
&lt;/h2&gt;

&lt;p&gt;Runners are necessary to make pipelines function. Think of the Drone server as a marathon and a runner as a participant. Without participants, you can’t really have a marathon. A runner is the bit of code that actually does the work, the sever just gives the runner room to work.&lt;/p&gt;

&lt;p&gt;Setting up a runner is just like setting up the server. First, we’ll pull the image off of DockerHub (This is where most docker images are hosted) and then we’ll run it with a configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Pull the runner by running the following command in the cloud console:&lt;br&gt;
&lt;code&gt;docker pull drone/drone-runner-docker:1&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The easiest way to do this next step is to copy the code below into Notepad or TextEdit and edit all of the options there. Below each of the options will be listed. Just paste the value after the equal sign on that line.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_RPC_HOST&lt;/code&gt;: The domain of your drone server&lt;br&gt;
Eg. drone.yourwebsite.com&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_RPC_SECRET&lt;/code&gt;: The shared secret from awhile ago. This value should be the same as DRONE_RPC_SECRET from the server config&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, simply copy the config and paste it into the cloud console and hit enter. Now, you’ve created your first runner!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now that everything is setup, you can head to your Drone server’s URL and start building pipelines. If you don’t know where to start, Drone’s documentation is where I’d suggest and can be found &lt;a href="https://docs.drone.io/quickstart/docker/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Enjoy and happy coding!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Integrating GitLab CI/CD, Flask, and Heroku</title>
      <dc:creator>Kyle Schwartz</dc:creator>
      <pubDate>Sat, 04 Jan 2020 17:40:21 +0000</pubDate>
      <link>https://dev.to/kylejschwartz/integrating-gitlab-ci-cd-flask-and-heroku-2oi6</link>
      <guid>https://dev.to/kylejschwartz/integrating-gitlab-ci-cd-flask-and-heroku-2oi6</guid>
      <description>&lt;p&gt;This tutorial assumes you already have a working flask application within a virtual environment and have your code hosted on GitLab. Also ensure you have Gunicorn installed. You can install it from &lt;code&gt;pip install gunicorn&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Ready
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;pip freeze &amp;gt; requirements.txt&lt;/code&gt; to grab all the requirements for running your application.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;Procfile&lt;/code&gt; file. Inside, place the following code &lt;code&gt;web: gunicorn &amp;lt;name of the app.py file&amp;gt;:&amp;lt;app-name&amp;gt;&lt;/code&gt; where app-name is usually “app”.&lt;/p&gt;

&lt;p&gt;Push everything to GitLab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting Everything
&lt;/h2&gt;

&lt;p&gt;Create a new Heroku application. Using a short name will make later steps easier.&lt;/p&gt;

&lt;p&gt;Create a new file in your app root called &lt;code&gt;.gitlab-ci.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is a cookie-cutter example of a GitLab CI/CD config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;app.py file name&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s"&gt;— apt-get update -qy&lt;/span&gt;
        &lt;span class="s"&gt;— apt-get install -y python-dev python-pip&lt;/span&gt;
        &lt;span class="s"&gt;— pip install -r requirements.txt&lt;/span&gt;

&lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s"&gt;— apt-get update -qy&lt;/span&gt;
        &lt;span class="s"&gt;— apt-get install -y ruby-dev&lt;/span&gt;
        &lt;span class="s"&gt;— gem install dpl&lt;/span&gt;
        &lt;span class="s"&gt;— dpl — provider=heroku — app=[Heroku App Name] — api-key=$HEROKU_SECRET_KEY&lt;/span&gt;
    &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s"&gt;— master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now swap out &lt;code&gt;[app.py file name]&lt;/code&gt; with your file name and &lt;code&gt;[Heroku App Name]&lt;/code&gt; with the name of your Heroku app.&lt;/p&gt;

&lt;p&gt;To set the HEROKU_SECRET_KEY,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Get your Heroku API key from &lt;a href="https://dashboard.heroku.com/account" rel="noopener noreferrer"&gt;https://dashboard.heroku.com/account&lt;/a&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Within GitLab, go to &lt;strong&gt;Settings → CI / CD → Secret variables&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new variable and set the &lt;strong&gt;Variable key&lt;/strong&gt; to &lt;strong&gt;HEROKU_SECRET_KEY&lt;/strong&gt; and the &lt;strong&gt;Variable Value&lt;/strong&gt; to your &lt;strong&gt;Heroku API Key&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set the protected switch to &lt;strong&gt;ON&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Push the changes to GitLab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now that everything is all setup, head over to your Heroku app URL and enjoy the fruits of your labour.&lt;/p&gt;

</description>
      <category>gitlab</category>
      <category>cicd</category>
      <category>flask</category>
      <category>heroku</category>
    </item>
    <item>
      <title>Using Githooks for CI/CD</title>
      <dc:creator>Kyle Schwartz</dc:creator>
      <pubDate>Sat, 04 Jan 2020 17:35:40 +0000</pubDate>
      <link>https://dev.to/kylejschwartz/using-githooks-for-ci-cd-2291</link>
      <guid>https://dev.to/kylejschwartz/using-githooks-for-ci-cd-2291</guid>
      <description>&lt;p&gt;A tutorial on how to to use &lt;a href="https://www.npmjs.com/package/git-scripts" rel="noopener noreferrer"&gt;git-scripts&lt;/a&gt; for CI/CD&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the package.json
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;package.json&lt;/code&gt; by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install git-scripts to the package by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev git-scripts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add the Git Hooks
&lt;/h2&gt;

&lt;p&gt;After the &lt;code&gt;devDependencies&lt;/code&gt; section, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"git-scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^0.2.1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"git"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="nl"&gt;"pre-push"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;command(s) to run before git push&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>git</category>
      <category>cicd</category>
      <category>npm</category>
    </item>
    <item>
      <title>Useful Bits of Code From Around The Web</title>
      <dc:creator>Kyle Schwartz</dc:creator>
      <pubDate>Sat, 21 Dec 2019 20:48:23 +0000</pubDate>
      <link>https://dev.to/kylejschwartz/useful-bits-of-code-from-around-the-web-409k</link>
      <guid>https://dev.to/kylejschwartz/useful-bits-of-code-from-around-the-web-409k</guid>
      <description>&lt;h2&gt;
  
  
  &lt;a href="https://stackoverflow.com/a/46129280" rel="noopener noreferrer"&gt;Reading Files in JS&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Text File
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="c1"&gt;// outputs the content of the text file&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  JSON File
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;     
   &lt;span class="c1"&gt;// outputs a javascript object from the parsed json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
    </item>
  </channel>
</rss>
