Skip to main content
< Back to Blog

Automate Your Code with GitHub Actions #5: Real-World GitHub Actions: DevContainers, GitHub Pages, and Cloudflare Workers

Now that we have covered the fundamentals of GitHub Actions, it is time to explore real-world examples! You can use these examples right as they are, modify them to fit your needs, or use them as a starting point for your own workflows.

Each recipe is designed to showcase a specific use case, providing detailed explanations, code snippets, and best practices to help you get started quickly.

Who is Bas Steins?

Bas is a software developer and technology trainer based in the triangle between the Netherlands, Germany, and Belgium. For almost two decades, he has been helping people turn their ideas into software and helping other developers write better code. This series is based on his mini-guide "Automate Your Code with GitHub Actions".

Pre-Build DevContainers

Devcontainers are a great way to ensure that your development environment is consistent across all developers. This is especially useful when you have a large team or when you have a complex development environment.

In essence, a devcontainer is a container that contains all the tools and dependencies required to build and run your project. This includes the programming language, libraries, tools, and extensions that you need to develop your project.

The definition of a devcontainer lives in a directory called .devcontainer in the root of your project. This directory contains a devcontainer.json file that specifies the configuration of the devcontainer.

However, building complex devcontainers can be time-consuming and error-prone. To simplify this process, you can pre-build devcontainers for your team in a GitHub Action.

For each commit to the main branch, we're going to update the pre-built devcontainer image. This way, your team can pull the latest devcontainer image and start developing without having to build the devcontainer themselves.

What you'll learn

  • Using a GitHub Action on the push event
  • Setting up QEMU to enable cross-platform builds
  • Building a Docker image in a GitHub Action using the devcontainers/ci action
  • Pushing the Docker image to GitHub Container Registry

Here is the workflow that we're going to create:

name: Pre-build Devcontainer

on:
    workflow_dispatch:
    push:
        branches:
        - main

jobs:
    build_devcontainer:
        runs-on: ubuntu-24.04
        steps:
        - name: Checkout code
          uses: actions/checkout@v4

        - name: Set up QEMU
          uses: docker/setup-qemu-action@v3

        - name: Set up Docker Buildx
          uses: docker/setup-buildx-action@v3
          with:
            version: v0.16.1
            platforms: linux/amd64,linux/arm64
            install: true
            use: true

        - name: Login to GitHub Container Registry
          uses: docker/login-action@v3
          with:
            registry: ghcr.io
            username: ${{ github.repository_owner }}
            password: ${{ secrets.GITHUB_TOKEN }}

        - name: Pre-build dev container image
          uses: devcontainers/ci@v0.3
          with:
            imageName: ghcr.io/bascodes/prebuild-devcontainer-gha
            # cacheTo: type=inline  # This is the default value.
            runCmd: sleep 1
            push: always
            platform: linux/amd64,linux/arm64

In order for this to work, we need a dev container configuration file in .devcontainer/devcontainer.json.

This file looks like this:

{
    "name": "devcontainers-ci",
    "build": {
        "dockerfile": "./Dockerfile",
        "context": ".",
        "cacheFrom": "type=registry,ref=ghcr.io/bascodes/prebuild-devcontainer-gha:latest"
    },
    "remoteUser": "root",
    "features": {
        "ghcr.io/devcontainers/features/github-cli:1": "latest"
    }
}

☝️ When setting up your repository with a devcontainer.json file and a GitHub Actions workflow, please remove the cacheFrom argument from the devcontainer.json file at first. On the first run, there is no image to cache from. Once your workflow ran once successfully, you can add the cacheFrom argument to the devcontainer.json file.

Seeing it in action

Once you open your project in VSCode, you will be prompted to open the project in a dev container. The dev container will be pulled from the GitHub Container Registry and set up in your local environment.

You can verify that the build process actually used the cache by checking the logs of the GitHub Actions workflow. All the layers should be marked with CACHED.

Publishing a Static Website to GitHub Pages

GitHub Pages is a static site hosting service that allows you to publish websites directly from a GitHub repository. You can use GitHub Pages to host project documentation, personal blogs, or any other static content that you want to share with the world.

In this recipe, we will create a GitHub Actions workflow that automatically builds and deploys a static website to GitHub Pages whenever changes are pushed to the main branch. This workflow will use a Node.js-based static site generator called Hugo to build the website and deploy it to GitHub Pages.

What you'll learn

  • Using a GitHub Action on the push event
  • Setting up Hugo to build a static website
  • Deploying the website to GitHub Pages
  • Using the CNAME file to configure a custom domain

Setting Up the Repository With Hugo

Before we create the GitHub Actions workflow, we need to set up our repository with a static website project using Hugo. If you already have a Hugo project, you can skip this step.

  1. Create a new Hugo site by running the following command in your terminal:
hugo new site my-hugo-site
  1. Change into the newly created directory:
cd my-hugo-site
  1. Add a theme to your Hugo site. You can choose from a variety of themes available on the Hugo Themes website.

  2. Create a new content page by running:

hugo new posts/my-first-post.md
  1. Edit the content of the my-first-post.md file to add some sample content.

  2. Start the Hugo server to preview your site:

hugo server -D
  1. Open your browser and navigate to http://localhost:1313 to view your Hugo site.

Fine. Now it runs on localhost. How do we deploy it to GitHub Pages?

Creating the GitHub Actions Workflow

To deploy our Hugo site to GitHub Pages automatically, we will create a GitHub Actions workflow that builds the site and deploys it to the gh-pages branch. This workflow will run whenever changes are pushed to the main branch.

  1. Create a new directory named .github/workflows in the root of your repository.
  2. Inside the .github/workflows directory, create a new YAML file named deploy.yml.
  3. Add the following workflow configuration to the deploy.yml file:
name: Deploy to GitHub Pages

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v3
        with:
          hugo-version: 'latest'

      - name: Build site
        run: hugo --minify

      - name: Deploy to GitHub Pages
        uses: peaceiris/actions-gh-pages@v4
        with:
          personal_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./public
          publish_branch: gh-pages
          cname: mydomain.com
  1. Replace mydomain.com with your custom domain if you have one. If you don't have a custom domain, you can remove the cname field from the workflow configuration.
  2. Commit the changes to your repository.

Configuring GitHub Pages

To enable GitHub Pages for your repository and configure it to use the gh-pages branch, follow these steps:

  1. Go to your repository on GitHub.
  2. Click on the Settings tab.
  3. Scroll down to the GitHub Pages section.
  4. In the Source drop-down menu, select the gh-pages branch.
  5. Click Save.
  6. GitHub Pages will now be enabled for your repository, and your Hugo site will be published at https://<username>.github.io/<repository>.
  7. If you have a custom domain, you can add a CNAME file to your repository with your domain name.

That's it! Your Hugo site is now automatically built and deployed to GitHub Pages whenever changes are pushed to the main branch.

Setting up a Custom Domain

If you have a custom domain that you want to use with your GitHub Pages site, follow these steps to configure it:

  1. Create a new file named CNAME in the root of your repository.
  2. Add your custom domain to the CNAME file:
mydomain.com
  1. Commit the changes to your repository.
  2. Update the cname field in the GitHub Actions workflow configuration to match your custom domain.
  3. Go to your domain registrar and configure the DNS settings to point to username.github.io.

After configuring your custom domain, your Hugo site will be accessible at https://mydomain.com.

Using Wrangler to Deploy to Cloudflare Workers

Cloudflare Workers is a serverless platform that allows you to deploy code to Cloudflare's edge network. This enables you to run code closer to your users, reducing latency and improving performance.

In this example, we will use GitHub Actions to deploy a Cloudflare Worker using the wrangler CLI. We will set up a workflow that automatically deploys the worker on every push to the main branch.

What you'll learn

  • Using a GitHub Action on the push event
  • Setting up wrangler to deploy a Cloudflare Worker
  • Using secrets to store sensitive information
  • Deploying a Cloudflare Worker on every push

Setting up a Hono App

Before we create the GitHub Actions workflow, we need to set up a Cloudflare Workers project using wrangler. If you already have a project set up, you can skip this step.

  1. Install the wrangler CLI by running the following command in your terminal:
npm install -g @cloudflare/wrangler
  1. Create a new Cloudflare Workers project by running:
wrangler generate my-worker
  1. Change into the newly created directory:
cd my-worker
  1. Edit the wrangler.toml file to configure your project settings. You will need to set the account_id and zone_id fields.

  2. Write your Cloudflare Worker code in the src directory. You can create a new JavaScript file or modify the existing index.js file.

  3. Test your Cloudflare Worker locally by running:

wrangler dev
  1. Open your browser and navigate to http://localhost:8787 to test your worker.

Great! Now you have a Cloudflare Workers project set up.

Creating the GitHub Actions Workflow

To automate the deployment of your Cloudflare Worker using GitHub Actions, we will create a workflow that runs the wrangler publish command on every push to the main branch.

  1. Create a new directory named .github/workflows in the root of your repository.
  2. Inside the .github/workflows directory, create a new YAML file named deploy.yml.
  3. Add the following workflow configuration to the deploy.yml file:
name: Deploy Cloudflare Worker

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install wrangler
        run: npm install -g @cloudflare/wrangler

      - name: Build and deploy worker
        run: wrangler publish
        env:
          CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
  1. Save the deploy.yml file.
  2. Set up your Cloudflare API token as a secret in your repository. Go to your repository on GitHub, navigate to Settings > Secrets, and add a new secret named CF_API_TOKEN with your Cloudflare API token as the value.
  3. Commit and push the changes to your repository.

In the next article, we'll continue with more real-world recipes — including data automation with issue templates, web scraping on a schedule, and publishing Python packages. See you there!

Your Download is in Progress…

Giveaways. Cheat Sheets. eBooks. Discounts. And great content from our blog!