diff --git a/.woodpecker.yml b/.woodpecker.yml
index ceb5737..51f8375 100644
--- a/.woodpecker.yml
+++ b/.woodpecker.yml
@@ -9,6 +9,8 @@ pipeline:
     build_args:
     - ALPINE_VERSION=${ALPINE_VERSION}
     - BASE_IMAGE=registry.nulo.in/sutty/monit
+    - GEOIP2_DATABASE=https://archive.archlinux.org/packages/g/geoip2-database/geoip2-database-20191203-1-any.pkg.tar.xz 
+    - CRAWLERS=https://raw.githubusercontent.com/monperrus/crawler-user-agents/master/crawler-user-agents.json
     username: sutty
     secrets:
     - docker_password
diff --git a/Dockerfile b/Dockerfile
index d93a8d9..0e3337f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,3 +2,44 @@ ARG ALPINE_VERSION=3.13.6
 ARG BASE_IMAGE=sutty/monit
 FROM ${BASE_IMAGE}:${ALPINE_VERSION}
 MAINTAINER "f <f@sutty.nl>"
+
+ARG GEOIP2_DATABASE
+ARG CRAWLERS
+ARG ACCESS_LOGS_FLAGS="--database=sqlite3:///root/development.sqlite3"
+
+ENV ACCESS_LOGS_FLAGS=${ACCESS_LOGS_FLAGS}
+
+# Install nginx and remove default config
+RUN apk add --no-cache nginx daemonize access_log nginx-prometheus-exporter \
+    && rm -rf /etc/nginx
+
+# Add ssl group so nginx has access to certificates
+RUN addgroup -S -g 777 ssl
+RUN addgroup nginx ssl
+
+# Databases
+RUN wget "${CRAWLERS}" -O /tmp/crawler-user-agents.json
+RUN wget ${GEOIP2_DATABASE} -O - | tar -xJf - \
+  && rm usr/share/GeoIP/GeoLite2-ASN.mmdb .BUILDINFO .MTREE .PKGINFO
+
+COPY ./monit.conf /etc/monit.d/nginx.conf
+COPY ./prometheusd.sh /usr/local/bin/prometheusd
+COPY ./nginx /etc/nginx
+
+# Install modules after rewriting /etc/nginx
+RUN apk add --no-cache nginx-mod-http-brotli nginx-mod-http-geoip2
+
+# Add support for request_uri parsing if access_log >= 0.3.0
+RUN mv /etc/nginx/access_logd_`access_log -v`.conf /etc/nginx/access_logd.conf
+RUN chown -R nginx:nginx /etc/nginx
+RUN nginx -t
+
+# Shared configuration
+VOLUME /etc/nginx/sites
+VOLUME /etc/letsencrypt
+VOLUME /var/lib/letsencrypt
+
+EXPOSE 80
+EXPOSE 443
+EXPOSE 443/udp
+EXPOSE 9113
diff --git a/monit.conf b/monit.conf
new file mode 100644
index 0000000..7c860eb
--- /dev/null
+++ b/monit.conf
@@ -0,0 +1,12 @@
+check process access_log with pidfile /run/access_logd.pid
+  start program = "/usr/bin/access_logd"
+  stop program = "/usr/bin/access_logd stop"
+
+check process nginx with pidfile /run/nginx.pid
+  start program = "/usr/sbin/nginx"
+  stop  program = "/usr/sbin/nginx -s stop"
+  if failed host localhost port 80 3 times within 5 cycles then restart
+
+check process prometheus with pidfile /tmp/prometheus.pid
+  start program = "/usr/local/bin/prometheusd start"
+   stop program = "/usr/local/bin/prometheusd stop"
diff --git a/nginx/access_logd_0.2.0.conf b/nginx/access_logd_0.2.0.conf
new file mode 100644
index 0000000..0f95d89
--- /dev/null
+++ b/nginx/access_logd_0.2.0.conf
@@ -0,0 +1 @@
+log_format access_logd escape=json '{"host":"$host","msec":$msec,"server_protocol":"$server_protocol","request_method":"$request_method","request_completion":"$request_completion","uri":"$uri","query_string":"$query_string","status":$status,"sent_http_content_type":"$sent_http_content_type","sent_http_content_encoding":"$sent_http_content_encoding","sent_http_etag":"$sent_http_etag","sent_http_last_modified":"$sent_http_last_modified","http_accept":"$http_accept","http_accept_encoding":"$http_accept_encoding","http_accept_language":"$http_accept_language","http_pragma":"$http_pragma","http_cache_control":"$http_cache_control","http_if_none_match":"$http_if_none_match","http_dnt":"$http_dnt","http_user_agent":"$http_user_agent","http_origin":"$http_origin","http_referer":{"origin":"$http_origin","referrer":"$http_referer","policy":"origin-when-cross-origin"},"request_time":$request_time,"bytes_sent":$bytes_sent,"body_bytes_sent":$body_bytes_sent,"request_length":$request_length,"http_connection":"$http_connection","pipe":"$pipe","connection_requests":$connection_requests,"geoip2_data_country_name":"$geoip2_data_country_name","geoip2_data_city_name":"$geoip2_data_city_name","ssl_server_name":"$ssl_server_name","ssl_protocol":"$ssl_protocol","ssl_early_data":"$ssl_early_data","ssl_session_reused":"$ssl_session_reused","ssl_curves":"$ssl_curves","ssl_ciphers":"$ssl_ciphers","ssl_cipher":"$ssl_cipher","sent_http_x_xss_protection":"$sent_http_x_xss_protection","sent_http_x_frame_options":"$sent_http_x_frame_options","sent_http_x_content_type_options":"$sent_http_x_content_type_options","sent_http_strict_transport_security":"$sent_http_strict_transport_security","nginx_version":"$nginx_version","pid":"$pid","remote_user":"$remote_user"}';
diff --git a/nginx/access_logd_0.3.0.conf b/nginx/access_logd_0.3.0.conf
new file mode 100644
index 0000000..645d731
--- /dev/null
+++ b/nginx/access_logd_0.3.0.conf
@@ -0,0 +1 @@
+log_format access_logd escape=json '{"host":"$host","msec":$msec,"server_protocol":"$server_protocol","request_method":"$request_method","request_completion":"$request_completion","uri":"$uri","query_string":"$query_string","status":$status,"sent_http_content_type":"$sent_http_content_type","sent_http_content_encoding":"$sent_http_content_encoding","sent_http_etag":"$sent_http_etag","sent_http_last_modified":"$sent_http_last_modified","http_accept":"$http_accept","http_accept_encoding":"$http_accept_encoding","http_accept_language":"$http_accept_language","http_pragma":"$http_pragma","http_cache_control":"$http_cache_control","http_if_none_match":"$http_if_none_match","http_dnt":"$http_dnt","http_user_agent":"$http_user_agent","http_origin":"$http_origin","http_referer":{"origin":"$http_origin","referrer":"$http_referer","policy":"origin-when-cross-origin"},"request_time":$request_time,"bytes_sent":$bytes_sent,"body_bytes_sent":$body_bytes_sent,"request_length":$request_length,"http_connection":"$http_connection","pipe":"$pipe","connection_requests":$connection_requests,"geoip2_data_country_name":"$geoip2_data_country_name","geoip2_data_city_name":"$geoip2_data_city_name","ssl_server_name":"$ssl_server_name","ssl_protocol":"$ssl_protocol","ssl_early_data":"$ssl_early_data","ssl_session_reused":"$ssl_session_reused","ssl_curves":"$ssl_curves","ssl_ciphers":"$ssl_ciphers","ssl_cipher":"$ssl_cipher","sent_http_x_xss_protection":"$sent_http_x_xss_protection","sent_http_x_frame_options":"$sent_http_x_frame_options","sent_http_x_content_type_options":"$sent_http_x_content_type_options","sent_http_strict_transport_security":"$sent_http_strict_transport_security","nginx_version":"$nginx_version","pid":"$pid","remote_user":"$remote_user","request_uri":"$request_uri"}';
diff --git a/nginx/dhparam.pem b/nginx/dhparam.pem
new file mode 100644
index 0000000..088f967
--- /dev/null
+++ b/nginx/dhparam.pem
@@ -0,0 +1,8 @@
+-----BEGIN DH PARAMETERS-----
+MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
+87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
+YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
+7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
+ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
+-----END DH PARAMETERS-----
\ No newline at end of file
diff --git a/nginx/maps/redirect_to_https.conf b/nginx/maps/redirect_to_https.conf
new file mode 100644
index 0000000..bad436a
--- /dev/null
+++ b/nginx/maps/redirect_to_https.conf
@@ -0,0 +1,5 @@
+map "$scheme:$uri" $redirect_to_https {
+  default 1;
+  ~^https: 0;
+  ~:/.well-known/acme-challenge/ 0;
+}
diff --git a/nginx/mime.types b/nginx/mime.types
new file mode 100644
index 0000000..4de7c52
--- /dev/null
+++ b/nginx/mime.types
@@ -0,0 +1,95 @@
+types {
+  text/html                                        html htm shtml;
+  text/css                                         css;
+  text/xml                                         xml;
+  image/gif                                        gif;
+  image/jpeg                                       jpeg jpg;
+  application/javascript                           js;
+  application/atom+xml                             atom;
+  application/rss+xml                              rss;
+
+  text/mathml                                      mml;
+  text/plain                                       txt yaml yml;
+  text/vnd.sun.j2me.app-descriptor                 jad;
+  text/vnd.wap.wml                                 wml;
+  text/x-component                                 htc;
+
+  image/png                                        png;
+  image/svg+xml                                    svg svgz;
+  image/tiff                                       tif tiff;
+  image/vnd.wap.wbmp                               wbmp;
+  image/webp                                       webp;
+  image/x-icon                                     ico;
+  image/x-jng                                      jng;
+  image/x-ms-bmp                                   bmp;
+
+  application/epub+zip                             epub epub3;
+  application/font-woff                            woff;
+  application/java-archive                         jar war ear;
+  application/json                                 json;
+  application/mac-binhex40                         hqx;
+  application/msword                               doc;
+  application/pdf                                  pdf;
+  application/postscript                           ps eps ai;
+  application/rtf                                  rtf;
+  application/vnd.apple.mpegurl                    m3u8;
+  application/vnd.google-earth.kml+xml             kml;
+  application/vnd.google-earth.kmz                 kmz;
+  application/vnd.ms-excel                         xls;
+  application/vnd.ms-fontobject                    eot;
+  application/vnd.ms-powerpoint                    ppt;
+  application/vnd.oasis.opendocument.graphics      odg;
+  application/vnd.oasis.opendocument.presentation  odp;
+  application/vnd.oasis.opendocument.spreadsheet   ods;
+  application/vnd.oasis.opendocument.text          odt;
+  application/vnd.openxmlformats-officedocument.presentationml.presentation
+                                                   pptx;
+  application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
+                                                   xlsx;
+  application/vnd.openxmlformats-officedocument.wordprocessingml.document
+                                                   docx;
+  application/vnd.wap.wmlc                         wmlc;
+  application/x-7z-compressed                      7z;
+  application/x-cocoa                              cco;
+  application/x-java-archive-diff                  jardiff;
+  application/x-java-jnlp-file                     jnlp;
+  application/x-makeself                           run;
+  application/x-perl                               pl pm;
+  application/x-pilot                              prc pdb;
+  application/x-rar-compressed                     rar;
+  application/x-redhat-package-manager             rpm;
+  application/x-sea                                sea;
+  application/x-shockwave-flash                    swf;
+  application/x-stuffit                            sit;
+  application/x-tcl                                tcl tk;
+  application/x-x509-ca-cert                       der pem crt;
+  application/x-xpinstall                          xpi;
+  application/xhtml+xml                            xhtml;
+  application/xspf+xml                             xspf;
+  application/zip                                  zip;
+
+  application/octet-stream                         bin exe dll;
+  application/octet-stream                         deb;
+  application/octet-stream                         dmg;
+  application/octet-stream                         iso img;
+  application/octet-stream                         msi msp msm;
+
+  audio/midi                                       mid midi kar;
+  audio/mpeg                                       mp3;
+  audio/ogg                                        ogg;
+  audio/x-m4a                                      m4a;
+  audio/x-realaudio                                ra;
+
+  video/3gpp                                       3gpp 3gp;
+  video/mp2t                                       ts;
+  video/mp4                                        mp4;
+  video/mpeg                                       mpeg mpg;
+  video/quicktime                                  mov;
+  video/webm                                       webm;
+  video/x-flv                                      flv;
+  video/x-m4v                                      m4v;
+  video/x-mng                                      mng;
+  video/x-ms-asf                                   asx asf;
+  video/x-ms-wmv                                   wmv;
+  video/x-msvideo                                  avi;
+}
diff --git a/nginx/nginx.conf b/nginx/nginx.conf
new file mode 100644
index 0000000..06105b0
--- /dev/null
+++ b/nginx/nginx.conf
@@ -0,0 +1,58 @@
+user nginx nginx;
+worker_processes auto;
+pid /run/nginx.pid;
+
+include /etc/nginx/modules/*.conf;
+
+events {
+  worker_connections 1024;
+}
+
+http {
+  charset utf-8;
+
+  include mime.types;
+  include snippets/privacy.conf;
+  include snippets/brotli.conf;
+  include snippets/gzip.conf;
+  include access_logd.conf;
+
+  resolver 127.0.0.11;
+
+  default_type text/plain;
+  server_names_hash_bucket_size 64;
+
+  sendfile on;
+  tcp_nopush on;
+  tcp_nodelay on;
+
+  client_max_body_size 111M;
+  client_body_buffer_size 2084k;
+
+  keepalive_timeout  65;
+  proxy_read_timeout 360s;
+  proxy_send_timeout 360s;
+
+  geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
+    $geoip2_data_country_name country names en;
+  }
+
+  geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb {
+    $geoip2_data_city_name city names en;
+  }
+
+  include maps/*.conf;
+  include sites/*.conf;
+
+  server {
+    listen localhost:8080;
+
+    allow 127.0.0.1/32;
+    allow ::1/128;
+    deny all;
+
+    location = /stub_status {
+      stub_status;
+    }
+  }
+}
diff --git a/nginx/snippets/acme.conf b/nginx/snippets/acme.conf
new file mode 100644
index 0000000..2d8b9e0
--- /dev/null
+++ b/nginx/snippets/acme.conf
@@ -0,0 +1,6 @@
+location ^~ /.well-known/acme-challenge/ {
+  allow all;
+  root /var/lib/letsencrypt/;
+  default_type "text/plain";
+  try_files $uri =404;
+}
diff --git a/nginx/snippets/brotli.conf b/nginx/snippets/brotli.conf
new file mode 100644
index 0000000..a38e001
--- /dev/null
+++ b/nginx/snippets/brotli.conf
@@ -0,0 +1,3 @@
+brotli on;
+brotli_static on;
+brotli_types application/atom+xml application/javascript text/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component;
diff --git a/nginx/snippets/gzip.conf b/nginx/snippets/gzip.conf
new file mode 100644
index 0000000..fd0a235
--- /dev/null
+++ b/nginx/snippets/gzip.conf
@@ -0,0 +1,9 @@
+gzip on;
+gzip_static on;
+gzip_proxied any;
+gzip_http_version 1.1;
+gzip_comp_level 5;
+gzip_min_length 10240;
+gzip_vary on;
+gzip_types application/atom+xml application/javascript text/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component;
+gzip_disable "msie6";
diff --git a/nginx/snippets/privacy.conf b/nginx/snippets/privacy.conf
new file mode 100644
index 0000000..70db8cd
--- /dev/null
+++ b/nginx/snippets/privacy.conf
@@ -0,0 +1,14 @@
+# Don't send server version
+server_tokens off;
+
+# Logs are anonymous
+log_format main '127.0.0.1 - $remote_user [$time_local] "$request" '
+                '$status $body_bytes_sent "$http_referer" '
+                '"$http_user_agent" "127.0.0.1"';
+
+# Don't send IP addresses upstream
+proxy_set_header X-Real-IP 127.0.0.1;
+proxy_set_header X-Forwarded-For 127.0.0.1;
+
+# Every server has it's own log
+access_log  off;
diff --git a/nginx/snippets/ssl.conf b/nginx/snippets/ssl.conf
new file mode 100644
index 0000000..3473612
--- /dev/null
+++ b/nginx/snippets/ssl.conf
@@ -0,0 +1,21 @@
+listen 80;
+listen 443 ssl http2;
+
+add_header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload";
+
+ssl_certificate /etc/letsencrypt/live/$ssl_server_name/fullchain.pem;
+ssl_certificate_key /etc/letsencrypt/live/$ssl_server_name/privkey.pem;
+ssl_session_timeout 1d;
+ssl_session_cache shared:SSL:10m;
+ssl_session_tickets off;
+ssl_dhparam /etc/nginx/dhparam.pem;
+ssl_protocols TLSv1.2 TLSv1.3;
+ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
+ssl_prefer_server_ciphers off;
+ssl_stapling on;
+ssl_stapling_verify on;
+ssl_trusted_certificate /etc/ssl/cert.pem;
+
+if ($redirect_to_https) {
+  return 301 https://$http_host$request_uri;
+}
diff --git a/prometheusd.sh b/prometheusd.sh
new file mode 100755
index 0000000..b288038
--- /dev/null
+++ b/prometheusd.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+set -e
+
+pid=/tmp/prometheus.pid
+
+case $1 in
+  start) 
+    rm -f ${pid}
+    daemonize -c /tmp -p ${pid} -l ${pid} -u nobody \
+      /usr/bin/nginx-prometheus-exporter -nginx.scrape-uri http://127.0.0.1:8080/stub_status
+
+    ;;
+  stop)
+    cat /tmp/prometheus.pid | xargs -r kill
+
+    ;;
+esac
