diff --git a/.github/workflows/build-gluon.yml b/.github/workflows/build-gluon.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dd2600456a799d72901dfa9c8b2dc39cc6c29439
--- /dev/null
+++ b/.github/workflows/build-gluon.yml
@@ -0,0 +1,498 @@
+
+# Update this file after adding/removing/renaming a target by running
+# `make list-targets BROKEN=1 | ./contrib/actions/generate-actions.py > ./.github/workflows/build-gluon.yml`
+
+name: Build Gluon
+on:
+  push:
+    branches:
+      - master
+      - next
+      - v20*
+  pull_request:
+    types: [opened, synchronize, reopened]
+jobs:
+
+  ar71xx-generic:
+    name: ar71xx-generic
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh ar71xx-generic
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: ar71xx-generic_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: ar71xx-generic_output
+          path: output
+
+  ar71xx-tiny:
+    name: ar71xx-tiny
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh ar71xx-tiny
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: ar71xx-tiny_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: ar71xx-tiny_output
+          path: output
+
+  ar71xx-nand:
+    name: ar71xx-nand
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh ar71xx-nand
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: ar71xx-nand_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: ar71xx-nand_output
+          path: output
+
+  ath79-generic:
+    name: ath79-generic
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh ath79-generic
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: ath79-generic_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: ath79-generic_output
+          path: output
+
+  brcm2708-bcm2708:
+    name: brcm2708-bcm2708
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh brcm2708-bcm2708
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: brcm2708-bcm2708_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: brcm2708-bcm2708_output
+          path: output
+
+  brcm2708-bcm2709:
+    name: brcm2708-bcm2709
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh brcm2708-bcm2709
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: brcm2708-bcm2709_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: brcm2708-bcm2709_output
+          path: output
+
+  ipq40xx-generic:
+    name: ipq40xx-generic
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh ipq40xx-generic
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: ipq40xx-generic_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: ipq40xx-generic_output
+          path: output
+
+  ipq806x-generic:
+    name: ipq806x-generic
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh ipq806x-generic
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: ipq806x-generic_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: ipq806x-generic_output
+          path: output
+
+  lantiq-xrx200:
+    name: lantiq-xrx200
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh lantiq-xrx200
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: lantiq-xrx200_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: lantiq-xrx200_output
+          path: output
+
+  lantiq-xway:
+    name: lantiq-xway
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh lantiq-xway
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: lantiq-xway_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: lantiq-xway_output
+          path: output
+
+  mpc85xx-generic:
+    name: mpc85xx-generic
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh mpc85xx-generic
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: mpc85xx-generic_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: mpc85xx-generic_output
+          path: output
+
+  mpc85xx-p1020:
+    name: mpc85xx-p1020
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh mpc85xx-p1020
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: mpc85xx-p1020_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: mpc85xx-p1020_output
+          path: output
+
+  ramips-mt7620:
+    name: ramips-mt7620
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh ramips-mt7620
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: ramips-mt7620_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: ramips-mt7620_output
+          path: output
+
+  ramips-mt7621:
+    name: ramips-mt7621
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh ramips-mt7621
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: ramips-mt7621_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: ramips-mt7621_output
+          path: output
+
+  ramips-mt76x8:
+    name: ramips-mt76x8
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh ramips-mt76x8
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: ramips-mt76x8_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: ramips-mt76x8_output
+          path: output
+
+  ramips-rt305x:
+    name: ramips-rt305x
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh ramips-rt305x
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: ramips-rt305x_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: ramips-rt305x_output
+          path: output
+
+  sunxi-cortexa7:
+    name: sunxi-cortexa7
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh sunxi-cortexa7
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: sunxi-cortexa7_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: sunxi-cortexa7_output
+          path: output
+
+  x86-generic:
+    name: x86-generic
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh x86-generic
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: x86-generic_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: x86-generic_output
+          path: output
+
+  x86-geode:
+    name: x86-geode
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh x86-geode
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: x86-geode_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: x86-geode_output
+          path: output
+
+  x86-64:
+    name: x86-64
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh x86-64
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: x86-64_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: x86-64_output
+          path: output
+
+  ar71xx-mikrotik:
+    name: ar71xx-mikrotik
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh ar71xx-mikrotik
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: ar71xx-mikrotik_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: ar71xx-mikrotik_output
+          path: output
+
+  brcm2708-bcm2710:
+    name: brcm2708-bcm2710
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh brcm2708-bcm2710
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: brcm2708-bcm2710_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: brcm2708-bcm2710_output
+          path: output
+
+  mvebu-cortexa9:
+    name: mvebu-cortexa9
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh mvebu-cortexa9
+      - name: Archive build logs
+        if: ${{ !cancelled() }}
+        uses: actions/upload-artifact@v1
+        with:
+          name: mvebu-cortexa9_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: mvebu-cortexa9_output
+          path: output
+
diff --git a/contrib/actions/generate-actions.py b/contrib/actions/generate-actions.py
new file mode 100755
index 0000000000000000000000000000000000000000..d0a82dfdb23b81f95feffaf598753579f838e700
--- /dev/null
+++ b/contrib/actions/generate-actions.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+
+import sys
+
+ACTIONS_HEAD = """
+# Update this file after adding/removing/renaming a target by running
+# `make list-targets BROKEN=1 | ./contrib/actions/generate-actions.py > ./.github/workflows/build-gluon.yml`
+
+name: Build Gluon
+on:
+  push:
+    branches:
+      - master
+      - next
+      - v20*
+  pull_request:
+    types: [opened, synchronize, reopened]
+jobs:
+"""
+
+ACTIONS_TARGET="""
+  {target_name}:
+    name: {target_name}
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Install Dependencies
+        run: sudo contrib/actions/install-dependencies.sh
+      - name: Build
+        run: contrib/actions/run-build.sh {target_name}
+      - name: Archive build logs
+        if: ${{{{ !cancelled() }}}}
+        uses: actions/upload-artifact@v1
+        with:
+          name: {target_name}_logs
+          path: openwrt/logs
+      - name: Archive build output
+        uses: actions/upload-artifact@v1
+        with:
+          name: {target_name}_output
+          path: output
+"""
+
+output = ACTIONS_HEAD
+
+for target in sys.stdin:
+	output += ACTIONS_TARGET.format(target_name=target.strip())
+
+print(output)
diff --git a/contrib/actions/install-dependencies.sh b/contrib/actions/install-dependencies.sh
new file mode 100755
index 0000000000000000000000000000000000000000..60e4a9ee9a387b0ed64880c59b6a97d8491b8e4b
--- /dev/null
+++ b/contrib/actions/install-dependencies.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+set -e
+
+cp contrib/actions/sources.list /etc/apt/sources.list
+rm -rf /etc/apt/sources.list.d
+apt update
+apt install git subversion build-essential python gawk unzip libncurses5-dev zlib1g-dev libssl-dev wget time
+apt clean
+rm -rf /var/lib/apt/lists/*
diff --git a/contrib/actions/run-build.sh b/contrib/actions/run-build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..c3a279774e82a8afbfa95ac191c990c4f1c74bb3
--- /dev/null
+++ b/contrib/actions/run-build.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+set -e
+
+export BROKEN=1
+export GLUON_AUTOREMOVE=1
+export GLUON_DEPRECATED=1
+export GLUON_SITEDIR="contrib/ci/minimal-site"
+export GLUON_TARGET=$1
+export BUILD_LOG=1
+
+make update
+make -j2 V=s
diff --git a/contrib/actions/sources.list b/contrib/actions/sources.list
new file mode 100644
index 0000000000000000000000000000000000000000..64c6aae7dd8ce74dddf2f3d71511d60a173a29d1
--- /dev/null
+++ b/contrib/actions/sources.list
@@ -0,0 +1,2 @@
+deb http://mirror.netcologne.de/ubuntu/ bionic main restricted
+deb http://mirror.netcologne.de/ubuntu/ bionic-updates main restricted