Mastodon

Build static blog on GitHub Pages #1

Welcome

Everyone sometimes thinks about personal website. Nothing fancy, just static content with clever topics... sounds easy, isn't it? The only problem is how to host this page and how to do it fast (and as cheap as is possible). So where comes GitHub Page. The main reason why I choose this solution is the price and domain. 3sky.github.io will look cool, almost professional. The question is why I will do it harder than it's recommended? The answer is simple because I can. Technology is all about curiosity and people who like to do stuff. After a short introduction let's start.

  • Google Cloud Platform
  • Terraform
  • Hugo
  • Nginx

Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently. Terraform can manage existing and popular service providers as well as custom in-house solutions.

It's a very popular tool - I always want to learn how to use it. More or less in the correct way. Also managing infrastructure as a code it’s so satisfying.

  1. Getting project credentials.

    Set up a service account key, which Terraform will use to create and manage resources in your GCP project. Go to the create service account key page. Select the default service account or create a new one, select JSON as the key type, and click Create. This downloads a JSON file with all the credentials that will be needed for Terraform to manage the resources. This file should be located in a secure place for production projects, but for this example move the downloaded JSON file to the project directory. We will call this file auth.json

  2. Create main.tf

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    
    // Set local variable
    locals {
        region_eu = "europe-west3-a"
        project_name = "tokyo-baton-256120"
    }
    
    provider "google" {
        credentials = file("auth.json")     // path to `auth.json`
        project     = local.project_name
        region      = local.region_eu
    }
    
    // Terraform plugin for creating random ids
    resource "random_id" "instance_id" {
        byte_length = 8
    }
    
    // A single Google Cloud Engine instance
    resource "google_compute_instance" "default" {
        // count of instances
        count = 1
        // define name with random_id plugin
        name         = "app-${random_id.instance_id.hex}"
        // size of instance
        machine_type = "f1-micro"
        zone         = local.region_eu
    
    boot_disk {
        initialize_params {
            // image from GCP image list
            image = "ubuntu-1804-bionic-v20200129a"
        }
    }
    
    metadata = {
        // existing ssh key of kuba's
        ssh-keys = "kuba:${file("~/.ssh/id_rsa.pub")}"
    }
    
    // Make sure nginx is installed on all new instances for later steps
    metadata_startup_script = "sudo apt-get update;
    sudo apt-get install -yq nginx;"
    
    network_interface {
        network = "default"
            access_config {}
        }
    }
    
    data "google_compute_subnetwork" "my-subnetwork" {
        name   = "default-${local.region_eu}"
        region = "europe-west3"
    }
    
    // app-firewall open for incoming request on port 80
    resource "google_compute_firewall" "default" {
        name    = "app-firewall"
        network = "default"
        allow {
            protocol = "tcp"
            ports    = ["80"]
        }
    }
    
    // A variable for extracting the external ip of the instance
    output "ip" {
        value = "${google_compute_instance.default.0.network_interface.0.access_config.0.nat_ip}"
    }
    
    ...
    hcl
  3. Initialize a working directory containing Terraform configuration files

    1terraform init
    
    bash
  4. Apply the changes required to reach the desired state of the configuration

    1terraform apply
    
    bash
  5. Connect to instance via ssh

    1ssh user@ip
    2
    3# user = form line `metadata` secion
    4# ip = from `ip` variable output
    5# Example
    6# ssh kuba@35.123.25.1
    
    bash
  6. Destroy the Terraform-managed infrastructure

    WARNING - At the end of learning session destroy unused infrastructure - it's cheaper

    1terraform destroy
    
    bash

That was easy, isn't it? But remember it's infrastructure working on someone's else machines - you need to pay for it. Use Terraform wisely.

Hugo is one of the most popular open-source static site generators. With its amazing speed and flexibility, Hugo makes building websites fun again

Hugo is open-source and written in Go. In compare to Jekyll(Ruby) choice was easy.

  1. Install Hugo with the correct version

    1sudo snap install hugo
    
    bash
  2. Generate a new site

    1hugo new site <page-name>
    2
    3# Example
    4# hugo new site 3sky.io
    
    bash
  3. Go inside new project directory

    1cd <page-name>
    2# Exxample
    3# cd 3sky.io
    
    bash
  4. Select theme from Hugo Themes

    1git init
    2git submodule add <url of themes from github> themes/<themes name>
    3# Example
    4# git submodule add https://github.com/luizdepra/hugo-coder.git themes/hugo-coder
    
    bash
  5. Configure your config.toml

    1. Open config.toml

      1vim config.toml
      
      bash
    2. Setup minimal config

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      
      title = "Learning notes"
      theme = "hugo-coder"
      languagecode = "en"
      defaultcontentlanguage = "en"
      paginate = 20
      canonifyurls = true
      pygmentsstyle = "emacs"
      pygmentscodefences = true
      pygmentscodefencesguesssyntax = true
      # The personal key for counting users with Google Analytics
      googleAnalytics = "UA-159451243-1"
      # Maybe you want to comment somethig with disqus?
      disqusShortname = "3sky"
      
      [params]
          author = "Jakub Wołynko"
          info = "IT Developer"
          description = "Clean and minimal blog about IT"
          keywords = "blog,developer,personal"
          favicon_32 = "images/f32.png"
          favicon_16 = "images/f16.png"
      avatarurl = "images/avatar.jpg"
          footercontent = "Hosted for free by GitHub :*"
          hidecredits = false
          hidecopyright = false
          rtl = false
      [taxonomies]
          category = "categories"
          series = "series"
          tag = "tags"
      # Social links
      [[params.social]]
          name = "Github"
          icon = "fab fa-github fa-2x"
          weight = 1
          url = "https://github.com/3sky/"
      [[params.social]]
          name = "LinkedIN"
          icon = "fab fa-linkedin"
          weight = 2
          url = "https://www.linkedin.com/in/jakubwolynko/"
      [[params.social]]
          name = "Twitter"
          icon = "fab fa-twitter fa-2x"
          weight = 3
          url = "https://twitter.com/kuba_wolynko/"
      # Menu links
      [[menu.main]]
          name = "Blog"
          weight = 1
          url  = "/posts/"
      [[menu.main]]
          name = "About"
          weight = 2
          url = "/about/"
      
      ...
      toml
  6. Add the first post

    1hugo new posts/hello-world.md
    
    bash
  7. Customize it!

    1vim content/posts/hello-world.md
    
    bash
  8. Add about section

    1hugo new about.md
    
    bash
  9. Customize it!

    1vim content/about.md
    
    bash
  10. Add avatar

    1mkdir static/images
    2# that's my photo from Twitter
    3wget -Ostatic/images/avatar.jpg \
    4https://pbs.twimg.com/profile_images/1219265057265266688/ANJwVv2o_400x400.jpg
    
    console
  11. Uff now you're ready - generate your static site.

    1hugo
    
    bash

Now you have folder public with static content of your page. What's next? Upload to GitHub? No, that will be too fast and too easy. We need real tests. Let's say hello to Nginx.

Nginx (pronounced "engine X") is a web server that can also be used as a reverse proxy, load balancer, mail proxy, and HTTP cache. The software was created by Igor Sysoev and first publicly released in 2004.

Nginx is open-source, popular and fast. Another obvious choice.

  1. Copy public/ into /var/www/

    1sudo cp -R public /var/www/
    2
    3# -R = copy directories recursively
    
    bash
  2. Change owner of a file

     1sudo chown -R  \
     2$(ps aux|grep nginx|grep -v grep| grep -v master| cut -d" " -f1). \
     3/var/www/public/
     4
     5# -R = copy directories recursively
     6# $(ps aux|grep nginx|grep -v grep| grep -v master| cut -d" " -f1).
     7# = get owner of nginx worker
     8    # $(). = get output as a command argument, `.` = set same group as owner
     9
    10# ps aux|grep nginx|grep -v grep| grep -v master| cut -d" " -f1
    11    # a = show processes for all users
    12    # u = display the process's user/owner
    13    # x = also show processes not attached to a terminal
    14
    15# grep nginx|grep -v grep| grep -v master = filter output
    16    # search `nginx` string
    17    # -v = invert the sense of matching, to select non-matching lines
    18
    19# cut -d" " -f1 = get only first column od output
    20    # -d" " = use " " instead of TAB for field delimiter
    21    # -f1 = select only these fields(1)
    
    ...
    bash
  3. Change default config file

    1. Open file
    1sudo vim /etc/nginx/sites-enabled/default
    
    bash
    1. Change root directory

      1#line 41
      2root /var/www/html;
      3# into
      4root /var/www/public;
      
      bash
  4. Restart server

    1sudo systemctl restart nginx.service
    
    bash
  5. Check page status(should be 200 - OK)

    1curl -sL -w "%{http_code}\\n" localhost:80 -o /dev/null
    2# -s = Silent cURL's output
    3# -L = Follow redirects
    4# -w = Custom output format
    5# -o = Redirects the HTML output to /dev/null
    
    bash
  6. Destroy the Terraform-managed infrastructure

    WARNING - At the end of learning session destroy unused infrastructure - it's cheaper

    1terraform destroy
    
    bash

Now we have a working static site on GCP instance, with the usage of Terraform and Nginx. That's only beginning, another step will be deploying this site just inside GitHub Pages.