diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..4f9cefda0776745d43e853a665614dfb02c4c45e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.iml
+/.idea/*
+!/.idea/copyright/
+.DS_Store
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..de3af6cf386723523401061601451beb3ec52943
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,9 @@
+build:
+  stage: build
+  image:
+    name: gcr.io/kaniko-project/executor:debug
+    entrypoint: [""]
+  script:
+    - mkdir -p /kaniko/.docker
+    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
+    - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA} --destination $CI_REGISTRY_IMAGE:latest
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..9a3daca45cd91a628cf5d31eaaeb55ae89a63956
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,73 @@
+FROM alpine:3.15
+RUN apk add --no-cache \
+    nginx \
+    python3 \
+    py3-pip \
+    curl \
+    unzip \
+    php7 \
+    php7-fpm \
+    php7-mbstring \
+    php7-json \
+    php7-xml \
+    php7-dom \
+    php7-curl \
+    php7-exif \
+    php7-gd \
+    php7-iconv \
+    php7-intl \
+    php7-openssl \
+    php7-pdo \
+    php7-pdo_sqlite \
+    php7-pdo_pgsql \
+    php7-pecl-redis \
+    php7-sodium \
+    php7-tidy \
+    php7-pecl-uuid \
+    php7-zip \
+ && rm /etc/nginx/http.d/default.conf \
+ && rm /etc/php7/php-fpm.d/www.conf \
+ && mkdir -p /run/nginx \
+ && mkdir -p /var/www/snappymail \
+ && mkdir -p /config \
+ && pip3 install socrate==0.2.0
+
+# nginx / PHP config files
+COPY config/nginx-snappymail.conf /config/nginx-snappymail.conf
+COPY config/php-snappymail.conf /etc/php7/php-fpm.d/snappymail.conf
+
+# Snappymail login
+COPY login/include.php /var/www/snappymail/include.php
+COPY login/sso.php /var/www/snappymail/sso.php
+
+# Parsing configs moved to startup
+COPY defaults/php.ini /defaults/php.ini
+COPY defaults/application.ini /defaults/application.ini
+COPY defaults/default.ini /defaults/default.ini
+
+ENV APP_VERSION 2.15.1
+ENV SNAPPYMAIL_URL https://github.com/the-djmaze/snappymail/releases/download/v$APP_VERSION/snappymail-$APP_VERSION.zip
+
+# Install Snappymail from source
+
+RUN apk add --no-cache \
+      curl unzip \
+ && cd /var/www/snappymail \
+ && curl -L -O ${SNAPPYMAIL_URL} \
+ && unzip -q *.zip \
+ && rm -f *.zip \
+ && rm -rf data/ \
+ && find . -type d -exec chmod 755 {} \; \
+ && find . -type f -exec chmod 644 {} \; \
+ && chown -R nginx:nginx /var/www/snappymail \
+ && apk del unzip
+
+COPY start.py /start.py
+COPY config.py /config.py
+
+EXPOSE 80/tcp
+VOLUME ["/data"]
+
+ENTRYPOINT ["/start.py"]
+
+HEALTHCHECK CMD curl -f -L http://localhost/ || exit 1
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1949a53a90813eeb4dd4499fcd0ca9d00aa2a68c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,14 @@
+IMAGE := k8r.eu/justjanne/$(shell basename $(shell git remote get-url origin) .git)
+TAGS := $(shell git describe --always --tags HEAD)
+
+.PHONY: build
+build:
+	docker build --pull -t $(IMAGE):$(TAGS) .
+	docker tag $(IMAGE):$(TAGS) $(IMAGE):latest
+	@echo Successfully tagged $(IMAGE):$(TAGS) as latest
+
+.PHONY: push
+push: build
+	docker push $(IMAGE):$(TAGS)
+	docker push $(IMAGE):latest
+	@echo Successfully pushed $(IMAGE):$(TAGS) as latest
diff --git a/config.py b/config.py
new file mode 100755
index 0000000000000000000000000000000000000000..ec6f51510af3778b98e4a88f95d383c4dc79876c
--- /dev/null
+++ b/config.py
@@ -0,0 +1,15 @@
+#!/usr/bin/python3
+
+import os
+import logging as log
+import sys
+from socrate import system, conf
+
+args = os.environ.copy()
+
+log.basicConfig(stream=sys.stderr, level=args.get("LOG_LEVEL", "WARNING"))
+
+# Build final configuration paths
+conf.jinja("/config/nginx-snappymail.conf", args, "/etc/nginx/http.d/snappymail.conf")
+if os.path.exists("/var/run/nginx.pid"):
+    os.system("nginx -s reload")
diff --git a/config/nginx-snappymail.conf b/config/nginx-snappymail.conf
new file mode 100644
index 0000000000000000000000000000000000000000..374a65794fbc0d026e6c79fd5fac10226e4cfa23
--- /dev/null
+++ b/config/nginx-snappymail.conf
@@ -0,0 +1,46 @@
+server {
+    listen 80 default_server;
+    listen [::]:80 default_server;
+
+    root /var/www/snappymail;
+
+    # /dev/stdout (Default), <path>, off
+    access_log off;
+
+    # /dev/stderr (Default), <path>, debug, info, notice, warn, error, crit, alert, emerg
+    error_log /dev/stderr warn;
+
+    index index.php;
+
+    # set maximum body size to configured limit
+    client_max_body_size {{ MESSAGE_SIZE_LIMIT|int + 8388608 }};
+
+    location /healthz {
+        access_log off;
+        return 200 "OK\n";
+    }
+
+    location / {
+        try_files $uri /index.php?$query_string;
+    }
+
+    location ~ \.php$ {
+        fastcgi_split_path_info ^(.+\.php)(/.*)$;
+
+        fastcgi_intercept_errors on;
+        fastcgi_index  index.php;
+
+        fastcgi_keep_conn on;
+        include /etc/nginx/fastcgi_params;
+        fastcgi_pass unix:/var/run/php7-fpm.sock;
+        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+    }
+
+    location ~ /\.ht {
+        deny all;
+    }
+
+    location ^~ /data {
+        deny all;
+    }
+}
diff --git a/config/php-snappymail.conf b/config/php-snappymail.conf
new file mode 100644
index 0000000000000000000000000000000000000000..d60104007c6dbc8cbbfed6cef3d37f67a517b24c
--- /dev/null
+++ b/config/php-snappymail.conf
@@ -0,0 +1,101 @@
+; Start a new pool named 'snappymail'.
+; the variable $pool can be used in any directive and will be replaced by the
+; pool name ('snappymail' here)
+[snappymail]
+
+; Redirect worker stdout and stderr into main error log. If not set, stdout and 
+; stderr will be redirected to /dev/null according to FastCGI specs. 
+; Default value: no. 
+catch_workers_output = 1
+
+; Unix user/group of processes
+; Note: The user is mandatory. If the group is not set, the default user's group
+;       will be used.
+user = nginx
+group = nginx
+
+; The address on which to accept FastCGI requests.
+; Valid syntaxes are:
+;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific IPv4 address on
+;                            a specific port;
+;   '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
+;                            a specific port;
+;   'port'                 - to listen on a TCP socket to all addresses
+;                            (IPv6 and IPv4-mapped) on a specific port;
+;   '/path/to/unix/socket' - to listen on a unix socket.
+; Note: This value is mandatory.
+listen = /var/run/php7-fpm.sock
+
+; Set permissions for unix socket, if one is used. In Linux, read/write
+; permissions must be set in order to allow connections from a web server. Many
+; BSD-derived systems allow connections regardless of permissions.
+; Default Values: user and group are set as the running user
+;                 mode is set to 0660
+listen.owner = nginx
+listen.group = nginx
+listen.mode = 0660
+
+; Choose how the process manager will control the number of child processes.
+; Possible Values:
+;   static  - a fixed number (pm.max_children) of child processes;
+;   dynamic - the number of child processes are set dynamically based on the
+;             following directives. With this process management, there will be
+;             always at least 1 children.
+;             pm.max_children      - the maximum number of children that can
+;                                    be alive at the same time.
+;             pm.start_servers     - the number of children created on startup.
+;             pm.min_spare_servers - the minimum number of children in 'idle'
+;                                    state (waiting to process). If the number
+;                                    of 'idle' processes is less than this
+;                                    number then some children will be created.
+;             pm.max_spare_servers - the maximum number of children in 'idle'
+;                                    state (waiting to process). If the number
+;                                    of 'idle' processes is greater than this
+;                                    number then some children will be killed.
+;  ondemand - no children are created at startup. Children will be forked when
+;             new requests will connect. The following parameter are used:
+;             pm.max_children           - the maximum number of children that
+;                                         can be alive at the same time.
+;             pm.process_idle_timeout   - The number of seconds after which
+;                                         an idle process will be killed.
+; Note: This value is mandatory.
+pm = ondemand
+
+; The number of child processes to be created when pm is set to 'static' and the
+; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
+; This value sets the limit on the number of simultaneous requests that will be
+; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
+; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
+; CGI. The below defaults are based on a server without much resources. Don't
+; forget to tweak pm.* to fit your needs.
+; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
+; Note: This value is mandatory.
+pm.max_children = 5
+
+; The number of child processes created on startup.
+; Note: Used only when pm is set to 'dynamic'
+; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2
+; pm.start_servers = 2
+
+; The desired minimum number of idle server processes.
+; Note: Used only when pm is set to 'dynamic'
+; Note: Mandatory when pm is set to 'dynamic'
+; pm.min_spare_servers = 1
+
+; The desired maximum number of idle server processes.
+; Note: Used only when pm is set to 'dynamic'
+; Note: Mandatory when pm is set to 'dynamic'
+; pm.max_spare_servers = 3
+
+; This sets the maximum time in seconds a script is allowed to run before it is 
+; terminated by the parser. This helps prevent poorly written scripts from tying up 
+; the server. The default setting is 30s.
+; Note: Used only when pm is set to 'ondemand'
+pm.process_idle_timeout = 10s
+
+; The number of requests each child process should execute before respawning. 
+; This can be useful to work around memory leaks in 3rd party libraries. For endless
+; request processing specify '0'.
+; Equivalent to PHP_FCGI_MAX_REQUESTS. Default value: 0.
+; Noted: Used only when pm is set to 'ondemand'
+pm.max_requests = 200
diff --git a/defaults/application.ini b/defaults/application.ini
new file mode 100644
index 0000000000000000000000000000000000000000..bdcd86e2490965f9bd76df4c321d0d62b24ebddf
--- /dev/null
+++ b/defaults/application.ini
@@ -0,0 +1,19 @@
+; snappymail Webmail configuration file
+
+[webmail]
+attachment_size_limit = {{ MAX_FILESIZE }}
+
+[security]
+allow_admin_panel = Off
+
+[labs]
+allow_gravatar = Off
+custom_login_link='sso.php'
+custom_logout_link='/sso/logout'
+
+[contacts]
+enable = On
+allow_sync = On
+
+[defaults]
+contacts_autosave = On
diff --git a/defaults/default.ini b/defaults/default.ini
new file mode 100644
index 0000000000000000000000000000000000000000..be9a0969244aabe360f4dfbfbf086584eb413e43
--- /dev/null
+++ b/defaults/default.ini
@@ -0,0 +1,15 @@
+imap_host = "{{ FRONT_ADDRESS }}"
+imap_port = 10143
+imap_secure = "None"
+imap_short_login = Off
+sieve_use = On
+sieve_allow_raw = Off
+sieve_host = "{{ IMAP_ADDRESS }}"
+sieve_port = 4190
+sieve_secure = "None"
+smtp_host = "{{ FRONT_ADDRESS }}"
+smtp_port = 10025
+smtp_secure = "None"
+smtp_short_login = Off
+smtp_auth = On
+smtp_php_mail = Off
diff --git a/defaults/php.ini b/defaults/php.ini
new file mode 100644
index 0000000000000000000000000000000000000000..012e4af2810779982570f0b9d09875799724951b
--- /dev/null
+++ b/defaults/php.ini
@@ -0,0 +1,4 @@
+expose_php=Off
+date.timezone=UTC
+upload_max_filesize = {{ MAX_FILESIZE }}M
+post_max_size = {{ MAX_FILESIZE }}M
diff --git a/login/include.php b/login/include.php
new file mode 100644
index 0000000000000000000000000000000000000000..fde913247109583b106287907d8b0318c04d8c05
--- /dev/null
+++ b/login/include.php
@@ -0,0 +1,19 @@
+<?php
+
+// Rename this file to "include.php" to enable it.
+
+/**
+ * @return string
+ */
+function __get_custom_data_full_path()
+{
+	return '/data/'; // custom data folder path
+}
+
+/**
+ * @return string
+ */
+function __get_additional_configuration_name()
+{
+	return 'application.ini';
+}
diff --git a/login/sso.php b/login/sso.php
new file mode 100644
index 0000000000000000000000000000000000000000..ace5ce1844f9720eb3857ad25873d0fffc0b04bb
--- /dev/null
+++ b/login/sso.php
@@ -0,0 +1,16 @@
+<?php
+
+$_ENV['SNAPPYMAIL_INCLUDE_AS_API'] = true;
+include "index.php";
+
+// Retrieve email and password
+if (isset($_SERVER['HTTP_X_REMOTE_USER']) && isset($_SERVER['HTTP_X_REMOTE_USER_TOKEN'])) {
+	$email = $_SERVER['HTTP_X_REMOTE_USER'];
+	$password = $_SERVER['HTTP_X_REMOTE_USER_TOKEN'];
+	$ssoHash = \RainLoop\Api::CreateUserSsoHash($email, $password);
+
+	// redirect to webmail sso url
+	header('Location: /?sso&hash='.$ssoHash);
+} else {
+	header('HTTP/1.0 403 Forbidden');
+}
diff --git a/start.py b/start.py
new file mode 100755
index 0000000000000000000000000000000000000000..af1ef34cdad4ceefe993aee6ee777c7311f86d24
--- /dev/null
+++ b/start.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python3
+
+import os
+import shutil
+import logging as log
+import sys
+import subprocess
+from socrate import system, conf
+
+log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING"))
+
+# Actual startup script
+os.environ["FRONT_ADDRESS"] = system.resolve_address(os.environ.get("HOST_FRONT", "front"))
+os.environ["IMAP_ADDRESS"] = system.resolve_address(os.environ.get("HOST_IMAP", "imap"))
+
+os.environ["MAX_FILESIZE"] = str(int(int(os.environ.get("MESSAGE_SIZE_LIMIT"))*0.66/1048576))
+
+base = "/data/_data_/_default_/"
+shutil.rmtree(base + "domains/", ignore_errors=True)
+os.makedirs(base + "domains", exist_ok=True)
+os.makedirs(base + "configs", exist_ok=True)
+
+conf.jinja("/defaults/default.ini", os.environ, "/data/_data_/_default_/domains/default.ini")
+conf.jinja("/defaults/application.ini", os.environ, "/data/_data_/_default_/configs/application.ini")
+conf.jinja("/defaults/php.ini", os.environ, "/etc/php7/php.ini")
+# Start the fastcgi process manager now that config files have been adjusted
+os.system("php-fpm7")
+
+os.system("chown -R nginx:nginx /data")
+os.system("chmod -R a+rX /var/www/snappymail/")
+
+subprocess.call(["/config.py"])
+os.execv("/usr/sbin/nginx", ["nginx", "-g", "daemon off;"])