diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8ce607da1b8f3d7bbc6757398b5f6fb2fe594987..e9c0e0131d11423d2ba6833955cf4cc440d843b0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,28 +2,79 @@ stages:
   - test
   - deploy
 
+variables:
+  DB_ENGINE : django.db.backends.sqlite3
+
 before_script:
   - echo "preparing environment"
-  - virtualenv env
+  - virtualenv env -p `which python3`
   - . env/bin/activate
   - pip install -r pip-packages.txt
   
   
-test:
+run_tests:
   stage: test
   script:
     - echo "Running tests"
+    - envsubst < src/gms/settings_local.example.py > src/gms/settings_local.py
+    - python src/manage.py check
 
-deploy_test:
+deploy_testing:
   stage: deploy
+  tags:
+    - test
+  variables:
+    DB_NAME : /var/www/test/$CI_COMMIT_REF_NAME/.db/members.db
+    DEPLOY_HOST : $CI_COMMIT_REF_NAME.test.ucc.asn.au
   script:
     - echo "Deploy to test"
-    - . venv/bin/activate
-    - python3 src/manage.py makemigrations
-    - python3 src/manage.py migrate --run-syncdb
+    - rm -f /var/www/test/$CI_COMMIT_REF_NAME
+    - rm -f /etc/uwsgi/vassals/$CI_COMMIT_REF_NAME.ini
+    - mkdir .db
+    - envsubst < src/gms/settings_local.example.py > src/gms/settings_local.py
+    - ln -srT ./ /var/www/test/$CI_COMMIT_REF_NAME
+    - python src/manage.py collectstatic
+    - python src/manage.py makemigrations
+    - python src/manage.py migrate --run-syncdb
     - ln -s /etc/uwsgi/vassals/test.skel /etc/uwsgi/vassals/$CI_COMMIT_REF_NAME.ini
   environment:
     name: test/$CI_COMMIT_REF_NAME
     url: https://$CI_COMMIT_REF_NAME.test.ucc.asn.au
+    on_stop: stop_testing
   except:
-      - master
\ No newline at end of file
+      - master
+
+deploy_staging:
+  stage: deploy
+  tags:
+    - stage
+  variables:
+    DB_NAME : /var/www/stage/.db/members.db
+    DEPLOY_HOST : staging.test.ucc.asn.au
+  script:
+    - echo "Deploy to staging"
+    - rm -f /var/www/stage/$CI_PROJECT_NAME
+    - rm -f /etc/uwsgi/vassals/stage.ini
+    - ln -srT ./ /var/www/stage/$CI_PROJECT_NAME
+    - envsubst < src/gms/settings_local.example.py > src/gms/settings_local.py
+    - python src/manage.py collectstatic
+    - python src/manage.py makemigrations
+    - python src/manage.py migrate --run-syncdb
+    - ln -s /etc/uwsgi/vassals/stage.skel /etc/uwsgi/vassals/stage.ini
+  environment:
+    name: stage
+    url: https://stage.test.ucc.asn.au
+  only:
+      - master
+
+stop_testing:
+  stage: deploy
+  variables:
+    GIT_STRATEGY: none
+  when: manual
+  environment:
+    name: test/$CI_COMMIT_REF_NAME
+    action: stop
+  script:
+    - rm -f /var/www/test/$CI_COMMIT_REF_NAME
+    - rm -f /etc/uwsgi/vassals/$CI_COMMIT_REF_NAME.ini
\ No newline at end of file
diff --git a/pip-packages.txt b/pip-packages.txt
index e3059d633868f97b4faeca19c6e4efbef693ac57..1db0727343abf1e89c77d8d19d21f4812fef8214 100644
--- a/pip-packages.txt
+++ b/pip-packages.txt
@@ -12,3 +12,4 @@ pytz==2018.7
 six==1.12.0
 squareconnect==2.20181212.0
 urllib3==1.24.1
+ldap3==2.5.2
diff --git a/src/gms/settings.py b/src/gms/settings.py
index f85d7625b5a0cbf10c3e0ee7bb362eca9749ef95..8354958c4897e4015db45a679eb803a827f91d8e 100644
--- a/src/gms/settings.py
+++ b/src/gms/settings.py
@@ -11,9 +11,6 @@ https://docs.djangoproject.com/en/2.1/ref/settings/
 # import local settings
 from gms.settings_local import *
 
-# DEBUG ALLOW
-ALLOWED_HOSTS = ['127.0.0.1', 'localhost', "130.95.13.36","portal.ucc.asn.au"]
-
 # Application definition
 
 INSTALLED_APPS = (
diff --git a/src/gms/settings_local.example.py b/src/gms/settings_local.example.py
index e5de56edfab269fe85b61843307852edfd6ac14c..dd91a37f199d522fb91248d6827c7108381d4ae5 100644
--- a/src/gms/settings_local.example.py
+++ b/src/gms/settings_local.example.py
@@ -14,29 +14,29 @@ ADMINS = (
 ### Database connection options ###
 DATABASES = {
     'default': {
-        'ENGINE': 'django.db.backends.sqlite3',     # Add 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+        'ENGINE': '${DB_ENGINE}',     # Add 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
         # this should end up in uccportal/.db/members.db
-        'NAME': os.path.join(ROOT_DIR, '.db', 'members.db'),   # Or path to database file if using sqlite3.
-        'USER': '',                                 # Not used with sqlite3.
-        'PASSWORD': '',                             # Not used with sqlite3.
-        'HOST': '',                                 # Set to empty string for localhost. Not used with sqlite3.
+        'NAME': '${DB_NAME}',   # Or path to database file if using sqlite3.
+        'USER': '${DB_USER}',                                 # Not used with sqlite3.
+        'PASSWORD': '${DB_SECRET}',                             # Not used with sqlite3.
+        'HOST': '${DB_HOST}',                                 # Set to empty string for localhost. Not used with sqlite3.
         'PORT': '',                                 # Set to empty string for default. Not used with sqlite3.
     },
     'memberdb_old': {
         'ENGINE': 'django.db.backends.postgresql',
         'NAME': 'uccmemberdb_2018',
         'USER': 'uccmemberdb',
-        'PASSWORD': 'something-secret-here',
+        'PASSWORD': '${OLDDB_SECRET}',
         'HOST': 'mussel.ucc.gu.uwa.edu.au',
         'PORT': '',
     }
 }
 
 # Make this unique, and don't share it with anybody.
-SECRET_KEY = 'something-unique-here'
+SECRET_KEY = '${APP_SECRET}'
 
 # Set this to whatever your ServerName/ServerAlias(es) are
-ALLOWED_HOSTS = []
+ALLOWED_HOSTS = ['${DEPLOY_HOST}']
 
 LOG_LEVEL = 'DEBUG'
 LOG_FILENAME = os.path.join(ROOT_DIR, "django.log")
@@ -45,13 +45,14 @@ import ldap
 from django_auth_ldap.config import LDAPSearch, ActiveDirectoryGroupType, LDAPGroupQuery
 
 # LDAP admin settings
+LDAP_BASE_DN = 'DC=ad,DC=ucc,DC=gu,DC=uwa,DC=edu,DC=au'
 LDAP_USER_SEARCH_DN = 'CN=Users,DC=ad,DC=ucc,DC=gu,DC=uwa,DC=edu,DC=au'
-LDAP_BIND_DN = ""
-LDAP_BIND_SECRET = ""
+LDAP_BIND_DN = 'CN=uccportal,CN=Users,DC=ad,DC=ucc,DC=gu,DC=uwa,DC=edu,DC=au'
+LDAP_BIND_SECRET = "${LDAP_SECRET}"
 
 # this could be ad.ucc.gu.uwa.edu.au but that doesn't resolve externally -
 # useful for testing, but should be changed in production so failover works
-AUTH_LDAP_SERVER_URI = 'ldaps://samson.ucc.gu.uwa.edu.au/'
+AUTH_LDAP_SERVER_URI = 'ldaps://ad.ucc.gu.uwa.edu.au/'
 
 # This is also a bad idea, should be changed in production
 AUTH_LDAP_GLOBAL_OPTIONS = {
@@ -92,9 +93,9 @@ AUTH_LDAP_USER_FLAGS_BY_GROUP = {
 }
 
 # the Square app and location data (set to sandbox unless you want it to charge people)
-SQUARE_APP_ID = 'maybe-sandbox-something-something-here'
-SQUARE_LOCATION = 'CBASEDE-this-is-probably-somewhere-in-Sydney'
-SQUARE_ACCESS_TOKEN = 'keep-this-very-secret'
+SQUARE_APP_ID = '${SQUARE_APP_ID}'
+SQUARE_LOCATION = '${SQUARE_LOCATION}'
+SQUARE_ACCESS_TOKEN = '${SQUARE_SECRET}'
 
 DISPENSE_BIN = '/usr/local/bin/dispense'
 
@@ -103,4 +104,4 @@ EMAIL_HOST = "secure.ucc.asn.au"
 EMAIL_PORT = 465
 EMAIL_USE_SSL = True
 EMAIL_HOST_USER = "uccportal"
-EMAIL_HOST_PASSWORD = "changeme"
+EMAIL_HOST_PASSWORD = "${EMAIL_SECRET}"