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/Makefile b/Makefile
index 34343356c3e47584f873dfb67ab30ad39ef2204f..9f5f46b59a1d31d340b1bd1341121567325c1082 100644
--- a/Makefile
+++ b/Makefile
@@ -40,10 +40,11 @@ $(eval $(call mkabspath,GLUON_TARGETSDIR))
 $(eval $(call mkabspath,GLUON_PATCHESDIR))
 
 GLUON_MULTIDOMAIN ?= 0
+GLUON_AUTOREMOVE ?= 0
 GLUON_DEBUG ?= 0
 
 export GLUON_RELEASE GLUON_REGION GLUON_MULTIDOMAIN GLUON_DEBUG GLUON_DEPRECATED GLUON_DEVICES \
-	 GLUON_TARGETSDIR GLUON_PATCHESDIR GLUON_TMPDIR GLUON_IMAGEDIR GLUON_PACKAGEDIR
+	 GLUON_TARGETSDIR GLUON_PATCHESDIR GLUON_TMPDIR GLUON_IMAGEDIR GLUON_PACKAGEDIR GLUON_AUTOREMOVE
 
 show-release:
 	@echo '$(GLUON_RELEASE)'
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
diff --git a/docs/user/getting_started.rst b/docs/user/getting_started.rst
index 5c542a870faa745396576f9e97eda19dfbabbffd..ee2a98e055d2b2af3b4571544f74eee300ed4871 100644
--- a/docs/user/getting_started.rst
+++ b/docs/user/getting_started.rst
@@ -208,6 +208,12 @@ GLUON_TARGET
 Special variables
 .................
 
+GLUON_AUTOREMOVE
+  Setting ``GLUON_AUTOREMOVE=1`` enables the ``CONFIG_AUTOREMOVE`` OpenWrt setting, which will delete package build
+  directories after a package build has finished to save space. This is mostly useful for CI builds from scratch. Do
+  not set this flag during development (or generally, when you want you reuse your build tree for subsequent builds),
+  as it significantly increases incremental build times.
+
 GLUON_DEBUG
   Setting ``GLUON_DEBUG=1`` will provide firmware images including debugging symbols usable with GDB or
   similar tools. Requires a device or target with at least 16 MB of flash space, e.g. `x86-64`. Unset by default.
diff --git a/targets/generic b/targets/generic
index b437a0269c941efcd1040361c6d143b8d5207604..968798ac84f48e1848277354ff0763471f0bb504 100644
--- a/targets/generic
+++ b/targets/generic
@@ -31,6 +31,7 @@ end
 
 config '# CONFIG_TARGET_ROOTFS_INITRAMFS is not set'
 
+config 'CONFIG_DEVEL=y'
 config 'CONFIG_ALL_NONSHARED=y'
 
 config '# CONFIG_PACKAGE_usbip is not set' -- fails to build
@@ -53,6 +54,10 @@ if envtrue.GLUON_MULTIDOMAIN then
 	config 'CONFIG_GLUON_MULTIDOMAIN=y'
 end
 
+if envtrue.GLUON_AUTOREMOVE then
+	config 'CONFIG_AUTOREMOVE=y'
+end
+
 if envtrue.GLUON_DEBUG then
 	config 'CONFIG_DEBUG=y'
 	config 'CONFIG_NO_STRIP=y'