diff --git a/.github/workflows/full-test.yaml b/.github/workflows/full-test.yaml
deleted file mode 100644
index eb36e70732d05a4eff9a8c33f2efae95c74cf3ac..0000000000000000000000000000000000000000
--- a/.github/workflows/full-test.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-name: full-test
-on: [push]
-
-
-jobs:
-
-  native-build:
-    runs-on: ubuntu-latest
-    steps:
-    
-      - name: Checkout repository
-        uses: actions/checkout@v4
-        with:
-          submodules: recursive
-
-      - name: Install required packages
-        run: sudo $GITHUB_WORKSPACE/.ci_scripts/native-build/install_packages.sh
-
-      - name: Build project with CMake
-        run: $GITHUB_WORKSPACE/build.sh -C $GITHUB_WORKSPACE
-
-      - name: Run CUnit tests
-        run: $GITHUB_WORKSPACE/.ci_scripts/native-build/run_tests.sh
-
-      - name: Run Valgrind on CUnit tests
-        run: $GITHUB_WORKSPACE/.ci_scripts/native-build/run_tests.sh valgrind
-
-      - name: Run cppcheck on source files
-        run: $GITHUB_WORKSPACE/.ci_scripts/native-build/run_cppcheck.sh
-      
-      - name: Add NFTables rules
-        run:  $GITHUB_WORKSPACE/.ci_scripts/native-build/add_nft_rules.sh
-
-      - name: Run NFQueue executables
-        run: $GITHUB_WORKSPACE/.ci_scripts/native-build/run_exec.sh
-
-
-  cross-compile:
-    runs-on: ubuntu-latest
-    container: fdekeers/openwrt_tl-wdr4900_gha
-
-    steps:
-
-      - name: Checkout repository
-        uses: actions/checkout@v4
-        with:
-          submodules: recursive
-
-      - name: Run cross-compilation
-        run: $GITHUB_WORKSPACE/build.sh -C $GITHUB_WORKSPACE -t $GITHUB_WORKSPACE/openwrt/tl-wdr4900.cmake
diff --git a/.gitlab-ci.yaml b/.gitlab-ci.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d2f4e93e1b32c4dd22ac6984bc055afff779c336
--- /dev/null
+++ b/.gitlab-ci.yaml
@@ -0,0 +1,20 @@
+variables:
+  GIT_SUBMODULE_STRATEGY: recursive
+
+
+# Natively build and test the project
+job-native-build:
+  script:
+    - sudo .ci_scripts/native-build/install_packages.sh
+    - firewall/build.sh -C firewall
+    - .ci_scripts/native-build/run_tests.sh
+    - .ci_scripts/native-build/run_tests.sh valgrind
+    - .ci_scripts/native-build/run_cppcheck.sh
+    - .ci_scripts/native-build/add_nft_rules.sh
+    - .ci_scripts/native-build/run_exec.sh
+
+
+# Cross-compile the project for the TL-WDR4900 router
+job-cross-compilation:
+  script:
+    - docker compose run cross-compilation /home/user/iot-firewall/docker_cmd.sh tl-wdr4900 $(id -u $USER) $(id -g $USER)
diff --git a/.ci_scripts/cross-compile/Dockerfile b/Dockerfile
similarity index 78%
rename from .ci_scripts/cross-compile/Dockerfile
rename to Dockerfile
index e75b90f70fc0e7859242ab766c50db41d8728bed..79c173b9886a77d4c0eb8b9b8e6043f7ba2f4639 100644
--- a/.ci_scripts/cross-compile/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,5 @@
 # Dockerfile describing the container used to
-# cross-compile the projet for OpenWrt,
-# in GitHub Actions.
+# cross-compile the projet for OpenWrt.
 # The default platform is the TP-Link WDR4900.
 
 # Base image: Ubuntu 22.04 LTS
@@ -13,8 +12,7 @@ ARG TOOLCHAIN_DIR=toolchain-powerpc_8540_gcc-11.2.0_musl
 ARG TARGET_DIR=target-powerpc_8540_musl
 
 # Set initial working directory
-ENV HOME=/root
-WORKDIR ${HOME}
+WORKDIR /
 
 # Install dependencies
 RUN apt-get update && \
@@ -36,8 +34,16 @@ RUN apt-get update && \
     zlib1g-dev \
     file \
     wget \
-    cmake \
-    python3-pip
+    cmake
+
+# Create non-root user
+ARG USER=user
+ARG UID=1000
+ARG HOME=/home/${USER}
+RUN groupadd --gid ${UID} ${USER} && \
+    useradd --uid ${UID} --gid ${UID} -m ${USER} -s /bin/bash
+USER ${USER}
+WORKDIR ${HOME}
 
 # Clone OpenWrt repository
 ENV OPENWRT_HOME=${HOME}/openwrt
@@ -50,8 +56,7 @@ RUN ${OPENWRT_HOME}/scripts/feeds update -a
 RUN ${OPENWRT_HOME}/scripts/feeds install -a
 
 # Configure OpenWrt toolchain
-COPY openwrt/${ROUTER}/config/config-minimal ${OPENWRT_HOME}/.config
-ENV FORCE_UNSAFE_CONFIGURE=1
+COPY --chown=$USER:$USER openwrt/${ROUTER}/config-minimal ${OPENWRT_HOME}/.config
 RUN make defconfig
 RUN make download
 RUN make -j $(($(nproc)+1))
@@ -62,5 +67,6 @@ ENV C_INCLUDE_PATH=${TARGET_PATH}/usr/include
 ENV LD_LIBRARY_PATH=${TARGET_PATH}/usr/lib
 ENV PATH=${TOOLCHAIN_PATH}/bin:$PATH
 
-# Get ready for next steps
-WORKDIR ${HOME}
+# Switch back to root user
+USER root
+WORKDIR /root
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 425a82e07ac3d23b1f316f54c40f0d55b972dbeb..70b0f20b48ef7ce25fe40f39029930dd9eeceb4e 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -1,5 +1,5 @@
 services:
-  openwrt:
+  cross-compilation:
     image: fdekeers/openwrt_tl-wdr4900
     #image: fdekeers/openwrt_linksys-wrt1200ac
     container_name: openwrt-firewall
@@ -8,6 +8,6 @@ services:
       #- ROUTER=linksys-wrt1200ac
     volumes:
       - .:/home/user/iot-firewall
-    command: ["/home/user/iot-firewall/build.sh", "-t", "/home/user/iot-firewall/openwrt/tl-wdr4900.cmake"]
-    #command: ["/home/user/iot-firewall/build.sh", "-t", "/home/user/iot-firewall/openwrt/linksys-wrt1200ac.cmake"]
+    command: ["/home/user/iot-firewall/docker_cmd.sh", "tl-wdr4900", "1000", "1000"]
+    #command: ["/home/user/iot-firewall/docker_cmd.sh", "linksys-wrt1200ac", "1000", "1000"]
     restart: no
diff --git a/docker_cmd.sh b/docker_cmd.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ed43159fab1ad2389b1a5fdb20d08cc8a2cf7c36
--- /dev/null
+++ b/docker_cmd.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+# Script to run inside the cross-compilation Docker container.
+
+
+# Base directory
+BASE_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
+
+
+### ARGUMENTS ###
+
+# Print usage information
+usage() {
+    echo "Usage: $0 ROUTER NEW_ID NEW_GID" 1>&2
+    exit 1
+}
+
+# Verify number of arguments
+if [[ $# -ne 2 ]] && [[ $# -ne 3 ]]; then
+    usage
+fi
+
+## Get command line arguments
+ROUTER=$1
+NEW_UID=$2
+# GID (optional)
+# If not provided, equal to UID
+if [[ $# -eq 2 ]]; then
+    NEW_GID=$NEW_UID
+elif [[ $# -eq 3 ]]; then
+    NEW_GID=$3
+fi
+
+
+### MAIN ###
+
+# Cross-compile sources
+"$BASE_DIR"/build.sh -C "$BASE_DIR" -t "$BASE_DIR"/firewall/openwrt/$ROUTER/$ROUTER.cmake
+
+# Change perimissions
+ROOT_UID=0
+for DIR in build bin; do
+    DIR="$BASE_DIR"/$DIR
+    find $DIR -uid $ROOT_UID -exec chown -h $NEW_UID {} \;
+    find $DIR -gid $ROOT_UID -exec chgrp -h $NEW_GID {} \;
+done