diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fc456ca
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+4get
diff --git a/Dockerfile b/Dockerfile
new file mode 100755
index 0000000..ebc922b
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,13 @@
+FROM alpine:latest
+
+# Install necessary packages
+RUN apk update && apk upgrade
+RUN apk add php apache2-ssl php83-fileinfo php83-openssl php83-iconv php83-common php83-dom php83-sodium php83-curl curl php83-pecl-apcu php83-apache2 imagemagick php83-pecl-imagick php-mbstring imagemagick-webp imagemagick-jpeg shadow
+
+COPY ./4get /var/www/html/4get/
+COPY ./httpd.conf /etc/apache2/httpd.conf
+COPY ./entrypoint.sh /entrypoint.sh
+COPY ./gen_config.php /gen_config.php
+WORKDIR /var/www/html/4get
+
+CMD ["sh", "-c", "sh /entrypoint.sh"]
diff --git a/entrypoint.sh b/entrypoint.sh
new file mode 100755
index 0000000..6518872
--- /dev/null
+++ b/entrypoint.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+set -e
+
+# Default PUID and PGID
+DEFAULT_PUID=1001
+DEFAULT_PGID=1001
+DEFAULT_PORT=80
+
+# Use provided PUID and PGID or fall back to defaults
+PUID=${PUID:-$DEFAULT_PUID}
+PGID=${PGID:-$DEFAULT_PGID}
+PORT=${PORT:-$DEFAULT_PORT}
+
+echo "Creating container user & group \"abc\" with UID: ${PUID} and GID: ${PGID}..."
+groupadd -g $PGID abc
+useradd -u $PUID -g abc -m abc
+
+echo "Generating 4get data/config.php from env..."
+php /gen_config.php
+
+echo "Setting 4get file permissions..."
+chown -R abc:abc /var/www/html/4get
+chmod -R 771 /var/www/html/4get
+
+echo "Changing port in /etc/apache2/httpd.conf to ${PORT}..."
+sed -i "s/^Listen .*/Listen ${PORT}/" /etc/apache2/httpd.conf
+
+echo "Starting apache2 webserver..."
+echo "4get should be up and running! :)"
+httpd -k start -D FOREGROUND
diff --git a/gen_config.php b/gen_config.php
new file mode 100755
index 0000000..8378ddd
--- /dev/null
+++ b/gen_config.php
@@ -0,0 +1,91 @@
+ getConstants());
+$from_env = array();
+
+$env = getenv();
+$fourget_env = array_filter($env, function($v, $k) {
+ return str_starts_with($k, "FOURGET");
+}, ARRAY_FILTER_USE_BOTH);
+
+foreach($fourget_env as $key => $val) {
+ $target_key = preg_replace('/^FOURGET_/', '', $key);
+ $from_env[$target_key] = trim($val, '\'"');
+};
+
+$merged_config = array_merge($from_config, $from_env);
+
+function type_to_string($n) {
+ $type = gettype($n);
+ if ($type === "NULL") {
+ return "null";
+ }
+ if ($type === "boolean") {
+ return $n ? 'true' : 'false';
+ }
+ if ($type === "string") {
+ if(is_numeric($n)) {
+ return $n;
+ }
+ return "\"$n\"";
+ }
+ if ($type === "array") {
+ return json_encode($n, JSON_UNESCAPED_SLASHES);
+ }
+ return $n;
+}
+
+
+function detect_captcha_dirs() {
+ $captcha_dir = "/var/www/html/4get/data/captcha/";
+ $categories = (array_map(function ($n) {
+ return explode("/", $n)[7];
+ }, glob($captcha_dir . "*")));
+
+
+ $result = array_map(function($category) {
+ return [$category, count(glob("/var/www/html/4get/data/captcha/" . $category . "/*" ))];
+ }, $categories);
+
+ return $result;
+}
+
+
+$special_keys = ["PROTO", "CAPTCHA_DATASET"];
+
+$output = " $val){
+ if(!in_array($key, $special_keys)) {
+ $stored_value = $val;
+ // conversion between arrays and comma separated env value.
+ // Handle case when original type of field is array and there is a type mismatch when a comma separted string is passed,
+ // then split on comma if string (and not numeric, boolean, null, etc)
+ //
+ // except in the case where the inital value in default config is null or boolean. Assuming null and boolean
+ // in default config will be never be assigned an array
+
+ if(gettype($from_config[$key]) != gettype($val) && !is_numeric($val) && !is_null($from_config[$key]) && gettype($from_config[$key]) != "boolean") {
+ $stored_value = explode(",", $val);
+ }
+ $output = $output . "\tconst " . $key . " = " . type_to_string($stored_value) . ";\n";
+
+ continue;
+ }
+
+
+ if($key === "CAPTCHA_DATASET") {
+ $output = $output . "\tconst " . $key . " = " . type_to_string(detect_captcha_dirs()) . ";\n";
+ }
+}
+
+$output = $output . "}\n";
+$output = $output . "?>";
+
+file_put_contents("./data/config.php", $output);
+?>
+
diff --git a/httpd.conf b/httpd.conf
new file mode 100755
index 0000000..4ae4a4c
--- /dev/null
+++ b/httpd.conf
@@ -0,0 +1,98 @@
+Listen 80
+ServerTokens OS
+ServerRoot /var/www
+ServerSignature On
+ServerName localhost
+
+DocumentRoot "/var/www/html/4get"
+
+LogLevel warn
+CustomLog /dev/null common
+ErrorLog /dev/null
+
+
+ RewriteEngine On
+ RewriteCond %{THE_REQUEST} ^\w+\ /(.*)\.php(\?.*)?\ HTTP/
+ RewriteRule ^ http://%{HTTP_HOST}/%1 [R=301]
+ RewriteCond %{REQUEST_FILENAME}.php -f
+ RewriteRule .* $0.php
+ Options FollowSymLinks
+ AllowOverride None
+ Require all granted
+
+
+# deny access to private resources
+
+ Require all denied
+
+ Require all denied
+
+
+
+LoadModule rewrite_module modules/mod_rewrite.so
+LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
+LoadModule authn_file_module modules/mod_authn_file.so
+LoadModule authn_core_module modules/mod_authn_core.so
+LoadModule authz_host_module modules/mod_authz_host.so
+LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
+LoadModule authz_user_module modules/mod_authz_user.so
+LoadModule authz_core_module modules/mod_authz_core.so
+LoadModule access_compat_module modules/mod_access_compat.so
+LoadModule auth_basic_module modules/mod_auth_basic.so
+LoadModule reqtimeout_module modules/mod_reqtimeout.so
+LoadModule filter_module modules/mod_filter.so
+LoadModule mime_module modules/mod_mime.so
+LoadModule log_config_module modules/mod_log_config.so
+LoadModule env_module modules/mod_env.so
+LoadModule headers_module modules/mod_headers.so
+LoadModule setenvif_module modules/mod_setenvif.so
+LoadModule version_module modules/mod_version.so
+LoadModule unixd_module modules/mod_unixd.so
+LoadModule status_module modules/mod_status.so
+LoadModule autoindex_module modules/mod_autoindex.so
+LoadModule dir_module modules/mod_dir.so
+LoadModule alias_module modules/mod_alias.so
+LoadModule negotiation_module modules/mod_negotiation.so
+
+
+User abc
+Group abc
+
+
+
+
+
+ AllowOverride none
+ Require all denied
+
+
+
+
+
+
+ DirectoryIndex index.html
+
+
+
+ Require all denied
+
+
+
+
+
+ RequestHeader unset Proxy early
+
+
+
+ TypesConfig /etc/apache2/mime.types
+ AddType application/x-compress .Z
+ AddType application/x-gzip .gz .tgz
+
+
+
+ MIMEMagicFile /etc/apache2/magic
+
+
+IncludeOptional /etc/apache2/conf.d/*.conf
+
+
diff --git a/rebuild b/rebuild
new file mode 100755
index 0000000..06e550b
--- /dev/null
+++ b/rebuild
@@ -0,0 +1,3 @@
+git clone https://git.lolcat.ca/lolcat/4get.git
+cd 4get; git pull; cd ..
+docker build --no-cache . -t fourget-apache