<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Andrew Beaton</title>
    <link>https://andrewbeaton.net/</link>
    <description>Recent content on Andrew Beaton</description>
    <image>
      <title>Andrew Beaton</title>
      <url>https://andrewbeaton.net/me.jpeg</url>
      <link>https://andrewbeaton.net/me.jpeg</link>
    </image>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Tue, 20 Jun 2023 00:00:00 +0000</lastBuildDate><atom:link href="https://andrewbeaton.net/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Automating Linux Containers and Virtual Machines on Proxmox.</title>
      <link>https://andrewbeaton.net/posts/2023/06/proxmox-automate-lxcs-vms/</link>
      <pubDate>Tue, 20 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2023/06/proxmox-automate-lxcs-vms/</guid>
      <description>A guide to automating the creation of linux containers and virtual machines on Proxmox using scripts.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Automation plays a key role in standardising and simplifying the process of building environments.</p>
<p>Continuing on my journey of automating my home lab setup, I found a very good resource that&rsquo;s available for <a href="https://www.proxmox.com/en/">Proxmox</a> users to automate the installation of various Linux containers and Virtual Machines. You can find them from user <a href="https://github.com/tteck/">tteckster</a> here <a href="https://tteck.github.io/Proxmox/">https://tteck.github.io/Proxmox/</a></p>
<p>By using these scripts, we can save time, ensure consistency, and reduce the chances of human error during the environment build process.</p>
<h2 id="why-automate-lxc-and-vm-builds">Why Automate LXC and VM Builds?</h2>
<p>Automation offers several notable benefits when it comes to building Linux containers and VMs:</p>
<h3 id="time-and-effort-savings"><strong>Time and Effort Savings</strong></h3>
<p>Manually configuring and setting up containers or VMs can be a time-consuming and labor-intensive task.</p>
<p>By automating the build process using command line scripts, we can save significant time and effort.</p>
<p>Scripts eliminate the need to manually perform repetitive steps, allowing for faster deployment.</p>
<h3 id="consistency-and-reproducibility"><strong>Consistency and Reproducibility</strong></h3>
<p>Maintaining consistency across multiple containers or VMs is vital in ensuring reliable application deployment.</p>
<p>Command line scripts enable us to define the exact configuration and settings required for each container or VM.</p>
<p>By automating the build process, every instance is built using the same steps, ensuring consistency and reproducibility across different environments.</p>
<h3 id="error-reduction"><strong>Error Reduction</strong></h3>
<p>Manual configuration is prone to human error. Even a small mistake in the build process can lead to significant issues, affecting the stability and performance.</p>
<p>Automation minimises the chances of human error by executing a predefined set of instructions consistently.</p>
<p>Scripts can perform complex and error-prone tasks accurately, reducing the risk of misconfiguration or missteps.</p>
<h3 id="flexibility-and-customisation"><strong>Flexibility and Customisation</strong></h3>
<p>These command line scripts provide a flexible and customisable approach to building Linux containers and VMs.</p>
<p>These scripts often offer various options and parameters that allow us to tailor the build process according to their specific requirements.</p>
<p>We can choose different configurations, select specific software packages, and define resource allocation based on our application&rsquo;s needs.</p>
<h2 id="introducing-the-command-line-scripts">Introducing the Command Line Scripts</h2>
<p>This brilliant <a href="https://tteck.github.io/Proxmox/">website</a> by <a href="https://github.com/tteck/">tteckster</a> provides a collection of command line scripts that enable the automation of Linux Container (LXC) and Virtual Machine (VM) builds on <a href="https://www.proxmox.com/en/">Proxmox</a>.</p>
<p>These scripts enable us to create in an interactive manner, offering options for both basic and advanced configurations.</p>
<h3 id="basic-setup">Basic Setup</h3>
<p>The basic setup uses default settings, making it a convenient option for users who prefer a quick and straight forward setup.</p>
<p>To run the basic script for your specific machine, go through the list of options available and use the command in the Proxmox shell.</p>
<p>For example, to create a Linux Container for Cloudflared, we can use the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>bash -c <span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>wget -qLO - https://github.com/tteck/Proxmox/raw/main/ct/cloudflared.sh<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>
</span></span></code></pre></div><p>Or to create a MariaDB container, we can use the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>bash -c <span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>wget -qLO - https://github.com/tteck/Proxmox/raw/main/ct/mariadb.sh<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>
</span></span></code></pre></div><h3 id="advanced-setup">Advanced Setup</h3>
<p>For more flexibility and customisation, the advanced setup feature of the scripts allows us to alter the default settings according to our needs.</p>
<p>This function utilises the <code>whiptail</code> command to present options in a dialogue box format, allowing us to modify the options available, such as increased memory, disk size and set options such as static IP addresses and DNS.</p>
<p>To run the advanced setup script, when prompted, choose the <!-- raw HTML omitted --> settings options when presented after running your chosen script.</p>
<p>After selecting your options, the script collects and verifies the input in order to generate the final configuration for the container or virtual machine.</p>
<h2 id="summary">Summary</h2>
<p>Automating our Proxmox builds with command line scripts streamlines the deployment process, reduces manual effort, and ensures consistency and reproducibility.</p>
<p>By using the provided basic or advanced setup scripts from the website, we can easily build Linux Containers or Virtual Machines on <a href="https://www.proxmox.com/en/">Proxmox</a> tailored to our specific needs in a repeatable manner.</p>
<p>Remember to visit <a href="https://tteck.github.io/Proxmox/">https://tteck.github.io/Proxmox/</a> for more details and documentation on the available scripts.</p>
<p>There are also a number of other scripts available and can be found by searching on GitHub. For example, user <a href="https://github.com/roib20">roib20</a> has created Proxmox helper scripts for TrueNAS and CloudInit which can be found here <a href="https://github.com/roib20/proxmox-scripts.">https://github.com/roib20/proxmox-scripts</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Using Hugo v0.113.0 and Drone</title>
      <link>https://andrewbeaton.net/posts/2023/06/drone-io-latest-hugo/</link>
      <pubDate>Sat, 10 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2023/06/drone-io-latest-hugo/</guid>
      <description>Building a Docker image for Drone to run the latest version of Hugo.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>These days, optimising workflows and automating processes is key to efficient software development and infrastructure management.</p>
<p>In my previous posts I covered how to configure Drone to build Hugo and deploy to various destinations, such as an FTP / Web server or Cloudflare Pages.</p>
<p>As I&rsquo;ve been using and learning more about Hugo, I noticed that the Docker Image I was using to build my Hugo files in Drone was quite out of date and wouldn&rsquo;t let me use some of the latest features available. After a brief search on the web, I couldn&rsquo;t find a more recent version.</p>
<p>So, with a couple of spare hours on a Saturday morning, I did some research and looked in to building my own Docker Image and have it published to GitHub&rsquo;s Container Registry.</p>
<p>And we now have the <a href="https://ghcr.io/andrewbeaton/hugo-drone">andrewbeaton/hugo-drone</a> Docker image.</p>
<h2 id="what-is-it">What is it?</h2>
<p><code>andrewbeaton/hugo-drone</code> is a Docker image specifically designed to facilitate Hugo site builds and deployments.</p>
<p>Built upon the popular Drone CI/CD platform, this image contains a preconfigured environment with Hugo and other necessary dependencies, aiming to streamline the setup process and ensuring consistency across different development environments.</p>
<p>The image is based on <a href="https://rockylinux.org/">RockyLinux</a> and installs the current version of <a href="https://gohugo.io/">Hugo</a>, which is currently <a href="https://github.com/gohugoio/hugo/releases/tag/v0.113.0">v0.113.0</a>.</p>
<p>My aim is to build and release a new versioned image, for each major release that comes along.</p>
<h2 id="step-1-installing-docker">Step 1: Installing Docker</h2>
<p>Before we can use <code>andrewbeaton/hugo-drone</code>, we need to have Docker installed on our system. Docker allows us to run containers, which are lightweight, isolated environments that encapsulate our applications and their dependencies. Follow these instructions to install Docker on your operating system.</p>
<h2 id="step-2-pulling-the-image">Step 2: Pulling the Image</h2>
<p>Once Docker is installed, we can pull the <code>andrewbeaton/hugo-drone</code> image from the <a href="https://github.com/andrewbeaton/hugo-drone/pkgs/container/hugo-drone">GitHub Images Repository</a>.</p>
<p>Open your terminal or command prompt and enter the following command:</p>
<pre tabindex="0"><code>docker pull ghcr.io/andrewbeaton/hugo-drone:latest
</code></pre><p>This command will fetch the latest version of the image and make it available on your system for usage.</p>
<h2 id="step-3-creating-a-hugo-project">Step 3: Creating a Hugo Project</h2>
<p>To work with <code>andrewbeaton/hugo-drone</code>, you need to have an existing Hugo project or create a new one.</p>
<p>If you haven&rsquo;t set up a Hugo project yet, follow these steps:</p>
<ol>
<li>
<p><strong>Install Hugo:</strong><br>
Visit the official Hugo website and download the appropriate binary for your operating system. Follow the installation instructions provided.</p>
</li>
<li>
<p><strong>Create a New Hugo Site:</strong><br>
In your terminal or command prompt, navigate to your desired project directory and run the following command:</p>
<pre tabindex="0"><code>hugo new site my-hugo-site
</code></pre><p>This command will create a new Hugo site with the name &ldquo;my-hugo-site&rdquo; in the current directory.</p>
</li>
<li>
<p><strong>Add a Theme:</strong><br>
Navigate to your Hugo site&rsquo;s directory and add a theme of your choice. You can explore various themes on the Hugo Themes website or use a specific theme by following its documentation.</p>
</li>
</ol>
<h2 id="step-4-setting-up-a-drone-configuration-file">Step 4: Setting Up a Drone Configuration File</h2>
<p>Drone relies on a configuration file named <code>.drone.yml</code> to define the build pipeline.</p>
<p>Create a new file named <code>.drone.yml</code> in the root of your Hugo project and add the following content as a starting point:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">pipeline</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">type</span>: <span style="color:#ae81ff">docker</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">default</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Build with Hugo</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">ghcr.io/andrewbeaton/hugo-drone:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pull</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">echo &#34;Checking Hugo version.&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">hugo version</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">cd /drone/src/hugo/</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">hugo --environment production --verbose --debug </span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">ls -al /drone/src/hugo/public</span>
</span></span></code></pre></div><p>This configuration instructs Drone to use the <code>andrewbeaton/hugo-drone</code> image and execute the <code>hugo</code> command for <code>production</code> to build your Hugo site. I like to enable verbose and debug output to help with problem-solving, and I also output the current version of Hugo with each build.</p>
<h2 id="step-5-building-and-deploying-with-drone">Step 5: Building and Deploying with Drone</h2>
<p>Now that everything is set up, you can build and deploy your Hugo site with Drone.</p>
<p>Commit and push the changes you made to your <code>.drone.yml</code> file. The Drone pipeline will automatically trigger, building your Hugo site.</p>
<p>Take a look at some of my other posts for examples on how to deploy to a web server or Cloudflare Pages.</p>
<h2 id="summary">Summary</h2>
<p>The <code>andrewbeaton/hugo-drone</code> Docker image simplifies the process of building Hugo sites by providing a preconfigured environment. By following the steps outlined in this blog post, you can use this image to automate your Hugo builds, saving time and effort in the development and deployment process.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Create and Publish a Docker Image to GitHub&#39;s Container Registry using GitHub Actions.</title>
      <link>https://andrewbeaton.net/posts/2023/06/docker-github-registry-actions/</link>
      <pubDate>Fri, 09 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2023/06/docker-github-registry-actions/</guid>
      <description>A guide on how to publish a Docker image to GitHub&amp;#39;s Container Registry using GitHub Actions.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In this tutorial, I will walk you through the process of publishing a Docker image to GitHub&rsquo;s Container Registry using GitHub Actions. By using GitHub Actions, you can automate the build and publish process, making it easier to distribute your Docker images.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Before getting started, make sure you have the following:</p>
<ol>
<li>A GitHub account.</li>
<li>A Dockerfile that describes your application&rsquo;s dependencies and build instructions.</li>
<li>A GitHub repository where you want to publish your Docker image.</li>
</ol>
<h2 id="step-1-set-up-github-actions-workflow">Step 1: Set up GitHub Actions workflow</h2>
<p>GitHub Actions allow you to automate tasks by creating workflows.</p>
<p>To publish a Docker image, we&rsquo;ll create a workflow file named <code>publish.yml</code>.</p>
<p>Create a new directory called <code>.github/workflows</code> in the root of your repository, if it doesn&rsquo;t already exist.</p>
<p>Inside this directory, create a new file named <code>publish.yml</code> and add the following content:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">Publish Docker Image</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">on</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">push</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">branches</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">main</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">jobs</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">build-and-publish</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">ubuntu-latest</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">steps</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Checkout code</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v2</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Login to GitHub Container Registry</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">docker/login-action@v1</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">with</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">registry</span>: <span style="color:#ae81ff">ghcr.io</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">username</span>: <span style="color:#ae81ff">${{ github.actor }}</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">password</span>: <span style="color:#ae81ff">${{ secrets.GITHUB_TOKEN }}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Build and push Docker image</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">docker/build-push-action@v2</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">with</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">context</span>: <span style="color:#ae81ff">.</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">push</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">tags</span>: <span style="color:#ae81ff">ghcr.io/${{ github.repository_owner }}/${{ github.repository }}:${{ github.sha }}</span>
</span></span></code></pre></div><p>This workflow will trigger whenever you push changes to the <code>main</code> branch. It checks out the code, logs in to GitHub&rsquo;s Container Registry using your GitHub credentials, and builds and pushes the Docker image to the registry.</p>
<h2 id="step-2-configure-the-dockerfile">Step 2: Configure the Dockerfile</h2>
<p>In your repository, create a file named <code>Dockerfile</code> and add the necessary instructions to build your Docker image. Here&rsquo;s an example <code>Dockerfile</code> for a Node.js application:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Dockerfile" data-lang="Dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">FROM</span><span style="color:#e6db74"> node:14</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">WORKDIR</span><span style="color:#e6db74"> /app</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> package.json package-lock.json ./<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> npm ci --only<span style="color:#f92672">=</span>production<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> app.js .<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">CMD</span> [<span style="color:#e6db74">&#34;node&#34;</span>, <span style="color:#e6db74">&#34;app.js&#34;</span>]<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>Make sure to modify the <code>Dockerfile</code> to suit your application&rsquo;s requirements.</p>
<h2 id="step-3-push-changes-to-your-repository">Step 3: Push changes to your repository</h2>
<p>Commit and push the <code>Dockerfile</code>, <code>publish.yml</code>, and any other files you may have modified to your repository.</p>
<h2 id="step-4-monitor-the-workflow-execution">Step 4: Monitor the workflow execution</h2>
<p>After pushing the changes, navigate to the &ldquo;Actions&rdquo; tab in your GitHub repository. You should see the workflow you created (&ldquo;Publish Docker Image&rdquo;) listed there. Click on it to monitor the execution.</p>
<h2 id="step-5-verify-the-docker-image-in-github-container-registry">Step 5: Verify the Docker image in GitHub Container Registry</h2>
<p>Once the workflow execution is complete, go to the &ldquo;Packages&rdquo; tab in your GitHub repository. You should see your Docker image listed there. Click on it to view the details.</p>
<h2 id="summary">Summary</h2>
<p>You have successfully published a Docker image to GitHub&rsquo;s Container Registry using GitHub Actions. By automating this process, you can easily distribute your Docker images and ensure consistent deployment across different environments. GitHub Actions provides a powerful platform for automating various tasks in your development workflow, saving you time and effort.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Create and Publish a Docker Image to GitHub&#39;s Container Registry</title>
      <link>https://andrewbeaton.net/posts/2023/06/docker-github-container-registry/</link>
      <pubDate>Thu, 08 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2023/06/docker-github-container-registry/</guid>
      <description>A guide on how to publish a Docker image to GitHub&amp;#39;s Container Registry using Docker Push.</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Docker has become an essential tool in modern software development, enabling easy and efficient containerisation of applications. GitHub&rsquo;s Container Registry provides a convenient way to store and manage Docker images within the GitHub ecosystem.</p>
<p>In this tutorial, we will walk through the process of creating, editing, and publishing a Docker image to GitHub&rsquo;s Container Registry.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Before we begin, ensure that you have the following:</p>
<ol>
<li>A GitHub account</li>
<li>Docker installed on your local machine</li>
<li>Basic familiarity with Docker commands</li>
</ol>
<h2 id="step-1-create-a-dockerfile">Step 1: Create a Dockerfile</h2>
<p>The first step is to create a Dockerfile, which defines the instructions to build your Docker image. Open a text editor and create a new file called <code>Dockerfile</code>. Here&rsquo;s a basic example:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Dockerfile" data-lang="Dockerfile"><span style="display:flex;"><span><span style="color:#75715e"># Use a base image</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">FROM</span><span style="color:#e6db74"> ubuntu:latest</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># Set the working directory</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">WORKDIR</span><span style="color:#e6db74"> /app</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># Copy files to the container</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> . /app<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># Install dependencies</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> apt-get update <span style="color:#f92672">&amp;&amp;</span> apt-get install -y &lt;your-package-name&gt;<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># Specify the command to run when the container starts</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">CMD</span> [<span style="color:#e6db74">&#34;&lt;your-command&gt;&#34;</span>]<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>Customise the <code>FROM</code> line with the base image you want to use and replace <code>&lt;your-package-name&gt;</code> with the required packages for your application. Also, update <code>&lt;your-command&gt;</code> with the command to start your application.</p>
<h2 id="step-2-build-the-docker-image">Step 2: Build the Docker Image</h2>
<p>Once you have the Dockerfile ready, you can build the Docker image.</p>
<p>Open a terminal or command prompt and navigate to the directory containing the Dockerfile.</p>
<p>Run the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker build -t &lt;image-name&gt; .
</span></span></code></pre></div><p>Replace <code>&lt;image-name&gt;</code> with the desired name for your Docker image.</p>
<p>The <code>.</code> at the end specifies the build context, which includes the files needed for building the image.</p>
<p>Wait for the build process to complete.</p>
<p>Docker will execute the instructions in the Dockerfile and generate the image.</p>
<h2 id="step-3-tag-the-docker-image">Step 3: Tag the Docker Image</h2>
<p>To publish the Docker image to GitHub&rsquo;s Container Registry, you need to tag it accordingly.</p>
<p>Run the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker tag &lt;image-name&gt; ghcr.io/&lt;username&gt;/&lt;repository&gt;:&lt;tag&gt;
</span></span></code></pre></div><p>Replace <code>&lt;username&gt;</code> with your GitHub username, <code>&lt;repository&gt;</code> with the name of the repository you want to push the image to, and <code>&lt;tag&gt;</code> with the desired tag (e.g., version number or <code>latest</code>).</p>
<h2 id="step-4-log-in-to-github-container-registry">Step 4: Log in to GitHub Container Registry</h2>
<p>Before you can publish the image, you need to authenticate with GitHub&rsquo;s Container Registry.</p>
<p>Run the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker login ghcr.io -u &lt;username&gt;
</span></span></code></pre></div><p>Replace <code>&lt;username&gt;</code> with your GitHub username. You will be prompted to enter your GitHub password or a personal access token.</p>
<h2 id="step-5-publish-the-docker-image">Step 5: Publish the Docker Image</h2>
<p>Now that you&rsquo;re logged in, you can publish the Docker image to GitHub&rsquo;s Container Registry.</p>
<p>Run the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker push ghcr.io/&lt;username&gt;/&lt;repository&gt;:&lt;tag&gt;
</span></span></code></pre></div><p>Replace <code>&lt;username&gt;</code>, <code>&lt;repository&gt;</code>, and <code>&lt;tag&gt;</code> with the values you used in Step 3.</p>
<p>Wait for the push process to complete. Once finished, your Docker image will be available in GitHub&rsquo;s Container Registry, associated with your specified repository.</p>
<h2 id="step-6-update-and-re-publish">Step 6: Update and Re-Publish</h2>
<p>If you make changes to your Docker image or need to update it with a new version, follow the steps again from Step 2 onwards.</p>
<p>Remember to tag the image with a new version number or an appropriate tag, and push it to GitHub&rsquo;s Container Registry.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Markdown Cheat Sheet</title>
      <link>https://andrewbeaton.net/posts/2023/06/markdown-cheat-sheet/</link>
      <pubDate>Wed, 07 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2023/06/markdown-cheat-sheet/</guid>
      <description>A cheat sheet of some of the most commonly used Markdown syntax and their corresponding options.</description>
      <content:encoded><![CDATA[<h1 id="introduction">Introduction</h1>
<p>Markdown is a lightweight markup language that allows you to write formatted text using a plain-text syntax.</p>
<p>It&rsquo;s widely used for writing documentation, blog posts, and even creating web pages.</p>
<p>In this cheat sheet, I&rsquo;ll cover the most commonly used Markdown syntax and their corresponding formatting options.</p>
<h2 id="headings">Headings</h2>
<p>You can create headings by using one to six hash characters (<code>#</code>) at the beginning of the line. The number of hashes represents the heading level.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span># Heading 1
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Heading 2
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">### Heading 3
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#### Heading 4
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">##### Heading 5
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">###### Heading 6
</span></span></span></code></pre></div><h2 id="emphasis">Emphasis</h2>
<p>You can emphasise text using the following options:</p>
<ul>
<li><strong>Bold</strong>: Surround the text with double asterisks (<code>**</code>) or double underscores (<code>__</code>).</li>
<li><em>Italic</em>: Surround the text with single asterisks (<code>*</code>) or single underscores (<code>_</code>).</li>
<li><em><strong>Bold and Italic</strong></em>: Combine both using triple asterisks (<code>***</code>) or triple underscores (<code>___</code>).</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>**Bold**
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="font-weight:bold">__Bold__</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="font-style:italic">*Italic*</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="font-style:italic">_Italic_</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="font-style:italic">**</span>*Bold and Italic***
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="font-weight:bold">___Bold and Italic___</span>
</span></span></code></pre></div><h2 id="lists">Lists</h2>
<p>Markdown supports both ordered and unordered lists.</p>
<ul>
<li><strong>Unordered List</strong>: Begin each item with a hyphen (<code>-</code>), plus sign (<code>+</code>), or asterisk (<code>*</code>).</li>
<li><strong>Ordered List</strong>: Begin each item with a number followed by a period (<code>1.</code>, <code>2.</code>, etc.).</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span><span style="color:#66d9ef">-</span> Item 1
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> Item 2
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> Item 3
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">1.</span> Item 1
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">2.</span> Item 2
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">3.</span> Item 3
</span></span></code></pre></div><h2 id="links">Links</h2>
<p>You can create links in Markdown using the following syntax:</p>
<ul>
<li><strong>Inline Links</strong>: <code>[Link Text](URL)</code></li>
<li><strong>Reference Links</strong>: <code>[Link Text][Reference ID]</code> and later <code>[Reference ID]: URL</code></li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>[<span style="color:#f92672">Google</span>](<span style="color:#a6e22e">https://www.google.co.uk</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[Andrew Beaton][1]
</span></span><span style="display:flex;"><span>[1]: https://andrewbeaton.net
</span></span></code></pre></div><h2 id="images">Images</h2>
<p>To include images in your Markdown document, use the following format:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>![<span style="color:#f92672">Alt Text</span>](<span style="color:#a6e22e">URL</span>)
</span></span></code></pre></div><h2 id="code-blocks">Code Blocks</h2>
<p>You can display code blocks or inline code using backticks (<code>`</code>):</p>
<ul>
<li>
<p><strong>Inline Code</strong>: Surround the code with single backticks.</p>
</li>
<li>
<p><strong>Code Block</strong>: Surround the code with triple backticks, optionally specifying the language for syntax highlighting.</p>
</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>console.log(&#34;Hello, Markdown!&#34;);
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">greet</span>():
</span></span><span style="display:flex;"><span>    print(<span style="color:#e6db74">&#34;Hello, Markdown!&#34;</span>)
</span></span></code></pre></div><h2 id="blockquotes">Blockquotes</h2>
<p>Blockquotes are used to display quoted text. You can create a blockquote by using a greater than symbol (<code>&gt;</code>).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span><span style="color:#66d9ef">&gt; </span><span style="font-style:italic">This is a blockquote.
</span></span></span></code></pre></div><h2 id="horizontal-rule">Horizontal Rule</h2>
<p>To create a horizontal rule, use three or more hyphens (<code>---</code>), asterisks (<code>***</code>), or underscores (<code>___</code>).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>---
</span></span></code></pre></div><h2 id="tables">Tables</h2>
<p>Tables can be created using hyphens (<code>-</code>) and pipes (<code>|</code>) to define the columns and rows.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>| Column 1 | Column 2 |
</span></span><span style="display:flex;"><span>| -------- | -------- |
</span></span><span style="display:flex;"><span>| Row 1    | Row 1    |
</span></span><span style="display:flex;"><span>| Row 2    | Row 2    |
</span></span></code></pre></div><h2 id="escaping-characters">Escaping Characters</h2>
<p>To display characters that have special meaning in Markdown, you can use a backslash (<code>\</code>) before the character to escape it.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>\*This is not italic\*
</span></span></code></pre></div><h2 id="task-lists">Task Lists</h2>
<p>You can create task lists using square brackets (<code>[ ]</code> for incomplete tasks and <code>[x]</code> for completed tasks).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span><span style="color:#66d9ef">- [ ]</span> Task 1
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- [x]</span> Task 2
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- [ ]</span> Task 3
</span></span></code></pre></div><h2 id="strikethrough">Strikethrough</h2>
<p>To strike through text, use two tilde characters (<code>~~</code>).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>~~This text is strikethrough.~~ 
</span></span></code></pre></div><h2 id="footnotes">Footnotes</h2>
<p>Markdown supports footnotes, allowing you to add additional information or references at the bottom of the page.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>Here is some text with a footnote[^1].
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[^1]: This is the footnote content.
</span></span></code></pre></div><h2 id="superscript-and-subscript">Superscript and Subscript</h2>
<p>To create superscript and subscript text, use the caret (<code>^</code>) for superscript and tilde (<code>~</code>) for subscript.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>This is a superscript: X^2^
</span></span><span style="display:flex;"><span>This is a subscript: H~2~O
</span></span></code></pre></div><h2 id="abbreviations">Abbreviations</h2>
<p>Markdown allows you to define abbreviations, which can be useful for providing explanations or definitions.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>The HTML stands for Hypertext Markup Language. [^HTML]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[^HTML]: Hypertext Markup Language
</span></span></code></pre></div><h2 id="raw-html">Raw HTML</h2>
<p>Markdown supports the use of raw HTML code for more advanced formatting options. You can embed HTML elements directly within your Markdown document.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>This is a &lt;<span style="color:#f92672">span</span> <span style="color:#a6e22e">style</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;color: red;&#34;</span>&gt;red&lt;/<span style="color:#f92672">span</span>&gt; text.
</span></span></code></pre></div><h2 id="inline-math-equations">Inline Math Equations</h2>
<p>If you need to include mathematical equations, you can use LaTeX syntax within Markdown to render them.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>The quadratic equation is \(ax^2 + bx + c = 0\).
</span></span></code></pre></div><h2 id="definition-lists">Definition Lists</h2>
<p>Markdown also supports definition lists for glossaries or terms with corresponding explanations.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>Term 1
</span></span><span style="display:flex;"><span>:   This is the definition of Term 1.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Term 2
</span></span><span style="display:flex;"><span>:   This is the definition of Term 2.
</span></span></code></pre></div><h2 id="inline-html">Inline HTML</h2>
<p>Markdown allows you to directly insert HTML code inline within your Markdown document. This can be useful for more complex formatting or embedding multimedia.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>This is an &lt;<span style="color:#f92672">kbd</span>&gt;inline HTML&lt;/<span style="color:#f92672">kbd</span>&gt; example.
</span></span></code></pre></div><h2 id="definition-of-acronyms">Definition of Acronyms</h2>
<p>Similar to abbreviations, Markdown supports the definition of acronyms using the same syntax.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>The HTTP stands for Hypertext Transfer Protocol. [^HTTP]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>[^HTTP]: Hypertext Transfer Protocol
</span></span></code></pre></div><h2 id="emoji">Emoji</h2>
<p>Markdown supports the use of emojis to add visual elements to your text. You can include emojis using emoji codes or Unicode characters. 😃</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>I am feeling 😃 today!
</span></span></code></pre></div><h2 id="automatic-url-linking">Automatic URL Linking</h2>
<p>By default, Markdown automatically converts URLs into clickable links. You don&rsquo;t need to use any specific syntax.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>Visit my website at https://andrewbeaton.net
</span></span></code></pre></div><h2 id="escape-characters">Escape Characters</h2>
<p>If you want to display characters that have a special meaning in Markdown, you can escape them using a backslash (<code>\</code>).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>\*This is not a bullet point\*
</span></span></code></pre></div><hr>
<h2 id="summary">Summary</h2>
<p>This cheat sheet covers the most commonly used Markdown syntax.</p>
<p>Markdown provides a simple and efficient way to format text without getting in the way of your writing.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Setting Up Multi-Factor Authentication (MFA) on Ubuntu 22.04</title>
      <link>https://andrewbeaton.net/posts/2023/06/ubuntu-mfa/</link>
      <pubDate>Sun, 04 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2023/06/ubuntu-mfa/</guid>
      <description>Setting Up Multi-Factor Authentication (MFA) on Ubuntu 22.04</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>These days, securing your systems and data is of great importance.</p>
<p>One powerful security measure is Multi-Factor Authentication (MFA), which adds an extra layer of protection by requiring users to provide additional credentials beyond just a password.</p>
<p>In this post, I will guide you through the process of setting up MFA on Ubuntu 22.04, enhancing the security of your system.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Before we begin, make sure you have the following:</p>
<ul>
<li>A user account with sudo privileges.</li>
<li>Ubuntu 22.04 installed (Not tested on other versions).</li>
<li>An MFA authenticator app, such as Google Authenticator or Authy.</li>
</ul>
<h2 id="step-1-install-the-required-packages">Step 1: Install the Required Packages</h2>
<p>The first step is to install the necessary packages that will enable MFA on your Ubuntu system.</p>
<p>Open a terminal and run the following commands:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo apt update
</span></span><span style="display:flex;"><span>sudo apt install libpam-google-authenticator -y
</span></span></code></pre></div><p>These commands will update your package lists and install the <em>libpam-google-authenticator</em> package, which will be used to generate MFA codes.</p>
<h2 id="step-2-configure-mfa-for-a-user">Step 2: Configure MFA for a User</h2>
<p>Once the package is installed, you can configure MFA for a specific user account.</p>
<p>In the terminal, execute the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>google-authenticator
</span></span></code></pre></div><p>This command will initiate the setup process and present you with a series of questions.</p>
<p>You will be prompted to scan a QR code with an MFA authenticator app, such as Google Authenticator or Authy. Alternatively, you can enter the provided key manually into your authenticator app.</p>
<p>You will be asked if you want to update the <em>.google_authenticator</em> file. Press y and hit Enter to proceed.</p>
<p>You will be asked a series of questions. It is recommended to answer &lsquo;y&rsquo; for all the questions to enable the maximum level of security. These questions include options such as disallowing multiple uses of the same authentication token and enabling rate limiting.</p>
<p>Once you have completed the setup, you will be provided with backup codes.</p>
<p>It is crucial to store these backup codes in a secure location, as they can be used to access your account if you lose access to your MFA device.</p>
<h2 id="step-3-configure-ssh-to-use-mfa">Step 3: Configure SSH to Use MFA</h2>
<p>To enable MFA for SSH logins, you need to configure the SSH daemon to utilise MFA.</p>
<p>Open the SSH configuration file by running the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo nano /etc/pam.d/sshd
</span></span></code></pre></div><p>In the editor, add the following line at the top of the file:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span>auth <span style="color:#66d9ef">required</span> pam_google_authenticator.so
</span></span></code></pre></div><p>Save the changes and exit the editor by pressing Ctrl + X, followed by Y, and then hitting Enter.</p>
<h2 id="step-4-restart-ssh-service">Step 4: Restart SSH Service</h2>
<p>To apply the changes made to the SSH configuration, you need to restart the SSH service.</p>
<p>Run the following command to restart SSH:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo systemctl restart sshd
</span></span></code></pre></div><h2 id="step-5-test-mfa">Step 5: Test MFA</h2>
<p>Now that MFA is set up, it&rsquo;s time to test if it&rsquo;s working as expected.</p>
<p>Open a new terminal window and attempt to SSH into your Ubuntu system using the user account you configured for MFA.</p>
<p>You should be prompted for your MFA verification code after entering your password.</p>
<h2 id="summary">Summary</h2>
<p>You have successfully set up Multi-Factor Authentication (MFA) on your Ubuntu 22.04 system.</p>
<p>By implementing MFA, you have significantly enhanced the security of your system and reduced the risk of unauthorised access.</p>
<p>Remember to keep your backup codes safe in case you need them.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Creating an Ackee Container with Docker Compose</title>
      <link>https://andrewbeaton.net/posts/2023/06/docker-compose-ackee/</link>
      <pubDate>Thu, 01 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2023/06/docker-compose-ackee/</guid>
      <description>Creating an Ackee Container with Docker Compose</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p><a href="https://ackee.electerious.com/">Ackee</a> is a self-hosted, open-source, privacy focused, analytics platform that provides useful insights into your website&rsquo;s traffic.</p>
<p>By running Ackee in a <a href="https://www.docker.com/">Docker</a> container, you can easily deploy and manage it on your own server.</p>
<p>In this guide, I&rsquo;ll talk you through the process of creating an Ackee Docker container and setting it up using <a href="https://docs.docker.com/compose/">Docker Compose</a>.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Before you start, ensure you have the following:</p>
<ul>
<li>
<p>Docker installed on your server.</p>
</li>
<li>
<p>Docker Compose installed on your server.</p>
</li>
<li>
<p>Basic knowledge of working with Docker and Docker Compose.</p>
</li>
</ul>
<h2 id="create-a-docker-compose-file">Create a Docker Compose File</h2>
<p>Open your text editor and create a new file named docker-compose.yml.</p>
<p>In this file, we define the configuration for the Ackee Docker container.</p>
<h2 id="define-the-docker-compose-configuration">Define the Docker Compose Configuration</h2>
<p>Copy and paste the following configuration into your docker-compose.yml file:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">version</span>: <span style="color:#e6db74">&#39;3&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">ackee</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">electerious/ackee</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">container_name</span>: <span style="color:#ae81ff">ackee</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;3000:3000&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">environment</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">WAIT_HOSTS=mongodb:27017</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">DATABASE_URI=mongodb://mongo:27017/ackee</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">depends_on</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">mongo</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">mongo</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">mongo</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">container_name</span>: <span style="color:#ae81ff">mongo</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#39;27017:27017&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">ackee-mongo:/data/db</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">ackee-mongo</span>:
</span></span></code></pre></div><p>This configuration defines two services: ackee and mongo.</p>
<p>The ackee service uses the electerious/ackee Docker image, exposes port 3000, sets the DATABASE_URI environment variable to connect to the MongoDB instance, and depends on the mongo service.</p>
<p>The mongo service uses the mongo Docker image and mounts a volume to persist MongoDB data.</p>
<h2 id="save-the-docker-compose-file">Save the Docker Compose File</h2>
<p>Save the docker-compose.yml file in your desired directory on your server. Make sure you remember the location as we&rsquo;ll use it in the next step.</p>
<h2 id="start-the-ackee-docker-container">Start the Ackee Docker Container</h2>
<p>Open a terminal or command prompt and navigate to the directory where you saved the docker-compose.yml file.</p>
<p>Run the following command to start the Ackee Docker container:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker-compose up -d
</span></span></code></pre></div><p>Docker Compose will download the necessary Docker images and start the Ackee and MongoDB containers in detached mode.</p>
<h2 id="access-ackee-in-your-web-browser">Access Ackee in your Web Browser</h2>
<p>Open your web browser and enter the following URL:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-arduino" data-lang="arduino"><span style="display:flex;"><span>http:<span style="color:#75715e">//localhost:3000
</span></span></span></code></pre></div><p>You should now see the Ackee login page.</p>
<p>Create a new user account and log in to the Ackee dashboard.</p>
<p>You have now successfully created an Ackee Docker container and set it up using Docker Compose. You can now start analyzing your website&rsquo;s traffic using Ackee&rsquo;s powerful analytics features.</p>
<h2 id="additional-configuration-options">Additional Configuration Options</h2>
<p>If you want to use a different port for Ackee, you can modify the ports section in the docker-compose.yml file:</p>
<pre tabindex="0"><code>ports:
    - &#34;3000:3000&#34;
</code></pre><p>To allow your domains to connect to Ackee, you can set the ACKEE_ALLOW_ORIGIN environment variable and list your domains:</p>
<pre tabindex="0"><code>ACKEE_ALLOW_ORIGIN=https://domain1.com,https://domain2.com
</code></pre><p>You can specify your username and password in the docker-compose.yml file with the environment variables:</p>
<pre tabindex="0"><code>- ACKEE_USERNAME=username
- ACKEE_PASSWORD=password 
</code></pre><p>Remember to regularly update the docker-compose.yml file to use the latest version of Ackee and MongoDB images to benefit from the latest features and security patches.</p>
<h2 id="summary">Summary</h2>
<p>With Docker Compose, managing your Ackee deployment becomes seamless, allowing you to focus on gaining valuable insights from your website&rsquo;s analytics data.</p>
<p>If you want to look further in to any of the above tools, do take a look at my previous posts and read the official documentation from the following sites:</p>
<p><a href="https://ackee.electerious.com/">Ackee</a><br>
<a href="https://www.docker.com/">Docker</a>
<a href="https://docs.docker.com/compose/">Docker Compose</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Deploying to Cloudflare Pages with Drone</title>
      <link>https://andrewbeaton.net/posts/2023/05/drone-io-cloudflare-pages-deploy/</link>
      <pubDate>Wed, 31 May 2023 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2023/05/drone-io-cloudflare-pages-deploy/</guid>
      <description>Deploying to Cloudflare Pages with Drone</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Due to some unexpected downtime with my current web host, and a bit of spare time on my hands, I thought I would give a go at configuring Drone to deploy to Cloudflare Pages.</p>
<p>A very basic description of Cloudflare Pages, is that it&rsquo;s a platform that makes it easy to create and host websites whilst Cloudflare takes care of the more technical side of website hosting. For a more technical overview, take a look at the official documentation.</p>
<p>For my use case, as I use Hugo to generate all my static website files, I can just use Cloudflare Pages to host the content. With my domain name already proxying through Cloudflare, everything is now all handled in one place, and so far, it all just works.</p>
<p>So let&rsquo;s cover off what&rsquo;s needed to get Drone to deploy your Hugo (or static files) to Cloudflare Pages.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Before getting started, make sure you have the following prerequisites in place:</p>
<ul>
<li><em><strong>A working Hugo website:</strong></em>
<ul>
<li>Set up a Hugo website.</li>
</ul>
</li>
<li><em><strong>A Git repository:</strong></em>
<ul>
<li>Host your Hugo website&rsquo;s code in a Gitea / Git repository.</li>
</ul>
</li>
<li><em><strong>A working Drone instance:</strong></em>
<ul>
<li>Your Drone instance should be working correctly with your Gitea repository.</li>
</ul>
</li>
<li><em><strong>A Cloudflare account:</strong></em>
<ul>
<li>Your Cloudflare account is running, and you have configured both a new Cloudflare Page and have a Cloudflare Workers API set up.</li>
</ul>
</li>
</ul>
<h2 id="a-drone-build-step-for-cloudflare-pages">A Drone Build Step for Cloudflare Pages</h2>
<p>This guide follows on from my previous post where I walk through setting up a full drone pipeline with Test, Staging and Production builds and deployments. To catch up have a look at <a href="/posts/2023/05/complete-drone-pipeline/">Creating a Full Drone Pipeline with Gitea and Drone</a></p>
<p>The following is a step that will build static content located in /drone/src/<!-- raw HTML omitted -->/. Deploy to a Cloudflare Page defined by <!-- raw HTML omitted -->, and a <a href="https://docs.drone.io/secret/repository/">Drone secret</a> called &lt;CLOUDFLARE_API_TOKEN&gt; containing a <a href="https://developers.cloudflare.com/workers/wrangler/ci-cd/#create-a-cloudflare-api-token">Cloudflare API token</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span>- <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Build Node.js</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">node:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>: 
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">npm install npm@latest -g </span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">mkdir -p dist</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">cp -R /drone/src/&lt;your static files location&gt;/* dist/ </span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Deploy to Cloudflare Pages</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">node:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">environment</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">CLOUDFLARE_API_TOKEN</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">from_secret</span>: <span style="color:#ae81ff">CLOUDFLARE_API_TOKEN</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>: 
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">npm install wrangler --save-dev  </span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">cd /drone/src/dist/</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">npx wrangler pages deploy /drone/src/dist --project-name &#34;&lt;project&gt;&#34; --env production --branch main --commit-dirty=true</span>
</span></span></code></pre></div><p>There are a number of Docker images out there using Wrangler to deploy to Cloudflare. Unfortunately they all seem to use the previous version of the Cloudflare API which will deprecated shortly. So I went down the route of building Wrangler and NodeJS directly.</p>
<p>Do get in touch if you find a more recent Docker image for me to try.</p>
<h2 id="a-drone-pipeline-for-cloudflare-pages">A Drone Pipeline for Cloudflare Pages</h2>
<p>This is a direct copy of my current production build pipeline. This has added debugging information that I find useful whilst making changes.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">pipeline</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">type</span>: <span style="color:#ae81ff">docker</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Production Environment&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">branch</span>: 
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">main </span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">event</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">include</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">push</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>:   
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Clone Git Submodules</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">alpine/git </span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">git submodule init</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">git submodule update --recursive --remote</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Build with Hugo</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">binaryronin/drone-hugo:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pull</span>: <span style="color:#ae81ff">always </span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">echo &#34;Checking Hugo version.&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">hugo version</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">cd /drone/src/hugo/</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">hugo --environment production --verbose --debug </span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">ls -al /drone/src/hugo/public</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Build Node.js</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">node:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">ls -la /drone/src/</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">npm install npm@latest -g</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">pwd</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">mkdir -p dist</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">cp -R /drone/src/hugo/public/* dist/</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">ls -la dist/</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Deploy to Cloudflare Pages</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">node:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">environment</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">CLOUDFLARE_API_TOKEN</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">from_secret</span>: <span style="color:#ae81ff">CLOUDFLARE_API_TOKEN</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">ls -la /drone/src/</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">npm install wrangler --save-dev </span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">npx wrangler --version</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">cd /drone/src/dist/</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">npx wrangler pages deploy /drone/src/dist --project-name &#34;&lt;project-name&gt;&#34; --env production --branch main --commit-message &#34;Drone Production Build&#34; --commit-dirty=true</span>
</span></span></code></pre></div><h2 id="summary">Summary</h2>
<p>Once deployed, a new Deployment will be available for you in your Cloudflare Pages area that can be accessed either by the temporary <a href="https://developers.cloudflare.com/pages/platform/preview-deployments/">preview deployment</a> domain or your <a href="https://developers.cloudflare.com/pages/platform/preview-deployments/#preview-aliases">preview alias</a> project domain.</p>
<p>Once happy you can now set up a <a href="https://developers.cloudflare.com/pages/platform/custom-domains/">custom domain</a> to point to the new Page.</p>
<p>Although a few extra steps than an existing Docker Cloudflare setup, this method does allow you to clearly see what&rsquo;s going on and debug any issues should they happen.</p>
<p>If you want to look further in to any of the above tools, do take a look at my previous posts and read the official documentation from the following sites:</p>
<p><a href="https://developers.cloudflare.com/workers/">Cloudflare Workers</a>
<a href="https://gitea.io/en-us/">Gitea</a>
<a href="https://www.drone.io/">Drone</a>
<a href="https://gohugo.io/">Hugo</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Creating a Full Drone Pipeline with Gitea and Drone</title>
      <link>https://andrewbeaton.net/posts/2023/05/complete-drone-pipeline/</link>
      <pubDate>Mon, 29 May 2023 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2023/05/complete-drone-pipeline/</guid>
      <description>Creating a Full Drone Pipeline with Gitea and Drone</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In my previous posts, I&rsquo;ve covered how to set up Drone, Gitea and deploy a build to an FTP server.
In this post, I&rsquo;ll be covering how to configure a full pipeline to include:</p>
<ul>
<li>A continuous testing build on each commit to the Develop branch.</li>
<li>An automated build to a staging environment on commit to the Main branch.</li>
<li>A manual deployment to a production environment using the Promote function in Drone.</li>
</ul>
<p><img loading="lazy" src="/Gitea-Drone-Workflow.png" alt="Gitea Drone Setup"  />
</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Before getting started, make sure you have the following prerequisites in place:</p>
<ul>
<li><em><strong>A working Hugo website:</strong></em>
<ul>
<li>Set up a Hugo website locally.</li>
</ul>
</li>
<li><em><strong>A Git repository:</strong></em>
<ul>
<li>Host your Hugo website&rsquo;s code in a Gitea repository.</li>
</ul>
</li>
<li><em><strong>A working Drone instance:</strong></em>
<ul>
<li>Your Drone instance should be working correctly with your Gitea repository.</li>
</ul>
</li>
<li><em><strong>An FTP server</strong></em>
<ul>
<li>An FTP server configured with username and password, a valid user home directory and web content loaded from that location.</li>
</ul>
</li>
</ul>
<h2 id="what-is-a-drone-pipeline">What is a Drone Pipeline?</h2>
<p>In Drone, a pipeline refers to a sequence of steps and actions that are executed in a predefined order to build, test, and deploy software. It provides a structured and automated workflow for managing the different stages of the development process.</p>
<p>A pipeline in Drone is typically defined using a configuration file named &lsquo;.drone.yml&rsquo;. This file specifies the steps to be executed, the order in which they should run, and any required configurations or dependencies.</p>
<p>Here are the key components and concepts associated with a pipeline in Drone:</p>
<ul>
<li>
<p><em><strong>Stages:</strong></em><br>
A pipeline is divided into stages, which represent different phases of the software development lifecycle. Common stages include building, testing, and deploying. Each stage contains one or more steps that define the actions to be performed.</p>
</li>
<li>
<p><em><strong>Steps:</strong></em><br>
Steps are the individual units of work within a stage. They represent specific actions to be executed, such as running a command, running tests, or deploying the application. Steps can be executed sequentially or in parallel, depending on the requirements.</p>
</li>
<li>
<p><em><strong>Dependencies:</strong></em><br>
A step in a pipeline may have dependencies on previous steps. This allows for the establishment of a logical flow, where certain steps must be completed successfully before proceeding to the next ones. Dependencies ensure that the pipeline runs in a consistent and controlled manner.</p>
</li>
<li>
<p><em><strong>Conditions:</strong></em><br>
Conditions are used to control the execution of steps based on specific criteria. For example, a step may only run if a certain condition is met, such as the branch name, the outcome of a previous step, or the presence of a specific environment variable. Conditions provide flexibility and allow for conditional execution based on the project&rsquo;s needs.</p>
</li>
<li>
<p><em><strong>Artifacts:</strong></em><br>
Artifacts are files or directories generated during the pipeline execution that can be passed between steps or stored for later use. They allow for sharing data, test reports, build artifacts, or any other relevant files between different stages of the pipeline.</p>
</li>
<li>
<p><em><strong>Triggers:</strong></em><br>
Triggers determine when the pipeline should run. They can be defined to automatically start the pipeline on specific events, such as code pushes, pull requests, or scheduled intervals. Triggers ensure that the pipeline is executed whenever a relevant change occurs, maintaining an up-to-date and automated development process.</p>
</li>
</ul>
<h2 id="development-build">Development Build</h2>
<p>In my current setup, every commit to the Develop branch is picked up by Drone and creates a build.
This build pulls the develop branch from the Gitea repository, installs the Hugo modules and builds the Hugo website in development mode.</p>
<p>I have also set this to fail on any warnings, so that I can quickly see if there are any problems with my code.</p>
<p>This step is where I would run any tests on the output code and fail the build should any fail. More to come on that in future posts.</p>
<p>The specific steps for this in the drone.yaml file are:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">pipeline</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">type</span>: <span style="color:#ae81ff">docker</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#e6db74">&#34;Test Environment&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">branch</span>: 
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">develop </span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">event</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">include</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">push</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>:   
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Clone Git Submodules</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">alpine/git </span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">git submodule init</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">git submodule update --recursive --remote</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Build with Hugo</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">binaryronin/drone-hugo:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pull</span>: <span style="color:#ae81ff">always </span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">echo &#34;Checking Hugo version.&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">hugo version</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">cd /drone/src/hugo/</span>
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Disable panicOnWarning due to bug in Hugo.</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">hugo --environment development --verbose --debug</span> <span style="color:#75715e"># --panicOnWarning</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">ls -al /drone/src/hugo/public</span>
</span></span></code></pre></div><p>As you can see, every push to the &lsquo;develop&rsquo; branch will trigger the following steps.
I have this configured to also show debug and more verbose information to help with investigating any problems.
You&rsquo;ll see I also specify the development environment in Hugo, this is to prevent items such as Google Analytics from running in a test setup.</p>
<h2 id="staging-build">Staging Build</h2>
<p>My staging build is run when a commit is made to the main branch. A nice approach would be to lock down the main branch so that no commits can be made directly to it. Any merges from the develop branch must come via a pull request. A tad overkill for a home setup, but it&rsquo;s good practice.</p>
<p>This build will do the same as the Test build, but also includes a step to deploy to my staging web server.</p>
<pre tabindex="0"><code>---
kind: pipeline
type: docker
name: &#34;Staging Environment&#34;

trigger:
  branch:
    - main
  event:
    include: 
      - push

steps:
  - name: Clone Git Submodules
    image: alpine/git
    commands:
      - git submodule init
      - git submodule update --recursive --remote

  - name: Build with Hugo
    image: binaryronin/drone-hugo:latest
    pull: always 
    commands:
      - echo &#34;Checking Hugo version.&#34;
      - hugo version
      - cd /drone/src/hugo/
      - hugo --environment develop --verbose
      - ls -al /drone/src/hugo/public

  - name: Deploy to Staging FTP
    image: cschlosser/drone-ftps
    environment:
        FTP_USERNAME:
          from_secret: staging_ftp_username
        FTP_PASSWORD:
          from_secret: staging_ftp_password 
        PLUGIN_SECURE: true
        PLUGIN_VERIFY: true
        PLUGIN_HOSTNAME:
          from_secret: staging_ftp_hostname
        PLUGIN_SRC_DIR: /hugo/public/
        PLUGIN_DEST_DIR: 
          from_secret: staging_ftp_directory
        PLUGIN_AUTO_CONFIRM: true
        PLUGIN_DEBUG: true 
        PLUGIN_ONLY_NEWER: true
</code></pre><p>You can see that I specify the environment for Hugo, as development. And this time, take advantage of Drone secrets for the Staging server details and credentials.</p>
<h2 id="production-build">Production Build</h2>
<p>Now the production build is slightly different, in that it can only be run through Drone by promoting an existing successful Staging build.</p>
<pre tabindex="0"><code>---
kind: pipeline
type: docker
name: &#34;Production Environment&#34;

trigger:
  target: 
    - production

steps:
  - name: Clone Git Submodules
    image: alpine/git
    commands:
      - git submodule init
      - git submodule update --recursive --remote

  - name: Build with Hugo
    image: binaryronin/drone-hugo:latest
    pull: always 
    commands:
      - echo &#34;Checking Hugo version.&#34;
      - hugo version
      - cd /drone/src/hugo/
      - hugo --environment production --verbose
      - ls -al /drone/src/hugo/public

  - name: Deploy to Production FTP
    image: cschlosser/drone-ftps
    environment:
        FTP_USERNAME:
          from_secret: production_ftp_username
        FTP_PASSWORD:
          from_secret: production_ftp_password 
        PLUGIN_SECURE: true
        PLUGIN_VERIFY: true
        PLUGIN_HOSTNAME:
          from_secret: production_ftp_hostname
        PLUGIN_SRC_DIR: /hugo/public/
        PLUGIN_DEST_DIR: 
          from_secret: production_ftp_directory
        PLUGIN_AUTO_CONFIRM: true
        PLUGIN_DEBUG: true 
        PLUGIN_ONLY_NEWER: true
</code></pre><p>Here you&rsquo;ll see that we change the environment for Hugo to be production and use Drone secrets again to specify the Production details and credentials.</p>
<h2 id="complete-drone-configuration">Complete Drone Configuration</h2>
<p>Putting all of these steps together, the complete config.yml file looks like this:</p>
<pre tabindex="0"><code>---
kind: pipeline
type: docker
name: &#34;Test Environment&#34;

trigger:
  branch: 
    - develop 
  event:
    include:
      - push

steps:   
  - name: Clone Git Submodules
    image: alpine/git 
    commands:
      - git submodule init
      - git submodule update --recursive --remote

  - name: Build with Hugo
    image: binaryronin/drone-hugo:latest
    pull: always 
    commands:
      - echo &#34;Checking Hugo version.&#34;
      - hugo version
      - cd /drone/src/hugo/
      # Disable panicOnWarning due to bug in Hugo.
      - hugo --environment development --verbose --debug # --panicOnWarning
      - ls -al /drone/src/hugo/public

---
kind: pipeline
type: docker
name: &#34;Staging Environment&#34;

trigger:
  branch:
    - main
  event:
    include: 
      - push

steps:
  - name: Clone Git Submodules
    image: alpine/git
    commands:
      - git submodule init
      - git submodule update --recursive --remote

  - name: Build with Hugo
    image: binaryronin/drone-hugo:latest
    pull: always 
    commands:
      - echo &#34;Checking Hugo version.&#34;
      - hugo version
      - cd /drone/src/hugo/
      - hugo --environment development --verbose
      - ls -al /drone/src/hugo/public

  - name: Deploy to Staging FTP
    image: cschlosser/drone-ftps
    environment:
        FTP_USERNAME:
          from_secret: staging_ftp_username
        FTP_PASSWORD:
          from_secret: staging_ftp_password 
        PLUGIN_SECURE: true
        PLUGIN_VERIFY: true
        PLUGIN_HOSTNAME:
          from_secret: staging_ftp_hostname
        PLUGIN_SRC_DIR: /hugo/public/
        PLUGIN_DEST_DIR: 
          from_secret: staging_ftp_directory
        PLUGIN_AUTO_CONFIRM: true
        PLUGIN_DEBUG: true 
        PLUGIN_ONLY_NEWER: true

---
kind: pipeline
type: docker
name: &#34;Production Environment&#34;

trigger:
  target: 
    - production

steps:
  - name: Clone Git Submodules
    image: alpine/git
    commands:
      - git submodule init
      - git submodule update --recursive --remote

  - name: Build with Hugo
    image: binaryronin/drone-hugo:latest
    pull: always 
    commands:
      - echo &#34;Checking Hugo version.&#34;
      - hugo version
      - cd /drone/src/hugo/
      - hugo --environment production --verbose
      - ls -al /drone/src/hugo/public

  - name: Deploy to Production FTP
    image: cschlosser/drone-ftps
    environment:
        FTP_USERNAME:
          from_secret: production_ftp_username
        FTP_PASSWORD:
          from_secret: production_ftp_password 
        PLUGIN_SECURE: true
        PLUGIN_VERIFY: true
        PLUGIN_HOSTNAME:
          from_secret: production_ftp_hostname
        PLUGIN_SRC_DIR: /hugo/public/
        PLUGIN_DEST_DIR: 
          from_secret: production_ftp_directory
        PLUGIN_AUTO_CONFIRM: true
        PLUGIN_DEBUG: true 
        PLUGIN_ONLY_NEWER: true
</code></pre><h2 id="summary">Summary</h2>
<p>With the above setup, you can see how easily a full work flow can be configured in Drone that will enable automatic and continuous builds and deployments. Hopefully saving you some time in the future and catching any problems well before they reach the production environment.</p>
<p>I&rsquo;ll continue documenting my journey with Gitea, Drone and Hugo and share the interesting things I find along the way.</p>
<p>If you want to look further in to any of the above tools, do take a look at my previous posts and read the official documentation from the following sites:</p>
<p><a href="https://gitea.io/en-us/">Gitea</a>
<a href="https://www.drone.io/">Drone</a>
<a href="https://gohugo.io/">Hugo</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Deploy to an FTP server with Drone</title>
      <link>https://andrewbeaton.net/posts/2023/05/drone-io-ftp-deploy/</link>
      <pubDate>Mon, 29 May 2023 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2023/05/drone-io-ftp-deploy/</guid>
      <description>Deploy to an FTP server with Drone</description>
      <content:encoded><![CDATA[<p>In the previous posts, I covered how to set up Drone IO with either GitHub or Gitea, and deploy them to a server using SCP. This short post will cover how to set up Drone to deploy to an FTP server.</p>
<p>This is the setup that I&rsquo;m using for both my staging website and my production one (This one!).</p>
<p>Hugo does come with a built-in server for viewing your site locally but having a staging site gives me more confidence that everything will work correctly when deployed to my main website, especially as the whole process is automated.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Before getting started, make sure you have the following prerequisites in place:</p>
<ul>
<li><em><strong>A working Hugo website:</strong></em>
<ul>
<li>Set up a Hugo website locally.</li>
</ul>
</li>
<li><em><strong>A Git repository:</strong></em>
<ul>
<li>Host your Hugo website&rsquo;s code in a Git repository.</li>
</ul>
</li>
<li><em><strong>An FTP server</strong></em>
<ul>
<li>An FTP server configured with username and password, a valid user home directory and web content loaded from that location.</li>
</ul>
</li>
</ul>
<h2 id="step-1-configure-the-droneio-pipeline">Step 1: Configure the Drone.io Pipeline</h2>
<ol>
<li>In your websites Git repository, create a <code>.drone.yml</code> file in the root directory.</li>
<li>Add the following code to the <code>.drone.yml</code> file:</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">pipeline</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">your-pipeline-name</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Clone Git Submodules</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">alpine/git</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">git submodule init</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">git submodule update --recursive --remote</span>
</span></span><span style="display:flex;"><span>      
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Build with Hugo</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">binaryronin/drone-hugo:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pull</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">echo &#34;Checking Hugo version.&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">hugo version</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">cd /drone/src/hugo/</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">hugo --verbose </span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">ls -al /drone/src/hugo/public </span>
</span></span><span style="display:flex;"><span>      
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Deploy to FTP server</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">cschlosser/drone-ftps</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">environment</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">FTP_USERNAME</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">from_secret</span>: <span style="color:#ae81ff">ftp_username</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">FTP_PASSWORD</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">from_secret</span>: <span style="color:#ae81ff">ftp_password </span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">PLUGIN_SECURE</span>: <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">PLUGIN_VERIFY</span>: <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">PLUGIN_HOSTNAME</span>: <span style="color:#ae81ff">ftp://host:21</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">PLUGIN_SRC_DIR</span>: <span style="color:#ae81ff">/hugo/public/</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">PLUGIN_DEST_DIR</span>: <span style="color:#ae81ff">/home/ftp_username</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">PLUGIN_AUTO_CONFIRM</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">PLUGIN_DEBUG</span>: <span style="color:#66d9ef">true</span> 
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">PLUGIN_ONLY_NEWER</span>: <span style="color:#66d9ef">true</span>
</span></span></code></pre></div><p>Replace <code>your-pipeline-name</code> with a suitable name for your pipeline.</p>
<ol start="3">
<li>
<p>Adjust the <code>PLUGIN_HOSTNAME</code> and <code>PLUGIN_DEST_DIR</code> fields to match your remote server details and deployment directory.</p>
</li>
<li>
<p>Add secret for your remote server&rsquo;s username and password by going to your Drone.io repository settings and adding secrets with the keys <code>ftp_username</code>, <code>ftp_password</code> and the corresponding values.</p>
</li>
</ol>
<h2 id="step-2-trigger-the-pipeline">Step 2: Trigger the Pipeline</h2>
<ol>
<li>Push your updated <code>.drone.yml</code> file to your Git repository.</li>
<li>This will trigger the Drone.io pipeline to run.</li>
<li>Monitor the build process in the Drone.io interface to ensure everything is working correctly.</li>
<li>Once the pipeline completes successfully, your Hugo website will be deployed to the specified remote server.</li>
</ol>
<p>You have successfully set up Drone with an FTP server. Now, whenever you push changes to your Git repository, Drone.io will automatically build your Hugo website and deploy it to your remote FTP server.</p>
<p>I&rsquo;ll continue documenting my journey with Gitea, Drone and Hugo and share the interesting things I find along the way.</p>
<p>If you want to look further in to any of the above tools, do take a look at my previous posts and read the official documentation from the following sites:</p>
<p><a href="https://gitea.io/en-us/">Gitea</a>
<a href="https://www.drone.io/">Drone</a>
<a href="https://gohugo.io/">Hugo</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Set up Hugo with Drone and Gitea</title>
      <link>https://andrewbeaton.net/posts/2023/05/hugo-drone-io-gitea/</link>
      <pubDate>Sat, 20 May 2023 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2023/05/hugo-drone-io-gitea/</guid>
      <description>Set up Hugo with Drone and Gitea</description>
      <content:encoded><![CDATA[<p>If you prefer running your own local instances of Drone.io and Gitea using Docker containers, you can still automate your Hugo website deployment seamlessly.</p>
<p>In this guide, I&rsquo;ll walk you through the process of setting up Hugo with a local Drone.io instance and a local Gitea server, allowing you to automate your website deployment workflow in a self-hosted environment.</p>
<p>I used this setup initially, before changing the Drone deployment to upload through FTP to my local staging web server. If you&rsquo;re interested in this setup, you can find the details in the guide <a href="/posts/2023/05/drone-io-ftp-deploy/">Deploy to an FTP server with Drone</a>.</p>
<h2 id="note">Note</h2>
<p>The instructions below cover the setup and running of the Docker instances locally. If you are setting this up in your home lab, then just change the references from local to the details of your servers.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Before getting started, make sure you have the following prerequisites in place:</p>
<ul>
<li><strong>Docker installed:</strong>
<ul>
<li>Make sure you have Docker installed on your local machine or remote server.</li>
</ul>
</li>
<li><strong>Basic knowledge of Docker:</strong>
<ul>
<li>Familiarity with Docker and Docker Compose will be helpful.</li>
</ul>
</li>
<li><strong>A working Hugo website:</strong>
<ul>
<li>Set up a Hugo website locally.</li>
</ul>
</li>
</ul>
<h2 id="step-1-set-up-gitea">Step 1: Set up Gitea</h2>
<ol>
<li>Create a new directory on your machine for the Gitea Docker configuration.</li>
<li>Create a <code>docker-compose.yml</code> file within that directory and add the following content:</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">version</span>: <span style="color:#e6db74">&#39;3&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">gitea</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">gitea/gitea:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;3000:3000&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;2222:22&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./gitea-data:/data</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span></code></pre></div><ol start="3">
<li>Save the file and navigate to the Gitea Docker configuration directory in your terminal.</li>
<li>Run the command <code>docker-compose up -d</code> to start the Gitea container.</li>
</ol>
<p>Gitea should now be accessible at <a href="http://localhost:3000">http://localhost:3000</a>. Follow the on-screen instructions to set up an admin account and create a new repository for your Hugo website.</p>
<h2 id="step-2-set-up-droneio">Step 2: Set up Drone.io</h2>
<ol>
<li>Create a new directory on your machine for the Drone.io Docker configuration.</li>
<li>Create a <code>docker-compose.yml</code> file within that directory and add the following content:</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">version</span>: <span style="color:#e6db74">&#39;3&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">drone-server</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">drone/drone:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;8080:80&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./drone-data:/data</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">environment</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">DRONE_GITEA_SERVER=http://gitea:3000</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">DRONE_GITEA_CLIENT_ID=your-gitea-client-id</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">DRONE_GITEA_CLIENT_SECRET=your-gitea-client-secret</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">drone-runner</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">drone/drone-runner-docker:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">/var/run/docker.sock:/var/run/docker.sock</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span></code></pre></div><ol start="3">
<li>
<p>Save the file and navigate to the Drone.io Docker configuration directory in your terminal.</p>
</li>
<li>
<p>Replace <code>your-gitea-client-id</code> and <code>your-gitea-client-secret</code> with the appropriate values. These can be obtained by registering a new OAuth application within Gitea&rsquo;s settings.</p>
</li>
<li>
<p>Run the command <code>docker-compose up -d</code> to start the Drone.io containers.</p>
</li>
</ol>
<p>Drone.io should now be accessible at <a href="http://localhost:8080">http://localhost:8080</a>. Sign in with your Gitea credentials and authorise Drone.io to access your Gitea repositories.</p>
<h2 id="step-3-configure-the-droneio-pipeline">Step 3: Configure the Drone.io Pipeline</h2>
<ol>
<li>Within your Hugo website&rsquo;s repository, create a <code>.drone.yml</code> file in the root directory.</li>
<li>Add the following code to the <code>.drone.yml</code> file:</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">pipeline</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">your-pipeline-name</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: 
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Clone Git Submodules</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">alpine/git</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">git submodule init</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">git submodule update --recursive --remote</span>
</span></span><span style="display:flex;"><span>      
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Build with Hugo</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">binaryronin/drone-hugo:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pull</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">echo &#34;Checking Hugo version.&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">hugo version</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">cd /drone/src/hugo/</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">hugo --verbose </span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">ls -al /drone/src/hugo/public</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Deploy</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">appleboy</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">deploy</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">appleboy/drone-scp</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">settings</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">host</span>: <span style="color:#ae81ff">your-remote-host</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">username</span>: <span style="color:#ae81ff">your-remote-username</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">password</span>: <span style="color:#ae81ff">your-remote-password</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">source</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#ae81ff">/hugo/public/</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">target</span>: <span style="color:#ae81ff">/path/to/your/remote/directory</span>
</span></span></code></pre></div><p>Replace <code>your-pipeline-name</code> with a suitable name for your pipeline.</p>
<ol start="3">
<li>Adjust the <code>host</code>, <code>username</code>, <code>password</code>, and <code>target</code> fields to match your remote server details and deployment directory.</li>
</ol>
<h2 id="step-4-trigger-the-pipeline">Step 4: Trigger the Pipeline</h2>
<ol>
<li>Push your updated <code>.drone.yml</code> file to your Gitea repository.</li>
<li>This will trigger the Drone.io pipeline to run.</li>
<li>Monitor the build process in the Drone.io interface to ensure everything is working correctly.</li>
<li>Once the pipeline completes successfully, your Hugo website will be deployed to the specified remote server.</li>
</ol>
<p>You have successfully set up Hugo with a local Drone.io instance and a local Gitea server. Now, whenever you push changes to your Gitea repository, Drone.io will automatically build your Hugo website and deploy it to your remote server.</p>
<p>I&rsquo;ll continue documenting my journey with Gitea, Drone and Hugo and share the interesting things I find along the way.</p>
<p>If you want to look further in to any of the above tools, do take a look at my previous posts and read the official documentation from the following sites:</p>
<p><a href="https://gitea.io/en-us/">Gitea</a>
<a href="https://www.drone.io/">Drone</a>
<a href="https://gohugo.io/">Hugo</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Set up Hugo with Drone and GitHub</title>
      <link>https://andrewbeaton.net/posts/2023/05/hugo-drone-io-github/</link>
      <pubDate>Sat, 20 May 2023 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2023/05/hugo-drone-io-github/</guid>
      <description>Set up Hugo with Drone and GitHub</description>
      <content:encoded><![CDATA[<p>If you&rsquo;re looking for an efficient way to automate your Hugo website deployment, using a Docker Drone.io container as your continuous integration and delivery (CI/CD) platform can be a great choice.</p>
<p>In this guide, I&rsquo;ll walk you through the process of setting up Hugo with a Docker Drone.io container and GitHub, allowing you to streamline your website deployment workflow.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Before getting started, make sure you have the following prerequisites in place:</p>
<ul>
<li><em><strong>Docker installed:</strong></em>
<ul>
<li>Ensure you have Docker installed on your local machine.</li>
</ul>
</li>
<li><em><strong>Basic knowledge of Docker:</strong></em>
<ul>
<li>Familiarity with Docker and Docker Compose will be helpful.</li>
</ul>
</li>
<li><em><strong>A working Hugo website:</strong></em>
<ul>
<li>Set up a Hugo website locally.</li>
</ul>
</li>
<li><em><strong>A GitHub repository:</strong></em>
<ul>
<li>Host your Hugo website&rsquo;s code in a GitHub repository.</li>
</ul>
</li>
</ul>
<h2 id="step-1-set-up-a-docker-droneio-container">Step 1: Set Up a Docker Drone.io Container</h2>
<ol>
<li>Create a new directory on your machine for the Docker Drone.io container configuration.</li>
<li>Create a <code>docker-compose.yml</code> file within that directory and add the following content:</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">version</span>: <span style="color:#e6db74">&#39;3&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">drone-server</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">drone/drone:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;8080:80&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./drone-data:/data</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">environment</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">DRONE_GITHUB_CLIENT_ID=your-github-client-id</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">DRONE_GITHUB_CLIENT_SECRET=your-github-client-secret</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">drone-runner</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">drone/drone-runner-docker:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">/var/run/docker.sock:/var/run/docker.sock</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span></code></pre></div><ol start="3">
<li>
<p>Save the file and navigate to the Docker Drone.io container configuration directory in your terminal.</p>
</li>
<li>
<p>Replace <code>your-github-client-id</code> and <code>your-github-client-secret</code> with the appropriate values. These can be obtained by registering a new OAuth application within GitHub&rsquo;s settings.</p>
</li>
<li>
<p>Run the command <code>docker-compose up -d</code> to start the Docker Drone.io container.</p>
</li>
</ol>
<p>Drone.io should now be accessible at <a href="http://localhost:8080">http://localhost:8080</a>.</p>
<h2 id="step-2-connect-droneio-to-github">Step 2: Connect Drone.io to GitHub</h2>
<ol>
<li>Open Drone.io in your web browser at <a href="http://localhost:8080">http://localhost:8080</a>.</li>
<li>Sign in with your GitHub credentials.</li>
<li>Authorise Drone.io to access your GitHub repositories.</li>
</ol>
<h2 id="step-3-configure-the-droneio-pipeline">Step 3: Configure the Drone.io Pipeline</h2>
<ol>
<li>Within your Hugo website&rsquo;s GitHub repository, create a <code>.drone.yml</code> file in the root directory.</li>
<li>Add the following code to the <code>.drone.yml</code> file:</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">pipeline</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">your-pipeline-name</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Clone Git Submodules</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">alpine/git</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">git submodule init</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">git submodule update --recursive --remote</span>
</span></span><span style="display:flex;"><span>      
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Build with Hugo</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">binaryronin/drone-hugo:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">pull</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">commands</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">echo &#34;Checking Hugo version.&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">hugo version</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">cd /drone/src/hugo/</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">hugo --verbose </span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">ls -al /drone/src/hugo/public </span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Deploy</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">appleboy/drone-scp</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">settings</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">host</span>: <span style="color:#ae81ff">your-remote-host</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">username</span>: <span style="color:#ae81ff">your-remote-username</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">password</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">from_secret</span>: <span style="color:#ae81ff">your-remote-password-secret</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">source</span>: 
</span></span><span style="display:flex;"><span>        - <span style="color:#ae81ff">/hugo/public/</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">target</span>: <span style="color:#ae81ff">/path/to/your/remote/directory</span>
</span></span></code></pre></div><p>Replace <code>your-pipeline-name</code> with a suitable name for your pipeline.</p>
<ol start="3">
<li>
<p>Adjust the <code>host</code>, <code>username</code>, <code>password</code>, and <code>target</code> fields to match your remote server details and deployment directory.</p>
</li>
<li>
<p>Add a secret for your remote server&rsquo;s password by going to your Drone.io repository settings and adding a secret with the key <code>your-remote-password-secret</code> and the corresponding value.</p>
</li>
</ol>
<h2 id="step-4-trigger-the-pipeline">Step 4: Trigger the Pipeline</h2>
<ol>
<li>Push your updated <code>.drone.yml</code> file to your GitHub repository.</li>
<li>This will trigger the Drone.io pipeline to run.</li>
<li>Monitor the build process in the Drone.io interface to ensure everything is working correctly.</li>
<li>Once the pipeline completes successfully, your Hugo website will be deployed to the specified remote server.</li>
</ol>
<p>You have successfully set up Hugo with a Docker Drone.io container and GitHub. Now, whenever you push changes to your GitHub repository, Drone.io will automatically build your Hugo website and deploy it to your remote server.</p>
<p>I&rsquo;ll continue documenting my journey with Gitea, Drone and Hugo and share the interesting things I find along the way.</p>
<p>If you want to look further in to any of the above tools, do take a look at my previous posts and read the official documentation from the following sites:</p>
<p><a href="https://gitea.io/en-us/">Gitea</a>
<a href="https://www.drone.io/">Drone</a>
<a href="https://gohugo.io/">Hugo</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Using Terraform to create an LXC on Proxmox</title>
      <link>https://andrewbeaton.net/posts/2020/02/using-terraform-to-create-lxc-on-proxmox/</link>
      <pubDate>Tue, 18 Feb 2020 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2020/02/using-terraform-to-create-lxc-on-proxmox/</guid>
      <description>Using Terraform to create an LXC on Proxmox</description>
      <content:encoded><![CDATA[<p>I’ve been looking at automating as much of my home lab that’s running on <a href="https://www.proxmox.com/en/">Proxmox</a>  as possible, not only to get things up and running quickly should a failure happen but also to keep my skills current with the various automation tools out there at the moment.</p>
<p>From my previous posts, you can see that I use <a href="https://www.ansible.com/">Ansible</a> a fair bit for my personal projects, but at work, being a C# developer and working for an organisation that is predominantly Microsoft based, we use <a href="https://www.terraform.io/">Terraform</a> by HashiCorp for infrastructure automation.</p>
<p>I’ve been keeping a close eye on a project by Telmate on Github. They have been working on the <a href="https://github.com/Telmate/terraform-provider-proxmox">Terraform Proxmox Provider</a> and a few days ago a commit was made to allow the creation of <a href="https://en.wikipedia.org/wiki/LXC">Linux Containers (LXC)</a> in Proxmox as opposed to just the creation of Virtual Machines (VMs), so I was keen to give it a go.</p>
<h2 id="requirements">Requirements</h2>
<p>I’m using macOS Catalina as my development machine, so the instructions will be based on this platform, but the tools will be the same and installation may differ.</p>
<h4 id="go">Go</h4>
<p>Download and install Go from <a href="https://golang.org/dl/">Go’s website</a>. Or by a direct link to <a href="https://golang.org/doc/install?download=go1.13.3.darwin-amd64.pkg">MacOS Go 1.13.3</a></p>
<h4 id="terraform-provider-and-provisioner">Terraform Provider and Provisioner</h4>
<p>Using Go, get the latest Terraform provider and provisioner for Proxmox.</p>
<p>These instructions differ slightly from those on the <a href="https://github.com/Telmate/terraform-provider-proxmox">Terraform Proxmox Provider</a> Github page, but they are what worked for me.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Go" data-lang="Go"><span style="display:flex;"><span><span style="color:#66d9ef">go</span> <span style="color:#a6e22e">get</span> <span style="color:#a6e22e">github</span>.<span style="color:#a6e22e">com</span><span style="color:#f92672">/</span><span style="color:#a6e22e">Telmate</span><span style="color:#f92672">/</span><span style="color:#a6e22e">terraform</span><span style="color:#f92672">-</span><span style="color:#a6e22e">provider</span><span style="color:#f92672">-</span><span style="color:#a6e22e">proxmox</span><span style="color:#f92672">/</span><span style="color:#a6e22e">cmd</span><span style="color:#f92672">/</span><span style="color:#a6e22e">terraform</span><span style="color:#f92672">-</span><span style="color:#a6e22e">provider</span><span style="color:#f92672">-</span><span style="color:#a6e22e">proxmox</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">go</span> <span style="color:#a6e22e">install</span> <span style="color:#a6e22e">github</span>.<span style="color:#a6e22e">com</span><span style="color:#f92672">/</span><span style="color:#a6e22e">Telmate</span><span style="color:#f92672">/</span><span style="color:#a6e22e">terraform</span><span style="color:#f92672">-</span><span style="color:#a6e22e">provider</span><span style="color:#f92672">-</span><span style="color:#a6e22e">proxmox</span><span style="color:#f92672">/</span><span style="color:#a6e22e">cmd</span><span style="color:#f92672">/</span><span style="color:#a6e22e">terraform</span><span style="color:#f92672">-</span><span style="color:#a6e22e">provider</span><span style="color:#f92672">-</span><span style="color:#a6e22e">proxmox</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">go</span> <span style="color:#a6e22e">get</span> <span style="color:#a6e22e">github</span>.<span style="color:#a6e22e">com</span><span style="color:#f92672">/</span><span style="color:#a6e22e">Telmate</span><span style="color:#f92672">/</span><span style="color:#a6e22e">terraform</span><span style="color:#f92672">-</span><span style="color:#a6e22e">provider</span><span style="color:#f92672">-</span><span style="color:#a6e22e">proxmox</span><span style="color:#f92672">/</span><span style="color:#a6e22e">cmd</span><span style="color:#f92672">/</span><span style="color:#a6e22e">terraform</span><span style="color:#f92672">-</span><span style="color:#a6e22e">provisioner</span><span style="color:#f92672">-</span><span style="color:#a6e22e">proxmox</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">go</span> <span style="color:#a6e22e">install</span> <span style="color:#a6e22e">github</span>.<span style="color:#a6e22e">com</span><span style="color:#f92672">/</span><span style="color:#a6e22e">Telmate</span><span style="color:#f92672">/</span><span style="color:#a6e22e">terraform</span><span style="color:#f92672">-</span><span style="color:#a6e22e">provider</span><span style="color:#f92672">-</span><span style="color:#a6e22e">proxmox</span><span style="color:#f92672">/</span><span style="color:#a6e22e">cmd</span><span style="color:#f92672">/</span><span style="color:#a6e22e">terraform</span><span style="color:#f92672">-</span><span style="color:#a6e22e">provisioner</span><span style="color:#f92672">-</span><span style="color:#a6e22e">proxmox</span>
</span></span></code></pre></div><p>Copy them to the correct locations:</p>
<pre tabindex="0"><code>which terraform-provider-proxmox
~/go-workspace/bin/terraform-provider-proxmox
which terraform-provisioner-proxmox
~/go-workspace/bin/terraform-provisioner-proxmox 

cd ~/.terraform.d
mkdir plugins
cd plugins
cp ~/go-workspace/bin/terraform-provider-proxmox .
cp ~/go-workspace/bin/terraform-provisioner-proxmox .
</code></pre><h4 id="example-of-container-creation">Example of container creation</h4>
<p>Using the example below, after updating your own values, a new container will be created, ready to be started.</p>
<p>I found it simple enough to create a new container using the Proxmox GUI and comparing the values with the resources in the example below and a little trial and error.</p>
<p>For a list of all the resources available that you can set, it’s worth having a read through of the <a href="https://github.com/Telmate/terraform-provider-proxmox/blob/master/proxmox/resource_lxc.go">resource_lxc.go</a> code on Github.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>provider <span style="color:#e6db74">&#34;proxmox&#34;</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    pm_tls_insecure <span style="color:#f92672">=</span> true
</span></span><span style="display:flex;"><span>    pm_api_url <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;https://proxmox.home.lan:8006/api2/json&#34;</span>
</span></span><span style="display:flex;"><span>    pm_user <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;terraform@pam&#34;</span>
</span></span><span style="display:flex;"><span>    pm_password <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;&lt;secure password&gt;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>resource <span style="color:#e6db74">&#34;proxmox_lxc&#34;</span> <span style="color:#e6db74">&#34;lxc-test&#34;</span> <span style="color:#f92672">{</span> 
</span></span><span style="display:flex;"><span>    hostname <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;lxc-test-host&#34;</span>
</span></span><span style="display:flex;"><span>    cores <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>    memory <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;1024&#34;</span>
</span></span><span style="display:flex;"><span>    swap <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;2048&#34;</span>
</span></span><span style="display:flex;"><span>    network <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;eth0&#34;</span>
</span></span><span style="display:flex;"><span>        bridge <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;vmbr0&#34;</span>
</span></span><span style="display:flex;"><span>        ip <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;192.168.1.69/24&#34;</span>  
</span></span><span style="display:flex;"><span>        firewall <span style="color:#f92672">=</span> true
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    ostemplate <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;local:vztmpl/ubuntu-18.04-custom.tar.gz&#34;</span> 
</span></span><span style="display:flex;"><span>    password <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;&lt;secure password&gt;&#34;</span>
</span></span><span style="display:flex;"><span>    pool <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;terraform&#34;</span>
</span></span><span style="display:flex;"><span>    rootfs <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;local-lvm2:8&#34;</span> 
</span></span><span style="display:flex;"><span>    storage <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;local-lvm2&#34;</span>
</span></span><span style="display:flex;"><span>    target_node <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;proxmox&#34;</span>
</span></span><span style="display:flex;"><span>    unprivileged <span style="color:#f92672">=</span> true
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><h4 id="run">Run</h4>
<pre tabindex="0"><code>terraform init
terraform plan
terraform apply
</code></pre>]]></content:encoded>
    </item>
    
    <item>
      <title>Installing applications using Homebrew Cask on macOS</title>
      <link>https://andrewbeaton.net/posts/2019/10/installing-applications-using-homebrew/</link>
      <pubDate>Sun, 13 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2019/10/installing-applications-using-homebrew/</guid>
      <description>Installing applications using Homebrew Cask on macOS</description>
      <content:encoded><![CDATA[<p>In my previous guide we walked through <a href="/posts/2019/10/installing-homebrew-on-macos/">installing and using Homebrew</a>. Today we are going to look at extending Homebrew to support the installation of graphical applications. The kind you would normally drag to your Applications folder.</p>
<p>Homebrew Cask extends Homebrew. Bringing its simplicity and speed to the installation and management of GUI macOS applications such as Atom and Google Chrome.</p>
<p>To install an application or cask using Homebrew Cask you can run the following simple command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>brew cask install <span style="color:#f92672">[</span>application name<span style="color:#f92672">]</span>
</span></span></code></pre></div><p>An easy example that would install Spotify for example, is:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>brew cask install spotify
</span></span></code></pre></div><p>To search for an application, do:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>brew cask search <span style="color:#f92672">[</span>application name<span style="color:#f92672">]</span>
</span></span></code></pre></div><p>And finally, to remove an application:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>brew cask uninstall <span style="color:#f92672">[</span>application name<span style="color:#f92672">]</span>
</span></span></code></pre></div><p>Homebrew provides a nice little web page for finding applications that are available to be installed and you can access this on the Homebrew website.</p>
<p>Sometimes you may find it useful to be able to install a different version of an application, if you want a beta release or to run a previous version. 1Password 6 or Google Chrome Beta are good examples here.</p>
<p>We do this by using the Homebrew tap command to connect in another repository. We will be using the homebrew-cask-versions repository from GitHub.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>brew tap homebrew/cask-versions
</span></span></code></pre></div><p>And to install our specific version, we use this command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>brew cask install 1Password6
</span></span></code></pre></div>]]></content:encoded>
    </item>
    
    <item>
      <title>Installing HomeBrew on macOS</title>
      <link>https://andrewbeaton.net/posts/2019/10/installing-homebrew-on-macos/</link>
      <pubDate>Sun, 06 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2019/10/installing-homebrew-on-macos/</guid>
      <description>Installing HomeBrew on macOS</description>
      <content:encoded><![CDATA[<p>Homebrew calls itself &ldquo;The missing package manager for macOS&rdquo;. It really helps to simplify the installation of common tools and software on your Mac.</p>
<p>If you want to easily install command line tools such as cask, htop, wget, nmap, tree or virtually any other familiar unix command line tools, you can do so with a simple command. Homebrew downloads and builds the package for you.</p>
<p>If you spend a lot of time in the terminal environment then you should really see the benefit and value of Hombrew.</p>
<p>Before you can install Homebrew you need to make sure that you are running Mac OS X 10.10 or later and have the Command Line Tools for Xcode installed. This will allow you to build software from source. You can either install this directly from Apple or from the terminal by running this command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>sudo xcode-select --install
</span></span></code></pre></div><p>Once installed, which may take a few minutes, you can install Homebrew by running this command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>/usr/bin/ruby -e <span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>  
</span></span></code></pre></div><p>To confirm the installation was successful and that you are ready to go, run this command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>brew doctor
</span></span></code></pre></div><p>If you are the type of person who likes to read manuals, give the following command a go:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>brew help 
</span></span></code></pre></div><p>To show how simple it is to install something with Homebrew, you just need to use the following syntax:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>brew install <span style="color:#f92672">[</span>package name<span style="color:#f92672">]</span> 
</span></span></code></pre></div><p>So to install wget, it’s as easy as:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>brew install wget
</span></span></code></pre></div><p>You can search for packages with the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>brew search <span style="color:#f92672">[</span>package name<span style="color:#f92672">]</span>
</span></span></code></pre></div><p>And to remove a package, it’s:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>brew remove <span style="color:#f92672">[</span>package name<span style="color:#f92672">]</span>
</span></span></code></pre></div><p>Homebrew now defaults to sending anonymised behavioural analytics. If you do not want to participate in that for privacy purposes you can run the following command which will opt out of Homebrew analytics:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Bash" data-lang="Bash"><span style="display:flex;"><span>brew analytics off
</span></span></code></pre></div>]]></content:encoded>
    </item>
    
    <item>
      <title>Remove Proxmox 5.4 &#34;No Valid Subscription&#34; message</title>
      <link>https://andrewbeaton.net/posts/2019/09/proxmox-no-valid-subscription/</link>
      <pubDate>Sun, 29 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/posts/2019/09/proxmox-no-valid-subscription/</guid>
      <description>Remove Proxmox 5.4 &amp;#34;No Valid Subscription&amp;#34; message</description>
      <content:encoded><![CDATA[<p>If, like me, you are using Proxmox in your Homelab, it can get a bit annoying to see the “No valid Subscription” message, every time you log in.</p>
<p>Purchasing a subscription from Proxmox is certainly recommended if you’re planning to use it in anger or in a production environment as it will give you access to support, the enterprise repository and keep the developers supported.</p>
<p>But for a test environment, you can remove the message by simply editing one of the JavaScript files on the server.</p>
<p>This file does get overwritten when you update, so you will need to reapply when that happens.</p>
<h2 id="detailed-approach">Detailed Approach</h2>
<pre tabindex="0"><code>cd /usr/share/javascript/proxmox-widget-tookit
cp proxmoxlib.js proxmoxlib.js.old
vi proxmoxlib.js
</code></pre><p>Search for Active until you find it in the following line:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-JavaScript" data-lang="JavaScript"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">data</span>.<span style="color:#a6e22e">status</span> <span style="color:#f92672">!==</span> <span style="color:#e6db74">&#39;Active&#39;</span>) {
</span></span></code></pre></div><p>And change it to:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-JavaScript" data-lang="JavaScript"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#66d9ef">false</span>) {
</span></span></code></pre></div><p>Save the file and exit. Now restart the service to load the updated file:</p>
<pre tabindex="0"><code>systemctl restart pveproxy.service
</code></pre><h2 id="one-liner-approach">One Liner Approach</h2>
<pre tabindex="0"><code>sed -i.bak &#34;s/data.status !== &#39;Active&#39;/false/g&#34; /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js &amp;&amp; systemctl restart pveproxy.service
</code></pre><p>Even if you are feeling brave, I would recommend that you take a backup of proxmoxlib.js file before running the above command, just to be safe.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>About</title>
      <link>https://andrewbeaton.net/about/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://andrewbeaton.net/about/</guid>
      <description>about</description>
      <content:encoded><![CDATA[]]></content:encoded>
    </item>
    
    
  </channel>
</rss>
