diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..ae7657814edf25d36f36403c8007c748af3087b2
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,3 @@
+/.gitlab-ci.yml
+/.hadolint.yaml
+/README.md
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/.hadolint.yaml b/.hadolint.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..95c61c4f41e871fc45b70806ce0ffe9101e0407f
--- /dev/null
+++ b/.hadolint.yaml
@@ -0,0 +1,3 @@
+ignored:
+  - DL3008
+  - DL3018
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..7b3b2d853174aa9fedeef08c615a6957269db164
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,15 @@
+FROM registry.cyberbrain.pw/docker/alpine:latest
+
+WORKDIR /tmp/openwrt
+
+ENTRYPOINT [ "sh", "/entrypoint.sh" ]
+
+RUN set -ex && \
+    apk --no-cache add sudo git rsync openssh-client && \
+    rm -rf /var/cache/apk/* && \
+    addgroup -S openwrt && \
+    adduser -S openwrt -G openwrt -h /home/openwrt && \
+    chown -R openwrt:openwrt /tmp/openwrt
+
+COPY entrypoint.sh /entrypoint.sh
+COPY sync.sh /sync.sh
diff --git a/entrypoint.sh b/entrypoint.sh
new file mode 100644
index 0000000000000000000000000000000000000000..f4f39dafa876cdb0b0dcc4d38108b100f0ada2dd
--- /dev/null
+++ b/entrypoint.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env sh
+
+die() {
+    RED='\033[0;31m'
+    NC='\033[0m' # No Color
+    echo -e '\[ '"${RED}$1${NC}"' ]/'
+    exit 1
+}
+
+rsync -a /opt/ /home/openwrt/.ssh/ || die "Couldn't rsync user ssh settings"
+chown -R openwrt:openwrt /home/openwrt/.ssh || die "Couldn't change ownership for user ssh settings"
+chmod -R a-rwx,u+rwX /home/openwrt/.ssh || die "Couldn't change access rights for user ssh settings"
+
+exec sudo -u openwrt -g openwrt -E -H sh -c 'exec sh /sync.sh' || die "Couldn't run sync sript as user"
diff --git a/sync.sh b/sync.sh
new file mode 100644
index 0000000000000000000000000000000000000000..28daa28468fb29d1a4bb72c6a954c122ee9106b5
--- /dev/null
+++ b/sync.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env sh
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[0;33m'
+BLUE='\033[0;34m'
+NC='\033[39m' # No Color
+
+die() {
+    echo -e '[ '"${RED}$1${NC}"' ]'
+    exit 1
+}
+
+warning() {
+    echo -e '[ '"${YELLOW}$1${NC}"' ]'
+}
+
+notify() {
+    echo -e '[ '"${BLUE}$1${NC}"' ]'
+}
+
+success() {
+    echo -e '[ '"${GREEN}$1${NC}"' ]'
+}
+
+warning "Starting at $(date -u)"
+
+find overlay/ -type f -name .gitkeep -delete
+
+LC_ALL=C.UTF-8 rsync -avn --delete-after --exclude '*-opkg' -e "ssh -p ${OPENWRT_SSH_PORT:-22}" overlay/ "${OPENWRT_SSH_HOST:-root@192.168.0.1}:/overlay/upper/" || die "Couldn't rsync config"