<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2022-03-19T14:59:08+00:00</updated><id>/feed.xml</id><title type="html">Dennis Tanaka</title><subtitle>Seasoned IT professional with experience in systems analysis and software development. Most recently, I've worked with Golang, Ruby on Rails and Vue in terms of programming tools. I had also the opportunity to experience technologies such as Serverless Computing and Kubernetes. My current goals includes improving my management skills and learning more about DevOps and SRE.</subtitle><entry><title type="html">Provisioning KVM Virtual Machines with Cloud Init</title><link href="/2020/11/08/kvm_provisioning_with_cloud-init.html" rel="alternate" type="text/html" title="Provisioning KVM Virtual Machines with Cloud Init" /><published>2020-11-08T00:11:39+00:00</published><updated>2020-11-08T00:11:39+00:00</updated><id>/2020/11/08/kvm_provisioning_with_cloud-init</id><content type="html" xml:base="/2020/11/08/kvm_provisioning_with_cloud-init.html">&lt;h4&gt;Table of Contents&lt;/h4&gt;
&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#kvm-provisioning-with-cloud-init&quot; id=&quot;markdown-toc-kvm-provisioning-with-cloud-init&quot;&gt;KVM Provisioning with cloud-init&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot; id=&quot;markdown-toc-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#requirement&quot; id=&quot;markdown-toc-requirement&quot;&gt;Requirement&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#guide&quot; id=&quot;markdown-toc-guide&quot;&gt;Guide&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#install-required-packages&quot; id=&quot;markdown-toc-install-required-packages&quot;&gt;Install Required Packages&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#download-the-ubuntu-cloud-image&quot; id=&quot;markdown-toc-download-the-ubuntu-cloud-image&quot;&gt;Download the Ubuntu Cloud Image&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#verifying-the-downloaded-image&quot; id=&quot;markdown-toc-verifying-the-downloaded-image&quot;&gt;Verifying the Downloaded Image&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#branch-from-the-downloaded-image&quot; id=&quot;markdown-toc-branch-from-the-downloaded-image&quot;&gt;Branch from the Downloaded Image&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#create-the-provisioning-configuration&quot; id=&quot;markdown-toc-create-the-provisioning-configuration&quot;&gt;Create the Provisioning Configuration&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#bridge-networking&quot; id=&quot;markdown-toc-bridge-networking&quot;&gt;Bridge Networking&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#creating-a-new-virtual-machine&quot; id=&quot;markdown-toc-creating-a-new-virtual-machine&quot;&gt;Creating a New Virtual Machine&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#clean-up&quot; id=&quot;markdown-toc-clean-up&quot;&gt;Clean Up&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#references&quot; id=&quot;markdown-toc-references&quot;&gt;References&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#additional-information&quot; id=&quot;markdown-toc-additional-information&quot;&gt;Additional Information&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;kvm-provisioning-with-cloud-init&quot;&gt;KVM Provisioning with cloud-init&lt;/h1&gt;

&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;

&lt;p&gt;In a &lt;a href=&quot;/2020/11/07/kvm-and-cockpit.html&quot;&gt;previous post&lt;/a&gt;, I showed how I installed KVM on a spare laptop and used Cockpit to remotely manage virtual machines. In this post, I will to through the steps I took to quickly provision VMs based on Ubuntu Cloud Image with cloud-init.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://cloud-images.ubuntu.com/&quot;&gt;Ubuntu Cloud Images&lt;/a&gt; are official Ubuntu images meant to run on public clouds such as AWS. These images are usually used in conjunction with &lt;a href=&quot;https://cloud-init.io/&quot;&gt;cloud-init&lt;/a&gt;, a tool created by Canonical that is used to customize cloud images when virtual machines are first run.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cloud-init&lt;/code&gt; runs a set of user-defined configurations in the instance’s first boot and can be used, for example, to generate and setup SSH private keys. In this example, we are going to have something similar to what we get on AWS: an Ubuntu virtual machine we can connect remotely through SSH, in which we can run passwordless &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt; commands.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Ubuntu Cloud Images have shell access disabled by default, although we can customize this aspect as well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;requirement&quot;&gt;Requirement&lt;/h1&gt;

&lt;p&gt;Having installed KVM, following &lt;a href=&quot;/2020/11/07/kvm-and-cockpit.html&quot;&gt;Managing KVM Virtual Machines with Cockpit&lt;/a&gt; or a similar guide.&lt;/p&gt;

&lt;h1 id=&quot;guide&quot;&gt;Guide&lt;/h1&gt;

&lt;h2 id=&quot;install-required-packages&quot;&gt;Install Required Packages&lt;/h2&gt;

&lt;p&gt;We first needd to install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cloud-image-utils&lt;/code&gt;. This is needed to provision the client OS in the first boot.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;cloud-image-utils
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;download-the-ubuntu-cloud-image&quot;&gt;Download the Ubuntu Cloud Image&lt;/h2&gt;

&lt;p&gt;Ubuntu provides their cloud images at &lt;a href=&quot;https://cloud-images.ubuntu.com/&quot;&gt;https://cloud-images.ubuntu.com/&lt;/a&gt;. In my case, I chose to use Bionic 18.04 LTS. I’ve created a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/cloud_images&lt;/code&gt; folder to store such files:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;~/cloud_images&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;wget https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64.img
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;verifying-the-downloaded-image&quot;&gt;Verifying the Downloaded Image&lt;/h2&gt;

&lt;p&gt;To make sure the image is not corrupted nor has been tampered with, let’s execute the steps below. We use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpg&lt;/code&gt; to verify the image’s authenticity and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sha256&lt;/code&gt; to verify its integrity. The necessary tools are installed by default on Pop_OS! I’m using. For other cases, you can check the link below:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://ubuntu.com/tutorials/how-to-verify-ubuntu#2-necessary-software&quot;&gt;https://ubuntu.com/tutorials/how-to-verify-ubuntu#2-necessary-software&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But first, also download both the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SHA256SUMS&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SHA256SUMS.gpg&lt;/code&gt; files to the same folder. Then:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# check if we need to download the public key used to authenticate the checksum file:&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gpg &lt;span class=&quot;nt&quot;&gt;--keyid-format&lt;/span&gt; long &lt;span class=&quot;nt&quot;&gt;--verify&lt;/span&gt; SHA256SUMS.gpg SHA256SUMS
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For me, it returned something like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gpg: Signature made &amp;lt;date and time&amp;gt;...
gpg:                using RSA key &amp;lt;key ID&amp;gt;
gpg: Can't check signature: No public key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From this message, we know the ID of the key we need to request to the Ubuntu key server:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gpg &lt;span class=&quot;nt&quot;&gt;--keyid-format&lt;/span&gt; long &lt;span class=&quot;nt&quot;&gt;--keyserver&lt;/span&gt; hkp://keyserver.ubuntu.com &lt;span class=&quot;nt&quot;&gt;--recv-keys&lt;/span&gt; &amp;lt;key ID&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This command should report that the key was imported, what means that it was retrieved and added to the keyring. Now, we can inspect the key fingerprints:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gpg &lt;span class=&quot;nt&quot;&gt;--keyid-format&lt;/span&gt; long &lt;span class=&quot;nt&quot;&gt;--list-keys&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--with-fingerprint&lt;/span&gt; 0x&amp;lt;key ID&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It should display the key used to sign Ubuntu Cloud Images checksums. We can now verify the checksum file using the signature:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gpg &lt;span class=&quot;nt&quot;&gt;--keyid-format&lt;/span&gt; long &lt;span class=&quot;nt&quot;&gt;--verify&lt;/span&gt; SHA256SUMS.gpg SHA256SUMS
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This returned the following line in the output:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gpg: Good signature from &lt;span class=&quot;s2&quot;&gt;&quot;UEC Image Automatic Signing Key &amp;lt;cdimage@ubuntu.com&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;unknown]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Good signature&lt;/code&gt; means the checksum file was indeed created by Ubuntu. So, now we can check that the image’s sha256 checksum matches the downloaded checksum:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sha256sum&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; SHA256SUMS 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;OK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;An output like the following indicates the ISO file matches the checksum and should be used without problems.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bionic-server-cloudimg-amd64.img: OK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;branch-from-the-downloaded-image&quot;&gt;Branch from the Downloaded Image&lt;/h1&gt;

&lt;p&gt;We can get the details of the image we just downloaded with the command below:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;qemu-img info bionic-server-cloudimg-amd64.img

&lt;span class=&quot;c&quot;&gt;# Output&lt;/span&gt;
image: bionic-server-cloudimg-amd64.img
file format: qcow2
virtual size: 2.2 GiB &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;2361393152 bytes&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
disk size: 343 MiB
cluster_size: 65536
Format specific information:
    compat: 0.10
    refcount bits: 16
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we can see, the downloaded image is way too small for any practical purpose, so let’s create a new 20GB image based on the downloaded one:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;qemu-img create &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; qcow2 &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt; qcow2 &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; bionic-server-cloudimg-amd64.img  vm_0001-bionic-server-cloudimg-amd64.qcow2 20G
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;qemu-img info vm_0001-bionic-server-cloudimg-amd64.qcow2

&lt;span class=&quot;c&quot;&gt;# Output&lt;/span&gt;
image: vm_0001-bionic-server-cloudimg-amd64.qcow2
file format: qcow2
virtual size: 20 GiB &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;21474836480 bytes&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
disk size: 196 KiB
cluster_size: 65536
backing file: bionic-server-cloudimg-amd64.img
Format specific information:
    compat: 1.1
    lazy refcounts: &lt;span class=&quot;nb&quot;&gt;false
    &lt;/span&gt;refcount bits: 16
    corrupt: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: we could have also made a copy of the downloaded image and resized with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-img resize vm_0001-bionic-server-cloudimg-amd64.qcow2 20G&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;create-the-provisioning-configuration&quot;&gt;Create the Provisioning Configuration&lt;/h1&gt;

&lt;p&gt;Now, we are going to create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cloud-init&lt;/code&gt; configuration to be used in the guest provisioning. Let’s first create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user-data&lt;/code&gt; file containing the content below. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;meta-data&lt;/code&gt; file may be used in the future but, for now, let’s keep it empty.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;cloud-init
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;cloud-init
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;user-data
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;meta-data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#cloud-config&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;vm_0001&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;fqdn&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;vm_0001.localdomain&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;manage_etc_hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;ssh_pwauth&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;disable_root&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;home&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/home/ubuntu&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/bin/bash&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;sudo&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ALL=(ALL) NOPASSWD:ALL&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ssh-authorized-keys&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;SSH public key&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;SSH public key&amp;gt;&lt;/code&gt; needs to be replaced accordingly.&lt;/p&gt;

&lt;p&gt;For networking, we create a file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;network-config&lt;/code&gt;. This is an example for a fixed IP configuration:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;ethernets&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;enp1s0&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;dhcp4&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;addresses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;192.168.122.100/24&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;gateway4&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;192.168.122.1&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;nameservers&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;addresses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;192.168.122.1&lt;/span&gt;
       &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;8.8.8.8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In my case, I’ve used the dynamic IP configuration below:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;ethernets&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;enp1s0&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;dhcp4&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;I had named the interface &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ens1&lt;/code&gt;, but the guest VM was not able to have an IP address assigned when started. In these failed VM starts, network information was displayed during the boot and I noticed the interface was being identified as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enp1s0&lt;/code&gt;. So, I’ve changed the interface name in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;network-config&lt;/code&gt; file and the guests started getting IP addresses from the DHCP server.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s now create a disk image containing the provisioning configuration. This is where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cloud-image-utils&lt;/code&gt; package is used.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;cloud-localds &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--network-config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;network-config cloud-init-provisioning.qcow2 user-data meta-data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;One of the tutorials uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;genisoimage&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cloud-localds&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;bridge-networking&quot;&gt;Bridge Networking&lt;/h1&gt;

&lt;p&gt;Before creating a new virtual machine, we are going to create a network bridge on the host first. This will allow our virtual machines to connect to the local network directly and become visible in this context. Let’s first install the necessary dependency:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;bridge-utils
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, let’s edit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/network/interfaces&lt;/code&gt; file that was originally like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# interfaces(5) file used by ifup(8) and ifdown(8)
# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add the following lines after the existing content:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;auto lo
iface lo inet loopback

auto br0
iface br0 inet dhcp
        bridge_ports enp6s0
        bridge_stp off
        bridge_fd 0
        bridge_maxwait 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In my case, I opted for DHCP as I’ve reserved my host IP address in the router. Also, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bridge_ports&lt;/code&gt; need to be replaced accordingly (in my case, the ethernet interface on the host is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enp6s0&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Now, we just need to restart networking:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; /etc/init.d/networking restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Just by restarting the network, my ethernet adapter was still showing up with an IP address assigned. So, I restarted the host and only the bridge is visible now, as it is supposed to be.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;creating-a-new-virtual-machine&quot;&gt;Creating a New Virtual Machine&lt;/h1&gt;

&lt;p&gt;Now, we can create the new virtual machine:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;virt-install &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; vm_0001 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--virt-type&lt;/span&gt; kvm &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--vcpus&lt;/span&gt; 2 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--memory&lt;/span&gt; 2048 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--disk&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;cloud_images/vm_0001-bionic-server-cloudimg-amd64.qcow2,device&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;disk &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--disk&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;cloud-init/cloud-init-provisioning.qcow2,device&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;cdrom &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--os-type&lt;/span&gt; Linux &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--os-variant&lt;/span&gt; ubuntu18.04 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--graphics&lt;/span&gt; none &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--network&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bridge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;br0 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--import&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The machine will start its initialization process until it reaches the login prompt. According to our configuration, we are supposed to access the guest through SSH and no user is allowed shell access to it. We can go back to our shell with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl + ]&lt;/code&gt; key combination.&lt;/p&gt;

&lt;p&gt;In my case, my KVM host is not my main desktop, so the guest is on a separate machine, but accessing it from my desktop should not be a problem since the guest is using bridge networking. Since I set the SSH public key from my desktop in the cloud-init provisioning configuration, I can access the newly created guest with:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ssh ubuntu@&amp;lt;ip address of the guest&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can discover the IP address of the guest during its boot process when network information is displayed. But, as far as I know, the only way to check the IP address assigned to the guest afterwards is to check the list of DHCP clienst on my router’s admin screen. So, in this case, it’s probably a better idea to set a static IP address for the guest or, maybe, fix the guest’s IP address in the router. The article below mentions the same limitation:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://levelup.gitconnected.com/how-to-setup-bridge-networking-with-kvm-on-ubuntu-20-04-9c560b3e3991&quot;&gt;https://levelup.gitconnected.com/how-to-setup-bridge-networking-with-kvm-on-ubuntu-20-04-9c560b3e3991&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lastly, we can check some output generated by cloud-init in the following files:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;/run/cloud-init/result.json&lt;/li&gt;
  &lt;li&gt;/var/log/cloud-init.log&lt;/li&gt;
  &lt;li&gt;/var/log/cloud-init-output.log&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;clean-up&quot;&gt;Clean Up&lt;/h1&gt;

&lt;p&gt;cloud-init is setup to run everytime the machine starts and it can be left this way if we want to enforce those settings. If that’s not the case, we can disable cloud-init.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# this file disables cloud-init execution&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo touch&lt;/span&gt; /etc/cloud/cloud-init.disabled

&lt;span class=&quot;c&quot;&gt;# alternatively, we could remove the cloud-init package&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://ubuntu.com/tutorials/how-to-verify-ubuntu#1-overview&quot;&gt;https://ubuntu.com/tutorials/how-to-verify-ubuntu#1-overview&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://fabianlee.org/2020/02/23/kvm-testing-cloud-init-locally-using-kvm-for-an-ubuntu-cloud-image/&quot;&gt;https://fabianlee.org/2020/02/23/kvm-testing-cloud-init-locally-using-kvm-for-an-ubuntu-cloud-image/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stafwag.github.io/blog/blog/2019/03/03/howto-use-centos-cloud-images-with-cloud-init/&quot;&gt;https://stafwag.github.io/blog/blog/2019/03/03/howto-use-centos-cloud-images-with-cloud-init/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/@art.vasilyev/use-ubuntu-cloud-image-with-kvm-1f28c19f82f8&quot;&gt;https://medium.com/@art.vasilyev/use-ubuntu-cloud-image-with-kvm-1f28c19f82f8&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/@yping88/use-ubuntu-server-20-04-cloud-image-to-create-a-kvm-virtual-machine-with-fixed-network-properties-62ecae025f6c&quot;&gt;https://medium.com/@yping88/use-ubuntu-server-20-04-cloud-image-to-create-a-kvm-virtual-machine-with-fixed-network-properties-62ecae025f6c&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://help.ubuntu.com/community/KVM/Networking#Creating_a_network_bridge_on_the_host&quot;&gt;https://help.ubuntu.com/community/KVM/Networking#Creating_a_network_bridge_on_the_host&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;additional-information&quot;&gt;Additional Information&lt;/h2&gt;

&lt;p&gt;The URL below provides a very friendly overview of cloud-init:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/an-introduction-to-cloud-config-scripting&quot;&gt;https://www.digitalocean.com/community/tutorials/an-introduction-to-cloud-config-scripting&lt;/a&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">Table of Contents</summary></entry><entry><title type="html">Managing KVM Virtual Machines with Cockpit</title><link href="/2020/11/07/kvm-and-cockpit.html" rel="alternate" type="text/html" title="Managing KVM Virtual Machines with Cockpit" /><published>2020-11-07T06:00:57+00:00</published><updated>2020-11-07T06:00:57+00:00</updated><id>/2020/11/07/kvm-and-cockpit</id><content type="html" xml:base="/2020/11/07/kvm-and-cockpit.html">&lt;h4&gt;Table of Contents&lt;/h4&gt;
&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot; id=&quot;markdown-toc-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#preparation&quot; id=&quot;markdown-toc-preparation&quot;&gt;Preparation&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#lid&quot; id=&quot;markdown-toc-lid&quot;&gt;Lid&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#ssh&quot; id=&quot;markdown-toc-ssh&quot;&gt;SSH&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#hostname&quot; id=&quot;markdown-toc-hostname&quot;&gt;Hostname&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#checking-virtualization-support&quot; id=&quot;markdown-toc-checking-virtualization-support&quot;&gt;Checking Virtualization Support&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#installation&quot; id=&quot;markdown-toc-installation&quot;&gt;Installation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cockpit-interface&quot; id=&quot;markdown-toc-cockpit-interface&quot;&gt;Cockpit Interface&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#impressions&quot; id=&quot;markdown-toc-impressions&quot;&gt;Impressions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#edits&quot; id=&quot;markdown-toc-edits&quot;&gt;Edits&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#session-timeout&quot; id=&quot;markdown-toc-session-timeout&quot;&gt;Session Timeout&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#december-6th-2020&quot; id=&quot;markdown-toc-december-6th-2020&quot;&gt;December 6th, 2020&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#update-from-backports&quot; id=&quot;markdown-toc-update-from-backports&quot;&gt;Update from Backports&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#december-6th-2020-1&quot; id=&quot;markdown-toc-december-6th-2020-1&quot;&gt;December 6th, 2020&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#references&quot; id=&quot;markdown-toc-references&quot;&gt;References&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;

&lt;p&gt;Currently, I’m trying to use virtual machines and containers as much as possible. But, as I use multiple devices, I wanted to be able to manage those virtual machines easily from any of those machines. My idea was to use a laptop I had laying around for that purpose, so I started researching about the options I had and there were a couple of interesting options such as VMware, Proxmox and oVirt. I ultimately decided to use &lt;a href=&quot;https://cockpit-project.org/&quot;&gt;Cockpit&lt;/a&gt; to manage KVM virtual machines on the host. Cockpit is a web-based interface to manage servers, not a virtualization focused application like the mentioned options, but it has a module for VM management.&lt;/p&gt;

&lt;p&gt;There’s not a strong reason for that choice and I may test the other options in the future. It’s just that it seemed faster to start using it since I already had Pop_OS! installed on the laptop and I decided to install Cockpit on top of that. I knew it lacks a lot in terms of features compared to the other options, but I thought it was OK because this was my first experience with KVM. I knew what KVM is and was interested in trying it out, so I thought it would good to have to do things manually whenever Cockpit didn’t support something I’d like to do.&lt;/p&gt;

&lt;h1 id=&quot;preparation&quot;&gt;Preparation&lt;/h1&gt;

&lt;h2 id=&quot;lid&quot;&gt;Lid&lt;/h2&gt;

&lt;p&gt;I first setup my laptop to work with its lid closed so I could save on space by putting it on a stand that keeps the laptop in the vertical position.&lt;/p&gt;

&lt;p&gt;I just had to edit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/systemd/logind.conf&lt;/code&gt; file and make sure &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HandleLidSwitch&lt;/code&gt; is uncommented with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ignore&lt;/code&gt; value as below:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;HandleLidSwitch=ignore
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And restart the corresponding service:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;systemctl restart systemd-logind.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;ssh&quot;&gt;SSH&lt;/h2&gt;

&lt;p&gt;Next, I instaled SSH:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;ssh

&lt;span class=&quot;c&quot;&gt;# at this point, the server should be up and running. Checking it, just in case:&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl status ssh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And created the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;authorized_keys&lt;/code&gt; file to allow access from the PC I use the most:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; .ssh
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; .ssh/
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;authorized_keys
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vim authorized_keys
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;hostname&quot;&gt;Hostname&lt;/h2&gt;

&lt;p&gt;I also changed the hostname as the original name was not appropriate anymore:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# well, not sure I can consider this a homelab, but it's easy to remember :D&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;hostnamectl set-hostname homelab
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I also edited the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/hosts&lt;/code&gt; file and replaced the reference to the old hostname. That line looks like this now:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;127.0.1.1       homelab
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;checking-virtualization-support&quot;&gt;Checking Virtualization Support&lt;/h2&gt;

&lt;p&gt;A standard installation of Cockpit will not contain the module to manage virtual machines. Because my main goal is to use Cockpit for this specific purpose, I first checked that my CPU supports hardware virtualization.&lt;/p&gt;

&lt;p&gt;This was done with the following command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# if the command below returns 1 or more, it means virtualization is supported.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;egrep &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'(vmx|svm)'&lt;/span&gt; /proc/cpuinfo

&lt;span class=&quot;c&quot;&gt;# Another alternative is to use the following command:&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;kvm-ok
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In my case, as virtualization is supported, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kvm-ok&lt;/code&gt; returned an output like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;INFO: /dev/kvm exists
KVM acceleration can be used
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kvm-ok&lt;/code&gt; will even show an alert in the case virtualization is supported, but it’s disabled in the BIOS. In this case, it should be activated to enable virtualization at full speed.&lt;/p&gt;

&lt;h1 id=&quot;installation&quot;&gt;Installation&lt;/h1&gt;

&lt;p&gt;The Cockpit installation itself was extremely simple:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt update
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;cockpit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I also installed the following package, so I could manage virtual machines:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;cockpit-machines
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The corresponding service should be started after the installation and we can confirm through the command below:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;systemctl status cockpit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Compared to the &lt;a href=&quot;https://help.ubuntu.com/community/KVM/Installation&quot;&gt;Ubuntu KVM installation tutorial&lt;/a&gt;, this procedure didn’t install the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bridge-utils&lt;/code&gt; package which I may install later to allow virtual machines to access the local network directly.&lt;/p&gt;

&lt;p&gt;That same tutorial also mentions the need to add the user to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libvirtd&lt;/code&gt; group, but it was already done after the installation without me having to do anything.&lt;/p&gt;

&lt;p&gt;I could also have installed Virt-Manager that seems to be a much more feature-rich than the Cockpit’s VM management module. Although Red Hat is recommending the use of Cockpit instead of Virt-Manager, it’s still under development.&lt;/p&gt;

&lt;p&gt;But, for now, I will stick to using Cockpit because, as I said before, I’m interested in doing everything Cockpit doesn’t support manually, through the command-line.&lt;/p&gt;

&lt;h1 id=&quot;cockpit-interface&quot;&gt;Cockpit Interface&lt;/h1&gt;

&lt;p&gt;We can access Cockpit through the port 9090 on the host:&lt;/p&gt;

&lt;p&gt;https://ip-address:9090/&lt;/p&gt;

&lt;p&gt;The browser will display a warning since we are dealing with a self-signed certificate. I safely skipped it since I’m only accessing Cockpit on my local network. Then, the login screen is displayed:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/blog/kvm-and-cockpit/login.png&quot; alt=&quot;The Login Screen&quot; width=&quot;600px&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We just need to provide our credentials on that machine. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Reuse my password for privileged tasks&lt;/code&gt; option, as it suggests, makes the same credentials to be used for tasks such as installing updates, so we don’t have to provide the same credentials again.&lt;/p&gt;

&lt;p&gt;Once logged in, we can check the VM management interface where we can check information about our machines and change their state:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/blog/kvm-and-cockpit/vms.png&quot; alt=&quot;The Virtual Machines Screen&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We can also create new virtual machines and access them through the &lt;strong&gt;Consoles&lt;/strong&gt; tab:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/blog/kvm-and-cockpit/new-vm.png&quot; alt=&quot;Create New VMs&quot; width=&quot;600px&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It also provides a &lt;strong&gt;Terminal&lt;/strong&gt; menu that gives us shell access to the host what can prove to be convenient.&lt;/p&gt;

&lt;h1 id=&quot;impressions&quot;&gt;Impressions&lt;/h1&gt;

&lt;p&gt;For my impressions, at least in terms of virtual machine management, Cockpit certainly feels lacking for now and development doesn’t seem to be that fast. If it was not for my goal of knowing more about KVM it would probably not make that much sense.&lt;/p&gt;

&lt;p&gt;That said, it seems enough for my home usage. It’s nice to be able to have a glance on the existing virtual machines as it gives visibility on what is going on in the host. I will probably not use much of its features outside managing virtual machines, but being able to do simple checks and management tasks from a web interface is very convenient.&lt;/p&gt;

&lt;h1 id=&quot;edits&quot;&gt;Edits&lt;/h1&gt;

&lt;h2 id=&quot;session-timeout&quot;&gt;Session Timeout&lt;/h2&gt;

&lt;h6 id=&quot;december-6th-2020&quot;&gt;December 6th, 2020&lt;/h6&gt;

&lt;p&gt;Cockpit automatically log us out after 15 minutes of inactivity. We can configure this session timeout, in minutes, by editing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/cockpit/cockpit.conf&lt;/code&gt; file (it may be necessary to create it) with a content like the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[Session]
IdleTimeout=180
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;span class=&quot;info-source&quot;&gt;Source: https://cockpit-project.org/blog/cockpit-209.html&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;update-from-backports&quot;&gt;Update from Backports&lt;/h2&gt;

&lt;h6 id=&quot;december-6th-2020-1&quot;&gt;December 6th, 2020&lt;/h6&gt;

&lt;p&gt;As of now, 215 is the most recent version of Cockpit available in the Ubuntu 20.04 repositories, even though the most recent version of the application itself is 233. To update to a more recent version, the easiest way is to install the version (currently 231) from the Backports repository. I use the command below to update the Cockpit’s version and resolve its dependencies from Backports:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; focal-backports cockpit cockpit-machines
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;span class=&quot;info-source&quot;&gt;Source: &lt;a href=&quot;https://help.ubuntu.com/community/UbuntuBackports#Using_Backports&quot;&gt;https://help.ubuntu.com/community/UbuntuBackports#Using_Backports&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://computingforgeeks.com/how-to-install-cockpit-on-ubuntu-18-04-debian-9/&quot;&gt;https://computingforgeeks.com/how-to-install-cockpit-on-ubuntu-18-04-debian-9/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://cockpit-project.org/guide/latest/feature-virtualmachines&quot;&gt;https://cockpit-project.org/guide/latest/feature-virtualmachines&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;htps://www.redhat.com/en/blog/managing-virtual-machines-rhel-8-web-console&quot;&gt;htps://www.redhat.com/en/blog/managing-virtual-machines-rhel-8-web-console&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name></name></author><summary type="html">Table of Contents</summary></entry><entry><title type="html">Creating a Portfolio Website with Jekyll (and Hosting it on GitHub) - Part 2</title><link href="/2019/03/21/portfolio-with-jekyll-part2.html" rel="alternate" type="text/html" title="Creating a Portfolio Website with Jekyll (and Hosting it on GitHub) - Part 2" /><published>2019-03-21T11:31:46+00:00</published><updated>2019-03-21T11:31:46+00:00</updated><id>/2019/03/21/portfolio-with-jekyll-part2</id><content type="html" xml:base="/2019/03/21/portfolio-with-jekyll-part2.html">&lt;p&gt;In &lt;a href=&quot;/2018/07/14/portfolio-with-jekyll-part1.html&quot;&gt;Part 1&lt;/a&gt;, we took a quick look at Jekyll and how to create and deploy a website to GitHub Pages. In this second and final part, let’s explore some of the customization features Jekyll provides us.&lt;/p&gt;

&lt;h1 id=&quot;layouts&quot;&gt;Layouts&lt;/h1&gt;

&lt;p&gt;In the previous example, you may have noticed the layout definition below in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;front matter&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;layout: post&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;While the markdown file provides the content of a page, the structure and appearance are defined in the layout file. We can create our own layout files, but because we are using an existing theme, we can customize the theme’s layout files instead.&lt;/p&gt;

&lt;p&gt;First, let’s copy the layout files from the theme’s folder to our project (the specific folder to copy from will probably be different for you as it depends on the version of the packages installed).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; vendor/bundle/ruby/2.3.0/gems/minima-2.5.0/_layouts .&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we take a look at the _layouts folder, we can see the 4 files below:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;default.html&lt;/li&gt;
  &lt;li&gt;home.html&lt;/li&gt;
  &lt;li&gt;page.html&lt;/li&gt;
  &lt;li&gt;post.html&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we open the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default.html&lt;/code&gt; file, we can see contents like the below:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ page.lang | default: site.lang | default: &quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;en&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;}}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

  {%- include head.html -%}

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;

    {%- include header.html -%}

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;main&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;page-content&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;aria-label=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Content&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;wrapper&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        {{ content }}
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;

    {%- include footer.html -%}

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It is an ordinary HTML file, but we can see a couple of the features provided by Jekyll and the Liquid template language it uses.&lt;/p&gt;

&lt;p&gt;“Include” tags, like the below, allow us to include content from another file stored in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_includes&lt;/code&gt; folder:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-liquid&quot; data-lang=&quot;liquid&quot;&gt;&lt;span class=&quot;p&quot;&gt;{%-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;header.html&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-%}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;While the line below specifies where the content of a markdown file that uses the layout file will be injected:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;{{ content }}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we take a look at the contents of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;page.html&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;---
layout: default
---
&lt;span class=&quot;nt&quot;&gt;&amp;lt;article&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;post&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;header&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;post-header&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;post-title&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ page.title | escape }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;post-content&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    {{ content }}
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We can see that a layout itself can use another layout and that this layout can be used to display an article with a title in the top.&lt;/p&gt;

&lt;p&gt;Now, we can also open the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;about.md&lt;/code&gt; file that ships with Jekyll. We can see in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;front matter&lt;/code&gt; that this file uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;page&lt;/code&gt; layout.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;page&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;About&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;permalink&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/about/&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Also, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;front matter&lt;/code&gt; defines a title and this title is injected in the line below in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;page&lt;/code&gt; layout:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;post-title&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ page.title | escape }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now that we have an idea of how layouts work, let’s customize our website a little bit.&lt;/p&gt;

&lt;h1 id=&quot;includes&quot;&gt;Includes&lt;/h1&gt;

&lt;p&gt;In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default.html&lt;/code&gt; layout file, we can see the line below:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-liquid&quot; data-lang=&quot;liquid&quot;&gt;&lt;span class=&quot;p&quot;&gt;{%-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;header.html&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-%}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default.html&lt;/code&gt; layout includes the header and all other layouts uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default&lt;/code&gt; layout, it is obvious that all pages in our website includes the content in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;header.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the contents of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;header.html&lt;/code&gt; file. Because it is also part of the minima theme, we need to copy this file as well:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;_includes
&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;vendor/bundle/ruby/2.3.0/gems/minima-2.5.0/_includes/header.html _includes&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This include file is responsible for displaying the website header and shows many variables that Jekyll make available for us, as well as filters provided by the Liquid template language.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-liquid&quot; data-lang=&quot;liquid&quot;&gt;&lt;span class=&quot;p&quot;&gt;{%-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;default_paths&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pages&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-%}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The line above, for example, shows the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;site.pages&lt;/code&gt; variable. It is an array of Jekyll’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Page&lt;/code&gt; variables (you can check the list of attributes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Page&lt;/code&gt; variable contains in &lt;a href=&quot;https://jekyllrb.com/docs/variables/#page-variables&quot;&gt;Page Variables&lt;/a&gt;). Any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.html&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.md&lt;/code&gt; file in the root folder or a new subfolder that contains a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;front matter&lt;/code&gt; will be part of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;site.pages&lt;/code&gt; variable. Then, we execute Liquid’s &lt;a href=&quot;https://shopify.github.io/liquid/filters/map/&quot;&gt;map&lt;/a&gt; filter on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;site.pages&lt;/code&gt; to get an array of the paths of those pages.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-liquid&quot; data-lang=&quot;liquid&quot;&gt;&lt;span class=&quot;p&quot;&gt;{%-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;page_paths&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;header_pages&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;default_paths&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-%}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The next line creates a variable called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;page_paths&lt;/code&gt;. It is assigned the value in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;site.header_pages&lt;/code&gt;, but can also be assigned the value in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default_paths&lt;/code&gt; in the case the former does not exist, what is possible with the use of Liquid’s &lt;a href=&quot;https://shopify.github.io/liquid/filters/default/&quot;&gt;default&lt;/a&gt; filter. We are going to come back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;site.header_pages&lt;/code&gt; later.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-liquid&quot; data-lang=&quot;liquid&quot;&gt;&lt;span class=&quot;p&quot;&gt;{%-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;page_paths&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-%}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{%-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;my_page&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pages&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-%}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{%-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;my_page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-%}&lt;/span&gt;
  &amp;lt;a class=&quot;page-link&quot; href=&quot;&lt;span class=&quot;p&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;my_page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;relative_url&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;&quot;&amp;gt;&lt;span class=&quot;p&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;my_page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;&amp;lt;/a&amp;gt;
  &lt;span class=&quot;p&quot;&gt;{%-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;endif&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-%}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{%-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;endfor&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-%}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This last snippet iterates over the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;page_paths&lt;/code&gt; variable created before and creates a link in the header for each page that has a title (defined in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;front matter&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To test what was just shown, let’s create a new page &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notes.md&lt;/code&gt; in the project’s root folder. Now, let’s add the content below to the new file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;page&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Notes&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;permalink&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/notes/&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we refresh our website, we are going to see a new “Notes” link in the header. Add another page called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;contact.md&lt;/code&gt; to the root folder with the content below:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;page&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Contact&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;permalink&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/contact/&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A new link is created as well. The problem is that the links are created in the alphabetical order, but we may want a different order to put the “Contact” page last, for example. In that case, we can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;site.header_pages&lt;/code&gt; mentioned before. This currently does not exist, but we can easily create this variable by adding the following lines to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt; file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yml&quot; data-lang=&quot;yml&quot;&gt;&lt;span class=&quot;na&quot;&gt;header_pages&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;about.md&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;notes.md&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;contact.md&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You will notice the change will not be reflected immediately and will require the server to be restarted. After that, the header will look as expected.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/blog/jekyll-part2-configured_header.png&quot; alt=&quot;The Resulting Header&quot; width=&quot;600px&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;em&gt;The Resulting Header&lt;/em&gt;&lt;/p&gt;

&lt;h1 id=&quot;collections&quot;&gt;Collections&lt;/h1&gt;

&lt;p&gt;Now, we are going to explore &lt;a href=&quot;https://jekyllrb.com/docs/collections/&quot;&gt;Collections&lt;/a&gt; that are a great way to group related content. Let’s use this feature to implement the “Notes” section in our website.&lt;/p&gt;

&lt;p&gt;First, add the following content to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yml&quot; data-lang=&quot;yml&quot;&gt;&lt;span class=&quot;na&quot;&gt;collections&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;notes&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then, let’s create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_notes&lt;/code&gt; folder and add 2 files in it. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/_notes/note1.md&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;menu_title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Note 1 Menu Item&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Note 1 Title&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;

Note 1 content
&lt;span class=&quot;gt&quot;&gt;
&amp;gt; A nice blockquote&lt;/span&gt;

A &lt;span class=&quot;gs&quot;&gt;**formatted**&lt;/span&gt; line of &lt;span class=&quot;ge&quot;&gt;*text*&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/_notes/note2.md&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-markdown&quot; data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;menu_title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Note 2 Menu Item&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Note 2 Title&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;

Note 2 content
&lt;span class=&quot;gt&quot;&gt;
&amp;gt; A nice blockquote&lt;/span&gt;

A &lt;span class=&quot;gs&quot;&gt;**formatted**&lt;/span&gt; line of &lt;span class=&quot;ge&quot;&gt;*text*&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, let’s create a custom layout listing all our notes. It will be the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/_layouts/note.html&lt;/code&gt; file and will contain the following content:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;---
layout: default
---
&lt;span class=&quot;nt&quot;&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.note&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2rem&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1rem&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2rem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;.yellow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#fdf475&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;.blue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#cbf0f8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;.note-date&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.8rem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;font-style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;italic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;gray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;notes-container&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;header&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;notes-header&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;notes-title&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ page.title | escape }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;

  {%- for note in site.notes -%}
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;article&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;note {{ note.background }}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;header&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;note-header&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;h2&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;note-title&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ note.title | escape }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;note-date&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ note.date }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;note-content&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      {{ note.content }}
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
  {%- endfor -%}
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I added the styles directly in the layout, to keep things simple, as that is not the main focus of the article. As Jekyll has built-in support for Sass, please refer to the &lt;a href=&quot;https://jekyllrb.com/docs/assets/&quot;&gt;Docs&lt;/a&gt; to know how to manage your stylesheets.&lt;/p&gt;

&lt;p&gt;You can see we were able to access our notes through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;site.notes&lt;/code&gt; variable and even use a custom variable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;background&lt;/code&gt; we added to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;front matter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Restart the server and we can now access those notes in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/notes/&lt;/code&gt; path.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/blog/jekyll-part2-notes_page.png&quot; alt=&quot;The Notes Page&quot; width=&quot;600px&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Notes Page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The files we created in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_notes&lt;/code&gt; folder does not generate corresponding files in Jekyll’s build process. If you need, you can change this behavior as shown in &lt;a href=&quot;https://jekyllrb.com/docs/collections/#add-content&quot;&gt;Add content&lt;/a&gt;. This would generate files such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/_notes/note1.html&lt;/code&gt; in the build output. In our example, we could, for example, display only part of the content of the notes in the list and link each note to a page where the user can see their whole content.&lt;/p&gt;

&lt;h1 id=&quot;data-files&quot;&gt;Data Files&lt;/h1&gt;

&lt;p&gt;In this final section, we are going to take a quick look at &lt;a href=&quot;https://jekyllrb.com/docs/datafiles/&quot;&gt;Data Files&lt;/a&gt;. It allows us to create files with custom data to be used in our templates. Those can be YAML, JSON, or CSV files. Let’s do an example to illustrate its use.&lt;/p&gt;

&lt;p&gt;First, create a file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/_data/contacts.yml&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yml&quot; data-lang=&quot;yml&quot;&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Email&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;me@dennistanaka.com&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Phone&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;(00) 0000-0000&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Website&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http://github.com/dennistanaka&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is enough to make our data accessible in our templates in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;site.data.contacts&lt;/code&gt; variable. So, we can now edit our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/contact.md&lt;/code&gt; file with the following content:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-liquid&quot; data-lang=&quot;liquid&quot;&gt;---
layout: page
title: Contact
permalink: /contact/
---

&amp;lt;table&amp;gt;
  &lt;span class=&quot;p&quot;&gt;{%-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;site.data.contacts&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%}&lt;/span&gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td&amp;gt;&lt;span class=&quot;p&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;&lt;span class=&quot;p&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
  &lt;span class=&quot;p&quot;&gt;{%-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;endfor&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%}&lt;/span&gt;
&amp;lt;/table&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This will generate the below output:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/blog/jekyll-part2-contact_page.png&quot; alt=&quot;The Contact Page&quot; width=&quot;600px&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Contact Page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As we could see, we can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data Files&lt;/code&gt; to remove repetition in our pages by separating data and configuration. A practical use is illustrate in &lt;a href=&quot;https://jekyllrb.com/tutorials/navigation/&quot;&gt;Navigation&lt;/a&gt; where it is used to create custom navigation for a website.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;In these article, we could learn and practice basic Jekyll concepts such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Layouts&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Collections&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data Files&lt;/code&gt;. There are plenty of content was not covered in the articles, so I highly recommend reading the documentation, as it is very well written and easy to understand.&lt;/p&gt;</content><author><name></name></author><summary type="html">In Part 1, we took a quick look at Jekyll and how to create and deploy a website to GitHub Pages. In this second and final part, let’s explore some of the customization features Jekyll provides us.</summary></entry><entry><title type="html">Creating a Portfolio Website with Jekyll (and Hosting it on GitHub) - Part 1</title><link href="/2018/07/14/portfolio-with-jekyll-part1.html" rel="alternate" type="text/html" title="Creating a Portfolio Website with Jekyll (and Hosting it on GitHub) - Part 1" /><published>2018-07-14T13:16:58+00:00</published><updated>2018-07-14T13:16:58+00:00</updated><id>/2018/07/14/portfolio-with-jekyll-part1</id><content type="html" xml:base="/2018/07/14/portfolio-with-jekyll-part1.html">&lt;h1 id=&quot;repository-creation&quot;&gt;Repository Creation&lt;/h1&gt;

&lt;h1 id=&quot;jekyll-installation&quot;&gt;Jekyll Installation&lt;/h1&gt;

&lt;p&gt;In this article, I won’t cover the installation process. It is very well documented in the &lt;a href=&quot;https://jekyllrb.com/docs/installation/&quot;&gt;Jekyll documentation&lt;/a&gt; and I assume you are going to follow that, but I will try to present some guidelines. I also assume you have a working Git installation.&lt;/p&gt;

&lt;p&gt;Jekyll is distributed as a &lt;a href=&quot;https://guides.rubygems.org/rubygems-basics/&quot;&gt;Ruby Gem&lt;/a&gt; and can be installed on most systems. It is recommended to work on a Unix-based system such as macOS or Linux, but you should not have problems working on Windows as well. By the way, this article was written on a Windows machine with Windows Subsystem for Linux enabled. You can take a look at the &lt;a href=&quot;https://jekyllrb.com/docs/windows/#installation-via-bash-on-windows-10&quot;&gt;official documentation&lt;/a&gt; if you choose to go this path too.&lt;/p&gt;

&lt;p&gt;Whatever system you choose to work on, the requirements are the same. You are going to need to have Ruby, RubyGems and build tools (GCC and Make) installed. If you, like me, are a Rails developer and already have a Ruby development environment installed, you should be good to go after installing Jekyll with the following commands (we are also installing bundler, a gem that helps us manage other Ruby gems in our project):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;jekyll bundler&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h1 id=&quot;new-project&quot;&gt;New Project&lt;/h1&gt;

&lt;p&gt;Now, we are going to create a new Jekyll project:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;jekyll new dennistanaka.github.io &lt;span class=&quot;nt&quot;&gt;--skip-bundle&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We passed the option &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--skip-bundle&lt;/code&gt; because we don’t want to install our dependencies system-wide. Instead, we want the installation of our dependencies to be limited to our project. But first, as we know we are going to host our website on GitHub, we want to setup up our project accordingly. First, open the Gemfile file created on your project’s root folder.&lt;/p&gt;

&lt;p&gt;And remove the line declaring the dependency of the jekyll gem. It may differ depending on the version of the software you are working with, but in my case, I removed the following line:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;jekyll&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;~&amp;gt; 3.6.2&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And uncomment the following line:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# gem &quot;github-pages&quot;, group: :jekyll_plugins&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h1 id=&quot;dependencies-installation&quot;&gt;Dependencies Installation&lt;/h1&gt;

&lt;p&gt;We can now install or dependencies locally with the following command:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;dennistanaka.github.io
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--path&lt;/span&gt; vendor/bundle&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h1 id=&quot;local-server-startup&quot;&gt;Local Server Startup&lt;/h1&gt;

&lt;p&gt;After that we can serve our website with the following command:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;jekyll serve&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Just open a browser and access the following address:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;http://127.0.0.1:4000/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Great! We already have a working website. You can see Jekyll comes with a pre-defined look &amp;amp; feel. Jekyll supports themes and it uses a theme called minima by default. You can check this fact by opening the Gemfile file, where there is a line setting the minima gem as a dependency:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;minima&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;~&amp;gt; 2.0&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In this article, I will show you how we can start customizing our website. Although we can start our website from scratch, without a theme at all, it is probably easier to have a starting point, at least when using Jekyll for the first time.&lt;/p&gt;

&lt;p&gt;But, before that, let’s add our website to GitHub to manage the changes in our website. You will see that, in the case of a Jekyll website, adding the project to GitHub not only means that we are controlling its versions, but also means that we are deploying our website for public access.&lt;/p&gt;

&lt;p&gt;Before doing that, let’s edit our .gitignore file. The Jekyll project already comes with a .gitignore to prevent unnecessary files to be commited. But, as installing the gems locally is an optional step, it does not include entries to ignore the installed packages. So, let’s add the following lines to the .gitignore file:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.bundle
vendor
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can push our files to GitHub as usual:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git init
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;First commit&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git remote add origin git@github.com:dennistanaka/dennistanaka.github.io.git
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git push &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; origin master&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can now access your website at the URL provided by GitHub. In my case, it is: https://dennistanaka.github.io/. If you still can’t see your website, it may take some time for GitHub to build it.&lt;/p&gt;</content><author><name></name></author><summary type="html">Repository Creation Jekyll Installation In this article, I won’t cover the installation process. It is very well documented in the Jekyll documentation and I assume you are going to follow that, but I will try to present some guidelines. I also assume you have a working Git installation. Jekyll is distributed as a Ruby Gem and can be installed on most systems. It is recommended to work on a Unix-based system such as macOS or Linux, but you should not have problems working on Windows as well. By the way, this article was written on a Windows machine with Windows Subsystem for Linux enabled. You can take a look at the official documentation if you choose to go this path too. Whatever system you choose to work on, the requirements are the same. You are going to need to have Ruby, RubyGems and build tools (GCC and Make) installed. If you, like me, are a Rails developer and already have a Ruby development environment installed, you should be good to go after installing Jekyll with the following commands (we are also installing bundler, a gem that helps us manage other Ruby gems in our project): $ gem install jekyll bundler New Project Now, we are going to create a new Jekyll project: $ jekyll new dennistanaka.github.io --skip-bundle We passed the option --skip-bundle because we don’t want to install our dependencies system-wide. Instead, we want the installation of our dependencies to be limited to our project. But first, as we know we are going to host our website on GitHub, we want to setup up our project accordingly. First, open the Gemfile file created on your project’s root folder. And remove the line declaring the dependency of the jekyll gem. It may differ depending on the version of the software you are working with, but in my case, I removed the following line: gem &quot;jekyll&quot;, &quot;~&amp;gt; 3.6.2&quot; And uncomment the following line: # gem &quot;github-pages&quot;, group: :jekyll_plugins Dependencies Installation We can now install or dependencies locally with the following command: $ cd dennistanaka.github.io $ bundle install --path vendor/bundle Local Server Startup After that we can serve our website with the following command: $ bundle exec jekyll serve Just open a browser and access the following address: http://127.0.0.1:4000/ Great! We already have a working website. You can see Jekyll comes with a pre-defined look &amp;amp; feel. Jekyll supports themes and it uses a theme called minima by default. You can check this fact by opening the Gemfile file, where there is a line setting the minima gem as a dependency: gem &quot;minima&quot;, &quot;~&amp;gt; 2.0&quot; In this article, I will show you how we can start customizing our website. Although we can start our website from scratch, without a theme at all, it is probably easier to have a starting point, at least when using Jekyll for the first time. But, before that, let’s add our website to GitHub to manage the changes in our website. You will see that, in the case of a Jekyll website, adding the project to GitHub not only means that we are controlling its versions, but also means that we are deploying our website for public access. Before doing that, let’s edit our .gitignore file. The Jekyll project already comes with a .gitignore to prevent unnecessary files to be commited. But, as installing the gems locally is an optional step, it does not include entries to ignore the installed packages. So, let’s add the following lines to the .gitignore file: .bundle vendor Now we can push our files to GitHub as usual: $ git init $ git add . $ git commit -m &quot;First commit&quot; $ git remote add origin git@github.com:dennistanaka/dennistanaka.github.io.git $ git push -u origin master You can now access your website at the URL provided by GitHub. In my case, it is: https://dennistanaka.github.io/. If you still can’t see your website, it may take some time for GitHub to build it.</summary></entry></feed>