diff --git a/core/Dockerfile b/core/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..63c8458b12449fb4526b55b88e8b86ac3f706423
--- /dev/null
+++ b/core/Dockerfile
@@ -0,0 +1,105 @@
+#------------------------------------------------------------------------------
+#
+# Project: prism data access server
+# Authors: Stephan Meissl <stephan.meissl@eox.at>
+#
+#------------------------------------------------------------------------------
+# Copyright (C) 2019 EOX IT Services GmbH <https://eox.at>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies of this Software or works derived from this Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#-----------------------------------------------------------------------------
+
+FROM ubuntu:18.04
+MAINTAINER EOX
+LABEL name="prism data access server core" \
+      vendor="EOX IT Services GmbH <https://eox.at>" \
+      license="MIT Copyright (C) 2019 EOX IT Services GmbH <https://eox.at>" \
+      type="prism data access server core" \
+      version="0.0.1-dev"
+
+USER root
+
+RUN apt update && \
+    DEBIAN_FRONTEND=noninteractive apt install -y software-properties-common && \
+    add-apt-repository -y ppa:ubuntugis/ppa && \
+    apt update && \
+    DEBIAN_FRONTEND=noninteractive apt install -y \
+      python \
+      python-pip \
+      libpq-dev \
+      python-mapscript \
+      python-gdal \
+      gdal-bin \
+      postgresql-client \
+      python-redis && \
+  apt autoremove -y && \
+  apt clean && \
+  rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+
+# Install EOxServer (TODO: Use final release package)
+RUN mkdir /opt/eoxserver/
+
+WORKDIR /opt/eoxserver
+ADD eoxserver/eoxserver eoxserver
+ADD eoxserver/tools tools
+ADD eoxserver/setup.cfg eoxserver/setup.py eoxserver/MANIFEST.in eoxserver/README.rst eoxserver/requirements.txt ./
+RUN pip install -r requirements.txt && \
+    pip install . && \
+    pip install python-keystoneclient python-swiftclient
+
+ENV INSTANCE_ID="prism-data-access-server_core" \
+    COLLECTION= \
+    DB_USER= \
+    DB_PW= \
+    DB_HOST= \
+    DB_PORT= \
+    DB_NAME= \
+    INSTALL_DIR="/var/www/pdas/" \
+    DJANGO_USER="admin" \
+    DJANGO_MAIL="office@eox.at" \
+    DJANGO_PASSWORD="***REMOVED***" \
+    DATA_DIR="/data/" \
+    APACHE_CONF="/etc/httpd/conf.d/010_pdas.conf" \
+    APACHE_ServerName="pdas_instance" \
+    APACHE_ServerAdmin="office@eox.at" \
+    APACHE_ALIAS="pdas" \
+    REDIS_HOST= \
+    REDIS_PORT= \
+    REDIS_REGISTER_QUEUE_KEY= \
+    REDIS_REGISTERED_SET_KEY=
+
+ADD rgbnir_definition.json \
+    configure.sh \
+    wait-for-database.sh \
+    run-httpd.sh \
+    run-registrar.sh \
+    registrar.py \
+    /
+#    run-redis-manager.sh \
+#    redis-manager.py \
+
+RUN chmod -v +x \
+    /configure.sh \
+    /wait-for-database.sh \
+    /run-registrar.sh \
+    /run-httpd.sh
+#    /run-redis-manager.sh
+
+EXPOSE 80
+CMD ["/run-httpd.sh"]
diff --git a/core/configure.sh b/core/configure.sh
new file mode 100644
index 0000000000000000000000000000000000000000..13a7f9602c24798b1b33c2bb6e05557b2c713aca
--- /dev/null
+++ b/core/configure.sh
@@ -0,0 +1,614 @@
+#!/bin/bash
+echo "Running configure.sh"
+
+echo "Generating PDAS directory"
+mkdir -p "${INSTALL_DIR}"
+cd "${INSTALL_DIR}"
+
+if [ ! -d pdas_instance ] ; then
+    echo "Creating PRISM Data Access Server (PDAS) instance"
+    eoxserver-admin.py create_instance pdas_instance
+
+    echo "Configure PRISM Data Access Server (PDAS) instance"
+    cd "pdas_instance"
+
+    # Configure DBs
+    INSTALL_DIR_ESCAPED=`echo ${INSTALL_DIR} | sed -e 's,/$,,' | sed -e 's,/,\\\&,g'`
+    sed -e "s/'ENGINE': 'django.contrib.gis.db.backends.spatialite',/'ENGINE': 'django.contrib.gis.db.backends.postgis',/" -i pdas_instance/settings.py
+    sed -e "s/'NAME': join(PROJECT_DIR, 'data\/config.sqlite'),/'NAME': '${DB_NAME}',/" -i pdas_instance/settings.py
+    sed -e "/#'TEST_NAME': join(PROJECT_DIR, 'data\/test-config.sqlite'),/d" -i pdas_instance/settings.py
+    sed -e "s/'USER': '',/'USER': '${DB_USER}',/" -i pdas_instance/settings.py
+    sed -e "s/'PASSWORD': '',/'PASSWORD': '${DB_PW}',/" -i pdas_instance/settings.py
+    sed -e "s/'HOST': '',/'HOST': '${DB_HOST}',/" -i pdas_instance/settings.py
+    sed -e "s/'PORT': '',/'PORT': '${DB_PORT}',/" -i pdas_instance/settings.py
+
+    # Configure instance
+    sed -e "s/'disable_existing_loggers': True,/'disable_existing_loggers': False,/" -i pdas_instance/settings.py
+    HANDLERS="'handlers': {\n
+        'null': {\n
+            'level':'DEBUG',\n
+            'class':'logging.NullHandler',\n
+        },\n
+        'console': {\n
+            'level': 'DEBUG' if DEBUG else 'INFO',\n
+            'class': 'logging.StreamHandler',\n
+            'formatter': 'verbose' if DEBUG else 'simple',\n
+            'filters': [],\n
+        },\n
+    },"
+    LOGGERS="'loggers': {\n
+        'eoxserver': {\n
+            'handlers': ['console'],\n
+            'level': 'DEBUG' if DEBUG else 'INFO',\n
+            'propagate': False,\n
+        },
+    }"
+    sed -e "/^    'handlers': {$/,/^    },$/c `echo ${HANDLERS}`" -i pdas_instance/settings.py
+    sed -e "/^    'loggers': {$/,/^    }$/c `echo ${LOGGERS}`" -i pdas_instance/settings.py
+
+    sed -e "s,http_service_url=http://localhost:8000/ows,http_service_url=${APACHE_ALIAS}/ows," -i pdas_instance/conf/eoxserver.conf
+    sed -e "s/resampling_method=average/resampling_method=near/" -i pdas_instance/conf/eoxserver.conf
+    # TODO maxsize...
+
+    echo "EOXS_VALIDATE_IDS_NCNAME = False" >> pdas_instance/settings.py
+    echo "EOXS_OPENSEARCH_RECORD_MODEL = 'eoxserver.resources.coverages.models.Product'" >> pdas_instance/settings.py
+
+    echo "CACHES = {
+    'default': {
+        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
+        'LOCATION': '/var/tmp/django_cache',
+    }
+}" >> pdas_instance/settings.py
+
+    sed -e "/TEMPLATE_DEBUG = DEBUG/d" -i pdas_instance/settings.py
+
+    sed -e 's/DEBUG = True/DEBUG = False/' -i pdas_instance/settings.py
+
+    # Further configuration
+    echo "ALLOWED_HOSTS = ['*']" >> pdas_instance/settings.py
+    echo "USE_X_FORWARDED_HOST = True" >> pdas_instance/settings.py
+    echo "SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')" >> pdas_instance/settings.py
+
+    python manage.py migrate --noinput
+
+    # Check if collection exits in database and initialize database only if not
+    if python manage.py id check "${COLLECTION}"; then
+        echo "Initialize database"
+
+        python manage.py coveragetype import /rgbnir_definition.json --traceback
+
+        if [ "${COLLECTION}" == "VHR_IMAGE_2018" ]; then
+            echo "Initializing collection '${COLLECTION}'."
+
+            # PL00
+            python manage.py producttype create "${COLLECTION}"_Product_PL00 --traceback \
+                --coverage-type "RGBNir"
+            python manage.py browsetype create "${COLLECTION}"_Product_PL00 --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1000 15000 \
+                --green-range 1000 15000 \
+                --blue-range 1000 15000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PL00 "TRUE_COLOR" --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1000 15000 \
+                --green-range 1000 15000 \
+                --blue-range 1000 15000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PL00 "FALSE_COLOR" --traceback \
+                --red "nir" \
+                --green "red" \
+                --blue "green" \
+                --red-range 1000 15000 \
+                --green-range 1000 15000 \
+                --blue-range 1000 15000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PL00 "NDVI" --traceback \
+                --grey "(nir-red)/(nir+red)" --grey-range -1 1
+
+            # DM02
+            python manage.py producttype create "${COLLECTION}"_Product_DM02 --traceback \
+                --coverage-type "RGBNir"
+            python manage.py browsetype create "${COLLECTION}"_Product_DM02 --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 250 11500 \
+                --green-range 600 10000 \
+                --blue-range 1300 8500 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_DM02 "TRUE_COLOR" --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 250 11500 \
+                --green-range 600 10000 \
+                --blue-range 1300 8500 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_DM02 "FALSE_COLOR" --traceback \
+                --red "nir" \
+                --green "red" \
+                --blue "green" \
+                --red-range 400 28000 \
+                --green-range 250 11500 \
+                --blue-range 600 10000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_DM02 "NDVI" --traceback \
+                --grey "(nir-red)/(nir+red)" --grey-range -1 1
+
+            # KS03
+            python manage.py producttype create "${COLLECTION}"_Product_KS03 --traceback \
+                --coverage-type "RGBNir"
+            python manage.py browsetype create "${COLLECTION}"_Product_KS03 --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 10000 \
+                --green-range 1 10000 \
+                --blue-range 1 10000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_KS03 "TRUE_COLOR" --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 10000 \
+                --green-range 1 10000 \
+                --blue-range 1 10000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_KS03 "FALSE_COLOR" --traceback \
+                --red "nir" \
+                --green "red" \
+                --blue "green" \
+                --red-range 1 10000 \
+                --green-range 1 10000 \
+                --blue-range 1 10000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_KS03 "NDVI" --traceback \
+                --grey "(nir-red)/(nir+red)" --grey-range -1 1
+
+            # KS04
+            python manage.py producttype create "${COLLECTION}"_Product_KS04 --traceback \
+                --coverage-type "RGBNir"
+            python manage.py browsetype create "${COLLECTION}"_Product_KS04 --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 10000 \
+                --green-range 1 10000 \
+                --blue-range 1 10000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_KS04 "TRUE_COLOR" --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 10000 \
+                --green-range 1 10000 \
+                --blue-range 1 10000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_KS04 "FALSE_COLOR" --traceback \
+                --red "nir" \
+                --green "red" \
+                --blue "green" \
+                --red-range 1 10000 \
+                --green-range 1 10000 \
+                --blue-range 1 10000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_KS04 "NDVI" --traceback \
+                --grey "(nir-red)/(nir+red)" --grey-range -1 1
+
+            # PH1A
+            python manage.py producttype create "${COLLECTION}"_Product_PH1A --traceback \
+                --coverage-type "RGBNir"
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1A  --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 2000 \
+                --green-range 1 2000 \
+                --blue-range 1 2000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1A "TRUE_COLOR" --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 2000 \
+                --green-range 1 2000 \
+                --blue-range 1 2000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1A "FALSE_COLOR" --traceback \
+                --red "nir" \
+                --green "red" \
+                --blue "green" \
+                --red-range 1 2000 \
+                --green-range 1 2000 \
+                --blue-range 1 2000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1A "NDVI" --traceback \
+                --grey "(nir-red)/(nir+red)" --grey-range -1 1
+
+            # PH1B
+            python manage.py producttype create "${COLLECTION}"_Product_PH1B --traceback \
+                --coverage-type "RGBNir"
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1B --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 2000 \
+                --green-range 1 2000 \
+                --blue-range 1 2000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1B "TRUE_COLOR" --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 2000 \
+                --green-range 1 2000 \
+                --blue-range 1 2000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1B "FALSE_COLOR" --traceback \
+                --red "nir" \
+                --green "red" \
+                --blue "green" \
+                --red-range 1 2000 \
+                --green-range 1 2000 \
+                --blue-range 1 2000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1B "NDVI" --traceback \
+                --grey "(nir-red)/(nir+red)" --grey-range -1 1
+
+            # SP06
+            python manage.py producttype create "${COLLECTION}"_Product_SP06 --traceback \
+                --coverage-type "RGBNir"
+            python manage.py browsetype create "${COLLECTION}"_Product_SP06 --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1000 20000 \
+                --green-range 1000 20000 \
+                --blue-range 1000 20000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_SP06 "TRUE_COLOR" --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1000 20000 \
+                --green-range 1000 20000 \
+                --blue-range 1000 20000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_SP06 "FALSE_COLOR" --traceback \
+                --red "nir" \
+                --green "red" \
+                --blue "green" \
+                --red-range 1000 20000 \
+                --green-range 1000 20000 \
+                --blue-range 1000 20000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_SP06 "NDVI" --traceback \
+                --grey "(nir-red)/(nir+red)" --grey-range -1 1
+
+            # SP07
+            python manage.py producttype create "${COLLECTION}"_Product_SP07 --traceback \
+                --coverage-type "RGBNir"
+            python manage.py browsetype create "${COLLECTION}"_Product_SP07 --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1000 20000 \
+                --green-range 1000 20000 \
+                --blue-range 1000 20000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_SP07 "TRUE_COLOR" --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1000 20000 \
+                --green-range 1000 20000 \
+                --blue-range 1000 20000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_SP07 "FALSE_COLOR" --traceback \
+                --red "nir" \
+                --green "red" \
+                --blue "green" \
+                --red-range 1000 20000 \
+                --green-range 1000 20000 \
+                --blue-range 1000 20000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_SP07 "NDVI" --traceback \
+                --grey "(nir-red)/(nir+red)" --grey-range -1 1
+
+            # SW00
+            python manage.py producttype create "${COLLECTION}"_Product_SW00 --traceback \
+                --coverage-type "RGBNir"
+            python manage.py browsetype create "${COLLECTION}"_Product_SW00 --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 100 1500 \
+                --green-range 100 1500 \
+                --blue-range 100 1500 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_SW00 "TRUE_COLOR" --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 100 1500 \
+                --green-range 100 1500 \
+                --blue-range 100 1500 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_SW00 "FALSE_COLOR" --traceback \
+                --red "nir" \
+                --green "red" \
+                --blue "green" \
+                --red-range 100 1500 \
+                --green-range 100 1500 \
+                --blue-range 100 1500 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_SW00 "NDVI" --traceback \
+                --grey "(nir-red)/(nir+red)" --grey-range -1 1
+
+            # TR00
+            python manage.py producttype create "${COLLECTION}"_Product_TR00 --traceback \
+                --coverage-type "RGBNir"
+            python manage.py browsetype create "${COLLECTION}"_Product_TR00 --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 3000 \
+                --green-range 1 3000 \
+                --blue-range 1 3000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_TR00 "TRUE_COLOR" --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 3000 \
+                --green-range 1 3000 \
+                --blue-range 1 3000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_TR00 "FALSE_COLOR" --traceback \
+                --red "nir" \
+                --green "red" \
+                --blue "green" \
+                --red-range 1 3000 \
+                --green-range 1 3000 \
+                --blue-range 1 3000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_TR00 "NDVI" --traceback \
+                --grey "(nir-red)/(nir+red)" --grey-range -1 1
+
+            python manage.py collectiontype create "${COLLECTION}"_Collection --traceback \
+                --coverage-type "RGBNir" \
+                --product-type "${COLLECTION}"_Product_PL00 \
+                --product-type "${COLLECTION}"_Product_DM02 \
+                --product-type "${COLLECTION}"_Product_KS03 \
+                --product-type "${COLLECTION}"_Product_KS04 \
+                --product-type "${COLLECTION}"_Product_PH1A \
+                --product-type "${COLLECTION}"_Product_PH1B \
+                --product-type "${COLLECTION}"_Product_SP06 \
+                --product-type "${COLLECTION}"_Product_SP07 \
+                --product-type "${COLLECTION}"_Product_SW00 \
+                --product-type "${COLLECTION}"_Product_TR00
+
+            # Create collections for all/Level-1/Level-3 products
+            python manage.py collection create "${COLLECTION}" --type "${COLLECTION}"_Collection --traceback
+            python manage.py collection create "${COLLECTION}_Level_1" --type "${COLLECTION}"_Collection --traceback
+            python manage.py collection create "${COLLECTION}_Level_3" --type "${COLLECTION}"_Collection --traceback
+
+            # Register mask type
+            python manage.py masktype create --validity "${COLLECTION}"_Product_PL00 validity
+            python manage.py masktype create --validity "${COLLECTION}"_Product_DM02 validity
+            python manage.py masktype create --validity "${COLLECTION}"_Product_KS03 validity
+            python manage.py masktype create --validity "${COLLECTION}"_Product_KS04 validity
+            python manage.py masktype create --validity "${COLLECTION}"_Product_PH1A validity
+            python manage.py masktype create --validity "${COLLECTION}"_Product_PH1B validity
+            python manage.py masktype create --validity "${COLLECTION}"_Product_SP06 validity
+            python manage.py masktype create --validity "${COLLECTION}"_Product_SP07 validity
+            python manage.py masktype create --validity "${COLLECTION}"_Product_SW00 validity
+            python manage.py masktype create --validity "${COLLECTION}"_Product_TR00 validity
+
+        elif [ "${COLLECTION}" == "Emergency" ]; then
+            echo "Initializing collection '${COLLECTION}'."
+
+            # CS00
+            # CS01
+            # CS02
+            # CS03
+            # CS04
+            # DM01
+            # EQ02
+            # EW01
+            # EW02
+            # EW03
+            # GE01
+            # GY01
+            # IK02
+            # RE00
+            # RS02
+            # SP04
+            # SP05
+            # TX01
+
+            # DM02
+            # KS03
+            # SP06
+            # SP07
+
+            # PH1A
+            python manage.py producttype create "${COLLECTION}"_Product_PH1A --traceback \
+                --coverage-type "RGBNir"
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1A  --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 2000 \
+                --green-range 1 2000 \
+                --blue-range 1 2000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1A "TRUE_COLOR" --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 2000 \
+                --green-range 1 2000 \
+                --blue-range 1 2000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1A "FALSE_COLOR" --traceback \
+                --red "nir" \
+                --green "red" \
+                --blue "green" \
+                --red-range 1 2000 \
+                --green-range 1 2000 \
+                --blue-range 1 2000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1A "NDVI" --traceback \
+                --grey "(nir-red)/(nir+red)" --grey-range -1 1
+
+            # PH1B
+            python manage.py producttype create "${COLLECTION}"_Product_PH1B --traceback \
+                --coverage-type "RGBNir"
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1B --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 2000 \
+                --green-range 1 2000 \
+                --blue-range 1 2000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1B "TRUE_COLOR" --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1 2000 \
+                --green-range 1 2000 \
+                --blue-range 1 2000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1B "FALSE_COLOR" --traceback \
+                --red "nir" \
+                --green "red" \
+                --blue "green" \
+                --red-range 1 2000 \
+                --green-range 1 2000 \
+                --blue-range 1 2000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python manage.py browsetype create "${COLLECTION}"_Product_PH1B "NDVI" --traceback \
+                --grey "(nir-red)/(nir+red)" --grey-range -1 1
+
+            python manage.py collectiontype create "${COLLECTION}"_Collection --traceback \
+                --coverage-type "RGBNir" \
+                --product-type "${COLLECTION}"_Product_PH1A \
+                --product-type "${COLLECTION}"_Product_PH1B
+
+            python manage.py collection create "${COLLECTION}" --type "${COLLECTION}"_Collection --traceback
+
+        else
+            echo "Provided collection '${COLLECTION}' not valid."
+       fi
+
+        python manage.py storageauth create auth-cloud-ovh "${OS_AUTH_URL_SHORT}" \
+            --type keystone \
+            -p auth-version "${ST_AUTH_VERSION}" \
+            -p identity-api-version="${ST_AUTH_VERSION}" \
+            -p username "${OS_USERNAME}" \
+            -p password "${OS_PASSWORD}" \
+            -p tenant-name "${OS_TENANT_NAME}" \
+            -p tenant-id "${OS_TENANT_ID}" \
+            -p region-name "${OS_REGION_NAME}"
+
+        for bucket in "data10" "data11" "data12" "data13" "data14" "data15" "data16" "data17" "data18" "data20" "data21" "data22" "data23" "data24" "data25" "data26"; do
+            python manage.py storage create \
+                ${bucket} ${bucket} \
+                --type swift \
+                --storage-auth auth-cloud-ovh
+        done
+
+        echo "Creating admin user"
+        python manage.py shell -c "from django.contrib.auth.models import User; User.objects.create_superuser('${DJANGO_USER}', '${DJANGO_MAIL}', '${DJANGO_PASSWORD}')"
+
+    else
+        echo "Using existing database"
+    fi
+
+    # Collect static files
+    python manage.py collectstatic --noinput
+
+    chmod g+w -R .
+    chgrp users -R .
+else
+    echo "Using existing PRISM Data Access Server (PDAS) instance"
+fi
diff --git a/core/registrar.py b/core/registrar.py
new file mode 100644
index 0000000000000000000000000000000000000000..7b75541857f77d6d9b0bff24187ec9b9003f9169
--- /dev/null
+++ b/core/registrar.py
@@ -0,0 +1,345 @@
+#!/usr/bin/env python
+# -----------------------------------------------------------------------------
+#
+# Project: registrar.py
+# Authors: Stephan Meissl <stephan.meissl@eox.at>
+#
+# -----------------------------------------------------------------------------
+# Copyright (c) 2019 EOX IT Services GmbH
+#
+# Python script to register products.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies of this Software or works derived from this Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+# -----------------------------------------------------------------------------
+
+
+import sys
+import os
+import argparse
+import textwrap
+import logging
+import traceback
+import redis
+
+import lxml.etree
+from swiftclient.service import SwiftService
+
+import django
+from django.db import transaction
+from django.contrib.gis.geos import GEOSGeometry
+
+path = os.path.join(os.getenv('INSTALL_DIR', "/var/www/pdas"), "pdas_instance")
+if path not in sys.path:
+    sys.path.append(path)
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pdas_instance.settings")
+django.setup()
+
+from eoxserver.backends import access
+from eoxserver.resources.coverages import models
+from eoxserver.resources.coverages.registration.product import (
+    ProductRegistrator
+)
+from eoxserver.resources.coverages.registration.registrators.gdal import (
+    GDALRegistrator
+)
+
+
+# collection: [name]
+COLLECTION_MAP = {
+    "VHR_IMAGE_2018": ["VHR IMAGE 2018", ],
+    "Emergency": ["Emergency", ],
+}
+
+logger = logging.getLogger(__name__)
+
+
+def setup_logging(verbosity):
+    # start logging setup
+    # get command line level
+    verbosity = verbosity
+    if verbosity == 0:
+        level = logging.CRITICAL
+    elif verbosity == 1:
+        level = logging.ERROR
+    elif verbosity == 2:
+        level = logging.WARNING
+    elif verbosity == 3:
+        level = logging.INFO
+    else:
+        level = logging.DEBUG
+    logger.setLevel(level)
+    sh = logging.StreamHandler()
+    sh.setLevel(level)
+    formatter = logging.Formatter("%(asctime)s %(levelname)s: %(message)s")
+    sh.setFormatter(formatter)
+    logger.addHandler(sh)
+    # finished logging setup
+
+
+def add_mask(product):
+    metadata_item = product.metadata_items.all()[0]
+    with access.vsi_open(metadata_item) as f:
+        tree = lxml.etree.parse(f)
+    root = tree.getroot()
+    wkt = tree.xpath(
+        '//gsc:opt_metadata/gml:metaDataProperty/gsc:EarthObservationMetaData/eop:vendorSpecific/eop:SpecificInformation[eop:localAttribute/text() = "CF_POLY"]/eop:localValue/text()',
+        namespaces=root.nsmap
+    )[0]
+    geometry = GEOSGeometry(wkt)
+    mask_type = models.MaskType.objects.get(product_type=product.product_type)
+    models.Mask.objects.create(
+        product=product,
+        mask_type=mask_type,
+        geometry=geometry,
+    )
+
+
+def get_product_level(product):
+    try:
+        metadata_item = product.metadata_items.all()[0]
+        with access.vsi_open(metadata_item) as f:
+            tree = lxml.etree.parse(f)
+        root = tree.getroot()
+        xp = '/gsc:report/gsc:opt_metadata/gml:metaDataProperty/gsc:EarthObservationMetaData/eop:parentIdentifier/text()'
+        product_type_name = tree.xpath(xp, namespaces=root.nsmap)[0]
+        if product_type_name.endswith('Level_1'):
+            return 'Level_1'
+        if product_type_name.endswith('Level_3'):
+            return 'Level_3'
+        else:
+            raise Exception('Invalid product type name %s' % product_type_name)
+    except Exception as e:
+        logger.warning(
+            'Failed to determine product level for product %s, error was %s'
+            % (product.identifier, e)
+        )
+
+
+class RegistrationError(Exception):
+    pass
+
+
+@transaction.atomic
+def registrar(
+    collection,
+    objects_prefix, replace=False, client=None, registered_set_key=None
+):
+    logger.info("Starting registration of product '%s'." % objects_prefix)
+
+    container = objects_prefix.split("/")[1]
+    package = "/".join(objects_prefix.split("/")[2:])
+    metadata_package, data_package = None, None
+
+    with SwiftService() as swift:
+        list_parts_gen = swift.list(
+            container=container, options={"prefix": package},
+        )
+        for page in list_parts_gen:
+            if page["success"]:
+                for item in page["listing"]:
+                    if item["name"].endswith(".xml"):
+                        metadata_package = item["name"]
+                    elif item["name"].endswith(".TIF") or \
+                            item["name"].endswith(".tif"):
+                        data_package = item["name"]
+                    else:
+                        raise RegistrationError(
+                            "Product with objects prefix '%s' has "
+                            "wrong content '%s'."
+                            % (objects_prefix, item["name"])
+                        )
+            else:
+                raise RegistrationError(
+                    "No product found with objects prefix '%s'."
+                    % objects_prefix
+                )
+
+    if metadata_package is None or data_package is None:
+        raise RegistrationError(
+            "Product with objects prefix '%s' has missing content."
+            % objects_prefix
+        )
+
+    product_type = data_package.split("/")[1]
+
+    product, replaced = ProductRegistrator().register(
+        metadata_locations=[[container,
+                             metadata_package, ], ],
+        type_name="%s_Product_%s" % (collection, product_type),
+        replace=replace,
+        extended_metadata=True,
+        mask_locations=None,
+        package_path=None,
+        overrides={},
+    )
+    collection = models.Collection.objects.get(
+        identifier=collection
+    )
+    models.collection_insert_eo_object(collection, product)
+
+    level = get_product_level(product)
+    if level == 'Level_1':
+        collection_level_1 = models.Collection.objects.get(
+            identifier="%s_Level_1" % collection
+        )
+        models.collection_insert_eo_object(collection_level_1, product)
+    elif level == 'Level_3':
+        collection_level_3 = models.Collection.objects.get(
+            identifier="%s_Level_3" % collection
+        )
+        models.collection_insert_eo_object(collection_level_3, product)
+
+    report = GDALRegistrator().register(
+        data_locations=[[container, data_package, ], ],
+        metadata_locations=[[container,
+                             metadata_package, ], ],
+        coverage_type_name="RGBNir",
+        overrides={"identifier": "%s__coverage" % product.identifier},
+        replace=replace,
+    )
+    models.product_add_coverage(product, report.coverage)
+
+    try:
+        add_mask(product)
+    except Exception as e:
+        logger.info("Couldn't add mask.")
+        logger.debug(traceback.format_exc())
+        logger.warning("%s: %s\n" % (type(e).__name__, str(e)))
+
+    if client is not None:
+        logger.debug(
+            "Storing times in redis queue '%s" % registered_set_key
+        )
+        client.sadd(
+            registered_set_key, "%s/%s"
+            % (
+                product.begin_time.strftime("%Y%m%dT%H%M%S"),
+                product.end_time.strftime("%Y%m%dT%H%M%S")
+            )
+        )
+
+    logger.info(
+        "Successfully finished registration of product '%s'." % objects_prefix
+    )
+
+
+def registrar_redis_wrapper(
+    collection,
+    replace=False, host="localhost", port=6379,
+    register_queue_key="register_queue",
+    registered_set_key="registered_set",
+):
+    client = redis.Redis(
+        host=host, port=port, charset="utf-8", decode_responses=True
+    )
+    while True:
+        logger.debug("waiting for redis queue '%s'..." % register_queue_key)
+        value = client.brpop(register_queue_key)
+        try:
+            registrar(
+                collection,
+                value[1],
+                replace=replace,
+                client=client,
+                registered_set_key=registered_set_key
+            )
+        except Exception as e:
+            logger.debug(traceback.format_exc())
+            logger.error("%s: %s\n" % (type(e).__name__, str(e)))
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser()
+    parser.description = textwrap.dedent("""\
+    Register products.
+    """)
+
+    parser.add_argument(
+        "collection", default=None,
+        help=(
+            "Collection the registrar is run for."
+        )
+    )
+
+    parser.add_argument(
+        "--mode", default="standard", choices=["standard", "redis"],
+        help=(
+            "The mode to run the registrar. Either one-off (standard) or "
+            "reading from a redis queue."
+        )
+    )
+    parser.add_argument(
+        "--objects-prefix", default=None,
+        help=(
+            "Prefix to objects holding the metadata and data of product."
+        )
+    )
+    parser.add_argument(
+        "--replace", action="store_true",
+        help=(
+            "Replace existing products instead of skipping the registration."
+        )
+    )
+    parser.add_argument(
+        "--redis-register-queue-key", default="register_queue"
+    )
+    parser.add_argument(
+        "--redis-registered-set-key", default="registered_set"
+    )
+    parser.add_argument(
+        "--redis-host", default="localhost"
+    )
+    parser.add_argument(
+        "--redis-port", type=int, default=6379
+    )
+
+    parser.add_argument(
+        "-v", "--verbosity", type=int, default=3, choices=[0, 1, 2, 3, 4],
+        help=(
+            "Set verbosity of log output "
+            "(4=DEBUG, 3=INFO, 2=WARNING, 1=ERROR, 0=CRITICAL). (default: 3)"
+        )
+    )
+
+    arg_values = parser.parse_args()
+
+    setup_logging(arg_values.verbosity)
+
+    collection = arg_values.collection
+
+    if collection not in COLLECTION_MAP:
+        logger.critical("Provided collection '%s' is not valid." % collection)
+        sys.exit(1)
+
+    if arg_values.mode == "standard":
+        registrar(
+            collection,
+            arg_values.objects_prefix,
+            replace=arg_values.replace,
+        )
+    else:
+        registrar_redis_wrapper(
+            collection,
+            replace=arg_values.replace,
+            host=arg_values.redis_host,
+            port=arg_values.redis_port,
+            register_queue_key=arg_values.redis_register_queue_key,
+            registered_set_key=arg_values.redis_registered_set_key,
+        )
diff --git a/core/rgbnir_definition.json b/core/rgbnir_definition.json
new file mode 100644
index 0000000000000000000000000000000000000000..f0ab4f6b275da97a6ffe070a54a0ec8d801bac12
--- /dev/null
+++ b/core/rgbnir_definition.json
@@ -0,0 +1,78 @@
+[{
+    "bands": [
+        {
+            "definition": "http://www.opengis.net/def/property/OGC/0/Radiance",
+            "description": "Red Channel",
+            "gdal_interpretation": "RedBand",
+            "identifier": "red",
+            "name": "red",
+            "nil_values": [
+                {
+                    "reason": "http://www.opengis.net/def/nil/OGC/0/unknown",
+                    "value": 0
+                }
+            ],
+            "uom": "W.m-2.Sr-1",
+            "significant_figures": 5,
+            "allowed_value_ranges": [
+                [0, 65535]
+            ]
+        },
+        {
+            "definition": "http://www.opengis.net/def/property/OGC/0/Radiance",
+            "description": "Green Channel",
+            "gdal_interpretation": "GreenBand",
+            "identifier": "green",
+            "name": "green",
+            "nil_values": [
+                {
+                    "reason": "http://www.opengis.net/def/nil/OGC/0/unknown",
+                    "value": 0
+                }
+            ],
+            "uom": "W.m-2.Sr-1",
+            "significant_figures": 5,
+            "allowed_value_ranges": [
+                [0, 65535]
+            ]
+        },
+        {
+            "definition": "http://www.opengis.net/def/property/OGC/0/Radiance",
+            "description": "Blue Channel",
+            "gdal_interpretation": "BlueBand",
+            "identifier": "blue",
+            "name": "blue",
+            "nil_values": [
+                {
+                    "reason": "http://www.opengis.net/def/nil/OGC/0/unknown",
+                    "value": 0
+                }
+            ],
+            "uom": "W.m-2.Sr-1",
+            "significant_figures": 5,
+            "allowed_value_ranges": [
+                [0, 65535]
+            ]
+        },
+        {
+            "definition": "http://www.opengis.net/def/property/OGC/0/Radiance",
+            "description": "Nir Channel",
+            "gdal_interpretation": "NirBand",
+            "identifier": "nir",
+            "name": "nir",
+            "nil_values": [
+                {
+                    "reason": "http://www.opengis.net/def/nil/OGC/0/unknown",
+                    "value": 0
+                }
+            ],
+            "uom": "W.m-2.Sr-1",
+            "significant_figures": 5,
+            "allowed_value_ranges": [
+                [0, 65535]
+            ]
+        }
+    ],
+    "data_type": "Uint16",
+    "name": "RGBNir"
+}]
diff --git a/core/run-httpd.sh b/core/run-httpd.sh
new file mode 100644
index 0000000000000000000000000000000000000000..bc85173f279c2978761ed3f228fe9f5ee189a606
--- /dev/null
+++ b/core/run-httpd.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+/configure.sh
+
+echo "Running gunicorn"
+exec gunicorn --chdir ${INSTALL_DIR}/pdas_instance/ --bind :80 pdas_instance.wsgi:application --workers 8 --timeout 600 --access-logfile - --error-logfile - --log-level warning --disable-redirect-access-to-syslog
diff --git a/core/run-registrar.sh b/core/run-registrar.sh
new file mode 100644
index 0000000000000000000000000000000000000000..76848ac29b270df9eb92d87137e1bdef7abc1479
--- /dev/null
+++ b/core/run-registrar.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+/configure.sh
+
+echo "Running registrar"
+python /registrar.py ${COLLECTION} --mode redis --redis-host ${REDIS_HOST} --redis-port ${REDIS_PORT} --redis-register-queue-key ${REDIS_REGISTER_QUEUE_KEY} --redis-registered-set-key ${REDIS_REGISTERED_SET_KEY}
diff --git a/core/wait-for-database.sh b/core/wait-for-database.sh
new file mode 100644
index 0000000000000000000000000000000000000000..6d163cb4707cbc873d2da861b607c281e5139f11
--- /dev/null
+++ b/core/wait-for-database.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+# wait-for-database.sh
+
+set -e
+
+cmd="$@"
+
+until PGPASSWORD=${DB_PW} psql "${DB_NAME}" -h "${DB_HOST}" -U "${DB_USER}" -c '\q'; do
+  >&2 echo "Database is unavailable - sleeping"
+  sleep 5
+done
+
+>&2 echo "Database is up - executing command ${cmd}"
+exec ${cmd}