diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 94d4c6a7f43b798e193985f1534b69f0b0f814f2..caf5b58152b4d9d68302c52d07352b131eed4fba 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,6 +2,7 @@ stages:
   - lint
   - test
   - build
+	- deploy
 
 before_script:
   - apt-get update
@@ -65,7 +66,40 @@ unit_test:
         coverage_format: cobertura
         path: coverage.xml
 
-build_image:
+build nginx image:
+  image: docker:latest
+  stage: building
+  interruptible: true
+  except:
+    changes:
+      - "**/README.md"
+  only:
+    - rewrite
+  variables:
+    DOCKER_TLS_CERTDIR: "/certs"
+    GIT_SUBMODULE_STRATEGY: recursive
+    CERTIFICATE: $CERT_CHAIN_PEM
+    PRIVATE_KEY: $CERT_PRIV_KEY
+  tags:
+    - docker
+  services:
+    - docker:dind
+  before_script: []
+  script:
+    - >
+      docker build
+      --tag $CI_REGISTRY_IMAGE-nginx:latest
+      --build-arg certificate="$CERTIFICATE"
+      --build-arg private_key="$PRIVATE_KEY"
+      --cache-from $CI_REGISTRY_IMAGE-nginx:latest
+      --file nginx/Dockerfile
+      .
+		- docker tag $CI_REGISTRY_IMAGE-nginx:latest $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME-nginx
+    - docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY
+    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME-nginx
+
+
+build app image:
   stage: build
   except:
     refs:
@@ -92,3 +126,28 @@ build_image:
     - docker tag $CI_REGISTRY_IMAGE:latest $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
     - docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY
     - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
+
+
+deploy prod:
+  stage: deploy
+  variables:
+    SECRET_KEY: $SECRET_KEY
+    POSTGRES_DB: $POSTGRES_DB
+    POSTGRES_USER: $POSTGRES_USER
+    POSTGRES_PASSWORD: $POSTGRES_PASSWORD
+  except:
+    changes:
+      - README.md
+  only:
+    - master
+  before_script: []
+  script:
+    - docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY
+    - docker stack deploy -c docker-compose.yml project-allocator --with-registry-auth
+    - docker exec $(docker ps -qf "name=web" | head -n1) flask db upgrade
+  tags:
+    - deploy-prod
+  environment:
+    name: production
+    url: https://project-allocator.doc.ic.ac.uk
+
diff --git a/app/config.py b/app/config.py
index baa96da0054d4bb9f237c110acb62355d9e9164e..2cdd1762c85c0337b13578fee743a02b0dc88696 100644
--- a/app/config.py
+++ b/app/config.py
@@ -6,7 +6,6 @@ class BaseConfig:
 
     # Secret Keys ===============================================
     SECRET_KEY = os.environ.get("SECRET_KEY", "dev_secret_key")
-    WTF_CSRF_SECRET_KEY = os.environ.get("WTF_CSRF_SECRET_KEY", "dev_wtf_secret_key")
 
     # LDAP Service ==============================================
     LDAP_URL = "ldaps://ldaps-vip.cc.ic.ac.uk:636"
@@ -14,17 +13,16 @@ class BaseConfig:
 
     # Database ===================================================
     SQLALCHEMY_TRACK_MODIFICATIONS = True
+    SQLALCHEMY_DATABASE_URI = os.environ.get("DB_OVERRIDE", "sqlite:///dev.db")
 
 
 class DevConfig(BaseConfig):
-    SQLALCHEMY_DATABASE_URI = os.environ.get("DB_OVERRIDE", "sqlite:///dev.db")
     DEBUG = True
 
 
 class StagingConfig(BaseConfig):
-    SQLALCHEMY_DATABASE_URI = "sqlite:///staging.db"
+    pass
 
 
 class ProductionConfig(BaseConfig):
-    # This one should be changed to a postgres db
-    SQLALCHEMY_DATABASE_URI = "sqlite:///production.db"
+    SQLALCHEMY_DATABASE_URI = os.environ["DB_URL"]
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..37a68e44f4f21bf06abdca1c403974bea907657e
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,29 @@
+version: "3.9"
+
+services:
+  db:
+    image: postgres
+    environment:
+      - POSTGRES_USER
+      - POSTGRES_PASSWORD
+      - POSTGRES_DB
+    volumes:
+      - postgres_data:/var/lib/postgresql/data
+  web:
+    image: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_NAME}
+    environment:
+      - ENV=production
+      - SECRET_KEY
+      - DB_URL=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@db/$POSTGRES_DB
+    depends_on:
+      - db
+  reverse_proxy:
+    image: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_NAME}-nginx
+    ports:
+      - "80:80"
+      - "443:443"
+    depends_on:
+      - web
+
+volumes:
+  postgres_data:
diff --git a/nginx/Dockerfile b/nginx/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..03a50f59f3149a1f4b62843ad40d6e579b5ad92a
--- /dev/null
+++ b/nginx/Dockerfile
@@ -0,0 +1,12 @@
+FROM nginx
+ARG certificate
+ARG private_key
+
+# Copy configuration
+COPY ./nginx/ssl.conf /etc/nginx/conf.d/project-allocator.doc.ic.ac.uk.conf
+RUN mkdir /etc/nginx/certs
+RUN echo $certificate | sed 's/ CERTIFICATE/xCERTIFICATE/g;s/ /\n/g;s/xCERTIFICATE/ CERTIFICATE/g' > /etc/nginx/certs/fullchain.pem
+RUN echo $private_key | sed 's/ PRIVATE KEY/xPRIVATExKEY/g;s/ /\n/g;s/xPRIVATExKEY/ PRIVATE KEY/g' > /etc/nginx/certs/privkey.key
+
+
+
diff --git a/nginx/ssl.conf b/nginx/ssl.conf
new file mode 100644
index 0000000000000000000000000000000000000000..5aebbdbe5c68b643c3bb3e0a72602569876ae579
--- /dev/null
+++ b/nginx/ssl.conf
@@ -0,0 +1,39 @@
+# /etc/nginx/sites-available/project-allocator.doc.ic.ac.uk
+
+error_log stderr;
+access_log /dev/stdout;
+proxy_connect_timeout 500;
+proxy_send_timeout    500;
+proxy_read_timeout    500;
+send_timeout          500;
+
+server {
+    		listen 80;
+    		server_name project-allocator.doc.ic.ac.uk;
+    		return 301 https://$server_name$request_uri;
+}
+
+server {
+    		listen 443 ssl;
+    		server_name project-allocator.doc.ic.ac.uk;
+
+    		client_max_body_size 200M;
+
+    		ssl_certificate /etc/nginx/certs/fullchain.pem;
+    		ssl_certificate_key /etc/nginx/certs/privkey.key;
+    		ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+    		ssl_ciphers HIGH:!aNULL:!MD5;
+    		ssl_prefer_server_ciphers on;
+
+
+    location / {
+            # Pass the request to Gunicorn
+            proxy_pass http://127.0.0.1:8000;
+
+            # Set HTTP headers st our app knows where request came from
+            proxy_set_header Host $host;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+                  add_header X-Frame-Options "DENY";
+    }
+}