<?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>Forem: Nathan Bland</title>
    <description>The latest articles on Forem by Nathan Bland (@nathanbland).</description>
    <link>https://forem.com/nathanbland</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%2F4873%2F3cda0a3e-f48a-464f-9e4a-7fe53d727a85.jpg</url>
      <title>Forem: Nathan Bland</title>
      <link>https://forem.com/nathanbland</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nathanbland"/>
    <language>en</language>
    <item>
      <title>Setting up Drone CI for CI/CD homelab use - build log</title>
      <dc:creator>Nathan Bland</dc:creator>
      <pubDate>Fri, 27 Oct 2023 01:16:41 +0000</pubDate>
      <link>https://forem.com/nathanbland/setting-up-drone-for-homelab-use-build-log-25ij</link>
      <guid>https://forem.com/nathanbland/setting-up-drone-for-homelab-use-build-log-25ij</guid>
      <description>&lt;p&gt;Constantly on the search for something to replace jenkins as my be-all, end-all continuous build/deployment tool, I decided to try setting up a local instance of &lt;a href="https://docs.drone.io/server/overview/"&gt;&lt;code&gt;drone&lt;/code&gt;&lt;/a&gt;, as it looked fairly promising. This is a build log of my results. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 - setup and configuration
&lt;/h2&gt;

&lt;p&gt;As with my previous build-log setting up &lt;code&gt;goCD&lt;/code&gt;, this is going to use docker-compose on portainer. It's where almost all of my home-lab things live at this point, and I haven't really had strong reason to change it. Having said that, I have weird volume configurations, so I'll share simplified versions of those when/if needed.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.drone.io/server/overview/"&gt;docs&lt;/a&gt; for &lt;code&gt;drone&lt;/code&gt; first have you go through the setup process of creating an application on your desired source control platform. I find this to be a little backwards personally, so I'm going to start with the compose file instead and see if I regret it.&lt;/p&gt;

&lt;p&gt;The instructions for getting going with docker are pretty simple at first:&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="nv"&gt;$ &lt;/span&gt;docker pull drone/drone:2

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is absolutely nothing to write home about, but that just gets the image. Next up is the listed configuration options, most of which are required. Below is pulled straight from the setup instructions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_GITHUB_CLIENT_ID&lt;/code&gt;&lt;br&gt;
Required string value provides your GitHub oauth Client ID generated in the previous step.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_GITHUB_CLIENT_SECRET&lt;/code&gt;&lt;br&gt;
Required string value provides your GitHub oauth Client Secret generated in the previous step.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_RPC_SECRET&lt;/code&gt;&lt;br&gt;
Required string value provides the shared secret generated in the previous step. This is used to authenticate the rpc connection between the server and runners. The server and runner must be provided the same secret value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_SERVER_HOST&lt;/code&gt;&lt;br&gt;
Required string value provides your external hostname or IP address. If using an IP address you may include the port. For example drone.company.com.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_SERVER_PROTO&lt;/code&gt;&lt;br&gt;
Required string value provides your external protocol scheme. This value should be set to http or https. This field defaults to https if you configure ssl or acme. This value should be set to https if you deploy Drone behind a load balancer or reverse proxy with SSL termination.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;DRONE_USER_FILTER&lt;/code&gt;&lt;br&gt;
Optional comma-separated list of GitHub users or organizations. Registration is limited to users in this list, or users that are members of organizations in this list. Registration is open to the public if this value is unset.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given some of these values, it is easy to see why they want you to configure an application first, as you'll need those values. Oh well, &lt;a href="https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app"&gt;off to github I go to get credentials&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once I had those, I could put together the start of my compose file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "3.7"
services:
  drone:
    image: drone/drone:2
    environment:
      - DRONE_GITHUB_CLIENT_ID=super-secret-github-id
      - DRONE_GITHUB_CLIENT_SECRET=super-secret-github
      - DRONE_RPC_SECRET=super-shared-secret
      - DRONE_SERVER_HOST=drone.my-domain.local
      - DRONE_SERVER_PROTO=https
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/lib/drone:/data
    restart: unless-stopped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've filled in a couple values here with example data for security reasons, but details do need to match what you got from github, except for the &lt;code&gt;DRONE_RPC_SECRET&lt;/code&gt;. This is going to be a shared key between our main instance, and our runners, more on that later I think. You can use any random string, or use openssl to generate one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ openssl rand -hex 16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A final note about that above compose. The ports will be different, or may need to be. Changing the &lt;em&gt;left&lt;/em&gt; side changes what is exposed on your machine, and you can set that to whatever you like, so long as you have a way of directing your domain to it. Nginx-proxy-manager is great for this.&lt;/p&gt;

&lt;p&gt;This is, in theory, enough to spin the server up. So let's do that and see what we get.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - First user setup
&lt;/h2&gt;

&lt;p&gt;This landed me at the login page, which prompted a quick authorization from github, follwed by, a user login prompt again? Seems strange, but filling in the details and following the prompts worked flawlessly, so I won't question it. &lt;/p&gt;

&lt;p&gt;This landed me on a screen with all the repositories I had granted access to this application, which was pretty neat to see. Clicking on any of them displayed another screen mentioning how this repository is not active, which makes sense, and is exciting, but now we are getting ahead of ourselves. We need to setup a runner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 - Drone runner node
&lt;/h2&gt;

&lt;p&gt;We can add this to our existing docker compose file, directly below the main instance. This was also pretty short and simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;drone-runner-1:
    image: drone/drone-runner-docker:1
    container_name: drone-runner-1
    environment:
      - DRONE_RUNNER_CAPACITY=4
      - DRONE_RUNNER_NAME=docker-runner
      - DRONE_RPC_SECRET=super-shared-secret
      - DRONE_RPC_HOST=drone.my-domain.local
      - DRONE_RPC_PROTO=https
    ports:
      - "3331:3000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    restart: unless-stopped

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I added this to my existing compose, and the instructions say to check the logs for the following:&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="nv"&gt;$ &lt;/span&gt;docker logs runner

INFO[0000] starting the server
INFO[0000] successfully pinged the remote server 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I had that, so it seemed to be working.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 - Test an actual pipeline
&lt;/h2&gt;

&lt;p&gt;I seemed to be done with server setup, which shocked me, as that was really easy compared to some other options. Next up I needed to actually push a build-pipeline to a repo, and see if it would take.&lt;/p&gt;

&lt;p&gt;I found the repo I wanted, and clicked on the "activate" button from the web ui in drone. &lt;/p&gt;

&lt;p&gt;The example pipeline they gave seemed like I good start, so I went with that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#.drone.yml
kind: pipeline
type: docker
name: default

steps:
- name: greeting
  image: alpine
  commands:
  - echo hello
  - echo world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While I don't super love yaml for all the configuration, the naming and matter that the steps and commands were setup seemed pretty straight forward to me, which was nice. &lt;/p&gt;

&lt;p&gt;I added those changes to &lt;code&gt;.drone.yml&lt;/code&gt; in my repo and pushed it up. &lt;/p&gt;

&lt;p&gt;This, produced a very nice result, as my push got a little green check-mark in github, and clicking on that "build passing" took me directly to drone where the job had run with a list of the steps, and a console log of the output. It was beautiful, and simple.&lt;/p&gt;

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

&lt;p&gt;So far, I really, really like using drone. I'm still very new to it, and getting the hang of the build steps and configuration will take time, but getting the initial setup took no time at all, and produced amazing results. Stay tuned for more, thanks for reading.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>cicd</category>
      <category>buildlog</category>
      <category>devops</category>
    </item>
    <item>
      <title>Setting up GoCD in a docker environment - build log</title>
      <dc:creator>Nathan Bland</dc:creator>
      <pubDate>Fri, 07 Jul 2023 05:54:54 +0000</pubDate>
      <link>https://forem.com/nathanbland/setting-up-gocd-in-a-docker-environment-build-log-2a4b</link>
      <guid>https://forem.com/nathanbland/setting-up-gocd-in-a-docker-environment-build-log-2a4b</guid>
      <description>&lt;p&gt;Having worked with Jenkins in the past, I've been curious about GoCD for quite a while, and decided I would finally take the plunge and figure out how two set it up.&lt;br&gt;
A deployment of GoCD needs at least two parts, a server, and an agent. This will cover my experience and notes from doing that configuration and setup.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1 - Docker things
&lt;/h2&gt;

&lt;p&gt;Choose the specific version of the container/OS you'd like to use, for my build, I'm going with &lt;a href="https://hub.docker.com/r/gocd/gocd-server"&gt;&lt;code&gt;gocd/gocd-server&lt;/code&gt;&lt;/a&gt; version &lt;code&gt;23.1.0&lt;/code&gt; which can be pulled with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull gocd/gocd-server:v23.1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple usage from their docker docs would indicate that you can run it with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p8153&lt;/span&gt;:8153 gocd/gocd-server:v23.1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would spin up GoCD locally on port 8153, but since I'm going to be deploying this using portainer, I want to build out a docker compose file to do this.&lt;/p&gt;

&lt;p&gt;The docker docs do provide more useful information, such as what paths in the image contain useful data that you may want to preserve with volumes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/godata&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/home/go&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It includes the note that the &lt;code&gt;go&lt;/code&gt; user in the container should have access to these directories, and shares its user id - &lt;code&gt;1000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;An additional note that seemed useful here was around running custom entrypoint scripts, and loading configuration from an existing git repo, but at this point I wasn't sure I needed any of that, so I left it for now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - Portainer things
&lt;/h2&gt;

&lt;p&gt;I'm going to create a portainer stack to deploy this in, which probably adds unneeded complexity, but it is what I run most of my home lab systems in, so I'm at least fairly familiar with its pitfalls. Because I already have services deployed in this system, I stole one of my own configs and tweaked it to run GoCD. Below is what my stack/compose file looks like to test things out:&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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.2'&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;gocd-server&lt;/span&gt;&lt;span class="pi"&gt;:&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;gocd/gocd-server:v23.1.0&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;gocd-server&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8153:8153"&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="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;volume&lt;/span&gt;
        &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gocd-data&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/godata&lt;/span&gt;
        &lt;span class="na"&gt;volume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;nocopy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&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;volume&lt;/span&gt;
        &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gocd-home&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/home/go&lt;/span&gt;
        &lt;span class="na"&gt;volume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;nocopy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="c1"&gt;#environment:&lt;/span&gt;
    &lt;span class="c1"&gt;#depends_on:&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gocd-net&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;gocd-net&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;gocd-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver_opts&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nfs"&lt;/span&gt;
      &lt;span class="na"&gt;o&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;addr=&amp;lt;nas-ip&amp;gt;,nolock,soft,rw"&lt;/span&gt;
      &lt;span class="na"&gt;device&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:/storage-path/gocd/gocd-data"&lt;/span&gt;
  &lt;span class="na"&gt;gocd-home&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver_opts&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nfs"&lt;/span&gt;
      &lt;span class="na"&gt;o&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;addr=&amp;lt;nas-ip&amp;gt;,nolock,soft,rw"&lt;/span&gt;
      &lt;span class="na"&gt;device&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:/storage-path/gocd/gocd-home"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I should note I have a pretty unique storage system in place for my volumes on my portainer system, and I wouldn't recommend following that setup unless you absolutely know what you're doing. I've obscured some values in those volumes, but I wanted to include the setup for the sake of completeness.&lt;/p&gt;

&lt;p&gt;After a bit of debugging to get to the compose file you see above, it finally deployed without complaint, so now I could test and make sure the UI actually spun up. A quick visit to the IP and port showed I had moderate success so far, I had the start-up wizard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 - Agents
&lt;/h2&gt;

&lt;p&gt;My first visit to the gocd ui dropped me into a &lt;code&gt;Add a new pipeline&lt;/code&gt; screen, which present a whole host of things I hadn't used before, but made sense upon review. It wanted a &lt;code&gt;material&lt;/code&gt; which is a source of some kind, for most people - myself included - this will probably be a git repo.&lt;/p&gt;

&lt;p&gt;This did in turn, provide me with my first hiccup. Attempting a test connection to a public repo of mine of course failed, as I lacked any kind of authentication. I also feared I was getting ahead of myself as I knew that GoCD required an agent - which I hadn't setup yet - but I was already messing with pipelines.&lt;/p&gt;

&lt;p&gt;After poking around the GoCD docs a little more, I decided I wasn't quite ready for a pipeline, and went back to the install portion of the documentation to see what I should do next. It turns out, &lt;a href="https://docs.gocd.org/current/installation/install/agent/linux.html"&gt;that was setting up an agent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I browsed the available docker images for agents, and decided on an &lt;a href="https://hub.docker.com/r/gocd/gocd-agent-ubuntu-22.04"&gt;ubuntu 22 agent&lt;/a&gt;. This would also be version &lt;code&gt;23.1.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Unlike the server that required absolutely no env configuration unless you were in the advanced options, the agent docker required at least one env value, the server for it to talk to. Makes sense.&lt;/p&gt;

&lt;p&gt;Back to the docker compose file, I added another service entry:&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;gocd-agent-ubuntu&lt;/span&gt;&lt;span class="pi"&gt;:&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;gocd/gocd-agent-ubuntu-22.04:v23.1.0&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;gocd-agent-ubuntu&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="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;volume&lt;/span&gt;
        &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gocd-agent&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/godata&lt;/span&gt;
        &lt;span class="na"&gt;volume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;nocopy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&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;volume&lt;/span&gt;
        &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gocd-home&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/home/go&lt;/span&gt;
        &lt;span class="na"&gt;volume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;nocopy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&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;GO_SERVER_URL=https://ip.add.re.ss:8153/go&lt;/span&gt;
    &lt;span class="c1"&gt;#depends_on:&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gocd-net&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should be noted that their own docs say an https server url is required. I have my setup behind an nginx proxy manager, so I added an entry for it to get a signed cert, but I believe it can self-generate one for you to use if you toggle off a specific security setting for the agent (see the Configuring SSL section of the docker agent linked above).&lt;/p&gt;

&lt;p&gt;The next steps in the GoCd docs told me to head to the agents tab in the UI where I looked for this option in the admin drop-down menu despite it being a top-level menu item for far too long. I did see mine listed, and getting it attached to the server was as simple as selecting the checkbox next to its name and hitting the &lt;code&gt;enable&lt;/code&gt; button at the top.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 - Users
&lt;/h2&gt;

&lt;p&gt;The next thing I needed to do before actually giving any real data to GoCD to deal with, was configure user management, as right now it was wide open. Turns out this was not as simple as I was hoping. GoCD does not do user management of its own. It takes in an authentication service of some type. You can import users from that source, and give them specific permissions, but it won't let you just spin up a user in its own system. &lt;/p&gt;

&lt;p&gt;What it does allow out of the box, is either a password file, or LDAP server. At some point, I may spin up a docker container for LDAP, that would be cool for all sorts of things, but for this case I opted for a password file to try and keep things simple.&lt;/p&gt;

&lt;p&gt;The docs pointed me to a &lt;a href="https://github.com/gocd/gocd-filebased-authentication-plugin#readme"&gt;github repo for the plugin&lt;/a&gt; where I learned &lt;code&gt;gocd-passwd&lt;/code&gt; can be used to generate the hashed password.&lt;/p&gt;

&lt;p&gt;The example in the docs showed the file being in &lt;code&gt;/godata/config/&lt;/code&gt; on the container, so I connected to the container console with portainer, and set about making the file. However this was a misunderstanding on my part, as that command and file actually isn't part of the docker image. &lt;/p&gt;

&lt;p&gt;I did however, have an ubuntu agent, and the docs on the github repo showed how to use &lt;code&gt;htpasswd&lt;/code&gt; to generate a password file on ubuntu, so I attached to that console instead, and ran the following&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;# first grab the utils&lt;/span&gt;
apt-get update
apt-get &lt;span class="nb"&gt;install &lt;/span&gt;apache2-utils

&lt;span class="c"&gt;# genereate a password file called passwd, using bcrypt, for the user admin&lt;/span&gt;
htpasswd &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nt"&gt;-B&lt;/span&gt; passwd admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because I had the home directory mapped across both of these containers, I should be able to share this file between them, or simply copy it and delete the original once I had it on the server container.&lt;/p&gt;

&lt;p&gt;After reattaching to the server container, I confirmed the file was there, and moved it to where it belonged in the &lt;code&gt;/godata/config&lt;/code&gt; folder. &lt;/p&gt;

&lt;p&gt;Back in the UI, I went to &lt;code&gt;Admin -&amp;gt; Authorization Configurations&lt;/code&gt; and clicked add. Selected &lt;code&gt;password file authentication plugin&lt;/code&gt;, and filled in my details. I wasn't sure exactly what to call the &lt;code&gt;id&lt;/code&gt; for this auth config, so I went with the value in the example screenshot - &lt;code&gt;file-auth-config&lt;/code&gt;, and figured it would yell at me if that wasn't allowed.&lt;/p&gt;

&lt;p&gt;I then did the following: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I hit &lt;code&gt;Check connection&lt;/code&gt; and it reported that it was ok&lt;/li&gt;
&lt;li&gt;I hit &lt;code&gt;Allow only known users to login&lt;/code&gt;. &lt;em&gt;do not do this&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;I clicked &lt;code&gt;Save&lt;/code&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This was, a massive mistake, as I had not allowed my newly created user to login yet - it just got added - so I essentially locked myself out of the ui.&lt;/p&gt;

&lt;p&gt;If you happen to do this, good news, this configuration is written to a file, and you can manually edit that config. The file lives in &lt;code&gt;/godata/db/config.git/cruise-config.xml&lt;/code&gt;, and `&lt;code&gt;/godata/config/cruise-config.xml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Edit the line that looks like this&lt;br&gt;
&lt;code&gt;`xml&lt;br&gt;
&amp;lt;authConfig allowOnlyKnownUsersToLogin="true" id="file-auth-config" pluginId="cd.go.authentication.passwordfile"&amp;gt;&lt;br&gt;
`&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To look like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;`xml&lt;br&gt;
&amp;lt;authConfig allowOnlyKnownUsersToLogin="false" id="file-auth-config" pluginId="cd.go.authentication.passwordfile"&amp;gt;&lt;br&gt;
`&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Save those files, and if needed, restart your container.&lt;/p&gt;

&lt;p&gt;Once you have yourself back in the system - or hopefully didn't lock yourself out at first, you can navigate to &lt;code&gt;Admin -&amp;gt; Users management&lt;/code&gt; and check the little box that makes you a system admin.&lt;/p&gt;

&lt;p&gt;Once this is done, you can navigate back to &lt;code&gt;Admin -&amp;gt; Authorization configuration&lt;/code&gt; and edit that password file configuration, and check that &lt;code&gt;allow only known users to login&lt;/code&gt; if you want.&lt;/p&gt;

&lt;p&gt;Yay, a working user!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 - Pipelines!
&lt;/h2&gt;

&lt;p&gt;Having gotten users and agents setup, I was now back at my &lt;code&gt;Add a new pipeline&lt;/code&gt; screen from earlier. I realized I was being silly, as the volume I created for the home directory was for exactly this, to allow adding ssh keys. If you haven't done this, github has &lt;a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent"&gt;good docs&lt;/a&gt; on this subject.&lt;/p&gt;

&lt;p&gt;I created a new key from the docker container, and saved it to the volume so it wouldn't be lost on container restart.&lt;/p&gt;

&lt;p&gt;Next I added it to my github account - &lt;a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account"&gt;docs are here&lt;/a&gt; - and now it was time to see if it actually worked.&lt;/p&gt;

&lt;p&gt;It did not.&lt;/p&gt;

&lt;p&gt;This made me sad, but this felt like such a common thing that I had to be missing something, so back to the docs I went.&lt;/p&gt;

&lt;p&gt;Under &lt;code&gt;faq/troubleshooting&lt;/code&gt; I found a very useful page on &lt;a href="https://docs.gocd.org/current/faq/docker_container_ssh_keys.html"&gt;ssh keys and docker&lt;/a&gt;. The step I had been missing was running a clone in the console to accept the github server signature. This could have also been done with &lt;code&gt;ssh-keyscan&lt;/code&gt;. I opted to try and clone a repo, and it did prompt me. I accepted, and then tried to test my connection again in the UI. &lt;/p&gt;

&lt;p&gt;This time, it worked!&lt;/p&gt;

&lt;p&gt;I set my repo URL in the materials section, gave my pipeline a name of &lt;code&gt;build-and-deploy&lt;/code&gt; - we'll see if it actually ends up doing that - added a build stage, and a task. This got me to the point where I could click &lt;code&gt;save + run&lt;/code&gt; which finally landed me on the dashboard page.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>buildlog</category>
    </item>
    <item>
      <title>🎥 How to Build Your Own Continuous Automation &amp; Build Server - Using Jenkins &amp; Docker - #1</title>
      <dc:creator>Nathan Bland</dc:creator>
      <pubDate>Fri, 11 Oct 2019 01:48:46 +0000</pubDate>
      <link>https://forem.com/nathanbland/how-to-build-your-own-continuous-automation-build-server-using-jenkins-docker-1-9jd</link>
      <guid>https://forem.com/nathanbland/how-to-build-your-own-continuous-automation-build-server-using-jenkins-docker-1-9jd</guid>
      <description>&lt;p&gt;Cloud providers everywhere are trying to get you to use their automation pipelines and services. Let's build our own instead.&lt;/p&gt;

&lt;h1&gt;
  
  
  Video
&lt;/h1&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/sENw9EEU2e4"&gt;
&lt;/iframe&gt;
 &lt;/p&gt;

&lt;p&gt;Cover Photo by &lt;a href="https://unsplash.com/@christopher__burns?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Christopher Burns&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/8KfCR12oeUM"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>testing</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>🎥 Setting up a Kubernetes Cluster - Live Stream Replay (with notes)</title>
      <dc:creator>Nathan Bland</dc:creator>
      <pubDate>Wed, 02 Oct 2019 21:42:09 +0000</pubDate>
      <link>https://forem.com/nathanbland/setting-up-a-kubernetes-cluster-live-stream-replay-with-notes-i10</link>
      <guid>https://forem.com/nathanbland/setting-up-a-kubernetes-cluster-live-stream-replay-with-notes-i10</guid>
      <description>&lt;p&gt;Ever wanted to setup your own Kubernetes(k8s) cluster for development? Wanted to go a bit further than using &lt;code&gt;minikube&lt;/code&gt;? We'll walk through setting up 3 vms to create our very own k8 cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Video - notes below
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/RWUskyCbbSw"&gt;
&lt;/iframe&gt;
 &lt;/p&gt;
&lt;h2&gt;
  
  
  Notes and Summary
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;notes&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first ~30 minutes of this are VM install and setup, feel free to skip that.&lt;/li&gt;
&lt;li&gt;The GUI I'm using for KVMs is &lt;a href="https://virt-manager.org/"&gt;&lt;code&gt;virt-manager&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I did not have virtualization turned on in my system bios (new system didn't have the switch flipped yet) so this severely impacted performance.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;virt-clone&lt;/code&gt; should have provisioned a different mac address for each VM clone, still not sure what happened there.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Most of the instructions I ran through &lt;em&gt;aside&lt;/em&gt; from networking woes can be boiled down to this:&lt;/p&gt;
&lt;h4&gt;
  
  
  1. Setup support for installing packages over https
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install -y apt-transport-https&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  2. Add trusted key for packages we want to install
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  3. Add repository for Kubernetes(k8s)
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  4. Update package listings
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;sudo apt-get update&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  5. Install kubernetes, its tools, and docker.io
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;sudo apt install kubectl kubeadm docker.io&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  6. Disable swap memory. (it isn't supported)
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;sudo swapoff -a&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You'll also want to remove the swap entry from &lt;code&gt;fstab&lt;/code&gt; so you don't have to do this every time your system comes up (vm or bare metal).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo nano /etc/fstab&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Remove the entire line with &lt;code&gt;swap&lt;/code&gt;, but nothing else, be careful here.&lt;/p&gt;
&lt;h4&gt;
  
  
  7. Enable and start the docker service.
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;sudo systemctl enable docker.service&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  8. Setup the Docker Daemon
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;sudo nano /etc/docker/daemon.json&lt;/code&gt;&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exec-opts"&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="s2"&gt;"native.cgroupdriver=systemd"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"log-driver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json-file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"log-opts"&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;"max-size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"100m"&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;"storage-driver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"overlay2"&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;



&lt;p&gt;&lt;code&gt;sudo mkdir -p /etc/systemd/system/docker.service.d&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  9. Reload the docker daemon and system process
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;sudo systemctl daemon-reload &amp;amp;&amp;amp; sudo systemctl restart docker&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  10. Clone our VM.
&lt;/h4&gt;

&lt;p&gt;At this point you can clone your VM, you should be able to do this and get the same installs, but with different network MAC addresses. Some issues with my own setup prevented this from going smoothly, but this is the time to clone the VM if you want to go that route. &lt;/p&gt;

&lt;p&gt;Spin up two clones of our first VM. You'll need to change the &lt;code&gt;hostname&lt;/code&gt; at a minimum, and reboot (or restart the networking service).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo nano /etc/hostname&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I used &lt;code&gt;kube-worker-1&lt;/code&gt; and &lt;code&gt;kube-worker-2&lt;/code&gt;, but use whatever you like. So long as it doesn't have &lt;code&gt;_&lt;/code&gt; or &lt;code&gt;CAPS&lt;/code&gt; characters. I learned that the hard way.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo reboot&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps on our Manager node
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Initialize our k8 cluster
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;sudo kubeadm config images pull&lt;/code&gt; - (optional) The next command will do this by default, but it can take a while, my sanity prefers pulling the images first.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo kubeadm init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After running this command, you'll get output similar to this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir -p $HOME/.kube&lt;/code&gt;&lt;br&gt;
  &lt;code&gt;sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config&lt;/code&gt;&lt;br&gt;
  &lt;code&gt;sudo chown $(id -u):$(id -g) $HOME/.kube/config&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Along with a &lt;strong&gt;&lt;code&gt;join&lt;/code&gt;&lt;/strong&gt; command for the cluster. &lt;strong&gt;Copy this, save it&lt;/strong&gt; to a safe place. You'll need it later.&lt;/p&gt;

&lt;p&gt;If you lose this token, you can make a new one with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubeadm token create --print-join-command&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Establish Cluster Network - Using Weave
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3. View the networking services we just spun up
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;kubectl get pods --all-namespaces&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps on our Worker nodes
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Join our cluster
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;sudo kubeadm join ....&lt;/code&gt; - &lt;em&gt;This should be the command you copied/saved form the init command above.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Back to the Manager Node
&lt;/h4&gt;

&lt;p&gt;We can now check the status of our cluster:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get nodes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Profit&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Links:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/home/"&gt;Kubernetes Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.weave.works/docs/net/latest/kubernetes/kube-addon/"&gt;Weave networking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://virt-manager.org/"&gt;Virt-manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ubuntu.com/download/server"&gt;Ubuntu Server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>kubernetes</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Let's Build a Home Lab Server - A Build Log</title>
      <dc:creator>Nathan Bland</dc:creator>
      <pubDate>Tue, 28 May 2019 19:47:41 +0000</pubDate>
      <link>https://forem.com/nathanbland/let-s-build-a-home-lab-server-a-build-log-2e71</link>
      <guid>https://forem.com/nathanbland/let-s-build-a-home-lab-server-a-build-log-2e71</guid>
      <description>&lt;p&gt;A home lab is something I've been wanting for a very long time. In this post, I'll drag you along for the adventure that has been my build out, some troubles I faced, and how I solved them.&lt;/p&gt;

&lt;p&gt;A lot of people can get by starting out with a &lt;code&gt;raspberry pi&lt;/code&gt; as a home lab. I also started with one of these, but my needs have grown beyond what it can do. The pi (especially the pi 3 model b+) is still a great little tool, and if you are just getting started I'd recommend one. For the price they can't be beat. This is a bit of a mind dump, so if you want to jump around, here are the sections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Intro (you are here)&lt;/li&gt;
&lt;li&gt;Research&lt;/li&gt;
&lt;li&gt;The Build&lt;/li&gt;
&lt;li&gt;The Storage&lt;/li&gt;
&lt;li&gt;The Network&lt;/li&gt;
&lt;li&gt;The Software&lt;/li&gt;
&lt;li&gt;Extras&lt;/li&gt;
&lt;li&gt;Install and Troubleshooting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Research
&lt;/h2&gt;

&lt;p&gt;I spent a lot of time trying to figure out what parts, or system I should get for this. I wanted solid performance, but like everyone I didn't want to pay a truck load of money to get it. I fell into the rabbit hole of &lt;a href="https://www.reddit.com/r/homelab/"&gt;/r/homelab&lt;/a&gt; and &lt;a href="https://www.reddit.com/r/DataHoarder/"&gt;/r/DataHoarder/&lt;/a&gt; looking for suggestions. &lt;/p&gt;

&lt;p&gt;I found myself over at &lt;a href="https://www.serverbuilds.net/nas-killer-v30"&gt;serverbuilds.net&lt;/a&gt; looking through their build lists. This led me to looking through ebay, which is how I came across &lt;a href="https://www.metservers.com/"&gt;MET Servers&lt;/a&gt; who specialize in used enterprise hardware. I had found my sweet spot.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Build
&lt;/h2&gt;

&lt;p&gt;The prices on MET simply blew me away. I chose to start my configuration with a &lt;a href="https://www.metservers.com/Dell-PowerEdge-R710-6-Bay-LFF-2U-Rackmount-Server"&gt;&lt;code&gt;Dell R710&lt;/code&gt;&lt;/a&gt; for a couple of reasons. One, the backplate it uses (PERC H700) can handle large drives and can do SATA 6Gb/s. Here is the full configuration I ended up going with:&lt;/p&gt;

&lt;h3&gt;
  
  
  The Brain
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;• Dell PowerEdge R710 6-Bay LFF 2U Rackmount Server
--------------------------------------------------------
• Processors: 2x Intel Xeon X5660 2.8GHz 6 Core 12MB Cache Processors.
• Memory: 24GB DDR3 ECC Registered Memory (6 x 4GB)
• RAID Controller: Dell PERC H700 6Gbps SAS/SATA RAID Controller 512MB Cache (0 1 5 6 10 50 60)
• Hard Drive Bay x6 1: Dell 3.5 Tray with screws 
• Daughter Card: Embedded Broadcom NetXtreme II 5709C Gigabit Ethernet NIC
• Management: iDRAC 6 Express Management Module
• Networking: Additional Network Card Not Included
• Power Supplies: 2x Redundant 870W Power Supplies
• Rail Kit: Rail Kit Not Included
• Front Security Bezel: Bezel Included with Key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The configuration started at $50, which is crazy. The CPUs were a $40 upgrade, the ram cost $54, upping the PSUs to 870 watts was $15, and the drive bays were $10 a piece. The amazing thing about this configuration is that it comes with a 4 port gig Ethernet adapter built in. &lt;/p&gt;

&lt;p&gt;This cost me around $245 &lt;em&gt;shipped&lt;/em&gt;, which is less than I was finding some empty chassis for online. The issue with this of course, is that it had no drives. They did have an option for shipping it with drives, (4Tb @ $80) which wasn't a bad price. However, I wanted to try something else I had found online, which was shucking large external hard drives (which cost less for some reason) and using them as internal storage. While getting CPUs and ram used isn't really a big deal, write hours on hard drives can be, so sadly I had to buy that new.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Storage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bad idea - $6.99 - 1x Kingston Digital 16 GB DataTraveler SE9 G2 USB 3.0 Flash Drive (DTSE9G2/16GB)
Good idea - $67 -  WD Blue 3D NAND 500GB PC SSD - SATA III 6 Gb/s, 2.5"/7mm - WDS500G2B0A 
$8.95 - Protronix SATA Optical Bay 2nd Hard Drive Caddy, Universal for 12.7mm CD/DVD Drive Slot
$110 each - 6x WD 6TB Elements Desktop Hard Drive - USB 3.0 - WDBWLG0060HBK-NESN 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The seeming outlier here is the USB flash drive, but the cool thing is that it can be used as an OS drive, &lt;del&gt;so that I don't have to take up any of the storage bays for the operating system.&lt;/del&gt; The original plan was to use the flash drive to store the base OS. The flash drive couldn't handle the read/write cycles of the main os and died after about a month. I replaced it with the optical bay ssd holder and ssd combo, which has been working flawlessly ever since. I also didn't lose any data, which was a big relief.&lt;/p&gt;

&lt;p&gt;The WD elements drives all arrived earlier than everything else, which allowed me to test the drives in their enclosures to make sure they were all functional. I did a simple file transfer (around 10Gb) and S.M.A.R.T. status check on each of them. Afterwards it was time to coax them out of their shells. I followed a &lt;a href="https://www.youtube.com/watch?v=JZ-5FbSxpbk"&gt;youtube video&lt;/a&gt; on the process by the same person who wrote the &lt;code&gt;serverbuilds.net&lt;/code&gt; guide, &lt;code&gt;JDM_WAAAT&lt;/code&gt;, &lt;em&gt;who sadly, doesn't appear to have an account here&lt;/em&gt;. The process was actually easier for the 6Tb drives I had, and only required removing two screws.&lt;/p&gt;

&lt;p&gt;The drive inside is &lt;em&gt;not the best&lt;/em&gt;, but for my use will be fine. It also costs $50 &lt;em&gt;more&lt;/em&gt; if you &lt;a href="https://smile.amazon.com/WD-Blue-6TB-Hard-Drive/dp/B013HNYVCE"&gt;buy it without the enclosure&lt;/a&gt;, which still makes no sense to me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Network
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Netgear r7500v2 (already owned)
$40 - Dell PowerConnect 2748 48-port gigabit Ethernet switch
$20 - Cable Matters 5-Pack Snagless Cat 6a / Cat6a (SSTP/SFTP) Shielded Ethernet Cable in Blue 10 Feet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given that I was planning to create a Link Aggregation Group (&lt;code&gt;LAG&lt;/code&gt;) with the four gig ports that came with this box, I knew I was going to need some additional networking hardware. My router is fine, but only has four ports total - most of which are already in use, and doesn't support link aggregation. &lt;/p&gt;

&lt;p&gt;I went back to ebay and found a preowned &lt;code&gt;Dell PowerConnect 2748&lt;/code&gt; for around $40 &lt;em&gt;shipped&lt;/em&gt; which was more than enough for what I need now, and the future. Even better, the switch is managed, so I can set up my link aggregations, and VLANs if I so choose. &lt;/p&gt;

&lt;p&gt;For cables, I picked up some additional &lt;code&gt;cat 6a&lt;/code&gt; cables, which are better than cat 5e in every way, and cost just slightly more. They also support 10Gbe, which means if 10Gbe networking is ever affordable, I can upgrade without having to buy new cables. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Software
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;• FreeNAS 11
  • NextCloud
  • Plex Media Server
  • Docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I originally was going to use &lt;code&gt;unRAID&lt;/code&gt; for this setup, as it's ease-of-use was attractive to me, as was it's ability to add a single disk to an existing drive array. However, further research showed that the downsides of this benefit include reduced write speed to drives as you add more devices. This is an issue because one primary goal I have for this system is backups from my other devices, as well as a replacement for dropbox so I can stop shipping them my money. Frequent writes are common in both of these situations, which ultimately made me lean to &lt;a href="https://freenas.org/"&gt;&lt;code&gt;FreeNAS&lt;/code&gt;&lt;/a&gt;, which has better (supposedly) write speeds, and most of the same feature set. It also happens to be completely free (unlike unRAID) and is OSS.&lt;/p&gt;

&lt;p&gt;The two services (plugins in the world of freeNAS) that I've started with are &lt;a href="https://nextcloud.com/"&gt;&lt;code&gt;nextCloud&lt;/code&gt;&lt;/a&gt; and &lt;a href="http://plex.tv/"&gt;&lt;code&gt;plex&lt;/code&gt;&lt;/a&gt;, though plex is currently protesting. &lt;/p&gt;

&lt;p&gt;Docker comes installed and supported out of the box on FreeNAS, which is great.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extras
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$137 - CyberPower CP850PFCLCD PFC Sinewave UPS System, 850VA/510W
$50 - UNIVERSAL DEVICE PLACEMENT PORTABLE 12U FLOORSTANDING 19" SERVER RACK
$40 - Dell R610 R710 Static Server Rail Kit 2 Post 4 Post R G483G L K291G
$7.50 - Pasow 50pcs Cable Ties Reusable Fastening Wire Organizer
$70 - SiliconDust HDHomeRun Connect Duo 2-Tuner 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first four items on this list aren't really "extras" but don't really fit anywhere else. I'd argue a UPS is required to protect a system like this. A rack, though small - does wonders for space management, and organization. The rails go with the server, but also with the rack, since I didn't buy the kit from MET.&lt;/p&gt;

&lt;p&gt;The cable ties - which are reusable - is a purely quality of life item, but makes dealing with networking and power cables much easier.&lt;/p&gt;

&lt;p&gt;The TV tuner is definitely an extra, and I wouldn't even want it if I wasn't going to use it with plex's excellent live TV &amp;amp; DVR system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install and Troubleshooting
&lt;/h2&gt;

&lt;p&gt;Installing &lt;code&gt;freenas 11&lt;/code&gt; was straight forward, but not pain free. If you go the route I initially tried, which is running the install off of a flash drive, you technically need &lt;em&gt;two&lt;/em&gt; flash drives. One to put the installer image on, and one to install the OS &lt;em&gt;to&lt;/em&gt;. Fortunately, I had another flash drive that worked for this purpose. A pain point of this install though, was that the system - being the older hardware that it is - does not have usb 3. As such, installing onto the flash drive using usb 2.0 was a very time consuming process. Installing to the ssd later was faster, mostly because of its SATA interface, but also because I discovered the remote management utility built into this server let's you mount an ISO over the network, which meant I didn't have to use USB at all to install the system, which was great.&lt;/p&gt;

&lt;p&gt;The hard drives were easy enough to shuck as I mentioned above, however I did break a drive caddy when I accidentally installed the drives too far forward in the caddies, and thus wasn't making contact with the backplane. One of the screws seized on a caddy and I stripped it (which was totally my fault), this cost me another $7 on ebay to get a caddy. &lt;/p&gt;

&lt;p&gt;Once the drives were all properly installed in the drive bays, I did have to configure them each to be their own RAID 0 array to get them to pass through to freenas, something freenas really doesn't like because it removes some drive monitoring. It would be better if I was using a RAID controller that supported direct pass through, but this one doesn't and at this point I'm tired of spending money on this project. &lt;/p&gt;

&lt;p&gt;The ZFS pool configured easily. I'm only using one parity disk, something that at this size of pool (36 total TB) is frowned upon, but losing 12TB of space to parity isn't something I'm currently willing to do. &lt;/p&gt;

&lt;p&gt;The freenas interface is fairly easy to use, and after stumbling through creating the data pool above, the next challenge was the software I actually wanted. Plex and nextcloud.&lt;/p&gt;

&lt;p&gt;Nextcloud was easy, freenas has nextcloud as a "plugin" which uses a concept of a jail - similar to a virtual machine - to run the software you want in isolation from the rest of the system. The only configuration I had to do here was setting up a username and password during the nextcloud web based install. Super easy.&lt;/p&gt;

&lt;p&gt;Plex was a different matter. I wanted to be able to access plex files (things like pictures and videos) directly off of a network drive. This meant I had to setup a windows samba share in freenas. Freenas actually makes this trivial, and has an entire wizard to help you do this. I setup a user, named a share, and could connect to it from my network. Awesome. At this point I thought I was set, as plex also has an official plugin provided by freenas, just like nextcloud. No matter what I did though, I could not get the web interface to load to get past the initial configuration of plex. This was very frustrating and almost made me give up. &lt;/p&gt;

&lt;p&gt;I finally &lt;a href="https://www.ixsystems.com/community/threads/tutorial-how-to-install-plex-in-a-freenas-11-2-jail.19412/"&gt;found a guide&lt;/a&gt; that went through setting up plex in your own jail, so essentially creating the plugin, but from scratch. After a little trial and error, this method worked for me. Which meant both of my services were up and running as I had hoped.&lt;/p&gt;

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

&lt;p&gt;This was a &lt;em&gt;long&lt;/em&gt; process - mostly thanks to USB 2, and a failing flash drive - that involved a lot of headaches and trial and error. So much so that I know I've missed details when creating this build log. If you have any questions on any step, or anything I did that seems to skip forward in time, please drop a comment and I'll try to update and address it. I ended up not setting up a docker environment on this system, and am instead using jails for that purpose. Due to the way that freenas allocates memory and cpu resources, jails are much simpler. Got a cool idea for something I should do with this? &lt;em&gt;Also&lt;/em&gt; please drop a comment. &lt;/p&gt;

&lt;p&gt;Thanks for reading, and coming along with me on this adventure. &lt;/p&gt;

</description>
      <category>homelab</category>
      <category>guide</category>
      <category>linux</category>
      <category>buildlog</category>
    </item>
    <item>
      <title>Creating a Usable Backup Setup for Linux (ElementaryOS 5)</title>
      <dc:creator>Nathan Bland</dc:creator>
      <pubDate>Wed, 13 Mar 2019 00:56:34 +0000</pubDate>
      <link>https://forem.com/nathanbland/creating-a-usable-backup-setup-for-linux-elementaryos-5-5b75</link>
      <guid>https://forem.com/nathanbland/creating-a-usable-backup-setup-for-linux-elementaryos-5-5b75</guid>
      <description>&lt;h1&gt;
  
  
  Creating a Usable Backup Setup for Linux (ElementaryOS 5)
&lt;/h1&gt;

&lt;p&gt;Creating a backup solution is something most of us don't think about until we need it.&lt;/p&gt;

&lt;p&gt;This is a guide that is meant to be a step by step solution to that problem before it happens.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This is made for elementaryOS, but should work on any Debian based Linux distro, however YMMV if you are using something else.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Backup Media Device
&lt;/h2&gt;

&lt;p&gt;Before we even begin with some backup software, we need to have &lt;em&gt;something&lt;/em&gt; to back it up to. This can be a network location like a samba share, a secondary disk in the system itself, or a removable disk like an external hard drive. &lt;/p&gt;

&lt;p&gt;In my case, I'm using a 4Tb Western Digital Passport drive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Install The Software
&lt;/h2&gt;

&lt;p&gt;There are a ton of backup solutions in terms of software for Linux, most being based on either rsync, or duplicity. For this guide, we are going to be using a tool called &lt;em&gt;Déjà Dup Backup Tool&lt;/em&gt;. It's based on duplicity, which means we can back up to any kind of file store (even NTFS) and retain permissions, take snapshot backups, and keep file history, which is a very good thing for us. In my case, it allows me to make backups from both my windows install, and Linux install to the save drive, without needing different partitions. &lt;em&gt;An honorable mention goes to Timeshift, which I would have used if it provided any kind of support for NTFS drives&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Getting this installed in Elementary is straight forward. First, we need to open up the &lt;code&gt;AppCenter&lt;/code&gt;, either by finding it on the dock, or by going to the applications tab and typing in the name. &lt;/p&gt;

&lt;p&gt;Once we've got that open, we are going to type in &lt;code&gt;Backup&lt;/code&gt; in the search bar in the top right of the AppCenter. This will provide a list of many, many apps, most of which are "Non-Curated". &lt;code&gt;Déjà Dup&lt;/code&gt; falls into this category as well, and for me was the 5th listing from the top.&lt;/p&gt;

&lt;p&gt;After locating the listing, click on the &lt;code&gt;Free&lt;/code&gt; button on the far right, this will prompt you for your administrator (sudo) credentials to install the software. Enter them and hit &lt;code&gt;Authenticate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You you will be shown a progress bar for downloading, and then installing. Once the install is complete, you can close the AppCenter. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Configuring Backup
&lt;/h2&gt;

&lt;p&gt;Now that we have our backup tool installed, we need to open it. Click the &lt;code&gt;Applications&lt;/code&gt; menu button in the top left, and look for &lt;code&gt;Backups&lt;/code&gt; or type it in to search.&lt;/p&gt;

&lt;p&gt;We are greeted by an interface that has only two visible buttons, and several menu items. The buttons, &lt;code&gt;Restore...&lt;/code&gt; and &lt;code&gt;Back Up Now...&lt;/code&gt; provide quick ways to get started. &lt;/p&gt;

&lt;p&gt;Before we click through one of these, let's check our our menu items:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Overview - where we are now&lt;/li&gt;
&lt;li&gt;Folders to save - The things we want backed up, by default, this only backs up your home folder.&lt;/li&gt;
&lt;li&gt;Folders to ignore - Things you don't want included in your backup.&lt;/li&gt;
&lt;li&gt;Storage location - Where your backups will live.&lt;/li&gt;
&lt;li&gt;Scheduling - How often you want the system to backup&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3.1: Scheduling
&lt;/h3&gt;

&lt;p&gt;Let's start with that last menu item, and work our way up. First, turn &lt;code&gt;Automatic backup&lt;/code&gt; on. Now, how often we want this to run can vary. &lt;/p&gt;

&lt;p&gt;This will depend on your needs, and available storage. If you have more storage you may be able to do daily backups and keep them forever, or if you have much less you may only do weekly, and only keep a few&lt;/p&gt;

&lt;p&gt;A lot of this depends on what you feel is appropriate for your data. How often do you change files on your computer? Is that data saved somewhere else like google docs or GitHub? &lt;/p&gt;

&lt;p&gt;Personally, most of the work I do in Linux is code, and I use git for that. However, I do still have a lot of personalization that would take a lot of effort to get back, so for me, I'm going to set mine to backup every &lt;code&gt;Week&lt;/code&gt; and keep for &lt;code&gt;At  least six months&lt;/code&gt;. This gives me a reasonable amount of data, without going too far for what I do. Remember that this software uses snapshot backups, so they won't take as much storage as you probably think.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2: Storage Location
&lt;/h3&gt;

&lt;p&gt;A cool feature of &lt;code&gt;Déjà Dup&lt;/code&gt; is that you can backup to a cloud account (Google Drive or Next cloud) if you desire. I'm just going to do a local backup, but feel free to use one of those options if you want. Keep in mind that backups to a remote server will probably be much slower.&lt;/p&gt;

&lt;p&gt;At this point of &lt;code&gt;Déjà Dup&lt;/code&gt; we have two options, &lt;code&gt;Storage location&lt;/code&gt; and &lt;code&gt;Folder&lt;/code&gt;. You should adjust at least your storage location to point to your external drive.&lt;/p&gt;

&lt;p&gt;In my case the &lt;code&gt;Storage location&lt;/code&gt; is set to my &lt;code&gt;Passport&lt;/code&gt; external drive, and folder is just my computer name, &lt;code&gt;nathan-Z170XP-SLI&lt;/code&gt;. You can change that folder name to whatever you want.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3: Folders to ignore
&lt;/h3&gt;

&lt;p&gt;This menu is slightly deceiving. Anyone who has dealt with Linux backups before will know there are some system folders you should &lt;em&gt;definitely&lt;/em&gt; ignore if you want a system backup to be successful. Fortunately, &lt;code&gt;Déjà Dup&lt;/code&gt; provides are larger list, that is &lt;em&gt;always&lt;/em&gt; ignored. You can view this list by clicking the top right icon, selecting help, and browsing to &lt;code&gt;Settings&lt;/code&gt;. The help guide is generally useful and well written, I would recommend it if you have any other questions.&lt;/p&gt;

&lt;p&gt;I'm going to add one additional entry by hitting the plus, &lt;code&gt;/media&lt;/code&gt;, as I'm going to include my entire system, and I don't want to backup the drive I'm backing up &lt;em&gt;to&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.4: Folders to save
&lt;/h3&gt;

&lt;p&gt;By default, &lt;code&gt;Déjà Dup&lt;/code&gt; only backs up your home directory. I want more than this included in my backup, so I'm going to hit the plus icon near the bottom of the interface, and add an entry for root &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is going to tell it to backup &lt;em&gt;everything&lt;/em&gt; - excluding the folders on the ignore list - on the system, so you may not want to set a backup to this level.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.5: Backup.
&lt;/h3&gt;

&lt;p&gt;Clicking back to the &lt;code&gt;Overview&lt;/code&gt; section, we can now run our backup. Click &lt;code&gt;Back Up Now...&lt;/code&gt;, you will be informed that the system requires &lt;code&gt;duplicity&lt;/code&gt; with an option to install it in the top right, click &lt;code&gt;Install&lt;/code&gt;. Just like before you will be prompted for your administrator credentials, and be greeted by a progress bar.&lt;/p&gt;

&lt;p&gt;Once this install finishes you will be asked if you want to require a password for your backup. Depending on the nature of your work, and your tendency to remember or forget passwords, I would recommend password protecting this. If you don't use a password manager, you should start. However, if you don't feel you either need, or would remember a password, then select &lt;code&gt;Allow restoring without a password&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;In my case, I gave a password. Once you have an option selected, and a password given, the &lt;code&gt;Forward&lt;/code&gt; button becomes active, click it.&lt;/p&gt;

&lt;p&gt;This will start the backup itself. Depending on how much data you have, and which storage location you selected, this will take a long time. &lt;/p&gt;

&lt;p&gt;You can expand the details if you want to view exactly what it is doing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Testing The Restore
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Do not test this on the original source drive&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This may not be a practical use for everyone, as not everyone has extra drives laying around to try a backup with. If at all possible you should try restoring the system with your backup to know that it works. This particular solution requires you install an operating system &lt;em&gt;first&lt;/em&gt;, and then restore your backup. From there you can choose a full system restore, or cherry pick individual files to restore instead. &lt;/p&gt;

&lt;p&gt;Please, try it. Not only does this give you experience with using the restore function so you know how should the time actually arise when you need to. It will let you walk through any issues you encounter knowing your data is actually still safe on the original drive. This let's you create an action plan - even if it's just in a google keep note, or dropbox - for when you need to do a real restore, and can help reduce stress significantly during that time.&lt;/p&gt;

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

&lt;p&gt;We've made it, and you can now sleep a little easier knowing if your hard drive (or ssd) decides not to wake up tomorrow, you have a place to rescue your data from.&lt;/p&gt;

&lt;p&gt;I hope this guide was useful for you, I'm by no means an expert in the backup space, this is just a solution I use and is simple enough to run without getting in the way. If you have suggestions/corrections/comments please feel free to let me know below! &lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by Chris Yates on Unsplash&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>backup</category>
      <category>guide</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Episode 14: Building a JSON API - Twitter OAuth (OAuth 1.0)</title>
      <dc:creator>Nathan Bland</dc:creator>
      <pubDate>Thu, 07 Feb 2019 15:40:05 +0000</pubDate>
      <link>https://forem.com/nathanbland/episode-14-building-a-json-api---twitter-oauth-oauth-10-16ib</link>
      <guid>https://forem.com/nathanbland/episode-14-building-a-json-api---twitter-oauth-oauth-10-16ib</guid>
      <description>&lt;p&gt;Sometimes users don't want to make yet another account. In this episode we'll cover how to let them use a twitter account with OAuth 1.0 instead.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Ul7Y0msZy-I"&gt;
&lt;/iframe&gt;
 &lt;/p&gt;

&lt;p&gt;Thanks for watching! &lt;/p&gt;

&lt;p&gt;Source code:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/NathanBland" rel="noopener noreferrer"&gt;
        NathanBland
      &lt;/a&gt; / &lt;a href="https://github.com/NathanBland/core" rel="noopener noreferrer"&gt;
        core
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Repository for the "core" video series
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;core&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;An express.js powered json api built for the "core" series.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting started&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ git clone git@github.com:NathanBland/core.git
$ cd core
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ docker-compose up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/NathanBland/core" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>node</category>
      <category>passportjs</category>
      <category>authentication</category>
      <category>twitter</category>
    </item>
    <item>
      <title>Episode 13: Building a JSON API - Quickly Adding HTTPS</title>
      <dc:creator>Nathan Bland</dc:creator>
      <pubDate>Tue, 29 Jan 2019 01:41:42 +0000</pubDate>
      <link>https://forem.com/nathanbland/episode-13-building-a-json-api---quickly-adding-https-to-the-docker-setup-3m77</link>
      <guid>https://forem.com/nathanbland/episode-13-building-a-json-api---quickly-adding-https-to-the-docker-setup-3m77</guid>
      <description>&lt;p&gt;In this episode, we cover adding &lt;code&gt;HTTPS&lt;/code&gt; using &lt;code&gt;nginx&lt;/code&gt; with &lt;code&gt;docker-compose&lt;/code&gt; to our api.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/lQJlQ7Jmkmc"&gt;
&lt;/iframe&gt;
 &lt;/p&gt;

&lt;p&gt;Thanks for watching! &lt;/p&gt;

&lt;p&gt;Source code:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qF2jUiUG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-6a5bca60a4ebf959a6df7f08217acd07ac2bc285164fae041eacb8a148b1bab9.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/NathanBland"&gt;
        NathanBland
      &lt;/a&gt; / &lt;a href="https://github.com/NathanBland/core"&gt;
        core
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Repository for the "core" video series
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="instapaper_body md"&gt;
&lt;h1&gt;
core&lt;/h1&gt;
&lt;p&gt;An express.js powered json api built for the "core" series.&lt;/p&gt;
&lt;h2&gt;
Getting started&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ git clone git@github.com:NathanBland/core.git
$ cd core
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;$ docker-compose up
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/NathanBland/core"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>node</category>
      <category>docker</category>
      <category>dockercompose</category>
      <category>https</category>
    </item>
    <item>
      <title>Episode 12: Building a JSON API - User Authentication in Under an Hour</title>
      <dc:creator>Nathan Bland</dc:creator>
      <pubDate>Tue, 04 Dec 2018 10:01:44 +0000</pubDate>
      <link>https://forem.com/nathanbland/episode-12-building-a-json-api---user-authentication-in-under-an-hour-h99</link>
      <guid>https://forem.com/nathanbland/episode-12-building-a-json-api---user-authentication-in-under-an-hour-h99</guid>
      <description>&lt;p&gt;Grab a cup of coffee, maybe two.&lt;/p&gt;

&lt;p&gt;In this episode we add local-user authentication (username, password) to our JSON API in under an hour with help from &lt;code&gt;passport.js&lt;/code&gt;, &lt;code&gt;jwt&lt;/code&gt;, and a strong dose of patience.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/DTGCta_1nGQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This episode had so much, I almost broke it up several times while editing as it felt like it was too much. However, having an incomplete basic solution at the end of several episodes also felt wrong, so here we are. One hour later, one authentication enabled api.&lt;/p&gt;

&lt;p&gt;Thanks for watching! &lt;/p&gt;

&lt;p&gt;Source code:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/NathanBland" rel="noopener noreferrer"&gt;
        NathanBland
      &lt;/a&gt; / &lt;a href="https://github.com/NathanBland/core" rel="noopener noreferrer"&gt;
        core
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Repository for the "core" video series
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;core&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;An express.js powered json api built for the "core" series.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting started&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ git clone git@github.com:NathanBland/core.git
$ cd core
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ docker-compose up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/NathanBland/core" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>node</category>
      <category>mongodb</category>
      <category>javascript</category>
      <category>passportjs</category>
    </item>
    <item>
      <title>Episode 11.5: Building a JSON API - Input Validation and Sanitation - Lightning Round</title>
      <dc:creator>Nathan Bland</dc:creator>
      <pubDate>Fri, 30 Nov 2018 07:10:12 +0000</pubDate>
      <link>https://forem.com/nathanbland/episode-115-building-a-json-api---input-validation-and-sanitation---lightning-round-3b2i</link>
      <guid>https://forem.com/nathanbland/episode-115-building-a-json-api---input-validation-and-sanitation---lightning-round-3b2i</guid>
      <description>&lt;p&gt;Are half episodes a thing? (Apparently) Is 10 minutes a lightning round? &lt;/p&gt;

&lt;p&gt;If 10 minutes can be called a lightning round, then this is it. We cover all of our item route in what previously took us two episodes to do for user. &lt;em&gt;In particular&lt;/em&gt; we speed past some testing portions that work to speed things up. Hang on to your seats.. &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/1jvDrs2JgQ8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Whew. That was a lot. Think I should have included more, or done something extra? Let me know.&lt;/p&gt;

&lt;p&gt;Thanks for watching! &lt;/p&gt;

&lt;p&gt;Source code:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/NathanBland" rel="noopener noreferrer"&gt;
        NathanBland
      &lt;/a&gt; / &lt;a href="https://github.com/NathanBland/core" rel="noopener noreferrer"&gt;
        core
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Repository for the "core" video series
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;core&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;An express.js powered json api built for the "core" series.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting started&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ git clone git@github.com:NathanBland/core.git
$ cd core
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ docker-compose up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/NathanBland/core" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>node</category>
      <category>mongodb</category>
      <category>javascript</category>
      <category>docker</category>
    </item>
    <item>
      <title>Episode 11: Building a JSON API - Input Validation and Sanitation - Part 2</title>
      <dc:creator>Nathan Bland</dc:creator>
      <pubDate>Thu, 29 Nov 2018 23:06:35 +0000</pubDate>
      <link>https://forem.com/nathanbland/episode-11-building-a-json-api---input-validation-and-sanitation---part-2-2o7c</link>
      <guid>https://forem.com/nathanbland/episode-11-building-a-json-api---input-validation-and-sanitation---part-2-2o7c</guid>
      <description>&lt;p&gt;Input validation and sanitation, mostly sanitation. Finishing up the Read route, then continuing on to Update, and Delete.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/sm3236gXqT4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;There is still more to cover, in particular the item validations, but given that is a dynamic object almost entirely, almost all we could do is escape the values that are passed to it. Does it deserve its own episode? Let me know.&lt;/p&gt;

&lt;p&gt;Thanks for watching! &lt;/p&gt;

&lt;p&gt;Source code:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i3JOwpme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/NathanBland"&gt;
        NathanBland
      &lt;/a&gt; / &lt;a href="https://github.com/NathanBland/core"&gt;
        core
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Repository for the "core" video series
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
core&lt;/h1&gt;
&lt;p&gt;An express.js powered json api built for the "core" series.&lt;/p&gt;
&lt;h2&gt;
Getting started&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ git clone git@github.com:NathanBland/core.git
$ cd core
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;$ docker-compose up
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/NathanBland/core"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>node</category>
      <category>mongodb</category>
      <category>javascript</category>
      <category>docker</category>
    </item>
    <item>
      <title>Episode 10: Building a JSON API - Input Validation and Sanitation - Part 1</title>
      <dc:creator>Nathan Bland</dc:creator>
      <pubDate>Thu, 29 Nov 2018 08:21:14 +0000</pubDate>
      <link>https://forem.com/nathanbland/episode-10-building-a-json-api---input-validation-and-sanitation---part-1-mko</link>
      <guid>https://forem.com/nathanbland/episode-10-building-a-json-api---input-validation-and-sanitation---part-1-mko</guid>
      <description>&lt;p&gt;Dropping user provided data directly into your database is a bad idea. In this episode, we'll look at using &lt;code&gt;validator.js&lt;/code&gt; to help with that. We'll also spend a little time talking about npm packages, and trust.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/2xnXOcK2u1A"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I really didn't want to do this in more than one part, but it was going to be a very, very long episode. Part 2 will be along very soon (Source code already has it). As always, drop a comment if you would like to see me cover something else, or cover something differently.&lt;/p&gt;

&lt;p&gt;Thanks for watching! &lt;/p&gt;

&lt;p&gt;Source code:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/NathanBland" rel="noopener noreferrer"&gt;
        NathanBland
      &lt;/a&gt; / &lt;a href="https://github.com/NathanBland/core" rel="noopener noreferrer"&gt;
        core
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Repository for the "core" video series
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;core&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;An express.js powered json api built for the "core" series.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting started&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ git clone git@github.com:NathanBland/core.git
$ cd core
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ docker-compose up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/NathanBland/core" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>node</category>
      <category>mongodb</category>
      <category>javascript</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
