diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh
deleted file mode 100644
index ebcdab09250b880a89e23ca815a46494a27ae338..0000000000000000000000000000000000000000
--- a/docker-entrypoint.sh
+++ /dev/null
@@ -1,518 +0,0 @@
-#!/bin/bash
-
-####
-# Docker entrypoint to run hazard code or web services.
-####
-
-set -o errexit;
-set -o errtrace;
-
-readonly WUS="Western US";
-
-readonly CEUS="Central & Eastern US";
-
-readonly VERSION_2014B="v4.1.1";
-
-# check_config_file global return variable
-CHECK_CONFIG_FILE_RETURN="";
-
-# check_site_file global return variable
-CHECK_SITE_FILE_RETURN="";
-
-# get_cous_model global return variable
-GET_COUS_MODEL_RETURN="";
-
-# get_model global return variable
-GET_MODEL_RETURN="";
-
-# get_model_path global return variable
-GET_MODEL_PATH_RETURN="";
-
-# get_nshmp_program global return variable
-GET_NSHMP_PROGRAM_RETURN="";
-
-# Log file
-readonly LOG_FILE="${HAZ_HOME}/docker-entrypoint.log";
-
-MODEL=$(echo ${MODEL} | awk {'print toupper($0)'});
-PROGRAM=$(echo ${PROGRAM} | awk {'print tolower($0)'});
-
-# Docker usage
-readonly USAGE="
-  docker run \\
-      -e RUN_HAZARD=<true | false> \\
-      -e PROGRAM=<deagg | deagg-epsilon | hazard | rate> \\
-      -e MODEL=<WUS-20[08|14|18] | CEUS-20[08|14|18] | COUS-20[08|14|18] | AK-2007> \\
-      -v /absolute/path/to/sites/file:/app/sites.<geojson | csv> \\
-      -v /absolute/path/to/config/file:/app/config.json \\
-      -v /absolute/path/to/output:/app/output \\
-      code.chs.usgs.gov:5001/ghsc/nshmp/images/nshmp-haz-v2;
-";
-
-main() {
-  # Set trap for uncaught errors
-  trap 'error_exit "${BASH_COMMAND}" "$(< ${LOG_FILE})" "${USAGE}"' ERR;
-
-  if [ ${RUN_HAZARD} = true ]; then
-    run_hazard;
-  else
-    run_ws;
-  fi
-}
-
-####
-# Run hazard code.
-# Globals:
-#   (string) GET_MODEL_PATH_RETURN - The return of get_model_path
-#   (string) GET_NSHMP_PROGRAM_RETURN - The return of get_nshmp_program
-#   (string) CHECK_CONFIG_FILE_RETURN - The return of check_config_file
-#   (string) CHECK_SITE_FILE_RETURN - The return of check_site_file
-#   (numnber) IML - The intensity measure level for deagg-iml
-#   (string) JAVA_XMS - Java initial memory
-#   (string) JAVA_XMX - Java max memory
-#   (string) MODEL - The nshm
-#   (boolean) MOUNT_MODEL - Whether to mount the model instead of selecting model
-#   (string) PROGRAM - The program to run
-#   (number) RETURN_PERIOD - The return period for deagg
-# Arguments:
-#   None
-# Returns:
-#   None
-####
-run_hazard() {
-  # Get Java class to run
-  get_nshmp_program 2> ${LOG_FILE};
-  local nshmp_program="${GET_NSHMP_PROGRAM_RETURN}";
-
-  # Get model path
-  local nshmp_model_path="";
-  if [ ${MOUNT_MODEL} = true ]; then
-    nshmp_model_path="model";
-  else
-    get_model_path 2> ${LOG_FILE};
-    nshmp_model_path="${GET_MODEL_PATH_RETURN}";
-  fi
-
-  # Check site file
-  check_sites_file 2> ${LOG_FILE};
-  local site_file="${CHECK_SITE_FILE_RETURN}";
-
-  # Check config file
-  echo "{}" > ${CONFIG_FILE};
-  check_config_file 2> ${LOG_FILE};
-  local config_file="${CHECK_CONFIG_FILE_RETURN}";
-
-  # Monitor log file
-  tail -f ${LOG_FILE} &
-
-  # Run nshmp-haz
-  java -Xms${JAVA_XMS} -Xmx${JAVA_XMX} \
-      -cp /app/${PROJECT}.jar \
-      gov.usgs.earthquake.nshmp.${nshmp_program} \
-      "${nshmp_model_path}" \
-      "${site_file}" \
-      ${RETURN_PERIOD:+ "${RETURN_PERIOD}"} \
-      ${IML:+ "${IML}"} \
-      "${config_file}" 2> ${LOG_FILE} || \
-      error_exit "Failed running nshmp-haz" "$(tail -n 55 ${LOG_FILE})" "${USAGE}";
-
-  # Move artifacts to mounted volume
-  move_to_output_volume 2> ${LOG_FILE};
-}
-
-####
-# Run web services in Tomcat.
-# Globals:
-#   None
-# Arguments:
-#   None
-# Returns:
-#   None
-####
-run_ws() {
-  get_ws_models;
-
-  java -jar ${PROJECT}-ws.jar \
-      "-Dmicronaut.server.context-path=${CONTEXT_PATH}" \
-      -model=/app/models
-}
-
-####
-# Check that the config file is valid json.
-# Globals:
-#   (string) CONFIG_FILE - The config file name
-#   (string) CHECK_CONFIG_FILE_RETURN - The return for the function
-# Arguments:
-#   None
-# Returns:
-#   (string) CHECK_CONFIG_FILE_RETURN - The config file name
-####
-check_config_file() {
-  # Check if file is valid JSON
-  jq empty < ${CONFIG_FILE} 2> ${LOG_FILE} || \
-      error_exit "Config file is not valid JSON" "$(< ${LOG_FILE})" "${USAGE}";
-
-  # Return
-  CHECK_CONFIG_FILE_RETURN=${CONFIG_FILE};
-}
-
-####
-# Check that the sites file is valid.
-# Globals:
-#   (string) CHECK_SITE_FILE_RETURN - The return for the function
-# Arguments:
-#   None
-# Returns:
-#   (string) CHECK_SITE_FILE_RETURN - The site file name
-####
-check_sites_file() {
-  local site_file=$(ls sites*) 2> ${LOG_FILE} || \
-      error_exit "Site file does not exist." "$(< ${LOG_FILE})" "${USAGE}";
-
-  # Check if valid JSON or ASCII file
-  case ${site_file} in
-    *.geojson)
-      jq empty < ${site_file} 2> ${LOG_FILE} || \
-          error_exit "Site file [${site_file}] is not valid JSON" "$(< ${LOG_FILE})" "${USAGE}";
-      ;;
-    *.csv)
-      if [[ "$(file ${site_file} -b)" != "ASCII text"* ]]; then
-        error_exit \
-            "Site file [${site_file}] is not valid ASCII" \
-            "Site file is not valid ASCII" \
-            "${USAGE}";
-      fi
-      ;;
-    *)
-      error_exit "Bad site file [${site_file}]." "Bad site file." "${USAGE}";
-      ;;
-  esac
-
-  # Return
-  CHECK_SITE_FILE_RETURN=${site_file};
-}
-
-####
-# Download a repository from Github.
-# Globals:
-#   (string) LOG_FILE - The log file
-# Arguments:
-#   (string) user - The Github user
-#   (string) repo - The project to download
-#   (string) version - The version to download
-#   (string) directory - The direcotry name for repo download
-# Returns:
-#   None
-####
-download_repo() {
-  local usage="download_repo <user> <repo> <version>";
-
-  local user=${1};
-  local repo=${2};
-  local version=${3};
-  local directory=${4};
-  local url="https://github.com/${user}/${repo}/archive/${version}.tar.gz";
-
-  if [ ${version} == "null" ]; then
-    printf "\n Skipping download of [${user}/${repo}]\n";
-    return;
-  fi
-
-  printf "\n Downloading ${repo} [${url}] \n\n";
-
-  if [ -z "${directory}" ]; then
-    directory=${repo};
-  fi
-
-  curl -L ${url} | tar -xz 2> ${LOG_FILE} || \
-      error_exit "Could not download [${url}]" "$(< ${LOG_FILE})" "${usage}";
-
-  mv ${repo}-${version#v*} ${directory};
-}
-
-####
-# Exit script with error.
-# Globals:
-#   None
-# Arguments:
-#   (string) err - The error message
-#   (string) logs - The log for the error
-#   (string) usage - The Docker usage
-# Returns:
-#   None
-####
-error_exit() {
-  local err="${1}";
-  local logs="${2}";
-  local usage="${3}";
-
-  local message="
-    Error:
-    ${err}
-
-    ----------
-    Logs:
-
-    ${logs}
-
-    ----------
-    Usage:
-
-    ${usage}
-
-  ";
-
-  printf "${message}";
-
-  exit -1;
-}
-
-####
-# Returns the model path for deagg-epsilon and hazard-2018.
-# Globals:
-#   (string) MODEL - The nshm
-#   (string) PROGRAM - The program to run
-#   (string) GET_COUS_MODEL_RETURN - The return for the function
-#   (string) NSHM_VERSION - The NSHM repository version
-# Arguments:
-#   None
-# Returns:
-#   (string) GET_COUS_MODEL_RETURN - The cous model path
-####
-get_cous_model() {
-  local model="";
-  local version="${NSHM_VERSION}";
-
-  case ${MODEL} in
-    "AK-2007")
-      model="nshm-ak-2007";
-      ;;
-    "CONUS-2008")
-      model="nshm-cous-2008";
-      ;;
-    "CONUS-2014")
-      model="nshm-cous-2014";
-      ;;
-    "CONUS-2014B")
-      model="nshm-cous-2014";
-      version="${VERSION_2014B}";
-      ;;
-    "CONUS-2018")
-      model="nshm-cous-2018";
-      ;;
-    "HI-2020")
-      model="nshm-hi-2020";
-      ;;
-    *)
-      error_exit \
-          "Model [${MODEL}] not supported for program [${PROGRAM}]" \
-          "Model not supported" \
-          "${USAGE}";
-      ;;
-  esac
-
-  download_repo "usgs" ${model} ${version};
-
-  # Return
-  GET_COUS_MODEL_RETURN=${model};
-}
-
-####
-# Returns the model path for all programs except deagg-epsilon.
-# Globals:
-#   (string) MODEL - The nshm
-#   (string) PROGRAM - The program to run
-#   (string) GET_MODEL_RETURN - The return for the function
-#   (string) NSHM_VERSION - The NSHM repository version
-# Arguments:
-#   None
-# Returns:
-#   (string) GET_MODEL_RETURN - The model path
-####
-get_model() {
-  local model=""
-  local model_path=""
-  local version="master"
-
-  case ${MODEL} in
-    "AK-2007")
-      model="nshm-ak-2007";
-      model_path="${model}";
-      ;;
-    "HI-2020")
-      model="nshm-hi-2020";
-      model_path="${model}";
-      ;;
-    "CEUS-2008")
-      model="nshm-cous-2008";
-      model_path="${model}/${CEUS}/";
-      ;;
-    "CEUS-2014")
-      model="nshm-cous-2014";
-      model_path="${model}/${CEUS}/";
-      ;;
-    "CEUS-2014B")
-      model="nshm-cous-2014";
-      model_path="${model}/${CEUS}/";
-      version="${VERSION_2014B}";
-      ;;
-    "CEUS-2018")
-      model="nshm-cous-2018";
-      model_path="${model}/${CEUS}/";
-      ;;
-    "WUS-2008")
-      model="nshm-cous-2008";
-      model_path="${model}/${WUS}/";
-      ;;
-    "WUS-2014")
-      model="nshm-cous-2014";
-      model_path="${model}/${WUS}/";
-      ;;
-    "WUS-2014B")
-      model="nshm-cous-2014";
-      model_path="${model}/${WUS}/";
-      version="${VERSION_2014B}";
-      ;;
-    "WUS-2018")
-      model="nshm-cous-2018";
-      model_path="${model}/${WUS}/";
-      ;;
-    *)
-      error_exit \
-          "Model [${MODEL}] not supported for program [${PROGRAM}]" \
-          "Model not supported" \
-          "${USAGE}";
-      ;;
-  esac
-
-  download_repo "usgs" ${model} ${version};
-
-  # Return
-  GET_MODEL_RETURN=${model_path}
-}
-
-####
-# Returns the path to the model.
-# Globals:
-#   (string) PROGRAM - The program to run
-#   (string) GET_MODEL_PATH_RETURN - The return value for the funciton
-#   (string) GET_COUS_MODEL_RETURN -  The return for get_cous_model
-#   (string) GET_MODEL_RETURN - The return for get_model
-# Arguments:
-#   None
-# Returns:
-#   (string) GET_MODEL_PATH_RETURN - The model path
-####
-get_model_path() {
-  local nshmp_model_path="";
-
-  if [ ${PROGRAM} == 'deagg-epsilon' ] || [ ${PROGRAM} == 'hazard-2018' ]; then
-    get_cous_model 2> ${LOG_FILE};
-    nshmp_model_path="${GET_COUS_MODEL_RETURN}";
-  else
-    get_model 2> ${LOG_FILE};
-    nshmp_model_path="${GET_MODEL_RETURN}";
-  fi
-
-  # Return
-  GET_MODEL_PATH_RETURN=${nshmp_model_path};
-}
-
-####
-# Returns to nshmp-haz Java class to call.
-# Globals:
-#   (string) PROGRAM - The program to run: deagg | deagg-epsilon | hazard | rate
-#   (string) GET_NSHMP_PROGRAM_RETURN - The return value for the function
-# Arguments:
-#   None
-# Returns:
-#   (string) GET_NSHMP_PROGRAM_RETURN - The Java class to call
-####
-get_nshmp_program() {
-  local nshmp_program="";
-
-  case ${PROGRAM} in
-    "deagg")
-      nshmp_program="DeaggCalc";
-      ;;
-    "deagg-epsilon")
-      nshmp_program="DeaggEpsilon";
-      ;;
-    "deagg-iml")
-      nshmp_program="DeaggIml";
-      ;;
-    "hazard-2018")
-      nshmp_program="Hazard2018";
-      ;;
-    "hazard")
-      nshmp_program="HazardCalc";
-      ;;
-    "rate")
-      nshmp_program="RateCalc";
-      ;;
-    *)
-      error_exit "Program [${PROGRAM}] not supported" "Program not supported" "${USAGE}";
-      ;;
-  esac
-
-  # Return
-  GET_NSHMP_PROGRAM_RETURN=${nshmp_program};
-}
-
-####
-# Get NSHMs for web services.
-# Globals:
-#   (string) GET_COUS_MODEL_RETURN - The return of get_cous_model
-#   (string) LOG_FILE - The log file
-#   (string) WS_HOME - The home for running the web services
-# Arguments:
-#   None
-# Returns:
-#   None
-####
-get_ws_models() {
-  mkdir models 2> ${LOG_FILE};
-  cd models 2> ${LOG_FILE};
-  get_cous_model 2> ${LOG_FILE};
-  local nshm_model="${GET_COUS_MODEL_RETURN}";
-  local model="$(echo ${MODEL} | cut -d - -f1 | awk {'print tolower($0)'})" 2> ${LOG_FILE};
-  local year="$(echo ${MODEL} | cut -d - -f2 | awk {'print tolower($0)'})" 2> ${LOG_FILE};
-
-  if [ ${model} == 'conus' ]; then
-    mkdir wus ceus 2> ${LOG_FILE};
-    mv "${nshm_model}/${CEUS}" ceus/${year} 2> ${LOG_FILE};
-    mv "${nshm_model}/${WUS}" wus/${year} 2> ${LOG_FILE};
-    rm -r ${nshm_model};
-  else
-    mkdir ${model} 2> ${LOG_FILE};
-    mv ${nshm_model} ${model}/${year} 2> ${LOG_FILE};
-  fi
-
-  cd ${WS_HOME} 2> ${LOG_FILE};
-}
-
-####
-# Move artifacts to mounted volume.
-# Globals:
-#   (string) CONFIG_FILE - The config file name
-# Arguments:
-#   None
-# Returns:
-#   None
-####
-move_to_output_volume() {
-  # Get output directory
-  local hazout=$(jq -r '.output.directory' ${CONFIG_FILE});
-
-  if [ ${hazout} == null ]; then
-    hazout="hazout";
-  fi
-
-  # Copy output to volume output
-  cp -r ${hazout}/* output/. 2> ${LOG_FILE};
-}
-
-####
-# Run main
-####
-main "$@";
diff --git a/docker-entrypoint.ws.sh b/docker-entrypoint.ws.sh
deleted file mode 100644
index 9b2f240ae470a205317641023b814b191f8ebf44..0000000000000000000000000000000000000000
--- a/docker-entrypoint.ws.sh
+++ /dev/null
@@ -1,216 +0,0 @@
-#!/bin/bash
-
-####
-# Docker entrypoint to run web services.
-####
-
-readonly CEUS="Central & Eastern US";
-readonly CONTEXT_PATH="${CONTEXT_PATH:-/}";
-readonly DEBUG="${DEUB:-false}";
-readonly MODEL=$(echo "${MODEL:-${1}}"  | awk \{'print toupper($0)'\});
-readonly NSHM_VERSION="${NSHM_VERSION:-master}";
-readonly PROJECT="${PROJECT:-nshmp-haz-v2}";
-readonly WUS="Western US";
-readonly VERSION_2014B="v4.1.1";
-
-####
-# Start web services
-#
-# @param $1 nshm {String}
-#     The NSHM to download.
-# @param $1 nshm_version {String}
-#     The version to download from GitHub.
-#
-# @status Integer
-#     The result for get_model
-####
-main() {
-  local nshm=${1};
-  local nshm_version=${2};
-  local model_path;
-  local exit_status;
-
-  if [ "${DEBUG}" == "true" ]; then
-    set -x;
-  fi;
-
-  model_path=$(get_models "${nshm}" "${nshm_version}");
-  exit_status=${?};
-
-  echo "${model_path}";
-  ls;
-  ls "${model_path}";
-
-  if [ "${exit_status}" -eq 0 ]; then
-    java -jar "${PROJECT}-ws.jar" \
-        "-Dmicronaut.server.context-path=${CONTEXT_PATH}" \
-        --model="/app/${model_path}";
-    exit_status=${?};
-  fi
-
-  return ${exit_status};
-}
-
-####
-# Download a repository from Github.
-#
-# @param $1 repo {String}
-#     The repository name
-# @param $2 url {String}
-#     The url to download
-#
-# @status Integer
-#     The status of the curl call
-####
-download_repo() {
-  local repo=${1};
-  local url=${2};
-  local exit_status;
-
-  curl -L "${url}" | tar -xz;
-  exit_status=${?};
-
-  if [ ${exit_status} -eq 0 ]; then
-    mv "${repo}-*" "${repo}";
-  else
-    error_exit "Could not download [${url}]" ${exit_status};
-  fi
-
-  return ${exit_status};
-}
-
-####
-# Exit with an error message.
-#
-# @param $1 msg {String}
-#     The message for exit
-# @param $2 exit_status {Integer}
-#     The exit status
-####
-error_exit() {
-  local msg=${1};
-  local exit_status=${2}
-  echo "Error: ${msg}" >> /dev/stderr;
-  exit "${exit_status}";
-}
-
-####
-# Returns the model path for deagg-epsilon and hazard-2018.
-#
-# @param $1 nshm {String}
-#     The NSHM to download.
-# @param $1 nshm_version {String}
-#     The version to download from GitHub.
-#
-# @return String
-#     The model path
-# @status Integer
-#     The result of downloading the repository.
-####
-get_model() {
-  local nshm=${1};
-  local nshm_version=${2};
-  local model;
-  local url;
-  local exit_status;
-
-  if [ "${nshm_version}" == "null" ]; then
-    return 0;
-  fi
-
-  case ${nshm} in
-    "AK-2007")
-      model="nshm-ak-2007";
-      url="https://github.com/usgs/${model}/archive/${nshm_version}.tar.gz";
-      ;;
-    "CONUS-2008")
-      model="nshm-cous-2008";
-      url="https://github.com/usgs/${model}/archive/${nshm_version}.tar.gz";
-      ;;
-    "CONUS-2014")
-      model="nshm-cous-2014";
-      url="https://github.com/usgs/${model}/archive/${nshm_version}.tar.gz";
-      ;;
-    "CONUS-2014B")
-      model="nshm-cous-2014";
-      nshm_version="${VERSION_2014B}";
-      url="https://github.com/usgs/${model}/archive/${nshm_version}.tar.gz";
-      ;;
-    "CONUS-2018")
-      model="nshm-cous-2018";
-      url="https://github.com/usgs/${model}/archive/${nshm_version}.tar.gz";
-      ;;
-    "HI-2020")
-      model="nshm-hi-2020";
-      url="https://github.com/usgs/${model}/archive/${nshm_version}.tar.gz";
-      ;;
-    *)
-      error_exit "Model [${nshm}] not supported" 1;
-      ;;
-  esac
-
-  download_repo "${url}";
-  exit_status=${?};
-
-  echo ${model};
-  return ${exit_status}
-}
-
-####
-# Get NSHMs for web services.
-#
-# @param $1 nshm {String}
-#     The NSHM to download.
-# @param $1 nshm_version {String}
-#     The version to download from GitHub.
-#
-# @status Integer
-#     The result for get_model
-####
-get_models() {
-  local nshm=${1};
-  local nshm_version=${2};
-  local model_base_path="models";
-  local nshm_path;
-  local exit_status;
-
-  if [ -d "${model_base_path}" ]; then
-    rm -rf "${model_base_path:?}/*";
-  else
-    mkdir ${model_base_path};
-  fi
-
-  cd ${model_base_path} || error_exit "Could not change directory [${model_base_path}]" 1;
-  nshm_path=$(get_model "${nshm}" "${nshm_version}");
-  exit_status=${?};
-
-  if [ ${exit_status} -eq 0 ]; then
-    local model;
-    local year;
-    model="$(echo "${nshm}" | cut -d - -f1 | awk \{'print tolower($0)'\})";
-    year="$(echo "${nshm}" | cut -d - -f2 | awk \{'print tolower($0)'\})";
-
-    if [ "${model}" == 'conus' ]; then
-      mkdir wus ceus;
-      mv "${nshm_path}/${CEUS}" "ceus/${year}";
-      mv "${nshm_path}/${WUS}" "wus/${year}";
-      rm -r "${nshm_path}";
-    else
-      mkdir "${model}";
-      mv "${nshm_path}" "${model}/${year}";
-    fi
-  fi
-
-  cd ../;
-
-  echo ${model_base_path};
-  return ${exit_status};
-}
-
-####
-# Run main
-####
-main "${MODEL}" "${NSHM_VERSION}";
-exit_status=${?};
-
-exit ${exit_status};
diff --git a/scripts/docker-entrypoint.sh b/scripts/docker-entrypoint.sh
new file mode 100644
index 0000000000000000000000000000000000000000..3fbe1f8c47f4c07d72eb0bb6b7cf4049ee72313d
--- /dev/null
+++ b/scripts/docker-entrypoint.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+# shellcheck disable=SC1090
+
+source "$(dirname "${0}")/docker-config.inc.sh";
+exit_status=${?};
+[ "${exit_status}" -eq 0 ] || exit "${exit_status}";
+
+# Get nshmp program to call
+nshmp_program=$(get_nshmp_program "${PROGRAM}");
+exit_status=${?};
+check_exit_status "${exit_status}";
+
+# Get model path to use
+if [ "${MOUNT_MODEL}" = true ]; then
+  nshm_path="model";
+else
+  nshm_path=$(get_model_path "${MODEL}" "${NSHM_VERSION}");
+  exit_status=${?};
+  check_exit_status "${exit_status}";
+fi
+
+# Check site file and get site file path
+site_file=$(check_sites_file);
+exit_status=${?};
+check_exit_status "${exit_status}";
+
+# Check config file
+[ -f "${CONFIG_FILE}" ] || echo "{}" > "${CONFIG_FILE}";
+jq empty < "${CONFIG_FILE}";
+exit_status=${?};
+check_exit_status "${exit_status}";
+
+# Run nshmp-haz
+java -"Xmx${JAVA_XMX}" \
+    -cp "/app/${PROJECT}.jar" \
+    "gov.usgs.earthquake.nshmp.${nshmp_program}" \
+    "${nshm_path}" \
+    "${site_file}" \
+    ${RETURN_PERIOD:+ "${RETURN_PERIOD}"} \
+    ${IML:+ "${IML}"} \
+    "${CONFIG_FILE}";
+exit_status=${?};
+check_exit_status "${exit_status}";
+
+# Move results to container volume
+move_to_output_volume;
+exit_status=${?};
+check_exit_status "${exit_status}";
+
+exit ${exit_status};
diff --git a/scripts/docker-entrypoint.ws.sh b/scripts/docker-entrypoint.ws.sh
new file mode 100644
index 0000000000000000000000000000000000000000..ff2bc5aca605d735443783614ce89baf33908110
--- /dev/null
+++ b/scripts/docker-entrypoint.ws.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# shellcheck disable=SC1090
+
+source "$(dirname "${0}")/docker-config.inc.sh";
+exit_status=${?};
+[ "${exit_status}" -eq 0 ] || exit "${exit_status}";
+
+# Download models to use
+model_path=$(get_models "${MODEL}" "${NSHM_VERSION}");
+exit_status=${?};
+check_exit_status ${exit_status};
+
+# Run web services
+java -jar "${PROJECT}-ws.jar" \
+    "-Dmicronaut.server.context-path=${CONTEXT_PATH}" \
+    --model="/app/${model_path}";
+exit_status=${?};
+check_exit_status ${exit_status};
+
+exit ${exit_status};