From 3646c1ea6b68a612948c5728a256339d96954284 Mon Sep 17 00:00:00 2001 From: cytopia Date: Sun, 18 Dec 2022 16:39:21 +0100 Subject: [PATCH] Stash commit --- Dockerfiles/Dockerfile.alpine | 21 +- Dockerfiles/Dockerfile.debian | 21 +- Dockerfiles/data/create-vhost.sh | 239 +++++- .../data/docker-entrypoint.d/.httpd/README.md | 3 + .../.httpd/func-backend.sh | 283 +++++++ .../.httpd/func-vhostgen.sh | 103 +++ .../data/docker-entrypoint.d/.lib/README.md | 3 + .../data/docker-entrypoint.d/.lib/func-env.sh | 57 ++ .../docker-entrypoint.d/.lib/func-logger.sh | 72 ++ .../docker-entrypoint.d/.lib/func-misc.sh | 25 + .../data/docker-entrypoint.d/.lib/func-run.sh | 58 ++ .../.lib/func-validator.sh | 168 ++++ .../data/docker-entrypoint.d/00-base-libs.sh | 103 --- .../docker-entrypoint.d/01-env-vars-export.sh | 78 ++ .../data/docker-entrypoint.d/01-uid-gid.sh | 134 --- .../02-env-vars-validate.sh | 769 ++++++++++++++++++ .../data/docker-entrypoint.d/02-timezone.sh | 38 - .../docker-entrypoint.d/03-docker-logs.sh | 37 - .../data/docker-entrypoint.d/04-php-fpm.sh | 133 --- .../data/docker-entrypoint.d/05-main-vhost.sh | 214 ----- .../data/docker-entrypoint.d/06-mass-vhost.sh | 165 ---- .../data/docker-entrypoint.d/07-vhost-gen.sh | 194 ----- .../docker-entrypoint.d/09-fix-permissions.sh | 42 - .../docker-entrypoint.d/10-config-settings.sh | 66 -- .../data/docker-entrypoint.d/10-uid-gid.sh | 135 +++ .../data/docker-entrypoint.d/11-timezone.sh | 27 + .../data/docker-entrypoint.d/12-vhost-gen.sh | 231 ++++++ .../{08-cert-gen.sh => 13-cert-gen.sh} | 51 +- .../docker-entrypoint.d/14-fix-permissions.sh | 28 + .../{11-supervisord.sh => 15-supervisord.sh} | 5 +- .../data/docker-entrypoint.d/99-nginx.sh | 33 + Dockerfiles/data/docker-entrypoint.sh | 456 ++++++++--- Dockerfiles/data/vhost-gen/mass-plain.yml | 159 ++++ Dockerfiles/data/vhost-gen/mass-rproxy.yml | 160 ++++ README.md | 2 +- doc/environment-variables.md | 4 +- doc/features.md | 30 +- examples/README.md | 14 + examples/default-vhost__php-fpm/README.md | 13 + .../default-vhost__php-fpm/docker-compose.yml | 32 + .../integration-test.sh | 20 + examples/default-vhost__php-fpm/www/index.php | 2 + .../default-vhost__php-fpm__ssl/README.md | 17 + .../docker-compose.yml | 34 + .../integration-test.sh | 26 + .../default-vhost__php-fpm__ssl/www/index.php | 2 + .../README.md | 17 + .../docker-compose.yml | 28 + .../integration-test.sh | 26 + .../www/app.js | 9 + .../README.md | 17 + .../docker-compose.yml | 28 + .../integration-test.sh | 26 + .../www/server.py | 11 + .../default-vhost__static-files/README.md | 13 + .../docker-compose.yml | 19 + .../integration-test.sh | 20 + .../www/index.html | 2 + examples/mass-vhost__php-fpm__ssl/README.md | 81 ++ examples/mass-vhost__php-fpm__ssl/ca/.keep | 0 .../ca/devilbox-ca.crt | 31 + .../ca/devilbox-ca.key | 27 + .../ca/devilbox-ca.srl | 1 + .../docker-compose.yml | 38 + .../integration-test.sh | 39 + .../projects/sample/htdocs | 1 + .../projects/sample/src/index.php | 4 + .../projects/test/htdocs/index.php | 4 + .../mass-vhost__reverse-proxy__ssl/README.md | 8 + .../mass-vhost__reverse-proxy__ssl/ca/.keep | 0 .../ca/devilbox-ca.crt | 31 + .../ca/devilbox-ca.key | 27 + .../ca/devilbox-ca.srl | 1 + .../docker-compose.yml | 49 ++ .../integration-test.sh | 39 + .../intranet/index.html | 14 + .../projects/node/REAMDE.md | 0 .../projects/node/cfg/backend.txt | 1 + .../projects/node/src/app.js | 9 + .../projects/php/README.md | 0 .../projects/php/cfg/backend.txt | 1 + .../projects/php/htdocs/index.php | 2 + tests/00-test-html.sh | 2 +- tests/01-test-php.sh | 6 +- tests/02-timezone.sh | 6 +- tests/03-test-xargs.sh | 2 +- 86 files changed, 3820 insertions(+), 1327 deletions(-) create mode 100644 Dockerfiles/data/docker-entrypoint.d/.httpd/README.md create mode 100755 Dockerfiles/data/docker-entrypoint.d/.httpd/func-backend.sh create mode 100755 Dockerfiles/data/docker-entrypoint.d/.httpd/func-vhostgen.sh create mode 100644 Dockerfiles/data/docker-entrypoint.d/.lib/README.md create mode 100755 Dockerfiles/data/docker-entrypoint.d/.lib/func-env.sh create mode 100755 Dockerfiles/data/docker-entrypoint.d/.lib/func-logger.sh create mode 100755 Dockerfiles/data/docker-entrypoint.d/.lib/func-misc.sh create mode 100755 Dockerfiles/data/docker-entrypoint.d/.lib/func-run.sh create mode 100755 Dockerfiles/data/docker-entrypoint.d/.lib/func-validator.sh delete mode 100755 Dockerfiles/data/docker-entrypoint.d/00-base-libs.sh create mode 100755 Dockerfiles/data/docker-entrypoint.d/01-env-vars-export.sh delete mode 100755 Dockerfiles/data/docker-entrypoint.d/01-uid-gid.sh create mode 100755 Dockerfiles/data/docker-entrypoint.d/02-env-vars-validate.sh delete mode 100755 Dockerfiles/data/docker-entrypoint.d/02-timezone.sh delete mode 100755 Dockerfiles/data/docker-entrypoint.d/03-docker-logs.sh delete mode 100755 Dockerfiles/data/docker-entrypoint.d/04-php-fpm.sh delete mode 100755 Dockerfiles/data/docker-entrypoint.d/05-main-vhost.sh delete mode 100755 Dockerfiles/data/docker-entrypoint.d/06-mass-vhost.sh delete mode 100755 Dockerfiles/data/docker-entrypoint.d/07-vhost-gen.sh delete mode 100755 Dockerfiles/data/docker-entrypoint.d/09-fix-permissions.sh delete mode 100755 Dockerfiles/data/docker-entrypoint.d/10-config-settings.sh create mode 100755 Dockerfiles/data/docker-entrypoint.d/10-uid-gid.sh create mode 100755 Dockerfiles/data/docker-entrypoint.d/11-timezone.sh create mode 100755 Dockerfiles/data/docker-entrypoint.d/12-vhost-gen.sh rename Dockerfiles/data/docker-entrypoint.d/{08-cert-gen.sh => 13-cert-gen.sh} (55%) create mode 100755 Dockerfiles/data/docker-entrypoint.d/14-fix-permissions.sh rename Dockerfiles/data/docker-entrypoint.d/{11-supervisord.sh => 15-supervisord.sh} (98%) create mode 100755 Dockerfiles/data/docker-entrypoint.d/99-nginx.sh create mode 100644 Dockerfiles/data/vhost-gen/mass-plain.yml create mode 100644 Dockerfiles/data/vhost-gen/mass-rproxy.yml create mode 100644 examples/README.md create mode 100644 examples/default-vhost__php-fpm/README.md create mode 100644 examples/default-vhost__php-fpm/docker-compose.yml create mode 100755 examples/default-vhost__php-fpm/integration-test.sh create mode 100644 examples/default-vhost__php-fpm/www/index.php create mode 100644 examples/default-vhost__php-fpm__ssl/README.md create mode 100644 examples/default-vhost__php-fpm__ssl/docker-compose.yml create mode 100755 examples/default-vhost__php-fpm__ssl/integration-test.sh create mode 100644 examples/default-vhost__php-fpm__ssl/www/index.php create mode 100644 examples/default-vhost__reverse-proxy__node/README.md create mode 100644 examples/default-vhost__reverse-proxy__node/docker-compose.yml create mode 100755 examples/default-vhost__reverse-proxy__node/integration-test.sh create mode 100644 examples/default-vhost__reverse-proxy__node/www/app.js create mode 100644 examples/default-vhost__reverse-proxy__python/README.md create mode 100644 examples/default-vhost__reverse-proxy__python/docker-compose.yml create mode 100755 examples/default-vhost__reverse-proxy__python/integration-test.sh create mode 100644 examples/default-vhost__reverse-proxy__python/www/server.py create mode 100644 examples/default-vhost__static-files/README.md create mode 100644 examples/default-vhost__static-files/docker-compose.yml create mode 100755 examples/default-vhost__static-files/integration-test.sh create mode 100644 examples/default-vhost__static-files/www/index.html create mode 100644 examples/mass-vhost__php-fpm__ssl/README.md create mode 100644 examples/mass-vhost__php-fpm__ssl/ca/.keep create mode 100644 examples/mass-vhost__php-fpm__ssl/ca/devilbox-ca.crt create mode 100644 examples/mass-vhost__php-fpm__ssl/ca/devilbox-ca.key create mode 100644 examples/mass-vhost__php-fpm__ssl/ca/devilbox-ca.srl create mode 100644 examples/mass-vhost__php-fpm__ssl/docker-compose.yml create mode 100755 examples/mass-vhost__php-fpm__ssl/integration-test.sh create mode 120000 examples/mass-vhost__php-fpm__ssl/projects/sample/htdocs create mode 100644 examples/mass-vhost__php-fpm__ssl/projects/sample/src/index.php create mode 100644 examples/mass-vhost__php-fpm__ssl/projects/test/htdocs/index.php create mode 100644 examples/mass-vhost__reverse-proxy__ssl/README.md create mode 100644 examples/mass-vhost__reverse-proxy__ssl/ca/.keep create mode 100644 examples/mass-vhost__reverse-proxy__ssl/ca/devilbox-ca.crt create mode 100644 examples/mass-vhost__reverse-proxy__ssl/ca/devilbox-ca.key create mode 100644 examples/mass-vhost__reverse-proxy__ssl/ca/devilbox-ca.srl create mode 100644 examples/mass-vhost__reverse-proxy__ssl/docker-compose.yml create mode 100755 examples/mass-vhost__reverse-proxy__ssl/integration-test.sh create mode 100644 examples/mass-vhost__reverse-proxy__ssl/intranet/index.html create mode 100644 examples/mass-vhost__reverse-proxy__ssl/projects/node/REAMDE.md create mode 100644 examples/mass-vhost__reverse-proxy__ssl/projects/node/cfg/backend.txt create mode 100644 examples/mass-vhost__reverse-proxy__ssl/projects/node/src/app.js create mode 100644 examples/mass-vhost__reverse-proxy__ssl/projects/php/README.md create mode 100644 examples/mass-vhost__reverse-proxy__ssl/projects/php/cfg/backend.txt create mode 100644 examples/mass-vhost__reverse-proxy__ssl/projects/php/htdocs/index.php diff --git a/Dockerfiles/Dockerfile.alpine b/Dockerfiles/Dockerfile.alpine index 7efebb3..196e032 100644 --- a/Dockerfiles/Dockerfile.alpine +++ b/Dockerfiles/Dockerfile.alpine @@ -11,9 +11,9 @@ LABEL \ ### ### Build arguments ### -ARG VHOST_GEN_GIT_REF=1.0.3 -ARG WATCHERD_GIT_REF=v1.0.2 -ARG CERT_GEN_GIT_REF=0.7 +ARG VHOST_GEN_GIT_REF=1.0.5 +ARG WATCHERD_GIT_REF=v1.0.6 +ARG CERT_GEN_GIT_REF=0.9 ENV BUILD_DEPS \ make \ @@ -34,7 +34,7 @@ ENV RUN_DEPS \ ENV MY_USER=nginx ENV MY_GROUP=nginx ENV HTTPD_START="/usr/sbin/nginx" -ENV HTTPD_RELOAD="nginx -s stop" +ENV HTTPD_RELOAD="nginx -s stop 2>/dev/null" ### @@ -60,7 +60,7 @@ RUN set -eux \ && chmod +x /usr/bin/cert-gen \ \ # Install watcherd - && wget --no-check-certificate -O /usr/bin/watcherd https://raw.githubusercontent.com/devilbox/watcherd/${WATCHERD_GIT_REF}/watcherd \ + && wget --no-check-certificate -O /usr/bin/watcherd https://raw.githubusercontent.com/devilbox/watcherd/${WATCHERD_GIT_REF}/bin/watcherd \ && chmod +x /usr/bin/watcherd \ \ # Clean-up @@ -90,14 +90,25 @@ RUN set -eux \ && ln -sf /usr/bin/python3 /usr/bin/python +### +### Set timezone +### +RUN set -eux \ + && if [ -f /etc/localtime ]; then rm /etc/localtime; fi \ + && ln -s /usr/share/zoneinfo/UTC /etc/localtime + + ### ### Copy files ### COPY ./data/nginx/nginx.conf /etc/nginx/nginx.conf + COPY ./data/vhost-gen/main.yml /etc/vhost-gen/main.yml COPY ./data/vhost-gen/mass.yml /etc/vhost-gen/mass.yml + COPY ./data/vhost-gen/templates-main /etc/vhost-gen/templates-main COPY ./data/create-vhost.sh /usr/local/bin/create-vhost.sh + COPY ./data/docker-entrypoint.d /docker-entrypoint.d COPY ./data/docker-entrypoint.sh /docker-entrypoint.sh diff --git a/Dockerfiles/Dockerfile.debian b/Dockerfiles/Dockerfile.debian index 64063b7..f7bd554 100644 --- a/Dockerfiles/Dockerfile.debian +++ b/Dockerfiles/Dockerfile.debian @@ -11,9 +11,9 @@ LABEL \ ### ### Build arguments ### -ARG VHOST_GEN_GIT_REF=1.0.3 -ARG WATCHERD_GIT_REF=v1.0.2 -ARG CERT_GEN_GIT_REF=0.7 +ARG VHOST_GEN_GIT_REF=1.0.5 +ARG WATCHERD_GIT_REF=v1.0.6 +ARG CERT_GEN_GIT_REF=0.9 ENV BUILD_DEPS \ make \ @@ -31,7 +31,7 @@ ENV RUN_DEPS \ ENV MY_USER=nginx ENV MY_GROUP=nginx ENV HTTPD_START="/usr/sbin/nginx" -ENV HTTPD_RELOAD="nginx -s stop" +ENV HTTPD_RELOAD="nginx -s stop 2>/dev/null" ### @@ -58,7 +58,7 @@ RUN set -eux \ && chmod +x /usr/bin/cert-gen \ \ # Install watcherd - && wget --no-check-certificate -O /usr/bin/watcherd https://raw.githubusercontent.com/devilbox/watcherd/${WATCHERD_GIT_REF}/watcherd \ + && wget --no-check-certificate -O /usr/bin/watcherd https://raw.githubusercontent.com/devilbox/watcherd/${WATCHERD_GIT_REF}/bin/watcherd \ && chmod +x /usr/bin/watcherd \ \ # Clean-up @@ -89,14 +89,25 @@ RUN set -eux \ && ln -sf /usr/bin/python3 /usr/bin/python +### +### Set timezone +### +RUN set -eux \ + && if [ -f /etc/localtime ]; then rm /etc/localtime; fi \ + && ln -s /usr/share/zoneinfo/UTC /etc/localtime + + ### ### Copy files ### COPY ./data/nginx/nginx.conf /etc/nginx/nginx.conf + COPY ./data/vhost-gen/main.yml /etc/vhost-gen/main.yml COPY ./data/vhost-gen/mass.yml /etc/vhost-gen/mass.yml + COPY ./data/vhost-gen/templates-main /etc/vhost-gen/templates-main COPY ./data/create-vhost.sh /usr/local/bin/create-vhost.sh + COPY ./data/docker-entrypoint.d /docker-entrypoint.d COPY ./data/docker-entrypoint.sh /docker-entrypoint.sh diff --git a/Dockerfiles/data/create-vhost.sh b/Dockerfiles/data/create-vhost.sh index 7c8d0bb..575b385 100755 --- a/Dockerfiles/data/create-vhost.sh +++ b/Dockerfiles/data/create-vhost.sh @@ -4,16 +4,100 @@ set -e set -u set -o pipefail -VHOST_PATH="${1}" -VHOST_NAME="${2}" -VHOST_TLD="${3}" -VHOST_TPL="${4}" -CA_KEY="${5}" -CA_CRT="${6}" -GENERATE_SSL="${7}" -GEN_MODE="${8}" -VERBOSE="${9:-}" +VHOST_PATH="${1}" # watcherd (%%p): Absolute path to project directory +VHOST_NAME="${2}" # watcherd (%%n): Project directory name +VHOST_TLD="${3}" # ${MASS_VHOST_TLD_SUFFIX} +VHOST_TPL="${4}" # %%p/${MASS_VHOST_TPL} +MASS_VHOST_DOCROOT="${5}" +HTTP2_ENABLE="${6}" +DOCKER_LOGS="${7}" +TIMEOUT="${8}" +CA_KEY="${9}" # ${CA_KEY} +CA_CRT="${10}" # ${CA_CRT} +GENERATE_SSL="${11}" # ${MASS_VHOST_SSLGEN} +GEN_MODE="${12}" # ${MASS_VHOST_SSL_TYPE} +BACKEND="${13}" # ${MASS_VHOST_BACKEND} +VERBOSE="${14:-}" # "-v" or empty + +# ------------------------------------------------------------------------------------------------- +# ENTRYPOINT BOOTSTRAP START (copied from docker-entrypoint.sh) +# ------------------------------------------------------------------------------------------------- + +### +### This allows us to be able to access all entrypoint functions +### + +### +### DEBUG_ENTRYPOINT +### +if [ -z "${DEBUG_ENTRYPOINT:-}" ]; then + DEBUG_ENTRYPOINT="${DEFAULT_DEBUG_ENTRYPOINT}" +fi +if [ "${DEBUG_ENTRYPOINT}" != "0" ] \ + && [ "${DEBUG_ENTRYPOINT}" != "1" ] \ + && [ "${DEBUG_ENTRYPOINT}" != "2" ] \ + && [ "${DEBUG_ENTRYPOINT}" != "3" ] \ + && [ "${DEBUG_ENTRYPOINT}" != "4" ]; then + # Arbitrary integer (set to highest value + if [ -n "${DEBUG_ENTRYPOINT##*[!0-9]*}" ]; then + DEBUG_ENTRYPOINT=4 + else + DEBUG_ENTRYPOINT="${DEFAULT_DEBUG_ENTRYPOINT}" + fi +fi + +### +### DEBUG_RUNTIME +### +if [ -z "${DEBUG_RUNTIME:-}" ]; then + DEBUG_RUNTIME="${DEFAULT_DEBUG_RUNTIME}" +fi +if [ "${DEBUG_RUNTIME}" != "0" ] && [ "${DEBUG_RUNTIME}" != "1" ]; then + DEBUG_RUNTIME="${DEFAULT_DEBUG_RUNTIME}" +fi + +export "DEBUG_ENTRYPOINT" +export "DEBUG_RUNTIME" + +ENTRYPOINT_DIR="/docker-entrypoint.d" # All entrypoint scripts + +### +### Source available library functions +### +# shellcheck disable=SC2012 +for f in $( ls -1 "${ENTRYPOINT_DIR}/.lib/"*.sh | sort -u ); do + # shellcheck disable=SC1090 + . "${f}" +done + +### +### Source available HTTPD functions +### +# shellcheck disable=SC2012 +for f in $( ls -1 "${ENTRYPOINT_DIR}/.httpd/"*.sh | sort -u ); do + # shellcheck disable=SC1090 + . "${f}" +done + +### +### Source available entrypoint scripts +### +# shellcheck disable=SC2012 +#for f in $( ls -1 "${ENTRYPOINT_DIR}/"*.sh | sort -u ); do +# # shellcheck disable=SC1090 +# . "${f}" +#done + + + +# ------------------------------------------------------------------------------------------------- +# SSL +# ------------------------------------------------------------------------------------------------- + +### +### Generate vhost SSL certificate +### if [ "${GENERATE_SSL}" = "1" ]; then if [ ! -d "/etc/httpd/cert/mass" ]; then mkdir -p "/etc/httpd/cert/mass" @@ -30,11 +114,146 @@ if [ "${GENERATE_SSL}" = "1" ]; then fi fi -cmd="vhost-gen -p \"${VHOST_PATH}\" -n \"${VHOST_NAME}\" -c /etc/vhost-gen/mass.yml -o \"${VHOST_TPL}\" -s ${VERBOSE} -m ${GEN_MODE}" + + +# ------------------------------------------------------------------------------------------------- +# VHOST-GEN +# ------------------------------------------------------------------------------------------------- + +### +### Validate Backend +### +if [ -n "${BACKEND}" ]; then + ### + ### Backend=file: + ### + if echo "${BACKEND}" | grep -E '^file:' >/dev/null; then + # No need to validate backend string, has been done already in entrypoint + BACKEND_FILE_NAME="$( echo "${BACKEND}" | awk -F':' '{print $2}' )" + BACKEND_FILE_PATH="${VHOST_TPL}${BACKEND_FILE_NAME}" + log "info" "[Project: ${VHOST_NAME}] Backend config specified via file: ${VHOST_TPL}${BACKEND_FILE_NAME}" + if [ ! -f "${BACKEND_FILE_PATH}" ]; then + log "info" "[Project: ${VHOST_NAME}] Backend file does not exist: ${VHOST_TPL}${BACKEND_FILE_NAME}" + log "info" "[Project: ${VHOST_NAME}] Backend defaulting to: serve static files only" + BACKEND="" # Empty the backend + else + BACKEND_CONFIG="$( cat "${BACKEND_FILE_PATH}" )" + log "info" "[Project: ${VHOST_NAME}] Backend config file contents: ${BACKEND_CONFIG}" + if ! BACKEND_ERROR="$( backend_conf_is_valid "${BACKEND_CONFIG}" )"; then + log "warn" "[Project: ${VHOST_NAME}] Backend config is invalid: ${BACKEND_ERROR}" + log "warn" "[Project: ${VHOST_NAME}] Backend defaulting to: serve static files only" + BACKEND="" # Empty the backend + else + BACKEND="${BACKEND_CONFIG}" # Use config from file + fi + fi + ### + ### Backend=conf:::: + ### + else + log "info" "[Project: ${VHOST_NAME}] Backend config specified via env: ${BACKEND}" + # No need to validate backend string, has been done already in entrypoint + fi +else + log "info" "[Project: ${VHOST_NAME}] No Backend specified: Serving static files only" +fi + + +### +### Evaluate Backend +### +if [ -n "${BACKEND}" ]; then + be_type="$( get_backend_conf_type "${BACKEND}" )" # phpfpm or rproxy + be_prot="$( get_backend_conf_prot "${BACKEND}" )" # tpc, http, https + be_host="$( get_backend_conf_host "${BACKEND}" )" # + be_port="$( get_backend_conf_port "${BACKEND}" )" # + if [ "${be_type}" = "phpfpm" ]; then + log "info" "[Project: ${VHOST_NAME}] Backend PHP-FPM Remote: ${be_prot}://${be_host}:${be_port}" + # TODO: Generate cmd + elif [ "${be_type}" = "rproxy" ]; then + log "info" "[Project: ${VHOST_NAME}] Backend Reverse Proxy: ${be_prot}://${be_host}:${be_port}" + # TODO: Generate cmd + fi +else + # TODO: Generate cmd + be_type="" + be_prot="" + be_host="" + be_port="" +fi + +INDICES="index.html, index.htm" +PHP_FPM_ENABLE=0 +if [ "${be_type}" = "phpfpm" ]; then + INDICES="index.php, index.html, index.htm" + PHP_FPM_ENABLE=1 +fi + + +VHOST_GEN_CONFIG_NAME="mass-${VHOST_NAME}.yml" +VHOST_GEN_CONFIG_PATH="/etc/vhost-gen/${VHOST_GEN_CONFIG_NAME}" + +### +### Generate vhost-gen config file (not template) +### +# TODO: variablize nginx +# TODO: variablize alias +generate_vhostgen_conf \ + "nginx" \ + "/etc/httpd/vhost.d" \ + "${VHOST_TLD}" \ + "${MASS_VHOST_DOCROOT}" \ + "${INDICES}" \ + "$( to_python_bool "${HTTP2_ENABLE}" )" \ + "/etc/httpd/cert/mass" \ + "/etc/httpd/cert/mass" \ + "" \ + "$( to_python_bool "${DOCKER_LOGS}" )" \ + "$( to_python_bool "${PHP_FPM_ENABLE}" )" \ + "${be_host}" \ + "${be_port}" \ + "${TIMEOUT}" \ + '/devilbox-api/:/var/www/default/api:http(s)?://(.*)$' \ + "no" \ + "/httpd-status" > "${VHOST_GEN_CONFIG_PATH}" + + +### +### Default vhost-gen command +### + +if [ "${DEBUG_ENTRYPOINT}" -gt "1" ]; then + verbose="-v" +else + verbose="" +fi + + +if [ "${be_type}" = "rproxy" ]; then + cmd="vhost-gen -r \"${be_prot}://${be_host}:${be_port}\" -l / -n \"${VHOST_NAME}\" -c \"${VHOST_GEN_CONFIG_PATH}\" -o \"${VHOST_TPL}\" -s ${verbose} -m ${GEN_MODE}" +else + cmd="vhost-gen -p \"${VHOST_PATH}\" -n \"${VHOST_NAME}\" -c \"${VHOST_GEN_CONFIG_PATH}\" -o \"${VHOST_TPL}\" -s ${verbose} -m ${GEN_MODE}" +fi + +# TODO: do we use tempalte-main/ ? Check other nginx images +#run "vhost-gen -n localhost -r ${be_prot}://${be_host}:${be_port} -l / -t /etc/vhost-gen/templates-main/ -c ${config} -o ${template} ${verbose} -d -s -m ${ssl_type}" + + +# ------------------------------------------------------------------------------------------------- +# VHOST-GEN +# ------------------------------------------------------------------------------------------------- + + +### +### Verbose output? +### if [ -n "${VERBOSE}" ]; then echo "\$ ${cmd}" fi +### +### Execute +### if ! eval "${cmd}"; then echo "[FAILED] Failed to add vhost for ${VHOST_NAME}${VHOST_TLD}" exit 1 diff --git a/Dockerfiles/data/docker-entrypoint.d/.httpd/README.md b/Dockerfiles/data/docker-entrypoint.d/.httpd/README.md new file mode 100644 index 0000000..864773a --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/.httpd/README.md @@ -0,0 +1,3 @@ +# Functions `.httpd` + +This directory contains functions and validator specifically for the HTTPD server in this project. diff --git a/Dockerfiles/data/docker-entrypoint.d/.httpd/func-backend.sh b/Dockerfiles/data/docker-entrypoint.d/.httpd/func-backend.sh new file mode 100755 index 0000000..aeba186 --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/.httpd/func-backend.sh @@ -0,0 +1,283 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +### +### This file defines how the *_VHOST_BACKEND variable evaluates and validates. +### +### Supported backends formats: +### ------------------------------------------- +### Format-1: conf:::: +### Format-2: file: +### +### +### Format-1: conf:::: +### ------------------------------------------- +### Requirement: +### 1. type == "rproxy" is only supported for $MAIN_VHOST_BACKEND +### +### Valid formats: +### conf:phpfpm:tcp:: # Remote PHP-FPM server at : +### conf:rproxy:http:: # Reverse Proxy server at http://: +### conf:rproxy:https:: # Reverse Proxy server at https://: +### +### +### Format-2: file: +### ------------------------------------------- +### Requirement: +### 1. Only supported for $MASS_VHOST_BACKEND +### 2. Only supported for "rproxy" type +### +### It must be a file in the project directory, as each project will probably use +### a different backend host/port: +### File path: ${$MASS_VHOST_DOCROOT}/${$MASS_VHOST_TPL}/ +### Default: /shared/httpd//cfg/ +### +### The file must have the following content format: +### conf:rproxy::: +### Examples: +### conf:rproxy:http:10.0.0.1:3000 +### conf:rproxy:https:mydomain.com:8080 +### +### Note: If no file is found, a warning will be logged and no Reverse proxy will be created. +### + + + +# ------------------------------------------------------------------------------------------------- +# *_VHOST_BACKEND FUNCTIONS +# ------------------------------------------------------------------------------------------------- + +### +### Check if a backend is specified +### +backend_has_backend() { + # If the backend string is empty, we do not have a backend + if [ -z "${1}" ]; then + return 1 + fi +} + + +### +### This is a generick backend_string validator for 'conf', which also returns an error message. +### +backend_conf_is_valid() { + # Do we have a backend defined? + if ! backend_has_backend "${1}"; then + return 0 + fi + backend_prefix="$( get_backend_prefix "${1}" )" # file or conf + backend_conf_type="$( get_backend_conf_type "${1}" )" # phpfpm or rproxy + backend_conf_prot="$( get_backend_conf_prot "${1}" )" # tpc, http, https + #backend_conf_host="$( get_backend_conf_host "${1}" )" # + #backend_conf_port="$( get_backend_conf_port "${1}" )" # + + ### + ### Generic validation + ### + # 1. Prefix: only 'conf' is allowed + if [ "${backend_prefix}" != "conf" ]; then + echo "Invalid backend string '${1}'. It must start with 'conf:'" + return 1 + fi + # 2. Type: 'phpfpm' or 'rproxy' + if ! backend_is_valid_conf_type "${1}"; then + echo "Invalid backend conf: in: '${1}'. It must be 'phpfpm' or 'rproxy'" + return 1 + fi + # 3. Protocol: 'tcp', 'http' or 'https' + if ! backend_is_valid_conf_prot "${1}"; then + echo "Invalid backend conf: in: '${1}'. It must be 'tcp', 'http' or 'https'" + return 1 + fi + # 4. Host + if ! backend_is_valid_conf_host "${1}"; then + echo "Invalid backend conf: in: '${1}'. It must be valid hostname, IPv4 or IPv6 addr" + return 1 + fi + # 5. Port + if ! backend_is_valid_conf_port "${1}"; then + echo "Invalid backend conf: in: '${1}'. It must be a valid port" + return 1 + fi + + ### + ### Specific validation + ### + # 6. Validate conf phpfpm == tcp + if [ "${backend_conf_type}" = "phpfpm" ]; then + if [ "${backend_conf_prot}" != "tcp" ]; then + echo "Invalid backend conf: in: '${1}'. 'phpfpm' only supports 'tcp'" + return 1 + fi + fi + # 7. Validate conf rproxy == http(s)? + if [ "${backend_conf_type}" = "rproxy" ]; then + if [ "${backend_conf_prot}" != "http" ] && [ "${backend_conf_prot}" != "https" ]; then + echo "Invalid backend conf: in: '${1}'. 'rproxy' only supports 'http' or 'https'" + return 1 + fi + fi +} + + +### +### Check if the backend prefix inside the backend string is valid ('conf' or 'file') +### +backend_is_valid_prefix() { + local value + value="$( get_backend_prefix "${1}" )" + + if [ "${value}" != "conf" ] && [ "${value}" != "file" ]; then + return 1 + fi + return 0 +} + + +### +### Check if the backend file is a valid filename +### +backend_is_valid_file_file() { + local value + value="$( get_backend_file_file "${1}" )" + + # Is valid filename? + if ! is_file "${value}"; then + return 1 + fi + # No spaces allowed in filename allowed + if echo "${value}" | grep -E '\s' >/dev/null; then + return 1 + fi + # No weired characters in filename allowed + if echo "${value}" | grep -E '!|\$|\(|\)\[|\]' >/dev/null; then + return 1 + fi +} + + +### +### Check if the backend type inside the backend string is valid. +### +backend_is_valid_conf_type() { + local value + value="$( get_backend_conf_type "${1}" )" + + if [ "${value}" != "phpfpm" ] && [ "${value}" != "rproxy" ]; then + return 1 + fi + return 0 +} + + +### +### Check if the backend protocol inside the backend string is valid. +### +backend_is_valid_conf_prot() { + local value + value="$( get_backend_conf_prot "${1}" )" + + if [ "${value}" != "tcp" ] && [ "${value}" != "http" ] && [ "${value}" != "https" ]; then + return 1 + fi + return 0 +} + + +### +### Check if the backend host inside the backend string is valid. +### +backend_is_valid_conf_host() { + local value + value="$( get_backend_conf_host "${1}" )" + + if ! is_ip_addr "${value}" && ! is_hostname "${value}"; then + return 1 + fi + return 0 +} + + +### +### Check if the backend port inside the backend string is valid. +### +backend_is_valid_conf_port() { + local value + value="$( get_backend_conf_port "${1}" )" + + if ! is_port "${value}"; then + return 1 + fi + return 0 +} + + + +# ------------------------------------------------------------------------------------------------- +# GETTER FUNCTIONS +# ------------------------------------------------------------------------------------------------- + +### +### Get Backend prefix (conf or file) +### +### Returns the first element from either: +### conf:::: +### file: +### +get_backend_prefix() { + echo "${1}" | awk -F':' '{print $1}' +} + + +### +### Get backend file name +### +### Returns the second element from file: +### +get_backend_file_file() { + echo "${1}" | awk -F':' '{print $2}' +} + + +### +### Get Backend type (phpfpm or rproxy) +### +### Returns the second element from conf:::: +### +get_backend_conf_type() { + echo "${1}" | awk -F':' '{print $2}' +} + + +### +### Get Backend protocol (tcp, http or https) +### +### Returns the third element from conf:::: +### +get_backend_conf_prot() { + echo "${1}" | awk -F':' '{print $3}' +} + + +### +### Get Backend host +### +### Returns the 4th to 2nd last element from conf:::: +### +get_backend_conf_host() { + echo "${1}" | awk -F ':' -v OFS=':' '{$1="";$2="";$3="";$NF="";print}' | sed -e 's/^::://g' -e 's/:$//g' +} + + +### +### Get Backend port +### +### Returns the last element from conf:::: +### +get_backend_conf_port() { + echo "${1}" | awk -F':' '{print $NF}' +} diff --git a/Dockerfiles/data/docker-entrypoint.d/.httpd/func-vhostgen.sh b/Dockerfiles/data/docker-entrypoint.d/.httpd/func-vhostgen.sh new file mode 100755 index 0000000..e0bcc14 --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/.httpd/func-vhostgen.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +### +### This file defines vhost-gen generator functions. +### + + +# ------------------------------------------------------------------------------------------------- +# vhost-gen +# ------------------------------------------------------------------------------------------------- + +### +### Generate vhost-gen config file (not template) +### +generate_vhostgen_conf() { + local server="${1}" # nginx, apache22, apache24 + local conf_dir="${2}" # Store generated httpd.conf in this directory + local tld_suffix="${3}" + local docroot_subdir="${4}" + local index="${5}" # comma separated list of index files, e.g.: "index.html, index.php" + local http2_enable="${6}" # "yes" or "no" + local dir_crt="${7}" + local dir_key="${8}" + local log_prefix="${9}" # "yes" or "no" + local docker_logs="${10}" # "yes" or "no" + local php_fpm_enable="${11}" + local php_fpm_addr="${12}" + local php_fpm_port="${13}" + local timeout="${14}" + local alias="${15}" # alias1:path1[:cors], alias2:path2[:cors] + local server_status_enable="${16}" + local server_status_alias="${17}" + + alias_block="alias: []" + if [ -n "${alias}" ]; then + alias_block="alias:\n" + for item in ${alias//,/}; do + item_alias="$( echo "${item}" | awk -F':' '{print $1}' )" + item_path="$( echo "${item}" | awk -F':' '{print $2}' )" + item_cors="$( echo "${item}" | awk -F':' -v OFS=':' '{$1="";$2="";print}' | sed -e 's/^://g' -e 's/^://g' )" + alias_block+=" - alias: ${item_alias}\n" + alias_block+=" path: ${item_path}\n" + if [ -n "${item_cors}" ]; then + alias_block+=" xdomain_request:\n" + alias_block+=" enable: yes\n" + alias_block+=" origin: ${item_cors}\n" + fi + done + fi + + # https://github.com/devilbox/vhost-gen/blob/master/etc/conf.yml + OUT=$(cat </dev/null 2>&1 +} + + +### +### Get env variable by name +### +### This function allows an optional second parameter, which sets +### the default value, if the environment variable was not set. +### +### ${1}: name of the environment variable +### ${2}: (optional) default value, if not set +### +env_get() { + # Did we have a default value set? + if [ "${#}" -gt "1" ]; then + if ! env_set "${1}"; then + echo "${2}" + return 0 + fi + fi + # Just output the env value + printenv "${1}" +} + + + +# ------------------------------------------------------------------------------------------------- +# SANITY CHECKS +# ------------------------------------------------------------------------------------------------- + +### +### The following commands are required and used in the current script. +### +if ! command -v printenv >/dev/null 2>&1; then + >&2 "Error, printenv not found, but required." + exit 1 +fi diff --git a/Dockerfiles/data/docker-entrypoint.d/.lib/func-logger.sh b/Dockerfiles/data/docker-entrypoint.d/.lib/func-logger.sh new file mode 100755 index 0000000..4d15dcc --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/.lib/func-logger.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +### +### This file holds the global logger function. +### + + +# ------------------------------------------------------------------------------------------------- +# LOGGER +# ------------------------------------------------------------------------------------------------- + +### +### Log to stdout/stderr +### +### Internally used logger function to log 'ok', 'warn' and 'err' messages to stdout/stderr. +### +### DEBUG_ENTRYPOINT=0 err +### DEBUG_ENTRYPOINT=1 err, warn +### DEBUG_ENTRYPOINT=2 err, warn, ok, info +### DEBUG_ENTRYPOINT=3 err, warn, ok, info, debug +### DEBUG_ENTRYPOINT=4 err, warn, ok, info, debug, trace +### +log() { + local type="${1}" + local message="${2}" + + # https://unix.stackexchange.com/questions/124407/what-color-codes-can-i-use-in-my-bash-ps1-prompt + local clr_trace="\033[38;5;244m" # gray + local clr_debug="\033[38;5;244m" # gray + local clr_info="\033[0;34m" # blue + local clr_ok="\033[0;32m" # green + local clr_warn="\033[0;33m" # yellow + local clr_err="\033[0;31m" # red + local clr_rst="\033[0m" # reset color + + # Always show errors + if [ "${type}" = "err" ]; then + printf "${clr_err}[ERR] %s${clr_rst}\n" "${message}" 1>&2 # stdout -> stderr + fi + + # >= 1 (Errors & Warnings) + if [ "${DEBUG_ENTRYPOINT}" -ge "1" ]; then + if [ "${type}" = "warn" ]; then + printf "${clr_warn}[WARN] %s${clr_rst}\n" "${message}" 1>&2 # stdout -> stderr + fi + fi + # >= 2 (Errors, Warnings, OK & Info) + if [ "${DEBUG_ENTRYPOINT}" -ge "2" ]; then + if [ "${type}" = "ok" ]; then + printf "${clr_ok}[OK] %s${clr_rst}\n" "${message}" + fi + if [ "${type}" = "info" ]; then + printf "${clr_info}[INFO] %s${clr_rst}\n" "${message}" + fi + fi + # >= 3 (Errors, Warnings, OK, Info, Debug) + if [ "${DEBUG_ENTRYPOINT}" -ge "3" ]; then + if [ "${type}" = "debug" ]; then + printf "${clr_debug}[DBG] %s${clr_rst}\n" "${message}" + fi + fi + # >= 4 (Errors, Warnings, OK, Info, Debug, Trace) + if [ "${DEBUG_ENTRYPOINT}" -ge "4" ]; then + if [ "${type}" = "trace" ]; then + printf "${clr_trace}[TRC] %s${clr_rst}\n" "${message}" + fi + fi +} diff --git a/Dockerfiles/data/docker-entrypoint.d/.lib/func-misc.sh b/Dockerfiles/data/docker-entrypoint.d/.lib/func-misc.sh new file mode 100755 index 0000000..78cfae3 --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/.lib/func-misc.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +### +### This file holds misc functions. +### + + +# ------------------------------------------------------------------------------------------------- +# ENV FUNCTIONS +# ------------------------------------------------------------------------------------------------- + +### +### Cast a bash bool ("0" or "1") to Python bool ("yes" or "no") +### +to_python_bool() { + if [ "${1}" = "0" ]; then + echo "no" + elif [ "${1}" = "1" ]; then + echo "yes" + fi +} diff --git a/Dockerfiles/data/docker-entrypoint.d/.lib/func-run.sh b/Dockerfiles/data/docker-entrypoint.d/.lib/func-run.sh new file mode 100755 index 0000000..258eda6 --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/.lib/func-run.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +### +### This file holds the global run function to wrap all executed commands. +### + + +# ------------------------------------------------------------------------------------------------- +# RUN +# ------------------------------------------------------------------------------------------------- + +### +### Wrapper for run_run command +### +### Internally used function to execute commands and also be able to show +### these commands to stdout/stderr prior executing. +### +### DEBUG_ENTRYPOINT=0 - +### DEBUG_ENTRYPOINT=1 - +### DEBUG_ENTRYPOINT=2 - +### DEBUG_ENTRYPOINT=3 show command +### DEBUG_ENTRYPOINT=4 show command and output +### +run() { + local cmd="${1}" + + # Show commands in debug level + log "debug" "$(whoami)> ${cmd}" + + # Show outputs on failure + if ! STDOUT="$( /bin/sh -c "LANG=C LC_ALL=C ${cmd}" )"; then + if [ -n "${STDOUT}" ]; then + log "err" "${STDOUT}" + fi + exit 1 + fi + # Show command outputs in trace level + if [ -n "${STDOUT}" ]; then + log "trace" "${STDOUT}" + fi +} + + +# ------------------------------------------------------------------------------------------------- +# SANITY CHECKS +# ------------------------------------------------------------------------------------------------- + +### +### The following commands are required and used in the current script. +### +if ! command -v whoami >/dev/null 2>&1; then + >&2 "Error, whoami not found, but required." + exit 1 +fi diff --git a/Dockerfiles/data/docker-entrypoint.d/.lib/func-validator.sh b/Dockerfiles/data/docker-entrypoint.d/.lib/func-validator.sh new file mode 100755 index 0000000..0e95a04 --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/.lib/func-validator.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +### +### This file holds useful validator functions +### + + +# ------------------------------------------------------------------------------------------------- +# HELPER FUNCTIONS +# ------------------------------------------------------------------------------------------------- + +### +### Check if given value is a positive integer +### +is_int() { + if [ -z "${1}" ]; then + return 1 + fi + test -n "${1##*[!0-9]*}" +} + + +### +### Check if given value is a bool ('0' or '1') +### +is_bool() { + if [ "${1}" != "0" ] && [ "${1}" != "1" ]; then + return 1 + fi +} + + +### +### Check if given value is valid uid +### +is_uid() { + is_int "${1}" +} + + +### +### Check if given value is valid gid +### +is_gid() { + is_int "${1}" +} + + +### +### Check if given value is a valid port (1-65535) +### +is_port() { + if ! is_int "${1}"; then + return 1 + fi + if [ "${1}" -lt "1" ]; then + return 1 + fi + if [ "${1}" -gt "65535" ]; then + return 1 + fi +} + + +### +### Check if given string is a valid domain +### +is_domain() { + # Cannot be empty + if [ -z "${1}" ]; then + return 1 + fi + # Leading . (dot) + if echo "${1}" | grep -E '^\.' > /dev/null; then + return 1 + fi + # Trailing . (dot) + if echo "${1}" | grep -E '\.$' > /dev/null; then + return 1 + fi + # Space + if echo "${1}" | grep -E '\s' > /dev/null; then + return 1 + fi + # Some common-sense characters + if echo "${1}" | grep -E '&|@|\*|\(|\)|,|\?|_|#|\$|:|;|\\|/|%|\+|=|a<|>' > /dev/null; then + return 1 + fi +} + + +### +### Check if given value is valid hostname +### +is_hostname() { + # Cannot be empty + if [ -z "${1}" ]; then + return 1 + fi + # TODO: Add some hostname regex + return 0 +} + + +### +### Check if given value is valid IPv4 or IPv6 address +### +is_ip_addr() { + if is_ipv4_addr "${1}"; then + return 0 + fi + if is_ipv6_addr "${1}"; then + return 0 + fi + return 1 +} + + +### +### Check if given value is valid IPv4 address +### +is_ipv4_addr() { + # Cannot be empty + if [ -z "${1}" ]; then + return 1 + fi + + # This is only a very basic check to prevent typos during startup + echo "${1}" | grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' >/dev/null +} + + +### +### Check if given value is valid IPv6 address +### +is_ipv6_addr() { + # Cannot be empty + if [ -z "${1}" ]; then + return 1 + fi + # This is only a very basic check to prevent typos during startup + echo "${1}" | grep -E '^([A-Fa-f0-9:]+:+)+[A-Fa-f0-9]+$' >/dev/null +} + + +### +### Check if given value is a valid filename (no sub-/parent dir) +### +is_file() { + # Cannot be empty + if [ -z "${1}" ]; then + return 1 + fi + + # Not a sub-directory prefix + if [ "$( basename "${1}" )" != "${1}" ]; then + return 1 + fi + + # Not a parent directory suffix + if [ "$( dirname "${1}" )" != "." ]; then + return 1 + fi +} diff --git a/Dockerfiles/data/docker-entrypoint.d/00-base-libs.sh b/Dockerfiles/data/docker-entrypoint.d/00-base-libs.sh deleted file mode 100755 index 361ae34..0000000 --- a/Dockerfiles/data/docker-entrypoint.d/00-base-libs.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - - -############################################################ -# Functions -############################################################ - -### -### Log to stdout/stderr -### -log() { - local type="${1}" # ok, warn or err - local message="${2}" # msg to print - local debug="${3}" # 0: only warn and error, >0: ok and info - - local clr_ok="\033[0;32m" - local clr_info="\033[0;34m" - local clr_warn="\033[0;33m" - local clr_err="\033[0;31m" - local clr_rst="\033[0m" - - if [ "${type}" = "ok" ]; then - if [ "${debug}" -gt "0" ]; then - printf "${clr_ok}[OK] %s${clr_rst}\n" "${message}" - fi - elif [ "${type}" = "info" ]; then - if [ "${debug}" -gt "0" ]; then - printf "${clr_info}[INFO] %s${clr_rst}\n" "${message}" - fi - elif [ "${type}" = "warn" ]; then - printf "${clr_warn}[WARN] %s${clr_rst}\n" "${message}" 1>&2 # stdout -> stderr - elif [ "${type}" = "err" ]; then - printf "${clr_err}[ERR] %s${clr_rst}\n" "${message}" 1>&2 # stdout -> stderr - else - printf "${clr_err}[???] %s${clr_rst}\n" "${message}" 1>&2 # stdout -> stderr - fi -} - - -### -### Wrapper for run_run command -### -run() { - local cmd="${1}" # command to execute - local debug="${2}" # show commands if debug level > 1 - - local clr_red="\033[0;31m" - local clr_green="\033[0;32m" - local clr_reset="\033[0m" - - if [ "${debug}" -gt "1" ]; then - printf "${clr_red}%s \$ ${clr_green}${cmd}${clr_reset}\n" "$( whoami )" - fi - /bin/sh -c "LANG=C LC_ALL=C ${cmd}" -} - - -### -### Is argument a positive integer? -### -isint() { - test -n "${1##*[!0-9]*}" -} - - -### -### Is env variable set? -### -env_set() { - printenv "${1}" >/dev/null 2>&1 -} - - -### -### Get env variable by name -### -env_get() { - local env_name="${1}" - - # Did we have a default value specified? - if [ "${#}" -gt "1" ]; then - if ! env_set "${env_name}"; then - echo "${2}" - return 0 - fi - fi - # Just output the env value - printenv "${1}" -} - - -############################################################ -# Sanity Checks -############################################################ - -if ! command -v printenv >/dev/null 2>&1; then - log "err" "printenv not found, but required." "1" - exit 1 -fi diff --git a/Dockerfiles/data/docker-entrypoint.d/01-env-vars-export.sh b/Dockerfiles/data/docker-entrypoint.d/01-env-vars-export.sh new file mode 100755 index 0000000..d0d8043 --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/01-env-vars-export.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +### +### [SECTION 1] +### This file holds a function that ensures all environment variables are set (or its default val.) +### + + +# ------------------------------------------------------------------------------------------------- +# EXPORT FUNCTIONS +# ------------------------------------------------------------------------------------------------- + +### +### Ensure that env variables are exported. +### +### In case an environment variable was not specified, assign +### a default value and export it to the environment. +### +env_var_export() { + local env_varname="${1}" + local default="${2:-}" + + if ! env_set "${env_varname}"; then + _log_env_export "unset" "${env_varname}" "${default}" + else + default="$( env_get "${env_varname}" )" + _log_env_export "set" "${env_varname}" "${default}" + fi + export "${env_varname}=${default}" +} + + + +# ------------------------------------------------------------------------------------------------- +# HELPER FUNCTIONS +# ------------------------------------------------------------------------------------------------- + +### +### Use custom logger to log env variable status +### +_log_env_export() { + local state="${1}" # 'set' or 'unset' + local name="${2}" # Variable name + local value="${3}" # Variable value (either set value or default value) + + local debug="${DEBUG_ENTRYPOINT}" # 0: only warn and error, >0: ok and info + + local clr_set="\033[0;32m" # green + #local clr_unset="\033[0;34m" # blue + local clr_value="\033[0;32m" # green + local clr_info="\033[0;34m" # blue + local clr_rst="\033[0m" + + if [ "${debug}" -gt "0" ]; then + if [ "${state}" = "set" ]; then + printf "${clr_info}%-11s${clr_rst}%-8s${clr_set}\$%-27s${clr_rst}%-9s${clr_value}%s${clr_rst}\n" \ + "[INFO]" \ + "Set" \ + "${name}" \ + "Value:" \ + "${value}" + elif [ "${state}" = "unset" ]; then + printf "${clr_info}%-11s${clr_rst}%-8s${clr_rst}\$%-27s${clr_rst}%-9s${clr_value}%s${clr_rst}\n" \ + "[INFO]" \ + "Unset" \ + "${name}" \ + "Default:" \ + "${value}" + else + log "????" "Internal: Wrong value given to _log_env_export" + exit 1 + fi + fi +} diff --git a/Dockerfiles/data/docker-entrypoint.d/01-uid-gid.sh b/Dockerfiles/data/docker-entrypoint.d/01-uid-gid.sh deleted file mode 100755 index d95aeef..0000000 --- a/Dockerfiles/data/docker-entrypoint.d/01-uid-gid.sh +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - - -############################################################ -# Functions -############################################################ - -### -### Helper -### -_get_username_by_uid() { - if getent="$( getent passwd "${1}" )"; then - echo "${getent//:*}" - return 0 - fi - return 1 -} - -_get_groupname_by_gid() { - if getent="$( getent group "${1}" )"; then - echo "${getent//:*}" - return 0 - fi - return 1 -} - -_get_homedir_by_username() { - getent passwd "${1}" | cut -d: -f6 -} - -_get_homedir_by_groupname() { - grep -E ".*:x:[0-9]+:[0-9]+:$( _get_groupname_by_gid "${1}" ).*" /etc/passwd | cut -d: -f6 -} - - -### -### Change UID -### -set_uid() { - local uid_varname="${1}" - local username="${2}" - local debug="${3}" - #local homedir - #homedir="$( _get_homedir_by_username "${username}" )" - - local uid= # new uid - local spare_uid=9876 # spare uid to change another user to - - if ! env_set "${uid_varname}"; then - log "info" "\$${uid_varname} not set. Keeping default uid for '${username}'." "${debug}" - else - uid="$( env_get "${uid_varname}" )" - - if ! isint "${uid}"; then - log "err" "\$${uid_varname} is not an integer: '${uid}'" "${debug}" - exit 1 - else - # Username with this uid already exists - if target_username="$( _get_username_by_uid "${uid}" )"; then - # It is not our user, so we need to changes his/her uid to something else first - if [ "${target_username}" != "${username}" ]; then - log "warn" "User with ${uid} already exists: ${target_username}" "${debug}" - log "info" "Changing UID of ${target_username} to ${spare_uid}" "${debug}" - run "usermod -u ${spare_uid} ${target_username}" "${debug}" - fi - fi - # Change uid and fix homedir permissions - log "info" "Changing user '${username}' uid to: ${uid}" "${debug}" - run "usermod -u ${uid} ${username}" "${debug}" - fi - fi -} - - -### -### Change GID -### -set_gid() { - local gid_varname="${1}" - local groupname="${2}" - local debug="${3}" - #local homedir - #homedir="$( _get_homedir_by_groupname "${groupname}" )" - - local gid= # new gid - local spare_gid=9876 # spare gid to change another group to - - if ! env_set "${gid_varname}"; then - log "info" "\$${gid_varname} not set. Keeping default gid for '${groupname}'." "${debug}" - else - # Retrieve the value from env - gid="$( env_get "${gid_varname}" )" - - if ! isint "${gid}"; then - log "err" "\$${gid_varname} is not an integer: '${gid}'" "${debug}" - exit 1 - else - # Groupname with this gid already exists - if target_groupname="$( _get_groupname_by_gid "${gid}" )"; then - # It is not our group, so we need to changes his/her gid to something else first - if [ "${target_groupname}" != "${groupname}" ]; then - log "warn" "Group with ${gid} already exists: ${target_groupname}" "${debug}" - log "info" "Changing GID of ${target_groupname} to ${spare_gid}" "${debug}" - run "groupmod -g ${spare_gid} ${target_groupname}" "${debug}" - fi - fi - # Change ugd and fix homedir permissions - log "info" "Changing group '${groupname}' gid to: ${gid}" "${debug}" - run "groupmod -g ${gid} ${groupname}" "${debug}" - fi - fi -} - - -############################################################ -# Sanity Checks -############################################################ - -if ! command -v usermod >/dev/null 2>&1; then - log "err" "usermod not found, but required." "1" - exit 1 -fi -if ! command -v groupmod >/dev/null 2>&1; then - log "err" "groupmod not found, but required." "1" - exit 1 -fi -if ! command -v getent >/dev/null 2>&1; then - log "err" "getent not found, but required." "1" - exit 1 -fi diff --git a/Dockerfiles/data/docker-entrypoint.d/02-env-vars-validate.sh b/Dockerfiles/data/docker-entrypoint.d/02-env-vars-validate.sh new file mode 100755 index 0000000..88b6e15 --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/02-env-vars-validate.sh @@ -0,0 +1,769 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +### +### [SECTION 1] +### This file holds a function to validate the given environment variables. +### + + +# ------------------------------------------------------------------------------------------------- +# MAIN VALIDATOR +# ------------------------------------------------------------------------------------------------- + +### +### Validate environment variables +### +### This function is just a gate-keeper and calls the validate_() +### function for each environment variable to ensure the assigned +### value is correct. +### +env_var_validate() { + local name="${1}" + local value + + value="$( env_get "${name}" )" + func="validate_$( echo "${name}" | awk '{print tolower($0)}' )" + + # Call specific validator function: validate_() + $func "${name}" "${value}" +} + + + +# ------------------------------------------------------------------------------------------------- +# VALIDATE FUNCTIONS: GENERAL +# ------------------------------------------------------------------------------------------------- + +### +### Validate NEW_UID +### +validate_new_uid() { + local name="${1}" + local value="${2}" + + # Ignore if empty (no change) + if [ -z "${value}" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(not specified)" + return 0 + fi + if ! is_uid "${value}"; then + _log_env_valid "invalid" "${name}" "${value}" "Must be positive integer" + exit 1 + fi + _log_env_valid "valid" "${name}" "${value}" "User ID (uid)" "${value}" +} + + +### +### Validate NEW_GID +### +validate_new_gid() { + local name="${1}" + local value="${2}" + + # Ignore if empty (no change) + if [ -z "${value}" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(not specified)" + return 0 + fi + if ! is_gid "${value}"; then + _log_env_valid "invalid" "${name}" "${value}" "Must be positive integer" + exit 1 + fi + _log_env_valid "valid" "${name}" "${value}" "Group ID (gid)" "${value}" +} + + +### +### Validate TIMEZONE +### +validate_timezone() { + local name="${1}" + local value="${2}" + + # Show ignored + if [ "${value}" = "UTC" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(not specified)" + return 0 + fi + if [ ! -f "/usr/share/zoneinfo/${value}" ]; then + _log_env_valid "invalid" "${name}" "${value}" "File '${value}' must exist in: " "/usr/share/zoneinfo/" + exit 1 + fi + _log_env_valid "valid" "${name}" "${value}" "Timezone" "${value}" +} + + + +# ------------------------------------------------------------------------------------------------- +# VALIDATE FUNCTIONS: MAIN VHOST +# ------------------------------------------------------------------------------------------------- + + +### +### Validate MAIN_VHOST_ENABLE +### +validate_main_vhost_enable() { + local name="${1}" + local value="${2}" + _validate_bool "${name}" "${value}" "Default vhost" +} + + +### +### Validate MAIN_VHOST_BACKEND: :: +### +validate_main_vhost_backend() { + local name="${1}" + local value="${2}" + _validate_vhost_backend "${name}" "${value}" "main" "${MAIN_VHOST_ENABLE}" +} + + +### +### Validate MAIN_VHOST_BACKEND_TIMEOUT +### +validate_main_vhost_backend_timeout() { + local name="${1}" + local value="${2}" + _validate_vhost_backend_timeout "${name}" "${value}" "${MAIN_VHOST_ENABLE}" +} + + +### +### Validate MAIN_VHOST_DOCROOT +### +validate_main_vhost_docroot() { + local name="${1}" + local value="${2}" + local base_path="${MAIN_DOCROOT_BASE}" + _validate_vhost_docroot "${name}" "${value}" "${MAIN_VHOST_ENABLE}" "${MAIN_VHOST_BACKEND}" "${base_path}/${value}" +} + + +### +### Validate MAIN_VHOST_SSL_TYPE +### +validate_main_vhost_ssl_type() { + local name="${1}" + local value="${2}" + _validate_vhost_ssl_type "${name}" "${value}" "${MAIN_VHOST_ENABLE}" +} + + +### +### Validate MAIN_VHOST_SSL_CN +### +validate_main_vhost_ssl_cn() { + local name="${1}" + local value="${2}" + + # Show ignored + if [ "${MAIN_VHOST_ENABLE}" = "0" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(vhost disabled)" + return + fi + if [ "${MAIN_VHOST_SSL_TYPE}" = "plain" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(no ssl)" + return + fi + _log_env_valid "valid" "${name}" "${value}" "SSL cert subject" "CN = ${value}" +} + + +### +### Validate MAIN_VHOST_TPL: vhost-gen template directory +### +validate_main_vhost_tpl() { + local name="${1}" + local value="${2}" + local base_path="${MAIN_DOCROOT_BASE}" + _validate_vhost_tpl "${name}" "${value}" "${MAIN_VHOST_ENABLE}" "${base_path}/${value}" +} + + +### +### Validate MAIN_VHOST_STATUS_ENABLE: Status page enable/disable +### +validate_main_vhost_status_enable() { + local name="${1}" + local value="${2}" + + if ! is_bool "${value}"; then + _log_env_valid "invalid" "${name}" "${value}" "Must be 0 or 1" "" + exit 1 + fi + # Show ignored + if [ "${MAIN_VHOST_ENABLE}" = "0" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(vhost disabled)" + return + fi + if [ "${value}" = "0" ]; then + _log_env_valid "valid" "${name}" "${value}" "Status page" "Disabled" + else + _log_env_valid "valid" "${name}" "${value}" "Status page" "Enabled" + fi +} + + +### +### Validate MAIN_VHOST_STATUS_ALIAS: Status page URL +### +validate_main_vhost_status_alias() { + local name="${1}" + local value="${2}" + + # Show ignored + if [ "${MAIN_VHOST_ENABLE}" = "0" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(vhost disabled)" + return + fi + if [ "${MAIN_VHOST_STATUS_ENABLE}" = "0" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(status disabled)" + return + fi + _log_env_valid "valid" "${name}" "${value}" "Status page URL" "${value}" +} + + + +# ------------------------------------------------------------------------------------------------- +# VALIDATE FUNCTIONS: MASS VHOST +# ------------------------------------------------------------------------------------------------- + +### +### Validate MASS_VHOST_ENABLE +### +validate_mass_vhost_enable() { + local name="${1}" + local value="${2}" + _validate_bool "${name}" "${value}" "Mass vhost" + + # Ensure either of MASS or MAIN is actually enabled + if [ "${value}" = "0" ] && [ "${MAIN_VHOST_ENABLE}" = "0" ]; then + _log_env_valid "invalid" "${name}" "${value}" "MAIN_VHOST and MASS_HOST are both disabled" "" + exit 1 + fi +} + + +### +### Validate MASS_VHOST_BACKEND :: +### +validate_mass_vhost_backend() { + local name="${1}" + local value="${2}" + _validate_vhost_backend "${name}" "${value}" "mass" "${MASS_VHOST_ENABLE}" +} + + +### +### Validate MASS_VHOST_BACKEND_TIMEOUT +### +validate_mass_vhost_backend_timeout() { + local name="${1}" + local value="${2}" + _validate_vhost_backend_timeout "${name}" "${value}" "${MASS_VHOST_ENABLE}" +} + + +### +### Validate MASS_VHOST_DOCROOT +### +validate_mass_vhost_docroot() { + local name="${1}" + local value="${2}" + local base_path="${MASS_DOCROOT_BASE}" + _validate_vhost_docroot "${name}" "${value}" "${MASS_VHOST_ENABLE}" "${MASS_VHOST_BACKEND}" "${base_path}//${value}" +} + + +### +### Validate MASS_VHOST_TLD_SUFFIX (top-level domain suffix) +### +validate_mass_vhost_tld_suffix() { + local name="${1}" + local value="${2}" + + # If value is not empty + if [ -n "${value}" ]; then + if ! echo "${value}" | grep -E '^\.' > /dev/null; then + _log_env_valid "invalid" "${name}" "${value}" "Must start with a leading '.' when set" "" + _log_env_valid "invalid" "${name}" "${value}" "Not a valid project name" "" + fi + # Note: ${value:1} means it starts at the second character, + # when handing it over to the is_domain() check function. + if ! is_domain "${value:1}"; then + _log_env_valid "invalid" "${name}" "${value}" "Must be a valid domain name or empty" "" + exit 1 + fi + fi + # Show ignored + if [ "${MASS_VHOST_ENABLE}" = "0" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(vhost disabled)" + return + fi + if [ -z "${value}" ]; then + _log_env_valid "valid" "${name}" "${value}" "vHost domain" "" + else + _log_env_valid "valid" "${name}" "${value}" "Vhost domain" "${value}" + fi +} + + +### +### Validate MASS_VHOST_SSL_TYPE +### +validate_mass_vhost_ssl_type() { + local name="${1}" + local value="${2}" + _validate_vhost_ssl_type "${name}" "${value}" "${MASS_VHOST_ENABLE}" +} + + +### +### Validate MASS_VHOST_TPL: vhost-gen template directory +### +validate_mass_vhost_tpl() { + local name="${1}" + local value="${2}" + local base_path="${MASS_DOCROOT_BASE}" + _validate_vhost_tpl "${name}" "${value}" "${MASS_VHOST_ENABLE}" "${base_path}//${value}" +} + + + +# ------------------------------------------------------------------------------------------------- +# VALIDATE FUNCTIONS: MISC VALIDATION +# ------------------------------------------------------------------------------------------------- + +### +### Validate WORKER_CONNECTIONS +### +validate_worker_connections() { + local name="${1}" + local value="${2}" + _log_env_valid "valid" "${name}" "${value}" "worker_connections" "${value}" +} + + +### +### Validate WORKER_PROCESSES +### +validate_worker_processes() { + local name="${1}" + local value="${2}" + _log_env_valid "valid" "${name}" "${value}" "worker_processes" "${value}" +} + + +### +### Validate HTTPD2_ENABLE +### +validate_http2_enable() { + local name="${1}" + local value="${2}" + _validate_bool "${name}" "${value}" "HTTP/2" +} + + +### +### Validate DOCKER_LOGS +### +validate_docker_logs() { + local name="${1}" + local value="${2}" + _validate_bool "${name}" "${value}" "Log to" "0" "stdout and stderr" "/var/log/" +} + + + +# ------------------------------------------------------------------------------------------------- +# HELPER FUNCTIONS +# ------------------------------------------------------------------------------------------------- + +### +### Generic validator for bool (Enabled/Disabled) +### +_validate_bool() { + local name="${1}" + local value="${2}" + local message="${3}" + local ignore="${4:-0}" + local on="${5:-Enabled}" + local off="${5:-Disabled}" + + # Validate + if ! is_bool "${value}"; then + _log_env_valid "invalid" "${name}" "${value}" "Must be 0 or 1" "" + exit 1 + fi + + # Check if we ignore the value + if [ "${ignore}" = "1" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(disabled)" + return + fi + + # Show status + if [ "${value}" = "0" ]; then + _log_env_valid "valid" "${name}" "${value}" "${message}" "${off}" + else + _log_env_valid "valid" "${name}" "${value}" "${message}" "${on}" + fi +} + + +### +### Validate *_VHOST_BACKEND +### string: conf:::: +### string: file: +### +_validate_vhost_backend() { + local name="${1}" + local value="${2}" + local vhost="${3}" # either "main" or "mass" + local vhost_enabled="${4}" # either "0" or "1" + + backend_prefix="$( get_backend_prefix "${value}" )" # file or conf + backend_file_name="$( get_backend_file_file "${value}" )" # filename + backend_conf_type="$( get_backend_conf_type "${value}" )" # phpfpm or rproxy + backend_conf_prot="$( get_backend_conf_prot "${value}" )" # tpc, http, https + backend_conf_host="$( get_backend_conf_host "${value}" )" # + backend_conf_port="$( get_backend_conf_port "${value}" )" # + + # 1. If no backend is specified + if ! backend_has_backend "${value}"; then + # Check if vhost is disabled + if [ "${vhost_enabled}" = "0" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(vhost disabled)" + else + _log_env_valid "valid" "${name}" "${value}" "No remote backend" "Serving static files only" + fi + return + fi + + # 2. Validate prefix + if [ "${backend_prefix}" != "file" ] && [ "${backend_prefix}" != "conf" ]; then + _log_env_valid "invalid" "${name}" "${value}" "Invalid format" + _log_env_valid "invalid" "${name}" "${backend_prefix}" "Valid backend prefix: " "'conf' or 'file'" + _log_backend_examples "all" + exit 1 + fi + + # 3. Validate file: - the filename + if [ "${backend_prefix}" = "file" ]; then + if ! backend_is_valid_file_file "${value}"; then + _log_env_valid "invalid" "${name}" "${value}" "Invalid format" + _log_env_valid "invalid" "${name}" "${backend_file_name}" "filename is invalid" + _log_backend_examples "file" + exit 1 + fi + fi + + if [ "${backend_prefix}" = "conf" ]; then + + # 4. Validate conf + if ! backend_is_valid_conf_type "${value}"; then + _log_env_valid "invalid" "${name}" "${value}" "Invalid format" + _log_env_valid "invalid" "${name}" "${backend_conf_type}" " is invalid. Must be: " "'phpfpm' or 'rproxy'" + _log_backend_examples "conf" + exit 1 + fi + # 5. Validate conf + if ! backend_is_valid_conf_prot "${value}"; then + _log_env_valid "invalid" "${name}" "${value}" "Invalid format" + _log_env_valid "invalid" "${name}" "${backend_conf_prot}" " is invalid. Must be: " "'tcp', 'http' or 'https'" + _log_backend_examples "conf" + exit 1 + fi + # 6. Validate conf phpfpm == tcp + if [ "${backend_conf_type}" = "phpfpm" ]; then + if [ "${backend_conf_prot}" != "tcp" ]; then + _log_env_valid "invalid" "${name}" "${value}" "Invalid format" + _log_env_valid "invalid" "${name}" "${backend_conf_prot}" "phpfpm only supports protocol " "'tcp'" + _log_backend_examples "conf" + exit 1 + fi + fi + # 7. Validate conf rproxy == http(s)? + if [ "${backend_conf_type}" = "rproxy" ]; then + if [ "${backend_conf_prot}" != "http" ] && [ "${backend_conf_prot}" != "https" ]; then + _log_env_valid "invalid" "${name}" "${value}" "Invalid format" + _log_env_valid "invalid" "${name}" "${backend_conf_prot}" "rproxy only supports protocol " "'http' or 'https'" + _log_backend_examples "conf" + exit 1 + fi + fi + # 8. Validate conf + if ! backend_is_valid_conf_host "${value}"; then + _log_env_valid "invalid" "${name}" "${value}" "Invalid format" + _log_env_valid "invalid" "${name}" "${backend_conf_host}" " is invalid. Must be: " "hostname, IPv4 or IPv6 addr" + _log_backend_examples "conf" + exit 1 + fi + # 8. Validate conf + if ! backend_is_valid_conf_port "${value}"; then + _log_env_valid "invalid" "${name}" "${value}" "Invalid format" + _log_env_valid "invalid" "${name}" "${backend_conf_port}" " is invalid. Must be valid port" + _log_backend_examples "conf" + exit 1 + fi + + fi + + # 9. Validate MAIN_VHOST_BACKEND (does not YET support file:) + # TODO: implement file: support for MAIN_VHOST + if [ "${vhost}" = "main" ]; then + if [ "${backend_prefix}" = "file" ]; then + _log_env_valid "invalid" "${name}" "${value}" "Unsupported" + _log_env_valid "invalid" "${name}" "${backend_prefix}" "\$MAIN_VHOST_BACKEND does not support 'file'. Use: " "'conf'" + _log_backend_examples "conf" + exit 1 + fi + fi + + # 10. MASS_VHOST_BACKEND cannot use rproxy, otherwise all autogenerated mass vhosts + # would reverse proxy to the same :, which does not make any sense at all. + # Instead, it only supports file:, so that each project can define it's own reverse + # proxy definition in a file and each can have different hosts and ports. + if [ "${vhost}" = "mass" ]; then + if [ "${backend_prefix}" = "conf" ] && [ "${backend_conf_type}" = "rproxy" ]; then + _log_env_valid "invalid" "${name}" "${value}" "Unsupported" + _log_env_valid "invalid" "${name}" "\$MASS_VHOST_BACKEND' does not support 'conf' with type 'rproxy" + log "err" "" + log "err" "Why is this?" + log "err" " The MASS_VHOST automatically creates a vhost for each directory present in: ${MASS_DOCROOT_BASE}/" + log "err" " Now imagine you specify a reverse proxy at http://example:3000." + log "err" " Then every automatically created virtual host would point to that address." + log "err" " You will end up with many virtual hosts all pointing the the same backend." + log "err" " This makes only sense with 'phpfpm'." + log "err" "" + log "err" "What should I do?" + log "err" " Use 'MASS_VHOST_BACKEND=file:config.txt' instead!" + log "err" " This allows you to add a config file to every project at: ${MASS_DOCROOT_BASE}//${MASS_VHOST_TPL}/config.txt" + log "err" " Then every project can define its own reverse proxy backend." + log "err" "" + log "err" "What is in that file?" + log "err" " The file contains a single line with the same config string you supplied for MASS_VHOST_BACKEND:" + log "err" "" + log "err" " ${value}" + log "err" "" + log "err" " Each project config file can also have different protocol/host/port values to make sense." + exit 1 + fi + fi + + # 11. Check if vhost is disabled + if [ "${vhost_enabled}" = "0" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(vhost disabled)" + return + fi + + # 12. Show settings (file) + if [ "${backend_prefix}" = "file" ]; then + if [ "${vhost}" = "main" ]; then + _log_env_valid "valid" "${name}" "${value}" "Backend set in file" "${MAIN_DOCROOT_BASE}/${MAIN_VHOST_TPL}/${backend_file_name}" + else + _log_env_valid "valid" "${name}" "${value}" "Backend set in file" "${MASS_DOCROOT_BASE}//${MASS_VHOST_TPL}/${backend_file_name}" + fi + # 13. Show settings (conf) + elif [ "${backend_prefix}" = "conf" ]; then + if [ "${backend_conf_type}" = "phpfpm" ]; then + _log_env_valid "valid" "${name}" "${value}" "PHP via PHP-FPM" "Remote: ${backend_conf_prot}://${backend_conf_host}:${backend_conf_port}" + elif [ "${backend_conf_type}" = "rproxy" ]; then + _log_env_valid "valid" "${name}" "${value}" "Reverse Proxy" "Remote: ${backend_conf_prot}://${backend_conf_host}:${backend_conf_port}" + fi + fi +} + + +### +### Validate *_VHOST_BACKEND_TIMEOUT +### +_validate_vhost_backend_timeout() { + local name="${1}" + local value="${2}" + local vhost_enabled="${3}" + + if ! is_int "${value}"; then + _log_env_valid "invalid" "${name}" "${value}" "Invalid timeout. Must be positive integer" + exit 1 + fi + # Check if vhost is disabled + if [ "${vhost_enabled}" = "0" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(vhost disabled)" + return + fi + _log_env_valid "valid" "${name}" "${value}" "Timeout: " "${value}sec" +} + + +### +### Validate *_VHOST_DOCROOT +### +_validate_vhost_docroot() { + local name="${1}" + local value="${2}" + local vhost_enabled="${3}" + local vhost_backend="${4}" + local docroot_path="${5}" + + # Show ignored + if [ "${vhost_enabled}" = "0" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(vhost disabled)" + return + fi + # Check if we have a backend defined + if backend_has_backend "${value}"; then + if [ "$( get_backend_conf_type "${vhost_backend}" )" = "rproxy" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(using rproxy)" + return + fi + fi + _log_env_valid "valid" "${name}" "${value}" "Document root: " "${docroot_path}" +} + + +### +### Validate *_VHOST_SSL_TYPE +### +_validate_vhost_ssl_type() { + local name="${1}" + local value="${2}" + local vhost_enabled="${3}" + + if [ "${value}" != "plain" ] && [ "${value}" != "ssl" ] && [ "${value}" != "both" ] && [ "${value}" != "redir" ]; then + _log_env_valid "invalid" "${name}" "${value}" "Invalid type. Must be one of: " "plain, ssl, both, redir" + exit 1 + fi + + # Show ignored + if [ "${vhost_enabled}" = "0" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(vhost disabled)" + return + fi + + if [ "${value}" = "plain" ]; then + _log_env_valid "valid" "${name}" "${value}" "Vhost protocol" "HTTP only" + elif [ "${value}" = "ssl" ]; then + _log_env_valid "valid" "${name}" "${value}" "Vhost protocol" "HTTPS only" + elif [ "${value}" = "both" ]; then + _log_env_valid "valid" "${name}" "${value}" "Vhost protocol" "HTTP and HTTPS" + elif [ "${value}" = "redir" ]; then + _log_env_valid "valid" "${name}" "${value}" "Vhost protocol" "Redirect HTTP -> HTTPS" + fi +} + + +### +### Validate *_VHOST_TPL: vhost-gen template directory +### +_validate_vhost_tpl() { + local name="${1}" + local value="${2}" + local vhost_enabled="${3}" + local template_path="${4}" + + # Show ignored + if [ "${vhost_enabled}" = "0" ]; then + _log_env_valid "ignore" "${name}" "${value}" "(vhost disabled)" + return + fi + _log_env_valid "valid" "${name}" "${value}" "Template dir" "${template_path}" +} + + +# ------------------------------------------------------------------------------------------------- +# Logger +# ------------------------------------------------------------------------------------------------- + +### +### Use custom logger to log env variable validity +### +_log_env_valid() { + local state="${1}" # 'valid', `ignore` or 'invalid' + local name="${2}" # Variable name + local value="${3}" # Variable value + local message="${4:-}" # Message: what will happen (valid) or expected format (invalid) + local message_val="${5:-}" # value for message + + local debug="${DEBUG_ENTRYPOINT}" # 0: only warn and error, >0: ok and info + + local clr_valid="\033[0;32m" # green + local clr_invalid="\033[0;31m" # red + + local clr_expect="\033[0;31m" # red + local clr_ignore="\033[0;34m" # red + + local clr_ok="\033[0;32m" # green + local clr_fail="\033[0;31m" # red + local clr_rst="\033[0m" + + if [ "${debug}" -gt "0" ]; then + if [ "${state}" = "valid" ]; then + printf "${clr_ok}%-11s${clr_rst}%-8s${clr_valid}\$%-27s${clr_rst}%-20s${clr_valid}%s${clr_rst}\n" \ + "[OK]" \ + "Valid" \ + "${name}" \ + "${message}" \ + "${message_val}" + elif [ "${state}" = "ignore" ]; then + printf "${clr_ok}%-11s${clr_rst}%-8s${clr_rst}\$%-27s${clr_ignore}%-20s${clr_rst}%s\n" \ + "[OK]" \ + "Valid" \ + "${name}" \ + "ignored" \ + "${message}" + elif [ "${state}" = "invalid" ]; then + printf "${clr_fail}%-11s${clr_rst}%-8s${clr_invalid}\$%-27s${clr_rst}${clr_invalid}'%s'${clr_rst}. %s${clr_expect}%s${clr_rst}\n" \ + "[ERR]" \ + "Invalid" \ + "${name}" \ + "${value}" \ + "${message}" \ + "${message_val}" + else + log "????" "Internal: Wrong value given to _log_env_valid" + exit 1 + fi + fi +} + + +### +### Log backend examples as error messages +### +_log_backend_examples() { + local show="${1}" # "all", "file" or "conf" + + log "err" "" + if [ "${show}" = "all" ] || [ "${show}" = "conf" ]; then + log "err" "Format: conf::::" + fi + if [ "${show}" = "all" ] || [ "${show}" = "file" ]; then + log "err" "Format: file:" + fi + + if [ "${show}" = "all" ] || [ "${show}" = "conf" ]; then + log "err" "" + log "err" "Example: conf:phpfpm:tcp:10.0.0.100:9000" + log "err" "Example: conf:phpfpm:tcp:domain.com:9000" + log "err" "" + log "err" "Example: conf:rproxy:http:10.0.0.100:3000" + log "err" "Example: conf:rproxy:http:domain.com:443" + log "err" "" + log "err" "Example: conf:rproxy:https:10.0.0.100:8080" + log "err" "Example: conf:rproxy:https:domain.com:8443" + fi + if [ "${show}" = "all" ] || [ "${show}" = "file" ]; then + log "err" "" + log "err" "Example: file:config.txt" + fi +} + + diff --git a/Dockerfiles/data/docker-entrypoint.d/02-timezone.sh b/Dockerfiles/data/docker-entrypoint.d/02-timezone.sh deleted file mode 100755 index 19b31c0..0000000 --- a/Dockerfiles/data/docker-entrypoint.d/02-timezone.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - - -############################################################ -# Functions -############################################################ - -### -### Change Timezone -### -set_timezone() { - local env_varname="${1}" - local debug="${2}" - local timezone= - - if ! env_set "${env_varname}"; then - log "info" "\$${env_varname} not set." "${debug}" - # Unix Time - log "info" "Setting container timezone to: UTC" "${debug}" - run "ln -sf /usr/share/zoneinfo/UTC /etc/localtime" "${debug}" - else - timezone="$( env_get "${env_varname}" )" - if [ -f "/usr/share/zoneinfo/${timezone}" ]; then - # Unix Time - log "info" "Setting container timezone to: ${timezone}" "${debug}" - run "ln -sf /usr/share/zoneinfo/${timezone} /etc/localtime" "${debug}" - else - log "err" "Invalid timezone for \$${env_varname}." "${debug}" - log "err" "Timezone '${timezone}' does not exist." "${debug}" - exit 1 - fi - fi - log "info" "Docker date set to: $(date)" "${debug}" -} diff --git a/Dockerfiles/data/docker-entrypoint.d/03-docker-logs.sh b/Dockerfiles/data/docker-entrypoint.d/03-docker-logs.sh deleted file mode 100755 index 408832f..0000000 --- a/Dockerfiles/data/docker-entrypoint.d/03-docker-logs.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - - -############################################################ -# Functions -############################################################ - -### -### Set docker logs -### -export_docker_logs() { - local varname="${1}" - local debug="${2}" - local value="0" - - if ! env_set "${varname}"; then - log "info" "\$${varname} not set. Logging errors and access to log files inside container." "${debug}" - else - value="$( env_get "${varname}" )" - if [ "${value}" = "0" ]; then - log "info" "\$${varname} disabled. Logging errors and access to log files inside container." "${debug}" - elif [ "${value}" = "1" ]; then - log "info" "\$${varname} enabled. Logging errors and access to Docker log (stderr and stdout)" "${debug}" - else - log "err" "Invalid value for \$${varname}: ${value}" - log "err" "Must be '1' (for On) or '0' (for Off)" - exit 1 - fi - fi - - # Set docker logs variable - eval "export ${varname}=${value}" -} diff --git a/Dockerfiles/data/docker-entrypoint.d/04-php-fpm.sh b/Dockerfiles/data/docker-entrypoint.d/04-php-fpm.sh deleted file mode 100755 index 406ad98..0000000 --- a/Dockerfiles/data/docker-entrypoint.d/04-php-fpm.sh +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - - -############################################################ -# Functions -############################################################ - -### -### Ensure PHP_FPM_ENABLE is set -### -export_php_fpm_enable() { - local varname="${1}" - local debug="${2}" - local value="0" - - if ! env_set "${varname}"; then - log "info" "\$${varname} not set. Disabling PHP-FPM." "${debug}" - else - value="$( env_get "${varname}" )" - if [ "${value}" = "0" ]; then - log "info" "PHP-FPM: Disabled" "${debug}" - elif [ "${value}" = "1" ]; then - log "info" "PHP-FPM: Enabled" "${debug}" - else - log "err" "Invalid value for \$${varname}: ${value}" - log "err" "Must be '1' (for On) or '0' (for Off)" - exit 1 - fi - fi - - # Ensure variable is exported - eval "export ${varname}=${value}" -} - - -### -### Ensure PHP_FPM_SERVER_ADDR is set (if needed) -### -export_php_fpm_server_addr() { - local varname="${1}" - local debug="${2}" - local value= - - if [ "${PHP_FPM_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "err" "PHP-FPM is enabled, but \$${varname} not specified, but required." "${debug}" - exit 1 - fi - value="$( env_get "${varname}" )" - if [ -z "${value}" ]; then - log "err" "PHP-FPM enabled, but \$${varname} is empty." "${debug}" - exit 1 - fi - log "info" "PHP-FPM: Server address: ${value}" "${debug}" - fi - - # Ensure variable is exported - eval "export ${varname}=${value}" -} - - -### -### Ensure PHP_FPM_SERVER_PORT is set (if needed) -### -export_php_fpm_server_port() { - local varname="${1}" - local debug="${2}" - local value="9000" - - if [ "${PHP_FPM_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified, keeping default: ${value}" "${debug}" - else - value="$( env_get "${varname}" )" - - if [ -z "${value}" ]; then - log "err" "\$${varname} is empty." "${debug}" - exit 1 - fi - if ! isint "${value}"; then - log "err" "\$${varname} is not a valid integer: ${value}" "${debug}" - exit 1 - fi - if [ "${value}" -lt "1" ] || [ "${value}" -gt "65535" ]; then - log "err" "\$${varname} is not in a valid port range: ${value}" "${debug}" - exit 1 - fi - log "info" "PHP-FPM: Server port: ${value}" "${debug}" - fi - fi - - # Ensure variable is exported if not set - eval "export ${varname}=${value}" -} - - -### -### Ensure PHP_FPM_TIMEOUT is set (if needed) -### -export_php_fpm_timeout() { - local varname="${1}" - local debug="${2}" - local value="180" - - if [ "${PHP_FPM_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified, keeping default: ${value}" "${debug}" - else - value="$( env_get "${varname}" )" - - if [ -z "${value}" ]; then - log "err" "\$${varname} is empty." "${debug}" - exit 1 - fi - if ! isint "${value}"; then - log "err" "\$${varname} is not a valid integer: ${value}" "${debug}" - exit 1 - fi - if [ "${value}" -lt "0" ]; then - log "err" "\$${varname} must be greater than 0: ${value}" "${debug}" - exit 1 - fi - log "info" "PHP-FPM: Timeout: ${value}" "${debug}" - fi - fi - - # Ensure variable is exported if not set - eval "export ${varname}=${value}" -} diff --git a/Dockerfiles/data/docker-entrypoint.d/05-main-vhost.sh b/Dockerfiles/data/docker-entrypoint.d/05-main-vhost.sh deleted file mode 100755 index a6d27b0..0000000 --- a/Dockerfiles/data/docker-entrypoint.d/05-main-vhost.sh +++ /dev/null @@ -1,214 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - - -############################################################ -# Functions -############################################################ - -### -### Ensure MAIN_VHOST_ENABLE is exported -### -export_main_vhost_enable() { - local varname="${1}" - local debug="${2}" - local value="1" - - if ! env_set "${varname}"; then - log "info" "\$${varname} not set. Enabling default vhost." "${debug}" - else - value="$( env_get "${varname}" )" - if [ "${value}" = "0" ]; then - log "info" "Main vhost: Disabled" "${debug}" - elif [ "${value}" = "1" ]; then - log "info" "Main vhost: Enabled" "${debug}" - else - log "err" "Invalid value for \$${varname}: ${value}" - log "err" "Must be '1' (for On) or '0' (for Off)" - exit 1 - fi - fi - - # Ensure variable is exported - eval "export ${varname}=${value}" -} - - -### -### Ensure MAIN_VHOST_SSL_TYPE is set (if needed) -### -export_main_vhost_ssl_type() { - local varname="${1}" - local debug="${2}" - local value="plain" - - if [ "${MAIN_VHOST_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified, defaulting to: plain" "${debug}" - else - value="$( env_get "${varname}" )" - if [ "${value}" = "plain" ]; then - log "info" "Main vhost: Setting SSL type to: http only" "${debug}" - elif [ "${value}" = "ssl" ]; then - log "info" "Main vhost: Setting SSL type to: https only" "${debug}" - elif [ "${value}" = "both" ]; then - log "info" "Main vhost: Setting SSL type to: http and https" "${debug}" - elif [ "${value}" = "redir" ]; then - log "info" "Main vhost: Setting SSL type to: redirect http to https" "${debug}" - else - log "err" "Invalid value for \$${varname}: '${value}'. Allowed: plain, ssl, both or redir" "${debug}" - exit 1 - fi - fi - # Ensure variable is exported - eval "export ${varname}=${value}" - fi -} - - -### -### Ensure MAIN_VHOST_SSL_GEN is set (if needed) -### -export_main_vhost_ssl_gen() { - local varname="${1}" - local debug="${2}" - local value="0" - - if [ "${MAIN_VHOST_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified, defaulting to not generate SSL certificates" "${debug}" - else - value="$( env_get "${varname}" )" - if [ "${value}" = "0" ]; then - log "info" "Main vhost: Disable automatic generation of SSL certificates" "${debug}" - elif [ "${value}" = "1" ]; then - log "info" "Main vhost: Enable automatic generation of SSL certificates" "${debug}" - else - log "err" "Invalid value for \$${varname}: '${value}'. Allowed: 0 or 1" "${debug}" - exit 1 - fi - fi - # Ensure variable is exported - eval "export ${varname}=${value}" - fi -} - - -### -### Ensure MAIN_VHOST_SSL_CN is set (if needed) -### -export_main_vhost_ssl_cn() { - local varname="${1}" - local debug="${2}" - local value="localhost" - - if [ "${MAIN_VHOST_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified. Keeping default: ${value}" "${debug}" - else - value="$( env_get "${varname}" )" - if [ -z "${value}" ]; then - log "err" "\$${varname} set but empty. Cannot determine CN name for SSL certificate generation." "${debug}" - exit 1 - else - log "info" "Main vhost: SSL CN: ${value}" "${debug}" - fi - fi - # Ensure variable is exported - eval "export ${varname}=${value}" - fi -} - - -### -### Ensure MAIN_VHOST_DOCROOT is set (if needed) -### -export_main_vhost_docroot() { - local varname="${1}" - local debug="${2}" - local value="htdocs" - - if [ "${MAIN_VHOST_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified. Keeping default: ${value}" "${debug}" - else - value="$( env_get "${varname}" )" - log "info" "Main vhost: changing document root to: ${value}" "${debug}" - fi - # Ensure variable is exported - eval "export ${varname}=${value}" - fi -} - - -### -### Ensure MAIN_VHOST_TPL is set (if needed) -### -export_main_vhost_tpl() { - local varname="${1}" - local debug="${2}" - local value="cfg" - - if [ "${MAIN_VHOST_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified. Keeping default: ${value}" "${debug}" - else - value="$( env_get "${varname}" )" - log "info" "Main vhost: changing template dir to: ${value}" "${debug}" - fi - # Ensure variable is exported - eval "export ${varname}=${value}" - fi -} - - -### -### Ensure MAIN_VHOST_STATUS_ENABLE is set (if needed) -### -export_main_vhost_status_enable() { - local varname="${1}" - local debug="${2}" - local value="0" - - if [ "${MAIN_VHOST_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified, defaulting to disable httpd status page" "${debug}" - else - value="$( env_get "${varname}" )" - if [ "${value}" = "0" ]; then - log "info" "Main vhost: Disabling httpd status page" "${debug}" - elif [ "${value}" = "1" ]; then - log "info" "Main vhost: Enabling httpd status page" "${debug}" - else - log "err" "Invalid value for \$${varname}: '${value}'. Allowed: 0 or 1" "${debug}" - exit 1 - fi - fi - # Ensure variable is exported - eval "export ${varname}=${value}" - fi -} - - -### -### Ensure MAIN_VHOST_STATUS_ALIAS is set (if needed) -### -export_main_vhost_status_alias() { - local varname="${1}" - local debug="${2}" - local value="/httpd-status" - - if [ "${MAIN_VHOST_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified. Keeping default: ${value}" "${debug}" - else - value="$( env_get "${varname}" )" - log "info" "Main vhost: Changing status page alias to: ${value}" "${debug}" - fi - # Ensure variable is exported - eval "export ${varname}=${value}" - fi -} diff --git a/Dockerfiles/data/docker-entrypoint.d/06-mass-vhost.sh b/Dockerfiles/data/docker-entrypoint.d/06-mass-vhost.sh deleted file mode 100755 index 0c52504..0000000 --- a/Dockerfiles/data/docker-entrypoint.d/06-mass-vhost.sh +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - - -############################################################ -# Functions -############################################################ - -### -### Ensure MASS_VHOST_ENABLE is exported -### -export_mass_vhost_enable() { - local varname="${1}" - local debug="${2}" - local value="0" - - if ! env_set "${varname}"; then - log "info" "\$${varname} not set. Enabling default vhost." "${debug}" - else - value="$( env_get "${varname}" )" - if [ "${value}" = "0" ]; then - log "info" "Mass vhost: Disabled" "${debug}" - elif [ "${value}" = "1" ]; then - log "info" "Mass vhost: Enabled" "${debug}" - else - log "err" "Invalid value for \$${varname}: ${value}" - log "err" "Must be '1' (for On) or '0' (for Off)" - exit 1 - fi - fi - - # Ensure variable is exported - eval "export ${varname}=${value}" -} - - -### -### Ensure MASS_VHOST_SSL_TYPE is set (if needed) -### -export_mass_vhost_ssl_type() { - local varname="${1}" - local debug="${2}" - local value="plain" - - if [ "${MASS_VHOST_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified, defaulting to: plain" "${debug}" - else - value="$( env_get "${varname}" )" - if [ "${value}" = "plain" ]; then - log "info" "Mass vhost: Setting SSL type to: http only" "${debug}" - elif [ "${value}" = "ssl" ]; then - log "info" "Mass vhost: Setting SSL type to: https only" "${debug}" - elif [ "${value}" = "both" ]; then - log "info" "Mass vhost: Setting SSL type to: http and https" "${debug}" - elif [ "${value}" = "redir" ]; then - log "info" "Mass vhost: Setting SSL type to: redirect http to https" "${debug}" - else - log "err" "Invalid value for \$${varname}: '${value}'. Allowed: plain, ssl, both or redir" "${debug}" - exit 1 - fi - fi - fi - - # Ensure variable is exported - eval "export ${varname}=${value}" -} - - -### -### Ensure MASS_VHOST_SSL_GEN is set (if needed) -### -export_mass_vhost_ssl_gen() { - local varname="${1}" - local debug="${2}" - local value="0" - - if [ "${MASS_VHOST_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified, defaulting to not generate SSL certificates" "${debug}" - else - value="$( env_get "${varname}" )" - if [ "${value}" = "0" ]; then - log "info" "Mass vhost: Disable automatic generation of SSL certificates" "${debug}" - elif [ "${value}" = "1" ]; then - log "info" "Mass vhost: Enable automatic generation of SSL certificates" "${debug}" - else - log "err" "Invalid value for \$${varname}: '${value}'. Allowed: 0 or 1" "${debug}" - exit 1 - fi - fi - fi - - # Ensure variable is exported - eval "export ${varname}=${value}" -} - - -### -### Ensure MASS_VHOST_TLD is set (if needed) -### -export_mass_vhost_tld() { - local varname="${1}" - local debug="${2}" - local value="loc" - - if [ "${MASS_VHOST_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified. Keeping default: ${value}" "${debug}" - else - value="$( env_get "${varname}" )" - log "info" "Mass vhost: changing tld to: ${value}" "${debug}" - fi - fi - - # Ensure variable is exported - eval "export ${varname}=${value}" -} - - -### -### Ensure MASS_VHOST_DOCROOT is set (if needed) -### -export_mass_vhost_docroot() { - local varname="${1}" - local debug="${2}" - local value="htdocs" - - if [ "${MASS_VHOST_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified. Keeping default: ${value}" "${debug}" - else - value="$( env_get "${varname}" )" - log "info" "Mass vhost: changing document root to: ${value}" "${debug}" - fi - fi - - # Ensure variable is exported - eval "export ${varname}=${value}" -} - - -### -### Ensure MASS_VHOST_TPL is set (if needed) -### -export_mass_vhost_tpl() { - local varname="${1}" - local debug="${2}" - local value="cfg" - - if [ "${MASS_VHOST_ENABLE}" = "1" ]; then - if ! env_set "${varname}"; then - log "info" "\$${varname} not specified. Keeping default: ${value}" "${debug}" - else - value="$( env_get "${varname}" )" - log "info" "Mass vhost: changing template dir to: ${value}" "${debug}" - fi - fi - - # Ensure variable is exported - eval "export ${varname}=${value}" -} diff --git a/Dockerfiles/data/docker-entrypoint.d/07-vhost-gen.sh b/Dockerfiles/data/docker-entrypoint.d/07-vhost-gen.sh deleted file mode 100755 index 12c709f..0000000 --- a/Dockerfiles/data/docker-entrypoint.d/07-vhost-gen.sh +++ /dev/null @@ -1,194 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - - -############################################################ -# Functions -############################################################ - - -### -### Ensure HTTP2_ENABLE is exported -### -export_http2_enable() { - local varname="${1}" - local debug="${2}" - local value="1" - - if ! env_set "${varname}"; then - log "info" "\$${varname} not set. Enabling http2." "${debug}" - else - value="$( env_get "${varname}" )" - if [ "${value}" = "0" ]; then - log "info" "http2: Disabled" "${debug}" - elif [ "${value}" = "1" ]; then - log "info" "http2: Enabled" "${debug}" - else - log "err" "Invalid value for \$${varname}: ${value}" - log "err" "Must be '1' (for On) or '0' (for Off)" - exit 1 - fi - fi - - # Ensure variable is exported - eval "export ${varname}=${value}" -} - - -### -### Copy custom vhost-gen template -### -vhost_gen_copy_custom_template() { - local input_dir="${1}" - local output_dir="${2}" - local template_name="${3}" - local debug="${4}" - - if [ ! -d "${input_dir}" ]; then - run "mkdir -p ${input_dir}" "${debug}" - fi - - if [ -f "${input_dir}/${template_name}" ]; then - log "info" "vhost-gen: applying customized global template: ${template_name}" "${debug}" - run "cp ${input_dir}/${template_name} ${output_dir}/${template_name}" "${debug}" - else - log "info" "vhost-gen: no customized template found" "${debug}" - fi -} - - -### -### Set PHP_FPM -### -vhost_gen_php_fpm() { - local enable="${1}" - local addr="${2}" - local port="${3}" - local timeout="${4}" - local config="${5}" - local debug="${6}" - - if [ "${enable}" -eq "1" ]; then - run "sed -i'' 's/__PHP_ENABLE__/yes/g' ${config}" "${debug}" - run "sed -i'' 's/__PHP_ADDR__/${addr}/g' ${config}" "${debug}" - run "sed -i'' 's/__PHP_PORT__/${port}/g' ${config}" "${debug}" - run "sed -i'' 's/__PHP_TIMEOUT__/${timeout}/g' ${config}" "${debug}" - else - run "sed -i'' 's/__PHP_ENABLE__/no/g' ${config}" "${debug}" - fi -} - - -### -### Configure Docker logs -### -vhost_gen_docker_logs() { - local enable="${1}" - local config="${2}" - local debug="${3}" - - if [ "${enable}" -eq "1" ]; then - run "sed -i'' 's/__DOCKER_LOGS_ERROR__/yes/g' ${config}" "${debug}" - run "sed -i'' 's/__DOCKER_LOGS_ACCESS__/yes/g' ${config}" "${debug}" - else - run "sed -i'' 's/__DOCKER_LOGS_ERROR__/no/g' ${config}" "${debug}" - run "sed -i'' 's/__DOCKER_LOGS_ACCESS__/no/g' ${config}" "${debug}" - fi -} - - - -### -### Generate Main vhost? -### -vhost_gen_generate_main_vhost() { - local enable="${1}" - local docroot="${2}" - local config="${3}" - local template="${4}" - local ssl_type="${5}" - local verbose="${6}" - local debug="${7}" - - if [ "${enable}" -eq "1" ]; then - - # vhost-gen verbosity - if [ "${verbose}" -gt "0" ]; then - verbose="-v" - else - verbose="" - fi - # Adding custom nginx vhost template to ensure paths like: - # /vendor/index.php/arg1/arg2 will also work (just like Apache) - run "vhost-gen -n localhost -p ${docroot} -t /etc/vhost-gen/templates-main/ -c ${config} -o ${template} ${verbose} -d -s -m ${ssl_type}" "${debug}" - fi -} - - - -### -### Enable HTTPD status page? -### -vhost_gen_main_vhost_httpd_status() { - local enable="${1}" - local alias="${2}" - local config="${3}" - local debug="${4}" - - if [ "${enable}" -eq "1" ]; then - run "sed -i'' 's|__ENABLE_STATUS__|yes|g' ${config}" "${debug}" - run "sed -i'' 's|__STATUS_ALIAS__|${alias}|g' ${config}" "${debug}" - else - run "sed -i'' 's|__ENABLE_STATUS__|no|g' ${config}" "${debug}" - fi -} - - - -### -### Set DOCROOT_SUFFIX -### -vhost_gen_mass_vhost_docroot() { - local enable="${1}" - local docroot="${2}" - local config="${3}" - local debug="${4}" - - if [ "${enable}" -eq "1" ]; then - run "sed -i'' 's|__DOCROOT_SUFFIX__|${docroot}|g' ${config}" "${debug}" - fi -} - - -### -### Set TLD -### -vhost_gen_mass_vhost_tld() { - local enable="${1}" - local tld="${2}" - local config="${3}" - local debug="${4}" - - if [ "${enable}" -eq "1" ]; then - run "sed -i'' 's/__TLD__/${tld}/g' ${config}" "${debug}" - fi -} - - -### -### Set HTTP2_ENABLE -### -vhost_gen_http2() { - local enable="${1}" - local config="${2}" - local debug="${3}" - - if [ "${enable}" -eq "1" ]; then - run "sed -i'' 's/__HTTP2_ENABLE__/True/g' ${config}" "${debug}" - else - run "sed -i'' 's/__HTTP2_ENABLE__/False/g' ${config}" "${debug}" - fi -} diff --git a/Dockerfiles/data/docker-entrypoint.d/09-fix-permissions.sh b/Dockerfiles/data/docker-entrypoint.d/09-fix-permissions.sh deleted file mode 100755 index b2772da..0000000 --- a/Dockerfiles/data/docker-entrypoint.d/09-fix-permissions.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - - -############################################################ -# Functions -############################################################ - - -### -### Change UID -### -fix_perm() { - local uid_varname="${1}" - local gid_varname="${2}" - local directory="${3}" - local recursive="${4}" - local debug="${5}" - - local perm= - - # Get uid - if env_set "${uid_varname}"; then - perm="$( env_get "${uid_varname}" )" - fi - - # Get gid - if env_set "${gid_varname}"; then - perm="${perm}:$( env_get "${gid_varname}" )" - fi - - if [ -n "${perm}" ]; then - if [ "${recursive}" = "1" ]; then - run "chown -R ${perm} ${directory}" "${debug}" - else - run "chown ${perm} ${directory}" "${debug}" - fi - fi -} diff --git a/Dockerfiles/data/docker-entrypoint.d/10-config-settings.sh b/Dockerfiles/data/docker-entrypoint.d/10-config-settings.sh deleted file mode 100755 index d5c8826..0000000 --- a/Dockerfiles/data/docker-entrypoint.d/10-config-settings.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - - -############################################################ -# Functions -############################################################ - -### -### Change worker_processes -### -set_worker_processess() { - local wp_varname="${1}" - local debug="${2}" - local default="auto" - local config="/etc/nginx/nginx.conf" - - if ! env_set "${wp_varname}"; then - log "info" "\$${wp_varname} not set. Keeping default worker_processes: '${default}'." "${debug}" - run "sed -i'' 's/__WORKER_PROCESSES__/${default}/g' ${config}" "${debug}" - else - wp="$( env_get "${wp_varname}" )" - - if [ "${wp}" = "auto" ]; then - log "info" "\$${wp_varname} set to its default value: '${default}'." "${debug}" - run "sed -i'' 's/__WORKER_PROCESSES__/${default}/g' ${config}" "${debug}" - else - if ! isint "${wp}"; then - log "err" "\$${wp_varname} is not an integer: '${wp}'" "${debug}" - exit 1 - else - log "info" "Setting worker_processes to: ${wp}" "${debug}" - run "sed -i'' 's/__WORKER_PROCESSES__/${wp}/g' ${config}" "${debug}" - fi - fi - fi -} - - -### -### Change worker_connections -### -set_worker_connections() { - local wc_varname="${1}" - local debug="${2}" - local default="1024" - local config="/etc/nginx/nginx.conf" - - if ! env_set "${wc_varname}"; then - log "info" "\$${wc_varname} not set. Keeping default worker_connections: '${default}'." "${debug}" - run "sed -i'' 's/__WORKER_CONNECTIONS__/${default}/g' ${config}" "${debug}" - else - wc="$( env_get "${wc_varname}" )" - - if ! isint "${wc}"; then - log "err" "\$${wc_varname} is not an integer: '${wc}'" "${debug}" - exit 1 - else - log "info" "Setting worker_connections to: ${wc}" "${debug}" - run "sed -i'' 's/__WORKER_CONNECTIONS__/${wc}/g' ${config}" "${debug}" - fi - fi -} diff --git a/Dockerfiles/data/docker-entrypoint.d/10-uid-gid.sh b/Dockerfiles/data/docker-entrypoint.d/10-uid-gid.sh new file mode 100755 index 0000000..e68aa5e --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/10-uid-gid.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + + +# ------------------------------------------------------------------------------------------------- +# [SET] FUNCTIONS +# ------------------------------------------------------------------------------------------------- + +### +### Change UID +### +set_uid() { + local uid="${1}" + local username="${2}" + local spare_uid=9876 # spare uid to change another user to + + # If uid is empty, end this function + if [ -z "${uid}" ]; then + return + fi + + # Check if username with given uid already exists + if target_username="$( _get_username_by_uid "${uid}" )"; then + # It is not our user, so we need to changes his/her uid to something else first + if [ "${target_username}" != "${username}" ]; then + log "info" "User with ${uid} already exists: ${target_username}" + log "info" "Changing UID of ${target_username} to ${spare_uid}" + run "usermod -u ${spare_uid} ${target_username}" + fi + fi + log "info" "Setting uid to ${uid} (user: ${username})" + run "usermod -u ${uid} ${username}" + run "id ${username}" +} + + +### +### Change GID +### +set_gid() { + local gid="${1}" + local username="${2}" + local groupname="${3}" + + local spare_gid=9876 # spare gid to change another group to + + # If gid is empty, end this function + if [ -z "${gid}" ]; then + return + fi + + # Groupname with this gid already exists + if target_groupname="$( _get_groupname_by_gid "${gid}" )"; then + # It is not our group, so we need to changes his/her gid to something else first + if [ "${target_groupname}" != "${groupname}" ]; then + log "info" "Group with ${gid} already exists: ${target_groupname}" + log "info" "Changing GID of ${target_groupname} to ${spare_gid}" + run "groupmod -g ${spare_gid} ${target_groupname}" + fi + fi + # Change ugd and fix homedir permissions + log "info" "Setting gid to ${gid} (group: ${groupname})" + run "groupmod -g ${gid} ${groupname}" + run "id ${username}" +} + + + +# ------------------------------------------------------------------------------------------------- +# HELPER FUNCTIONS +# ------------------------------------------------------------------------------------------------- + +### +### Get username by its uid +### +_get_username_by_uid() { + if getent="$( getent passwd "${1}" )"; then + echo "${getent//:*}" + return 0 + fi + return 1 +} + + +### +### Get groupname by its gid +### +_get_groupname_by_gid() { + if getent="$( getent group "${1}" )"; then + echo "${getent//:*}" + return 0 + fi + return 1 +} + + +### +### Get home directory by username +### +_get_homedir_by_username() { + getent passwd "${1}" | cut -d: -f6 +} + + +### +### Get home directory by groupname +### +_get_homedir_by_groupname() { + grep -E ".*:x:[0-9]+:[0-9]+:$( _get_groupname_by_gid "${1}" ).*" /etc/passwd | cut -d: -f6 +} + + + +# ------------------------------------------------------------------------------------------------- +# SANITY CHECKS +# ------------------------------------------------------------------------------------------------- + +### +### The following commands are required and used in the current script. +### +if ! command -v usermod >/dev/null 2>&1; then + log "err" "usermod not found, but required." + exit 1 +fi +if ! command -v groupmod >/dev/null 2>&1; then + log "err" "groupmod not found, but required." + exit 1 +fi +if ! command -v getent >/dev/null 2>&1; then + log "err" "getent not found, but required." + exit 1 +fi diff --git a/Dockerfiles/data/docker-entrypoint.d/11-timezone.sh b/Dockerfiles/data/docker-entrypoint.d/11-timezone.sh new file mode 100755 index 0000000..9bb6d5c --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/11-timezone.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + + +# ------------------------------------------------------------------------------------------------- +# [SET] FUNCTIONS +# ------------------------------------------------------------------------------------------------- + +### +### Set Timezone +### +set_timezone() { + local timezone="${1}" + + # If uid is empty, end this function + if [ "${timezone}" = "UTC" ]; then + return + fi + + # Unix Time + log "info" "Setting timezone to ${timezone}" + run "ln -sf /usr/share/zoneinfo/${timezone} /etc/localtime" + run "date" +} diff --git a/Dockerfiles/data/docker-entrypoint.d/12-vhost-gen.sh b/Dockerfiles/data/docker-entrypoint.d/12-vhost-gen.sh new file mode 100755 index 0000000..be10844 --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/12-vhost-gen.sh @@ -0,0 +1,231 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + + +# ------------------------------------------------------------------------------------------------- +# ALL VHOST FUNCTIONS +# ------------------------------------------------------------------------------------------------- + +### +### Copy custom vhost-gen template +### +vhost_gen_copy_custom_template() { + local input_dir="${1}" + local output_dir="${2}" + local template_name="${3}" + + if [ ! -d "${input_dir}" ]; then + run "mkdir -p ${input_dir}" + fi + + if [ -f "${input_dir}/${template_name}" ]; then + log "info" "vhost-gen: applying customized global template: ${template_name}" + run "cp ${input_dir}/${template_name} ${output_dir}/${template_name}" + else + log "info" "vhost-gen: no customized template found" + fi +} + + +### +### Generate config for MAIN_VHOST +### +vhost_gen_main_generate_config() { + local server_type="${1}" # nginx, apache22 or apache24 + local backend_string="${2}" + local http2_enable="${3}" + local status_enable="${4}" + local status_alias="${5}" + local docker_logs="${6}" + local timeout="${7}" + local outpath="${8}" + + be_conf_type="$( get_backend_conf_type "${backend_string}" )" + be_conf_host="$( get_backend_conf_host "${backend_string}" )" + be_conf_port="$( get_backend_conf_port "${backend_string}" )" + + # Defaults + directory_index="index.html, index.htm" + php_fpm_enable="no" + + # PHP-FPM specific + if [ "${be_conf_type}" = "phpfpm" ]; then + php_fpm_enable="yes" + directory_index="index.php, index.html, index.htm" + fi + generate_vhostgen_conf \ + "${server_type}" \ + "/etc/httpd/conf.d" \ + "" \ + "" \ + "${directory_index}" \ + "$( to_python_bool "${http2_enable}" )" \ + "/etc/httpd/cert/main" \ + "/etc/httpd/cert/main" \ + "'default'" \ + "$( to_python_bool "${docker_logs}" )" \ + "${php_fpm_enable}" \ + "${be_conf_host}" \ + "${be_conf_port}" \ + "${timeout}" \ + "/devilbox-api/:/var/www/default/api:http(s)?://(.*)$, /vhost.d/:/etc/httpd" \ + "$( to_python_bool "${status_enable}" )" \ + "${status_alias}" \ + > "${outpath}" +} + + +### +### Configure Docker logs +### +vhost_gen_docker_logs() { + local enable="${1}" + local config="${2}" + + if [ "${enable}" -eq "1" ]; then + run "sed -i'' 's/__DOCKER_LOGS_ERROR__/yes/g' ${config}" + run "sed -i'' 's/__DOCKER_LOGS_ACCESS__/yes/g' ${config}" + else + run "sed -i'' 's/__DOCKER_LOGS_ERROR__/no/g' ${config}" + run "sed -i'' 's/__DOCKER_LOGS_ACCESS__/no/g' ${config}" + fi +} + + +### +### Set HTTP2_ENABLE +### +vhost_gen_http2() { + local enable="${1}" + local config="${2}" + + if [ "${enable}" -eq "1" ]; then + run "sed -i'' 's/__HTTP2_ENABLE__/True/g' ${config}" + else + run "sed -i'' 's/__HTTP2_ENABLE__/False/g' ${config}" + fi +} + + +### +### Set PHP_FPM +### +vhost_gen_php_fpm() { + local enable="${1}" + local addr="${2}" + local port="${3}" + local timeout="${4}" + local config="${5}" + + if [ "${enable}" -eq "1" ]; then + run "sed -i'' 's/__PHP_ENABLE__/yes/g' ${config}" + run "sed -i'' 's/__PHP_ADDR__/${addr}/g' ${config}" + run "sed -i'' 's/__PHP_PORT__/${port}/g' ${config}" + run "sed -i'' 's/__PHP_TIMEOUT__/${timeout}/g' ${config}" + else + run "sed -i'' 's/__PHP_ENABLE__/no/g' ${config}" + fi +} + + + +# ------------------------------------------------------------------------------------------------- +# MAIN VHOST FUNCTIONS +# ------------------------------------------------------------------------------------------------- + +### +### Enable HTTPD status page? +### +vhost_gen_main_vhost_httpd_status() { + local enable="${1}" + local alias="${2}" + local config="${3}" + + if [ "${enable}" -eq "1" ]; then + run "sed -i'' 's|__ENABLE_STATUS__|yes|g' ${config}" + run "sed -i'' 's|__STATUS_ALIAS__|${alias}|g' ${config}" + else + run "sed -i'' 's|__ENABLE_STATUS__|no|g' ${config}" + fi +} + + +### +### Generate Main vhost? +### +vhost_gen_main_generate() { + local enable="${1}" + local docroot="${2}" + local backend="${3}" + local config="${4}" + local template="${5}" + local ssl_type="${6}" + + local verbose + local reverse=0 + + # Check if reverse proxy or not + if [ -n "${backend}" ]; then + be_type="$( get_backend_conf_type "${backend}" )" # phpfpm or rproxy + be_prot="$( get_backend_conf_prot "${backend}" )" # tcp, http, https + be_host="$( get_backend_conf_host "${backend}" )" # + be_port="$( get_backend_conf_port "${backend}" )" # + if [ "${be_type}" = "rproxy" ]; then + reverse=1 + fi + fi + + if [ "${enable}" -eq "1" ]; then + # vhost-gen verbosity + if [ "${DEBUG_ENTRYPOINT}" -gt "1" ]; then + verbose="-v" + else + verbose="" + fi + + if [ "${reverse}" = "1" ]; then + run "vhost-gen -n localhost -r ${be_prot}://${be_host}:${be_port} -l / -t /etc/vhost-gen/templates-main/ -c ${config} -o ${template} ${verbose} -d -s -m ${ssl_type}" + else + # Adding custom nginx vhost template to ensure paths like: + # /vendor/index.php/arg1/arg2 will also work (just like Apache) + # https://www.reddit.com/r/nginx/comments/a6pw31/phpfpm_does_not_handle_subpathindexphparg1arg2/ + run "vhost-gen -n localhost -p ${docroot} -t /etc/vhost-gen/templates-main/ -c ${config} -o ${template} ${verbose} -d -s -m ${ssl_type}" + fi + fi +} + + + +# ------------------------------------------------------------------------------------------------- +# MASS VHOST FUNCTIONS +# ------------------------------------------------------------------------------------------------- + +### +### Set DOCROOT_SUFFIX +### +vhost_gen_mass_vhost_docroot() { + local enable="${1}" + local docroot="${2}" + local config="${3}" + + if [ "${enable}" -eq "1" ]; then + run "sed -i'' 's|__DOCROOT_SUFFIX__|${docroot}|g' ${config}" + fi +} + + +### +### Set TLD +### +vhost_gen_mass_vhost_tld() { + local enable="${1}" + local tld="${2}" + local config="${3}" + + if [ "${enable}" -eq "1" ]; then + run "sed -i'' 's/__TLD__/${tld}/g' ${config}" + fi +} diff --git a/Dockerfiles/data/docker-entrypoint.d/08-cert-gen.sh b/Dockerfiles/data/docker-entrypoint.d/13-cert-gen.sh similarity index 55% rename from Dockerfiles/data/docker-entrypoint.d/08-cert-gen.sh rename to Dockerfiles/data/docker-entrypoint.d/13-cert-gen.sh index 65e1095..500dfa7 100755 --- a/Dockerfiles/data/docker-entrypoint.d/08-cert-gen.sh +++ b/Dockerfiles/data/docker-entrypoint.d/13-cert-gen.sh @@ -5,9 +5,9 @@ set -u set -o pipefail -############################################################ -# Functions -############################################################ +# ------------------------------------------------------------------------------------------------- +# [ACTION] FUNCTIONS +# ------------------------------------------------------------------------------------------------- ### ### Generate CA @@ -15,27 +15,30 @@ set -o pipefail cert_gen_generate_ca() { local key="${1}" local crt="${2}" - local verbose="${3}" - local debug="${4}" + + #local verbose # Create directories if [ ! -d "$( dirname "${key}" )" ]; then - run "mkdir -p $( dirname "${key}" )" "${debug}" + run "mkdir -p $( dirname "${key}" )" fi if [ ! -d "$( dirname "${crt}" )" ]; then - run "mkdir -p $( dirname "${crt}" )" "${debug}" + run "mkdir -p $( dirname "${crt}" )" fi # cert-gen verbosity - if [ "${verbose}" -gt "0" ]; then - verbose="-v" - else - verbose="" - fi + #if [ "${DEBUG_RUNTIME}" -gt "0" ]; then + # verbose="-v" + #else + # verbose="" + #fi # Generate CA if it does not exist yet if [ ! -f "${key}" ] || [ ! -f "${crt}" ]; then - run "ca-gen ${verbose} -c DE -s Berlin -l Berlin -o Devilbox -u Devilbox -n 'Devilbox Root CA' -e 'cytopia@devilbox.org' ${key} ${crt}" "${DEBUG_LEVEL}" + log "warn" "(Re)creating Certificate Authority. You need to (Re)import it into your browser." + run "ca-gen -v -c DE -s Berlin -l Berlin -o Devilbox -u Devilbox -n 'Devilbox Root CA' -e 'cytopia@devilbox.org' ${key} ${crt}" + else + log "info" "Existing Certificate Authority files found in: $(dirname "${key}")" fi } @@ -52,8 +55,8 @@ cert_gen_generate_cert() { local csr="${6}" local crt="${7}" local domains="${8}" - local verbose="${9}" - local debug="${10}" + + #local verbose # If not enabled, skip SSL certificate eneration if [ "${enable}" != "1" ]; then @@ -67,21 +70,21 @@ cert_gen_generate_cert() { # Create directories if [ ! -d "$( dirname "${key}" )" ]; then - run "mkdir -p $( dirname "${key}" )" "${debug}" + run "mkdir -p $( dirname "${key}" )" fi if [ ! -d "$( dirname "${csr}" )" ]; then - run "mkdir -p $( dirname "${csr}" )" "${debug}" + run "mkdir -p $( dirname "${csr}" )" fi if [ ! -d "$( dirname "${crt}" )" ]; then - run "mkdir -p $( dirname "${crt}" )" "${debug}" + run "mkdir -p $( dirname "${crt}" )" fi # cert-gen verbosity - if [ "${verbose}" -gt "0" ]; then - verbose="-v" - else - verbose="" - fi + #if [ "${DEBUG_RUNTIME}" -gt "0" ]; then + # verbose="-v" + #else + # verbose="" + #fi # Get domain name and alt_names cn= @@ -98,5 +101,5 @@ cert_gen_generate_cert() { done alt_names="$( echo "${alt_names}" | xargs )" # tim - run "cert-gen ${verbose} -c DE -s Berlin -l Berlin -o Devilbox -u Devilbox -n '${cn}' -e 'admin@${cn}' -a '${alt_names}' ${ca_key} ${ca_crt} ${key} ${csr} ${crt}" "${debug}" + run "cert-gen -v -c DE -s Berlin -l Berlin -o Devilbox -u Devilbox -n '${cn}' -e 'admin@${cn}' -a '${alt_names}' ${ca_key} ${ca_crt} ${key} ${csr} ${crt}" } diff --git a/Dockerfiles/data/docker-entrypoint.d/14-fix-permissions.sh b/Dockerfiles/data/docker-entrypoint.d/14-fix-permissions.sh new file mode 100755 index 0000000..713e1e5 --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/14-fix-permissions.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + + +############################################################ +# Functions +############################################################ + + +### +### Fix permissions for MY_USER:MY_GROUP +### +fix_perm() { + local directory="${1}" + local recursive="${2}" + + # These are set in the Dockerfile + local perm="${MY_USER}:${MY_GROUP}" + + if [ "${recursive}" = "1" ]; then + run "chown -R ${perm} ${directory}" + else + run "chown ${perm} ${directory}" + fi +} diff --git a/Dockerfiles/data/docker-entrypoint.d/11-supervisord.sh b/Dockerfiles/data/docker-entrypoint.d/15-supervisord.sh similarity index 98% rename from Dockerfiles/data/docker-entrypoint.d/11-supervisord.sh rename to Dockerfiles/data/docker-entrypoint.d/15-supervisord.sh index abfc66a..2106394 100755 --- a/Dockerfiles/data/docker-entrypoint.d/11-supervisord.sh +++ b/Dockerfiles/data/docker-entrypoint.d/15-supervisord.sh @@ -26,6 +26,7 @@ supervisord_create() { echo "[supervisord]" echo "user=root" echo "nodaemon=true" + echo "loglevel=warn" echo echo "[program:httpd]" echo "command=${httpd_command}" @@ -35,8 +36,8 @@ supervisord_create() { echo "startsecs=1" echo "autorestart=true" echo "stdout_logfile=/dev/stdout" - echo "stdout_logfile_maxbytes=0" echo "stderr_logfile=/dev/stderr" + echo "stdout_logfile_maxbytes=0" echo "stderr_logfile_maxbytes=0" echo "stdout_events_enabled=true" echo "stderr_events_enabled=true" @@ -47,8 +48,8 @@ supervisord_create() { echo "autostart=true" echo "autorestart=false" echo "stdout_logfile=/dev/stdout" - echo "stdout_logfile_maxbytes=0" echo "stderr_logfile=/dev/stderr" + echo "stdout_logfile_maxbytes=0" echo "stderr_logfile_maxbytes=0" echo "stdout_events_enabled=true" echo "stderr_events_enabled=true" diff --git a/Dockerfiles/data/docker-entrypoint.d/99-nginx.sh b/Dockerfiles/data/docker-entrypoint.d/99-nginx.sh new file mode 100755 index 0000000..4faf7d6 --- /dev/null +++ b/Dockerfiles/data/docker-entrypoint.d/99-nginx.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + + +############################################################ +# Functions +############################################################ + +### +### Change worker_processes +### +nginx_set_worker_processess() { + local value="${1}" + local config="/etc/nginx/nginx.conf" + + log "info" "Setting Nginx worker_processes to: ${value}" + run "sed -i'' 's/__WORKER_PROCESSES__/${value}/g' ${config}" +} + + +### +### Change worker_connections +### +nginx_set_worker_connections() { + local value="${1}" + local config="/etc/nginx/nginx.conf" + + log "info" "Setting Nginx worker_connections to: ${value}" + run "sed -i'' 's/__WORKER_CONNECTIONS__/${value}/g' ${config}" +} diff --git a/Dockerfiles/data/docker-entrypoint.sh b/Dockerfiles/data/docker-entrypoint.sh index 44af6e0..d52d677 100755 --- a/Dockerfiles/data/docker-entrypoint.sh +++ b/Dockerfiles/data/docker-entrypoint.sh @@ -4,214 +4,388 @@ set -e set -u set -o pipefail +################################################################################################### +################################################################################################### ### -### Globals +### GLOBAL VARIABLES ### +################################################################################################### +################################################################################################### -# Set via Dockerfile -# MY_USER -# MY_GROUP -# HTTPD_START -# HTTPD_RELOAD - -# OpenSSL Certificate Authority file to generate -CA_KEY=/ca/devilbox-ca.key -CA_CRT=/ca/devilbox-ca.crt - - -# Path to scripts to source -CONFIG_DIR="/docker-entrypoint.d" -VHOST_GEN_DIR="/etc/vhost-gen/templates" -VHOST_GEN_CUST_DIR="/etc/vhost-gen.d" - - -# Wait this many seconds to start watcherd after httpd has been started -WATCHERD_STARTUP_DELAY="3" +# ------------------------------------------------------------------------------------------------- +# GENERAL GLOBAL VARIABLES +# ------------------------------------------------------------------------------------------------- +### The following env variables are set inside the Dockerfiles +### MY_USER +### MY_GROUP +### HTTPD_START +### HTTPD_RELOAD ### -### Source libs +### Base path for main (default) document root ### -init="$( find "${CONFIG_DIR}" -name '*.sh' -type f | sort -u )" -for f in ${init}; do - # shellcheck disable=SC1090 - . "${f}" -done - +MAIN_DOCROOT_BASE="/var/www/default" +MASS_DOCROOT_BASE="/shared/httpd" +### +### OpenSSL Certificate Authority file to generate +### +### If the /ca directory is mounted and those files already exist +### a new ca will not be generated, but reused. +### +CA_KEY=/ca/devilbox-ca.key +CA_CRT=/ca/devilbox-ca.crt -############################################################# -## Basic Settings -############################################################# +### +### Path to scripts to source +### +ENTRYPOINT_DIR="/docker-entrypoint.d" # All entrypoint scripts +VHOST_GEN_DIR="/etc/vhost-gen/templates" # vhost-gen default templates +VHOST_GEN_CUST_DIR="/etc/vhost-gen.d" # vhost-gen custom templates (must be mounted to add) ### -### Set Debug level +### Wait this many seconds to start watcherd after httpd has been started ### -DEBUG_LEVEL="$( env_get "DEBUG_ENTRYPOINT" "0" )" -log "info" "Debug level: ${DEBUG_LEVEL}" "${DEBUG_LEVEL}" +WATCHERD_STARTUP_DELAY="3" -DEBUG_RUNTIME="$( env_get "DEBUG_RUNTIME" "0" )" -log "info" "Runtime debug: ${DEBUG_RUNTIME}" "${DEBUG_LEVEL}" +# ------------------------------------------------------------------------------------------------- +# DEFAULT VALUES +# ------------------------------------------------------------------------------------------------- ### -### Change uid/gid +### Set the default debug level for entrypoint and runtime ### -set_uid "NEW_UID" "${MY_USER}" "${DEBUG_LEVEL}" -set_gid "NEW_GID" "${MY_GROUP}" "${DEBUG_LEVEL}" - +DEFAULT_DEBUG_ENTRYPOINT="2" +DEFAULT_DEBUG_RUNTIME="0" ### -### Set timezone +### Ensure that the following globals have a value: +### +### DEBUG_ENTRYPOINT +### DEBUG_RUNTIME +### +### If not, fall back to these +### +### DEFAULT_DEBUG_ENTRYPOINT +### DEFAULT_DEBUG_RUNTIME ### -set_timezone "TIMEZONE" "${DEBUG_LEVEL}" +### +### DEBUG_ENTRYPOINT +### +if [ -z "${DEBUG_ENTRYPOINT:-}" ]; then + DEBUG_ENTRYPOINT="${DEFAULT_DEBUG_ENTRYPOINT}" +fi +if [ "${DEBUG_ENTRYPOINT}" != "0" ] \ + && [ "${DEBUG_ENTRYPOINT}" != "1" ] \ + && [ "${DEBUG_ENTRYPOINT}" != "2" ] \ + && [ "${DEBUG_ENTRYPOINT}" != "3" ] \ + && [ "${DEBUG_ENTRYPOINT}" != "4" ]; then + # Arbitrary integer (set to highest value + if [ -n "${DEBUG_ENTRYPOINT##*[!0-9]*}" ]; then + DEBUG_ENTRYPOINT=4 + else + DEBUG_ENTRYPOINT="${DEFAULT_DEBUG_ENTRYPOINT}" + fi +fi ### -### Nginx settings +### DEBUG_RUNTIME ### -set_worker_processess "WORKER_PROCESSES" "${DEBUG_LEVEL}" -set_worker_connections "WORKER_CONNECTIONS" "${DEBUG_LEVEL}" +if [ -z "${DEBUG_RUNTIME:-}" ]; then + DEBUG_RUNTIME="${DEFAULT_DEBUG_RUNTIME}" +fi +if [ "${DEBUG_RUNTIME}" != "0" ] && [ "${DEBUG_RUNTIME}" != "1" ]; then + DEBUG_RUNTIME="${DEFAULT_DEBUG_RUNTIME}" +fi + +export "DEBUG_ENTRYPOINT" +export "DEBUG_RUNTIME" -############################################################# -## Variable exports -############################################################# +################################################################################################### +################################################################################################### ### -### Ensure Docker_LOGS is exported +### INCLUDES ### -export_docker_logs "DOCKER_LOGS" "${DEBUG_LEVEL}" +################################################################################################### +################################################################################################### +### +### Source available library functions +### +# shellcheck disable=SC2012 +for f in $( ls -1 "${ENTRYPOINT_DIR}/.lib/"*.sh | sort -u ); do + # shellcheck disable=SC1090 + . "${f}" +done ### -### Ensure PHP-FPM variables are exported +### Source available HTTPD functions ### -export_php_fpm_enable "PHP_FPM_ENABLE" "${DEBUG_LEVEL}" -export_php_fpm_server_addr "PHP_FPM_SERVER_ADDR" "${DEBUG_LEVEL}" -export_php_fpm_server_port "PHP_FPM_SERVER_PORT" "${DEBUG_LEVEL}" -export_php_fpm_timeout "PHP_FPM_TIMEOUT" "${DEBUG_LEVEL}" +# shellcheck disable=SC2012 +for f in $( ls -1 "${ENTRYPOINT_DIR}/.httpd/"*.sh | sort -u ); do + # shellcheck disable=SC1090 + . "${f}" +done ### -### Ensure global main/mass variables are eported +### Source available entrypoint scripts ### -export_http2_enable "HTTP2_ENABLE" "${DEBUG_LEVEL}" +# shellcheck disable=SC2012 +for f in $( ls -1 "${ENTRYPOINT_DIR}/"*.sh | sort -u ); do + # shellcheck disable=SC1090 + . "${f}" +done + +################################################################################################### +################################################################################################### ### -### Ensure MAIN_VHOST variables are exported +### MAIN ENTRYPOINT ### -export_main_vhost_enable "MAIN_VHOST_ENABLE" "${DEBUG_LEVEL}" -export_main_vhost_ssl_type "MAIN_VHOST_SSL_TYPE" "${DEBUG_LEVEL}" -export_main_vhost_ssl_gen "MAIN_VHOST_SSL_GEN" "${DEBUG_LEVEL}" -export_main_vhost_ssl_cn "MAIN_VHOST_SSL_CN" "${DEBUG_LEVEL}" -export_main_vhost_docroot "MAIN_VHOST_DOCROOT" "${DEBUG_LEVEL}" -export_main_vhost_tpl "MAIN_VHOST_TPL" "${DEBUG_LEVEL}" -export_main_vhost_status_enable "MAIN_VHOST_STATUS_ENABLE" "${DEBUG_LEVEL}" -export_main_vhost_status_alias "MAIN_VHOST_STATUS_ALIAS" "${DEBUG_LEVEL}" +################################################################################################### +################################################################################################### +# ------------------------------------------------------------------------------------------------- +# LOG SETTINGS +# ------------------------------------------------------------------------------------------------- ### -### Ensure MASS_VHOST variables are exported +### Set Debug level ### -export_mass_vhost_enable "MASS_VHOST_ENABLE" "${DEBUG_LEVEL}" -export_mass_vhost_ssl_type "MASS_VHOST_SSL_TYPE" "${DEBUG_LEVEL}" -export_mass_vhost_ssl_gen "MASS_VHOST_SSL_GEN" "${DEBUG_LEVEL}" -export_mass_vhost_tld "MASS_VHOST_TLD" "${DEBUG_LEVEL}" -export_mass_vhost_docroot "MASS_VHOST_DOCROOT" "${DEBUG_LEVEL}" -export_mass_vhost_tpl "MASS_VHOST_TPL" "${DEBUG_LEVEL}" +DEBUG_LEVEL="$( env_get "DEBUG_ENTRYPOINT" "${DEFAULT_DEBUG_ENTRYPOINT}" )" +log "info" "Debug level: ${DEBUG_LEVEL}" + +DEBUG_RUNTIME="$( env_get "DEBUG_RUNTIME" "${DEFAULT_DEBUG_RUNTIME}" )" +log "info" "Runtime debug: ${DEBUG_RUNTIME}" + + +# ------------------------------------------------------------------------------------------------- +# SET ENVIRONMENT VARIABLES AND DEFAULT VALUES +# ------------------------------------------------------------------------------------------------- + +log "info" "-------------------------------------------------------------------------" +log "info" "Environment Variables (set/default)" +log "info" "-------------------------------------------------------------------------" + +env_var_export "NEW_UID" +env_var_export "NEW_GID" +env_var_export "TIMEZONE" "UTC" + +env_var_export "MAIN_VHOST_ENABLE" "1" +env_var_export "MAIN_VHOST_BACKEND" +env_var_export "MAIN_VHOST_BACKEND_TIMEOUT" "180" +env_var_export "MAIN_VHOST_DOCROOT" "htdocs" +env_var_export "MAIN_VHOST_SSL_TYPE" "plain" +env_var_export "MAIN_VHOST_SSL_CN" "localhost" +env_var_export "MAIN_VHOST_TPL" "cfg" +env_var_export "MAIN_VHOST_STATUS_ENABLE" "0" +env_var_export "MAIN_VHOST_STATUS_ALIAS" "/httpd-status" + +env_var_export "MASS_VHOST_ENABLE" "0" +env_var_export "MASS_VHOST_BACKEND" +env_var_export "MASS_VHOST_BACKEND_TIMEOUT" "180" +env_var_export "MASS_VHOST_DOCROOT" "htdocs" +env_var_export "MASS_VHOST_TLD_SUFFIX" ".loc" +env_var_export "MASS_VHOST_SSL_TYPE" "plain" +env_var_export "MASS_VHOST_TPL" "cfg" + +env_var_export "WORKER_CONNECTIONS" "1024" +env_var_export "WORKER_PROCESSES" "auto" +env_var_export "HTTP2_ENABLE" "1" +env_var_export "DOCKER_LOGS" "1" + +export MAIN_VHOST_SSL_GEN=0 +export MASS_VHOST_SSL_GEN=0 +if [ "${MAIN_VHOST_SSL_TYPE}" != "plain" ]; then export MAIN_VHOST_SSL_GEN=1; fi +if [ "${MASS_VHOST_SSL_TYPE}" != "plain" ]; then export MASS_VHOST_SSL_GEN=1; fi + + +# ------------------------------------------------------------------------------------------------- +# VERIFY ENVIRONMENT VARIABLES +# ------------------------------------------------------------------------------------------------- + +log "info" "-------------------------------------------------------------------------" +log "info" "Validate Settings" +log "info" "-------------------------------------------------------------------------" + +log "info" "Settings: General:" +env_var_validate "NEW_UID" +env_var_validate "NEW_GID" +env_var_validate "TIMEZONE" + +log "info" "Settings: Main Vhost:" +env_var_validate "MAIN_VHOST_ENABLE" +env_var_validate "MAIN_VHOST_BACKEND" +env_var_validate "MAIN_VHOST_BACKEND_TIMEOUT" +env_var_validate "MAIN_VHOST_DOCROOT" +env_var_validate "MAIN_VHOST_SSL_TYPE" +env_var_validate "MAIN_VHOST_SSL_CN" +env_var_validate "MAIN_VHOST_TPL" +env_var_validate "MAIN_VHOST_STATUS_ENABLE" +env_var_validate "MAIN_VHOST_STATUS_ALIAS" + +log "info" "Settings: Mass Vhost:" +env_var_validate "MASS_VHOST_ENABLE" +env_var_validate "MASS_VHOST_BACKEND" +env_var_validate "MASS_VHOST_BACKEND_TIMEOUT" +env_var_validate "MASS_VHOST_DOCROOT" +env_var_validate "MASS_VHOST_TLD_SUFFIX" +env_var_validate "MASS_VHOST_SSL_TYPE" +env_var_validate "MASS_VHOST_TPL" + +log "info" "Settings: Misc:" +env_var_validate "WORKER_CONNECTIONS" +env_var_validate "WORKER_PROCESSES" +env_var_validate "HTTP2_ENABLE" +env_var_validate "DOCKER_LOGS" + + +# ------------------------------------------------------------------------------------------------- +# APPLY SETTINGS +# ------------------------------------------------------------------------------------------------- + +log "info" "-------------------------------------------------------------------------" +log "info" "Apply Settings" +log "info" "-------------------------------------------------------------------------" +### +### Change uid/gid +### +set_uid "${NEW_UID}" "${MY_USER}" +set_gid "${NEW_GID}" "${MY_USER}" "${MY_GROUP}" ### -### Default and/or mass vhost must be enabled (at least one of them) +### Set timezone ### -if [ "${MAIN_VHOST_ENABLE}" -eq "0" ] && [ "${MASS_VHOST_ENABLE}" -eq "0" ]; then - log "err" "Default vhost and mass vhosts are disabled." "${DEBUG_LEVEL}" - exit 1 -fi +set_timezone "${TIMEZONE}" -############################################################# -## vhost-gen Configuration -############################################################# +# ------------------------------------------------------------------------------------------------- +# VHOST-GEN: ALL +# ------------------------------------------------------------------------------------------------- ### -### Copy custom vhost-gen template +### Copy custom vhost-gen template (if they are mounted and exist) ### vhost_gen_copy_custom_template "${VHOST_GEN_CUST_DIR}" "${VHOST_GEN_DIR}" "nginx.yml" "${DEBUG_LEVEL}" ### -### Enable and configure PHP-FPM +### Configure Backend ### -vhost_gen_php_fpm "${PHP_FPM_ENABLE}" "${PHP_FPM_SERVER_ADDR}" "${PHP_FPM_SERVER_PORT}" "${PHP_FPM_TIMEOUT}" "/etc/vhost-gen/main.yml" "${DEBUG_LEVEL}" -vhost_gen_php_fpm "${PHP_FPM_ENABLE}" "${PHP_FPM_SERVER_ADDR}" "${PHP_FPM_SERVER_PORT}" "${PHP_FPM_TIMEOUT}" "/etc/vhost-gen/mass.yml" "${DEBUG_LEVEL}" +#MAIN_BACKEND_HOST="$( get_backend_conf_host "${MAIN_VHOST_BACKEND}" )" +#MAIN_BACKEND_PORT="$( get_backend_conf_port "${MAIN_VHOST_BACKEND}" )" +#MAIN_PHP_FPM_ENABLE=1 +#if [ "$( get_backend_conf_type "${MAIN_VHOST_BACKEND}" )" != "phpfpm" ]; then +# MAIN_PHP_FPM_ENABLE=0 +# # Remove directory index.php if we are not serving php +# run "sed -i'' 's/.*- index\.php//g' \"/etc/vhost-gen/main.yml\"" +#fi + +MASS_BACKEND_HOST="$( get_backend_conf_host "${MASS_VHOST_BACKEND}" )" +MASS_BACKEND_PORT="$( get_backend_conf_port "${MASS_VHOST_BACKEND}" )" +MASS_PHP_FPM_ENABLE=1 +if [ "$( get_backend_conf_type "${MASS_VHOST_BACKEND}" )" != "phpfpm" ]; then + MASS_PHP_FPM_ENABLE=0 + # Remove directory index.php if we are not serving php + run "sed -i'' 's/.*- index\.php//g' \"/etc/vhost-gen/mass.yml\"" +fi +#vhost_gen_php_fpm "${MAIN_PHP_FPM_ENABLE}" "${MAIN_BACKEND_HOST}" "${MAIN_BACKEND_PORT}" "${MAIN_VHOST_BACKEND_TIMEOUT}" "/etc/vhost-gen/main.yml" +vhost_gen_php_fpm "${MASS_PHP_FPM_ENABLE}" "${MASS_BACKEND_HOST}" "${MASS_BACKEND_PORT}" "${MASS_VHOST_BACKEND_TIMEOUT}" "/etc/vhost-gen/mass.yml" ### ### Configure Docker logs ### -vhost_gen_docker_logs "${DOCKER_LOGS}" "/etc/vhost-gen/main.yml" "${DEBUG_LEVEL}" -vhost_gen_docker_logs "${DOCKER_LOGS}" "/etc/vhost-gen/mass.yml" "${DEBUG_LEVEL}" - +#vhost_gen_docker_logs "${DOCKER_LOGS}" "/etc/vhost-gen/main.yml" +vhost_gen_docker_logs "${DOCKER_LOGS}" "/etc/vhost-gen/mass.yml" ### ### Set HTTP2 support ### -vhost_gen_http2 "${HTTP2_ENABLE}" "/etc/vhost-gen/main.yml" "${DEBUG_LEVEL}" -vhost_gen_http2 "${HTTP2_ENABLE}" "/etc/vhost-gen/mass.yml" "${DEBUG_LEVEL}" +#vhost_gen_http2 "${HTTP2_ENABLE}" "/etc/vhost-gen/main.yml" +vhost_gen_http2 "${HTTP2_ENABLE}" "/etc/vhost-gen/mass.yml" + +# ------------------------------------------------------------------------------------------------- +# VHOST-GEN: MAIN +# ------------------------------------------------------------------------------------------------- + +### +### vhost settings +### +#vhost_gen_main_vhost_httpd_status \ +# "${MAIN_VHOST_STATUS_ENABLE}" \ +# "${MAIN_VHOST_STATUS_ALIAS}" \ +# "/etc/vhost-gen/main.yml" + ### -### Main vhost settings +### Generate ### -vhost_gen_main_vhost_httpd_status \ +vhost_gen_main_generate_config \ + "nginx" \ + "${MAIN_VHOST_BACKEND}" \ + "${HTTP2_ENABLE}" \ "${MAIN_VHOST_STATUS_ENABLE}" \ "${MAIN_VHOST_STATUS_ALIAS}" \ - "/etc/vhost-gen/main.yml" \ - "${DEBUG_LEVEL}" + "${DOCKER_LOGS}" \ + "${MAIN_VHOST_BACKEND_TIMEOUT}" \ + "/etc/vhost-gen/main.yml" -vhost_gen_generate_main_vhost \ +vhost_gen_main_generate \ "${MAIN_VHOST_ENABLE}" \ - "/var/www/default/${MAIN_VHOST_DOCROOT}" \ + "${MAIN_DOCROOT_BASE}/${MAIN_VHOST_DOCROOT}" \ + "${MAIN_VHOST_BACKEND}" \ "/etc/vhost-gen/main.yml" \ - "/var/www/default/${MAIN_VHOST_TPL}" \ - "${MAIN_VHOST_SSL_TYPE}" \ - "${DEBUG_RUNTIME}" \ - "${DEBUG_LEVEL}" + "${MAIN_DOCROOT_BASE}/${MAIN_VHOST_TPL}" \ + "${MAIN_VHOST_SSL_TYPE}" + +# ------------------------------------------------------------------------------------------------- +# VHOST-GEN: MASS +# ------------------------------------------------------------------------------------------------- + +### +### vhost tld suffix +### +vhost_gen_mass_vhost_tld \ + "${MASS_VHOST_ENABLE}" \ + "${MASS_VHOST_TLD_SUFFIX}" \ + "/etc/vhost-gen/mass.yml" ### -### Mass vhost settings +### vhost docroot settings ### vhost_gen_mass_vhost_docroot \ "${MASS_VHOST_ENABLE}" \ "${MASS_VHOST_DOCROOT}" \ - "/etc/vhost-gen/mass.yml" \ - "${DEBUG_LEVEL}" + "/etc/vhost-gen/mass.yml" -vhost_gen_mass_vhost_tld \ - "${MASS_VHOST_ENABLE}" \ - "${MASS_VHOST_TLD}" \ - "/etc/vhost-gen/mass.yml" \ - "${DEBUG_LEVEL}" +# ------------------------------------------------------------------------------------------------- +# CERT-GEN CONFIGURATION +# ------------------------------------------------------------------------------------------------- -################################################################################ -# cert-getn Configuration -################################################################################ ### ### Create Certificate Signing request ### -cert_gen_generate_ca "${CA_KEY}" "${CA_CRT}" "${DEBUG_RUNTIME}" "${DEBUG_LEVEL}" +cert_gen_generate_ca "${CA_KEY}" "${CA_CRT}" ### ### Generate main vhost ssl certificate ### +# shellcheck disable=SC2153 cert_gen_generate_cert \ "${MAIN_VHOST_ENABLE}" \ "${MAIN_VHOST_SSL_TYPE}" \ @@ -220,47 +394,75 @@ cert_gen_generate_cert \ "/etc/httpd/cert/main/localhost.key" \ "/etc/httpd/cert/main/localhost.csr" \ "/etc/httpd/cert/main/localhost.crt" \ - "${MAIN_VHOST_SSL_CN}" \ - "${DEBUG_RUNTIME}" \ - "${DEBUG_LEVEL}" + "${MAIN_VHOST_SSL_CN}" -################################################################################ -# Fix directory permissions -################################################################################ +# ------------------------------------------------------------------------------------------------- +# FIX DIRECTORY PERMISSIONS +# ------------------------------------------------------------------------------------------------- -fix_perm "NEW_UID" "NEW_GID" "/ca" "1" "${DEBUG_LEVEL}" +fix_perm "/ca" "1" -################################################################################ -# RUN -################################################################################ +# ------------------------------------------------------------------------------------------------- +# NGINX-SPECIFIC BASIC SETTINGS +# ------------------------------------------------------------------------------------------------- + +### +### Nginx settings +### +nginx_set_worker_processess "${WORKER_PROCESSES}" +nginx_set_worker_connections "${WORKER_CONNECTIONS}" + + + +# ------------------------------------------------------------------------------------------------- +# NGINX-SPECIFIC BASIC SETTINGS +# ------------------------------------------------------------------------------------------------- ### ### Supervisor or plain ### -if [ "${MASS_VHOST_ENABLE}" -eq "1" ]; then +_HTTPD_VERSION="$( nginx -V 2>&1 | head -1 | awk '{print $3}' )" +_SUPVD_VERSION="$( supervisord -v )" +if [ "${MASS_VHOST_ENABLE}" -eq "1" ]; then verbose="" if [ "${DEBUG_RUNTIME}" -gt "0" ]; then verbose="-v" fi # Create watcherd sub commands - watcherd_add="create-vhost.sh '%%p' '%%n' '${MASS_VHOST_TLD}' '%%p/${MASS_VHOST_TPL}/' '${CA_KEY}' '${CA_CRT}' '${MASS_VHOST_SSL_GEN}' '${MASS_VHOST_SSL_TYPE}' '${verbose}'" + watcherd_add="create-vhost.sh" + watcherd_add+=" \\\"%%p\\\"" + watcherd_add+=" \\\"%%n\\\"" + watcherd_add+=" \\\"${MASS_VHOST_TLD_SUFFIX}\\\"" + watcherd_add+=" \\\"%%p/${MASS_VHOST_TPL}/\\\"" + watcherd_add+=" \\\"${MASS_VHOST_DOCROOT}\\\"" + watcherd_add+=" \\\"${HTTP2_ENABLE}\\\"" + watcherd_add+=" \\\"${DOCKER_LOGS}\\\"" + watcherd_add+=" \\\"${MASS_VHOST_BACKEND_TIMEOUT}\\\"" + watcherd_add+=" \\\"${CA_KEY}\\\"" + watcherd_add+=" \\\"${CA_CRT}\\\"" + watcherd_add+=" \\\"${MASS_VHOST_SSL_GEN}\\\"" + watcherd_add+=" \\\"${MASS_VHOST_SSL_TYPE}\\\"" + watcherd_add+=" \\\"${MASS_VHOST_BACKEND}\\\"" + watcherd_add+=" \\\"${verbose}\\\"" + watcherd_del="rm /etc/httpd/vhost.d/%%n.conf" watcherd_tri="${HTTPD_RELOAD}" supervisord_create \ "${HTTPD_START}" \ - "bash -c 'sleep ${WATCHERD_STARTUP_DELAY} && exec watcherd -v -p /shared/httpd -a \"${watcherd_add}\" -d \"${watcherd_del}\" -t \"${watcherd_tri}\"'" \ + "bash -c 'sleep ${WATCHERD_STARTUP_DELAY} && exec watcherd -v -p ${MASS_DOCROOT_BASE} -a \"${watcherd_add}\" -d \"${watcherd_del}\" -t \"${watcherd_tri}\"'" \ "/etc/supervisord.conf" - log "info" "Starting supervisord: $(supervisord -v)" "${DEBUG_LEVEL}" + log "info" "Starting supervisord: ${_SUPVD_VERSION} [HTTPD: ${_HTTPD_VERSION}]" exec /usr/bin/supervisord -c /etc/supervisord.conf else - log "info" "Starting webserver" "${DEBUG_LEVEL}" - exec ${HTTPD_START} + _HTTPD_VERSION="$( nginx -V 2>&1 | head -1 | awk '{print $3}' )" + log "info" "Starting webserver: ${_HTTPD_VERSION}" + exec "${HTTPD_START}" fi diff --git a/Dockerfiles/data/vhost-gen/mass-plain.yml b/Dockerfiles/data/vhost-gen/mass-plain.yml new file mode 100644 index 0000000..b3d08fa --- /dev/null +++ b/Dockerfiles/data/vhost-gen/mass-plain.yml @@ -0,0 +1,159 @@ +--- +# Generic vhost generator configuration file. +# Location: /etc/vhost-gen/mass.yml +# +# See: https://github.com/devilbox/vhost-gen +# +# If not specified or file is missing the following +# default values will be merged to your current (if any) +# configuration: +# +# server: nginx +# conf_dir: /etc/nginx/conf.d +# custom: +# vhost: +# port: +# name: +# prefix: +# suffix: +# docroot: +# suffix: +# log: +# access: +# prefix: +# stdout: no +# error: +# prefix: +# stderr: no +# dir: +# create: no +# path: /var/log/nginx +# listen: +# enable: no +# php_fpm: +# enable: no +# address: php +# port: 9000 +# alias: [] +# deny: [] +# server_status: +# enable: no +# alias: /server-status + + +# The server type determines which template +# from etc/templates/ will be chosen. +# Allowed server types: +# server: apache22 +# server: apache24 +# server: nginx +server: nginx + + +# Where to store the generated configuration files. +# This must be a directory the web server will read +# configuration files from. +conf_dir: /etc/httpd/vhost.d + + +# Custom directive +# Everything specified here will be directly replaced +# into the corresponding vhost directive: +# nginx: server { HERE } +# apache: HERE +# +# How to add multiline strings? +# +# custom: | +# custom statement 1 +# custom statement 2 +custom: + + +# Vhost definition +vhost: + # What port should this virtual host listen on + port: 80 + ssl_port: 443 + + # The virtual host name is specified as an command line argument + # to vhost-gen via '-n', however it is possible + # to prepend and/or append additional name strings. + name: + prefix: + suffix: __TLD__ + # The document root directory is specified as an command line argument + # to vhost-gen via '-p', however it is possible + # to prepend another subdirectory here. + docroot: + suffix: __DOCROOT_SUFFIX__ + # Array of indecies to serve as default files (e.g.: index.php, index.html, etc) + index: + - index.html + - index.htm + # SSL Definition + ssl: + http2: __HTTP2_ENABLE__ + dir_crt: /etc/httpd/cert/mass + dir_key: /etc/httpd/cert/mass + protocols: 'TLSv1 TLSv1.1 TLSv1.2' + honor_cipher_order: 'on' + ciphers: 'HIGH:!aNULL:!MD5' + + # Log definition + log: + # Log file settings (error/access log) + access: + # By default the vhost name is used for log file names. + # You can also prepand an additional string to the access log + # as shown here: + # -access.log + prefix: '' + # For use inside a docker container, enable this in order + # to redirect the access log to stdout instead of to file. + # NOTE: When enabling this, the prefix will have no effect and the access + # log will be stored under /tmp/www-access.log which will be a symlink of + # /dev/stdout + stdout: __DOCKER_LOGS_ACCESS__ + error: + # By default the vhost name is used for log file names. + # You can also prepand an additional string to the error log + # as shown here: + # -error.log + prefix: '' + # For use inside a docker container, enable this in order + # to redirect the error log to stderr instead of to file. + # NOTE: When enabling this, the prefix will have no effect and the error + # log will be stored under /tmp/www-error.log which will be a symlink of + # /dev/stderr + stderr: __DOCKER_LOGS_ERROR__ + # Directory to store log files in. + # Also define if the directory should be created or not. + dir: + create: yes + path: /var/log/nginx-stable + # Enable PHP-FPM + php_fpm: + enable: __PHP_ENABLE__ + # Hostname or IP address + address: __PHP_ADDR__ + port: __PHP_PORT__ + # Timeout to upstream FPM service + timeout: __PHP_TIMEOUT__ + # Create additional aliases + alias: + - alias: /devilbox-api/ + path: /var/www/default/api + # Allow cross-domain-request to this alias from the hosts/origin + # specified by the below defined regex + xdomain_request: + enable: yes + origin: 'http(s)?://(.*)$' + # Denies locations + deny: + - alias: '/\.git' + - alias: '/\.ht.*' + # Enable server status on the following alias + server_status: + enable: no + alias: /httpd-status diff --git a/Dockerfiles/data/vhost-gen/mass-rproxy.yml b/Dockerfiles/data/vhost-gen/mass-rproxy.yml new file mode 100644 index 0000000..20c924e --- /dev/null +++ b/Dockerfiles/data/vhost-gen/mass-rproxy.yml @@ -0,0 +1,160 @@ +--- +# Generic vhost generator configuration file. +# Location: /etc/vhost-gen/mass.yml +# +# See: https://github.com/devilbox/vhost-gen +# +# If not specified or file is missing the following +# default values will be merged to your current (if any) +# configuration: +# +# server: nginx +# conf_dir: /etc/nginx/conf.d +# custom: +# vhost: +# port: +# name: +# prefix: +# suffix: +# docroot: +# suffix: +# log: +# access: +# prefix: +# stdout: no +# error: +# prefix: +# stderr: no +# dir: +# create: no +# path: /var/log/nginx +# listen: +# enable: no +# php_fpm: +# enable: no +# address: php +# port: 9000 +# alias: [] +# deny: [] +# server_status: +# enable: no +# alias: /server-status + + +# The server type determines which template +# from etc/templates/ will be chosen. +# Allowed server types: +# server: apache22 +# server: apache24 +# server: nginx +server: nginx + + +# Where to store the generated configuration files. +# This must be a directory the web server will read +# configuration files from. +conf_dir: /etc/httpd/vhost.d + + +# Custom directive +# Everything specified here will be directly replaced +# into the corresponding vhost directive: +# nginx: server { HERE } +# apache: HERE +# +# How to add multiline strings? +# +# custom: | +# custom statement 1 +# custom statement 2 +custom: + + +# Vhost definition +vhost: + # What port should this virtual host listen on + port: 80 + ssl_port: 443 + + # The virtual host name is specified as an command line argument + # to vhost-gen via '-n', however it is possible + # to prepend and/or append additional name strings. + name: + prefix: + suffix: __TLD__ + # The document root directory is specified as an command line argument + # to vhost-gen via '-p', however it is possible + # to prepend another subdirectory here. + docroot: + suffix: __DOCROOT_SUFFIX__ + # Array of indecies to serve as default files (e.g.: index.php, index.html, etc) + index: + - index.php + - index.html + - index.htm + # SSL Definition + ssl: + http2: __HTTP2_ENABLE__ + dir_crt: /etc/httpd/cert/mass + dir_key: /etc/httpd/cert/mass + protocols: 'TLSv1 TLSv1.1 TLSv1.2' + honor_cipher_order: 'on' + ciphers: 'HIGH:!aNULL:!MD5' + + # Log definition + log: + # Log file settings (error/access log) + access: + # By default the vhost name is used for log file names. + # You can also prepand an additional string to the access log + # as shown here: + # -access.log + prefix: '' + # For use inside a docker container, enable this in order + # to redirect the access log to stdout instead of to file. + # NOTE: When enabling this, the prefix will have no effect and the access + # log will be stored under /tmp/www-access.log which will be a symlink of + # /dev/stdout + stdout: __DOCKER_LOGS_ACCESS__ + error: + # By default the vhost name is used for log file names. + # You can also prepand an additional string to the error log + # as shown here: + # -error.log + prefix: '' + # For use inside a docker container, enable this in order + # to redirect the error log to stderr instead of to file. + # NOTE: When enabling this, the prefix will have no effect and the error + # log will be stored under /tmp/www-error.log which will be a symlink of + # /dev/stderr + stderr: __DOCKER_LOGS_ERROR__ + # Directory to store log files in. + # Also define if the directory should be created or not. + dir: + create: yes + path: /var/log/nginx-stable + # Enable PHP-FPM + php_fpm: + enable: __PHP_ENABLE__ + # Hostname or IP address + address: __PHP_ADDR__ + port: __PHP_PORT__ + # Timeout to upstream FPM service + timeout: __PHP_TIMEOUT__ + # Create additional aliases + alias: + - alias: /devilbox-api/ + path: /var/www/default/api + # Allow cross-domain-request to this alias from the hosts/origin + # specified by the below defined regex + xdomain_request: + enable: yes + origin: 'http(s)?://(.*)$' + # Denies locations + deny: + - alias: '/\.git' + - alias: '/\.ht.*' + # Enable server status on the following alias + server_status: + enable: no + alias: /httpd-status diff --git a/README.md b/README.md index 07d05f0..728e214 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ The provided Docker images add a lot of injectables in order to customize it to MASS_VHOST_ENABLE
MASS_VHOST_SSL_TYPE
MASS_VHOST_SSL_GEN
- MASS_VHOST_TLD
+ MASS_VHOST_TLD_SUFFIX
MASS_VHOST_DOCROOT
MASS_VHOST_TPL
diff --git a/doc/environment-variables.md b/doc/environment-variables.md index f94d3ec..a7a2720 100644 --- a/doc/environment-variables.md +++ b/doc/environment-variables.md @@ -57,9 +57,9 @@ This Docker container adds a lot of injectables in order to customize it to your | Variable | Type | Default | Description | |----------|------|---------|-------------| -| `MASS_VHOST_ENABLE` | bool | `0` | You can enable mass virtual hosts by setting this value to `1`. Mass virtual hosts will be created for each directory present in `/shared/httpd` by the same name including a top-level domain suffix (which could also be a domain+tld). See `MASS_VHOST_TLD` for how to set it. | +| `MASS_VHOST_ENABLE` | bool | `0` | You can enable mass virtual hosts by setting this value to `1`. Mass virtual hosts will be created for each directory present in `/shared/httpd` by the same name including a top-level domain suffix (which could also be a domain+tld). See `MASS_VHOST_TLD_SUFFIX` for how to set it. | | `MASS_VHOST_SSL_TYPE` | string | `plain` |
  • plain - only serve via http
  • ssl - only serve via https
  • both - serve via http and https
  • redir - serve via https and redirect http to https
| | `MASS_VHOST_SSL_GEN` | bool | `0` | `0`: Do not generate an ssl certificate
`1`: Generate self-signed certificate automatically | -| `MASS_VHOST_TLD` | string | `.loc`| This string will be appended to the server name (which is built by its directory name) for mass virtual hosts and together build the final domain.
Default:`.loc`
Example:
Path: `/shared/httpd/temp`
`MASS_VHOST_TLD=.lan`
Server name: `temp.lan`
Example:
Path:`/shared/httpd/api`
`MASS_VHOST_TLD=.example.com`
Server name: `api.example.com` | +| `MASS_VHOST_TLD_SUFFIX` | string | `.loc`| This string will be appended to the server name (which is built by its directory name) for mass virtual hosts and together build the final domain.
Default:`.loc`
Example:
Path: `/shared/httpd/temp`
`MASS_VHOST_TLD_SUFFIX=.lan`
Server name: `temp.lan`
Example:
Path:`/shared/httpd/api`
`MASS_VHOST_TLD_SUFFIX=.example.com`
Server name: `api.example.com` | | `MASS_VHOST_DOCROOT` | string | `htdocs`| This is a subdirectory within your project dir under each project from which the web server will serve its files.
`/shared/httpd//$MASS_VHOST_DOCROOT/`
Default:
`/shared/httpd//htdocs/` | | `MASS_VHOST_TPL` | string | `cfg` | Directory within your new virtual host to look for templates to overwrite virtual host settings. See [vhost-gen](https://github.com/devilbox/vhost-gen/tree/master/etc/templates) for available template files.
`/shared/httpd//$MASS_VHOST_TPL/`
Resulting default path:
`/shared/httpd//cfg/` | diff --git a/doc/features.md b/doc/features.md index 0c7844a..ec6a30a 100644 --- a/doc/features.md +++ b/doc/features.md @@ -11,7 +11,7 @@ 1. Automated virtual hosts can be enabled by providing `-e MASS_VHOST_ENABLE=1`. 2. You should mount a local project directory into the Docker under `/shared/httpd` (`-v /local/path:/shared/httpd`). -3. You can optionally specify a global server name suffix via e.g.: `-e MASS_VHOST_TLD=.loc` +3. You can optionally specify a global server name suffix via e.g.: `-e MASS_VHOST_TLD_SUFFIX=.loc` 4. You can optionally specify a global subdirectory from which the virtual host will servve the documents via e.g.: `-e MASS_VHOST_DOCROOT=www` 5. Allow the Docker to expose its port via `-p 80:80`. 6. Have DNS names point to the IP address the container runs on (e.g. via `/etc/hosts`) @@ -19,30 +19,30 @@ With the above described settings, whenever you create a local directory under your projects dir such as `/local/path/mydir`, there will be a new virtual host created by the same name `http://mydir`. You can also specify a global suffix for the vhost names via -`-e MASS_VHOST_TLD=.loc`, afterwards your above created vhost would be reachable via +`-e MASS_VHOST_TLD_SUFFIX=.loc`, afterwards your above created vhost would be reachable via `http://mydir.loc`. Just to give you a few examples: **Assumption:** `/local/path` is mounted to `/shared/httpd` -| Directory | `MASS_VHOST_DOCROOT` | `MASS_VHOST_TLD` | Serving from (*) | Via | -|-----------|----------------------|------------------|--------------------------|----------------------| -| work1/ | htdocs/ | | /local/path/work1/htdocs | http://work1 | -| work1/ | www/ | | /local/path/work1/www | http://work1 | -| work1/ | htdocs/ | .loc | /local/path/work1/htdocs | http://work1.loc | -| work1/ | www/ | .loc | /local/path/work1/www | http://work1.loc | +| Directory | `MASS_VHOST_DOCROOT` | `MASS_VHOST_TLD_SUFFIX` | Serving from (*) | Via | +|-----------|----------------------|-------------------------|--------------------------|----------------------| +| work1/ | htdocs/ | | /local/path/work1/htdocs | http://work1 | +| work1/ | www/ | | /local/path/work1/www | http://work1 | +| work1/ | htdocs/ | .loc | /local/path/work1/htdocs | http://work1.loc | +| work1/ | www/ | .loc | /local/path/work1/www | http://work1.loc | (*) This refers to the directory on your host computer **Assumption:** `/tmp` is mounted to `/shared/httpd` -| Directory | `MASS_VHOST_DOCROOT` | `MASS_VHOST_TLD` | Serving from (*) | Via | -|-----------|----------------------|------------------|--------------------------|----------------------| -| api/ | htdocs/ | | /tmp/api/htdocs | http://api | -| api/ | www/ | | /tmp/api/www | http://api | -| api/ | htdocs/ | .test.com | /tmp/api/htdocs | http://api.test.com | -| api/ | www/ | .test.com | /tmp/api/www | http://api.test.com | +| Directory | `MASS_VHOST_DOCROOT` | `MASS_VHOST_TLD_SUFFIX` | Serving from (*) | Via | +|-----------|----------------------|-------------------------|--------------------------|----------------------| +| api/ | htdocs/ | | /tmp/api/htdocs | http://api | +| api/ | www/ | | /tmp/api/www | http://api | +| api/ | htdocs/ | .test.com | /tmp/api/htdocs | http://api.test.com | +| api/ | www/ | .test.com | /tmp/api/www | http://api.test.com | (*) This refers to the directory on your host computer @@ -53,7 +53,7 @@ docker run -it \ -p 80:80 \ -e MASS_VHOST_ENABLE=1 \ -e MASS_VHOST_DOCROOT=www \ - -e MASS_VHOST_TLD=.loc \ + -e MASS_VHOST_TLD_SUFFIX=.loc \ -v /local/path:/shared/httpd \ devilbox/nginx-stable ``` diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..734bcb6 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,14 @@ +# Examples + + +A Quick overview about available examples + +| Complexity | Virtual Host | Backend | Description | Link | +|------------|--------------|---------|-------------|------| +| simple | Default | None | Serve static files | [default-vhost__static-files](default-vhost__static-files) | +| simple | Default | NodsJS | Reverse Proxy to Node app | [default-vhost__reverse-proxy__node](default-vhost__reverse-proxy__node) | +| simple | Default | Python | Reverse Proxy to Python app | [default-vhost__reverse-proxy__python](default-vhost__reverse-proxy__python) | +| simple | Default | PHP-FPM | Serve PHP files | [default-vhost__php-fpm](default-vhost__php-fpm) | +| medium | Default | PHP-FPM | Serve PHP files over HTTPS (SSL) | [default-vhost__php-fpm__ssl](default-vhost__php-fpm__ssl) | +| complex | Mass vhost | PHP-FPM | Mass vhosting with auto-generated SSL for each host | [mass-vhost__php-fpm__ssl](mass-vhost__php-fpm__ssl) | +| complex | Mass vhost | Multi | Mass vhosting with auto-generated SSL for each host (PHP-FPM and NodeJS reverse Proxy) | [mass-vhost__reverse-proxy__ssl/](mass-vhost__reverse-proxy__ssl/) | diff --git a/examples/default-vhost__php-fpm/README.md b/examples/default-vhost__php-fpm/README.md new file mode 100644 index 0000000..26f47bf --- /dev/null +++ b/examples/default-vhost__php-fpm/README.md @@ -0,0 +1,13 @@ +# Example: PHP_FPM + +Docker Compose example with a remote PHP-FPM server. + +## Run +```bash +docker-compose up +``` + +## View +```bash +curl http://localhost:8000 +``` diff --git a/examples/default-vhost__php-fpm/docker-compose.yml b/examples/default-vhost__php-fpm/docker-compose.yml new file mode 100644 index 0000000..8811b21 --- /dev/null +++ b/examples/default-vhost__php-fpm/docker-compose.yml @@ -0,0 +1,32 @@ +--- +version: '2.3' + +services: + + # HTTPD Server + httpd: + image: devilbox/nginx-stable:alpine + build: + context: ../../Dockerfiles + dockerfile: Dockerfile.alpine + hostname: httpd + environment: + - NEW_UID=1000 + - NEW_GID=1000 + - MAIN_VHOST_BACKEND=conf:phpfpm:tcp:php:9000 + ports: + - "8000:80" + volumes: + - ./www:/var/www/default/htdocs + depends_on: + - php + + # PHP-FPM Server + php: + image: devilbox/php-fpm:8.2-base + hostname: php + environment: + - NEW_UID=1000 + - NEW_GID=1000 + volumes: + - ./www:/var/www/default/htdocs diff --git a/examples/default-vhost__php-fpm/integration-test.sh b/examples/default-vhost__php-fpm/integration-test.sh new file mode 100755 index 0000000..13a9bd4 --- /dev/null +++ b/examples/default-vhost__php-fpm/integration-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +docker-compose build +docker-compose up -d +sleep 10 + +if ! curl http://localhost:8000 | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi + +docker-compose logs || true +docker-compose stop || true +docker-compose rm -f || true diff --git a/examples/default-vhost__php-fpm/www/index.php b/examples/default-vhost__php-fpm/www/index.php new file mode 100644 index 0000000..df33e4e --- /dev/null +++ b/examples/default-vhost__php-fpm/www/index.php @@ -0,0 +1,2 @@ +[OK] +

PHP version:

diff --git a/examples/default-vhost__php-fpm__ssl/README.md b/examples/default-vhost__php-fpm__ssl/README.md new file mode 100644 index 0000000..42c36d7 --- /dev/null +++ b/examples/default-vhost__php-fpm__ssl/README.md @@ -0,0 +1,17 @@ +# Example: PHP_FPM + +Docker Compose example with a remote PHP-FPM server and serving HTTPS + +## Run +```bash +docker-compose up +``` + +## View +```bash +# HTTP +curl http://localhost:8000 + +# HTTPS +curl -k https://localhost:8443 +``` diff --git a/examples/default-vhost__php-fpm__ssl/docker-compose.yml b/examples/default-vhost__php-fpm__ssl/docker-compose.yml new file mode 100644 index 0000000..2e1a38b --- /dev/null +++ b/examples/default-vhost__php-fpm__ssl/docker-compose.yml @@ -0,0 +1,34 @@ +--- +version: '2.3' + +services: + + # HTTPD Server + httpd: + image: devilbox/nginx-stable:alpine + build: + context: ../../Dockerfiles + dockerfile: Dockerfile.alpine + hostname: httpd + environment: + - NEW_UID=1000 + - NEW_GID=1000 + - MAIN_VHOST_SSL_TYPE=both + - MAIN_VHOST_BACKEND=conf:phpfpm:tcp:php:9000 + ports: + - "8000:80" + - "8443:443" + volumes: + - ./www:/var/www/default/htdocs + depends_on: + - php + + # PHP-FPM Server + php: + image: devilbox/php-fpm:8.2-base + hostname: php + environment: + - NEW_UID=1000 + - NEW_GID=1000 + volumes: + - ./www:/var/www/default/htdocs diff --git a/examples/default-vhost__php-fpm__ssl/integration-test.sh b/examples/default-vhost__php-fpm__ssl/integration-test.sh new file mode 100755 index 0000000..dd41bcd --- /dev/null +++ b/examples/default-vhost__php-fpm__ssl/integration-test.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +docker-compose build +docker-compose up -d +sleep 10 + +if ! curl http://localhost:8000 | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi +if ! curl -k https://localhost:8443 | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi + +docker-compose logs || true +docker-compose stop || true +docker-compose rm -f || true diff --git a/examples/default-vhost__php-fpm__ssl/www/index.php b/examples/default-vhost__php-fpm__ssl/www/index.php new file mode 100644 index 0000000..df33e4e --- /dev/null +++ b/examples/default-vhost__php-fpm__ssl/www/index.php @@ -0,0 +1,2 @@ +[OK] +

PHP version:

diff --git a/examples/default-vhost__reverse-proxy__node/README.md b/examples/default-vhost__reverse-proxy__node/README.md new file mode 100644 index 0000000..4343c12 --- /dev/null +++ b/examples/default-vhost__reverse-proxy__node/README.md @@ -0,0 +1,17 @@ +# Example: Reverse Proxy (NodeJS) + +Docker Compose example with HTTPD acting as a Reverse Proxy and a remote NodeJS server. + +## Run +```bash +docker-compose up +``` + +## View +```bash +# HTTP +curl http://localhost:8000 + +# HTTPS +curl -k https://localhost:8443 +``` diff --git a/examples/default-vhost__reverse-proxy__node/docker-compose.yml b/examples/default-vhost__reverse-proxy__node/docker-compose.yml new file mode 100644 index 0000000..bf81681 --- /dev/null +++ b/examples/default-vhost__reverse-proxy__node/docker-compose.yml @@ -0,0 +1,28 @@ +--- +version: '2.3' + +services: + + # HTTPD Server + httpd: + image: devilbox/nginx-stable:alpine + build: + context: ../../Dockerfiles + dockerfile: Dockerfile.alpine + hostname: httpd + environment: + - MAIN_VHOST_BACKEND=conf:rproxy:http:node:3000 + - MAIN_VHOST_SSL_TYPE=both + ports: + - "8000:80" + - "8443:443" + depends_on: + - node + + # NodeJS Server + node: + image: node:19-alpine + hostname: node + command: node /app/app.js + volumes: + - ./www:/app diff --git a/examples/default-vhost__reverse-proxy__node/integration-test.sh b/examples/default-vhost__reverse-proxy__node/integration-test.sh new file mode 100755 index 0000000..dd41bcd --- /dev/null +++ b/examples/default-vhost__reverse-proxy__node/integration-test.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +docker-compose build +docker-compose up -d +sleep 10 + +if ! curl http://localhost:8000 | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi +if ! curl -k https://localhost:8443 | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi + +docker-compose logs || true +docker-compose stop || true +docker-compose rm -f || true diff --git a/examples/default-vhost__reverse-proxy__node/www/app.js b/examples/default-vhost__reverse-proxy__node/www/app.js new file mode 100644 index 0000000..3e01719 --- /dev/null +++ b/examples/default-vhost__reverse-proxy__node/www/app.js @@ -0,0 +1,9 @@ +const http = require('http'); +const server = http.createServer((req, res) => { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.write('[OK]\n'); + res.write('NodeJS is running\n'); + res.end(); +}); +server.listen(3000, '0.0.0.0'); diff --git a/examples/default-vhost__reverse-proxy__python/README.md b/examples/default-vhost__reverse-proxy__python/README.md new file mode 100644 index 0000000..bf7dde5 --- /dev/null +++ b/examples/default-vhost__reverse-proxy__python/README.md @@ -0,0 +1,17 @@ +# Example: Reverse Proxy (Python) + +Docker Compose example with HTTPD acting as a Reverse Proxy and a remote Python server. + +## Run +```bash +docker-compose up +``` + +## View +```bash +# HTTP +curl http://localhost:8000 + +# HTTPS +curl -k https://localhost:8443 +``` diff --git a/examples/default-vhost__reverse-proxy__python/docker-compose.yml b/examples/default-vhost__reverse-proxy__python/docker-compose.yml new file mode 100644 index 0000000..8c359ed --- /dev/null +++ b/examples/default-vhost__reverse-proxy__python/docker-compose.yml @@ -0,0 +1,28 @@ +--- +version: '2.3' + +services: + + # HTTPD Server + httpd: + image: devilbox/nginx-stable:alpine + build: + context: ../../Dockerfiles + dockerfile: Dockerfile.alpine + hostname: httpd + environment: + - MAIN_VHOST_BACKEND=conf:rproxy:http:python:3000 + - MAIN_VHOST_SSL_TYPE=both + ports: + - "8000:80" + - "8443:443" + depends_on: + - python + + # Python Server + python: + image: python:3-alpine + hostname: python + command: sh -c "pip install aiohttp==3.8.3; python -u /app/server.py" + volumes: + - ./www:/app diff --git a/examples/default-vhost__reverse-proxy__python/integration-test.sh b/examples/default-vhost__reverse-proxy__python/integration-test.sh new file mode 100755 index 0000000..dd41bcd --- /dev/null +++ b/examples/default-vhost__reverse-proxy__python/integration-test.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +docker-compose build +docker-compose up -d +sleep 10 + +if ! curl http://localhost:8000 | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi +if ! curl -k https://localhost:8443 | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi + +docker-compose logs || true +docker-compose stop || true +docker-compose rm -f || true diff --git a/examples/default-vhost__reverse-proxy__python/www/server.py b/examples/default-vhost__reverse-proxy__python/www/server.py new file mode 100644 index 0000000..87cf4cd --- /dev/null +++ b/examples/default-vhost__reverse-proxy__python/www/server.py @@ -0,0 +1,11 @@ +from aiohttp import web + +async def handle(request): + response = '[OK]\nHello from Python\n' + return web.Response(text=response) + +app = web.Application() +app.router.add_get('/', handle) +app.router.add_get('/{name}', handle) + +web.run_app(app, port=3000) diff --git a/examples/default-vhost__static-files/README.md b/examples/default-vhost__static-files/README.md new file mode 100644 index 0000000..44b8cf0 --- /dev/null +++ b/examples/default-vhost__static-files/README.md @@ -0,0 +1,13 @@ +# Example: Static files + +Docker Compose example with only serving static files. + +## Run +```bash +docker-compose up +``` + +## View +```bash +curl http://localhost:8000 +``` diff --git a/examples/default-vhost__static-files/docker-compose.yml b/examples/default-vhost__static-files/docker-compose.yml new file mode 100644 index 0000000..0e02dd0 --- /dev/null +++ b/examples/default-vhost__static-files/docker-compose.yml @@ -0,0 +1,19 @@ +--- +version: '2.3' + +services: + + # HTTPD Server + httpd: + image: devilbox/nginx-stable:alpine + build: + context: ../../Dockerfiles + dockerfile: Dockerfile.alpine + hostname: httpd + environment: + - NEW_UID=1000 + - NEW_GID=1000 + ports: + - "8000:80" + volumes: + - ./www:/var/www/default/htdocs diff --git a/examples/default-vhost__static-files/integration-test.sh b/examples/default-vhost__static-files/integration-test.sh new file mode 100755 index 0000000..13a9bd4 --- /dev/null +++ b/examples/default-vhost__static-files/integration-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +docker-compose build +docker-compose up -d +sleep 10 + +if ! curl http://localhost:8000 | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi + +docker-compose logs || true +docker-compose stop || true +docker-compose rm -f || true diff --git a/examples/default-vhost__static-files/www/index.html b/examples/default-vhost__static-files/www/index.html new file mode 100644 index 0000000..a18243f --- /dev/null +++ b/examples/default-vhost__static-files/www/index.html @@ -0,0 +1,2 @@ +[OK] +

It works!

diff --git a/examples/mass-vhost__php-fpm__ssl/README.md b/examples/mass-vhost__php-fpm__ssl/README.md new file mode 100644 index 0000000..b2a3cb1 --- /dev/null +++ b/examples/mass-vhost__php-fpm__ssl/README.md @@ -0,0 +1,81 @@ +# Example: PHP_FPM + +Docker Compose example with a remote PHP-FPM server. + +This example uses mass virtual hosting, i.e.: it creates **as many virtual hosts automatically as directories exist**. +This happens either during startup (initial setup) and also during run-time, whenever directories are created, renamed or removed. +It will also provide **SSL capable vhosts** that you can view in your browser **without SSL certificate warnings.** + + +Try it out yourself and add a directory into the [projects](projects/) directory. As soon as you create one, a new virtual host will be created. Keep in mind that files are being served from the `htdocs` directory within your newly created project. (The `htdocs` directory can also be a symlink). + +The `MASS_VHOST_TLD_SUFFIX` is set to `.loc`, so the project vhost name (its domain) will be: `.loc` + +## Example 1: During Startup + +The [projects](projects/) directory already contains two projects: + * `sample` + * `test` + +That means that during startup, two vhosts will be created: + * `sample.loc` + * `test.loc` + +The files for each vhost are being served from: + * `projects/sample/htdocs` (where `htdocs` symlinks to `src/`) + * `projects/test/htdocs` + +You can reach those two projects via: +```bash +# Ensure docker-compose is running +docker-compose up + +# Now verify +curl http://localhost:8000 -H 'host: sample.loc' +curl http://localhost:8000 -H 'host: test.loc' +``` + +## Example 2: During Run-time + +In this example we add more projects during run-time +```bash +# Ensure docker-compose is running +docker-compose up +``` + +Now as the HTTP and PHP container are up and running, we can add more projects: +``` +# Create project directory +# This will auto-create a new vhost 'it-works.tld' +mkdir projects/it-works/ + +# Add some code +mkdir projects/it-works/htdocs +echo '' > projects/it-works/htdocs/index.php +``` +Now you can access it via: +```bash +curl http://localhost:8000 -H 'host: it-works.loc' +``` + +**Note:** The other two vhosts from Example 1 are still available. + + +## Example 3: SSL and Browser access + +You migth have noticed the `ca/` directory. The HTTPD container also creates SSL certificates for all of the above described vhosts (and any you will create during startup- or run-time). +This is done via a certificate authority, so that each vhost certificate was signed by a CA. + +**What is the benefit?** + +1. You can import the CA files in the `ca/` directory into your browser +2. Add `/etc/hosts` entries: + ```bash + 127.0.0.1 sample.loc + 127.0.0.1 test.loc + 127.0.0.1 it-works.loc + ``` +3. Access them through your browser via valid https + * `https://sample.loc:8443 + * `https://test.loc:8443 + * `https://it-works.loc:8443 diff --git a/examples/mass-vhost__php-fpm__ssl/ca/.keep b/examples/mass-vhost__php-fpm__ssl/ca/.keep new file mode 100644 index 0000000..e69de29 diff --git a/examples/mass-vhost__php-fpm__ssl/ca/devilbox-ca.crt b/examples/mass-vhost__php-fpm__ssl/ca/devilbox-ca.crt new file mode 100644 index 0000000..3af9c7f --- /dev/null +++ b/examples/mass-vhost__php-fpm__ssl/ca/devilbox-ca.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFTTCCBDWgAwIBAgIUPAyieTMNDtvlnZZ9VeYADmWQBjYwDQYJKoZIhvcNAQEL +BQAwgbwxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNVBAcMBkJl +cmxpbjERMA8GA1UECgwIRGV2aWxib3gxETAPBgNVBAsMCERldmlsYm94MRkwFwYD +VQQDDBBEZXZpbGJveCBSb290IENBMSMwIQYJKoZIhvcNAQkBFhRjeXRvcGlhQGRl +dmlsYm94Lm9yZzElMCMGA1UELhMceVF2T3hUUVJBdGN3Q2VoRmhmcFZEc2FZa1pR +PTAeFw0yMjEyMTcxNTM5MDFaFw0zMjEyMTQxNTM5MDFaMIG8MQswCQYDVQQGEwJE +RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xETAPBgNVBAoMCERl +dmlsYm94MREwDwYDVQQLDAhEZXZpbGJveDEZMBcGA1UEAwwQRGV2aWxib3ggUm9v +dCBDQTEjMCEGCSqGSIb3DQEJARYUY3l0b3BpYUBkZXZpbGJveC5vcmcxJTAjBgNV +BC4THHlRdk94VFFSQXRjd0NlaEZoZnBWRHNhWWtaUT0wggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDqa9T1nKa3YSI+pChd9CdGkbzN52XmQr9/qu9HM9KH +AfRlfFvhvS8unzuiQeqfk9+BAFd2mC1Bu3+JrIE5QyJmzT3Uf7fYzxJNxEnuLFiy +nOHD7k0bfW9MuLsmbWb47ipTTYxQ2WUP7g1PC58zvyzk8eDDFAu153kUJRXYMv3B +n/X727ri4epObRCf+gF9XL/Wm36zM7yn0zQf07Q2x2/0BwaBwI5QSFvWKC4+JH2Q +2Ju2MfWEZziYHDGdr5PKCHtNRYY6wKi3k81IKT9+WvX4o/HjmWBV7ErUArV31JF0 +jSbVxEFvzsMw79xA4Xrk6qB75M9UrG3gEBIDdOEVjdTlAgMBAAGjggFDMIIBPzAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTJC87FNBEC1zAJ6EWF+lUOxpiRlDAO +BgNVHQ8BAf8EBAMCAYYwgfwGA1UdIwSB9DCB8YAUyQvOxTQRAtcwCehFhfpVDsaY +kZShgcKkgb8wgbwxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNV +BAcMBkJlcmxpbjERMA8GA1UECgwIRGV2aWxib3gxETAPBgNVBAsMCERldmlsYm94 +MRkwFwYDVQQDDBBEZXZpbGJveCBSb290IENBMSMwIQYJKoZIhvcNAQkBFhRjeXRv +cGlhQGRldmlsYm94Lm9yZzElMCMGA1UELhMceVF2T3hUUVJBdGN3Q2VoRmhmcFZE +c2FZa1pRPYIUPAyieTMNDtvlnZZ9VeYADmWQBjYwDQYJKoZIhvcNAQELBQADggEB +AEjnm9Qj9C2iZGCYqV4anLLNNwaC14aMYPAqWR3AGSyC34Mpe8rx2ZJITiU8VC9n +zlC+XteeW7PrXhuu2kjQmNNJZVRTGNp40/YtfszUxWJwFjg8nox+8R7hf1R9ptiR +KOImhF8e4GF048rqGDEJNeeSO9bv9goY61XNh/abWY4gsLS4Zi1Y9OdN3QS7BFRL +1NomJv9vNhhzt/e+1jEJHW1A/ZnbPBACeT8zNRSgpR6TJITOMs0w04xgwlt1VWeH +GjZDWlQBzC2vVNfTeDaDr7WwjDLiV3iM1qS0ycWEuWzXEnt3lLpXDNfEFliaG4xv +L8p82kLG0TNVibkyZt88/Ws= +-----END CERTIFICATE----- diff --git a/examples/mass-vhost__php-fpm__ssl/ca/devilbox-ca.key b/examples/mass-vhost__php-fpm__ssl/ca/devilbox-ca.key new file mode 100644 index 0000000..9feb676 --- /dev/null +++ b/examples/mass-vhost__php-fpm__ssl/ca/devilbox-ca.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA6mvU9Zymt2EiPqQoXfQnRpG8zedl5kK/f6rvRzPShwH0ZXxb +4b0vLp87okHqn5PfgQBXdpgtQbt/iayBOUMiZs091H+32M8STcRJ7ixYspzhw+5N +G31vTLi7Jm1m+O4qU02MUNllD+4NTwufM78s5PHgwxQLted5FCUV2DL9wZ/1+9u6 +4uHqTm0Qn/oBfVy/1pt+szO8p9M0H9O0Nsdv9AcGgcCOUEhb1iguPiR9kNibtjH1 +hGc4mBwxna+Tygh7TUWGOsCot5PNSCk/flr1+KPx45lgVexK1AK1d9SRdI0m1cRB +b87DMO/cQOF65Oqge+TPVKxt4BASA3ThFY3U5QIDAQABAoIBAEKkSxNT6FVDiN+z +/UHQcgXu0nTarq5KFXSu3H0qb1QwKxFazCgdhzdCz0ouYQviluxuc27kjiEcs4Ip +B0eHHVWKTWSGtnYtT+/JuJa8Bq8oSEpSCZuiCi0Oay3ediKYWnH6HsSxOLjRnPj2 +vdiRJaskVBhBL58T4ejnLhGbVWZgjtSkkfXgJnQaoROi7QPJV7msP4n9aM46O+m1 +TIwjzYBc9MZ6WI54irm0WEI86ewS77S6oEvieqaisiQYF/IsWT2YekUFWU+mPRBj +fSWtfXHB3wtP8e0btrfJa3h95bpF+oYcG3z3F0i1zumu5vKmtKlOjXumMQbCTKwN +RUfWGCECgYEA+n72vB7DkSjvyh7zeGTAKo+bhsg9Lcqe0/SvqpsBxUp8gzm5x+op +REcl7OOy6sZ9ms5LF7JTLxw/3/St/PvqS341Vr4PIiBzmU3PsqmQtPquXtz+ASP0 +8c48J4uftImOBQI4zdh8DPWxIbl4G2bSmmcPns5q4Fjg2Ew8u9C4IT0CgYEA75Jy +qmSeyk9ekBS4+ZgJWKBa33hanpaXZtxnkZs3u1dMMpPDPWF5zetwwdjJGTNZUQSP +XcsBRhsDNTFSqGApfVHrEvt7j+SITiil2A7x68+fMLWwZEA/YMdyVcexXOwnpFw6 +GWy4LquEiScGNm2fqoOltINnCp9kDUmnLaYubMkCgYEAv7nHvcrKIuOzTP+NmFt8 +3daW0n2WneLU2CQTBECqBUhyrrnTIVlvhmvycjMBcULFRmSZAyUhGBDGLvMG7Hgg +JvINfzvvN06hS/hLfVLdiDfKmJ8K5vKPezg/wIDUlwklo13E/oCwyfaPQeHENSzp +CvbQ9NrG4LoGNmd7oMEq/X0CgYBI8Exq5kGWFL4UncqHayuFSSUBnpHwcKbd0ULT +CO/Z4MU5LNWnbXL5J7JnwknPm1uZGAtSIglcP8MlQcQJsWVQW013tQs0jv6U1TlQ +45PyGH8+BEMU8p6ZJ3/+79JnGRskplOmA/y7cMrkOvZgQdX3wycDI3KOwGJkzUTR +2COQSQKBgQDxukAoRBs5YhLSs/LpmiFwDnlHU2D/5+zxyJpxChLkfFwm4i3KurDp +oNFeHD1dJ2D6pnyg86hwkhdGoxzA4zxc4FdMFFoi7qloogZdV/JClUsb9OI39vL6 +mq2uzEI0RLx0T+O3LvQ9yWRJE16QUys08pqFoggZkCPqnY6ks/2iag== +-----END RSA PRIVATE KEY----- diff --git a/examples/mass-vhost__php-fpm__ssl/ca/devilbox-ca.srl b/examples/mass-vhost__php-fpm__ssl/ca/devilbox-ca.srl new file mode 100644 index 0000000..501cd41 --- /dev/null +++ b/examples/mass-vhost__php-fpm__ssl/ca/devilbox-ca.srl @@ -0,0 +1 @@ +5D7E92287914BFA690E6873939DDAF116B551D3E diff --git a/examples/mass-vhost__php-fpm__ssl/docker-compose.yml b/examples/mass-vhost__php-fpm__ssl/docker-compose.yml new file mode 100644 index 0000000..df7a842 --- /dev/null +++ b/examples/mass-vhost__php-fpm__ssl/docker-compose.yml @@ -0,0 +1,38 @@ +--- +version: '2.3' + +services: + + # HTTPD Server + httpd: + image: devilbox/nginx-stable:alpine + build: + context: ../../Dockerfiles + dockerfile: Dockerfile.alpine + hostname: httpd + environment: + - NEW_UID=1000 + - NEW_GID=1000 + - MAIN_VHOST_ENABLE=0 + - MASS_VHOST_ENABLE=1 + - MASS_VHOST_BACKEND=conf:phpfpm:tcp:php:9000 + - MASS_VHOST_TLD_SUFFIX=.loc + - MASS_VHOST_SSL_TYPE=both + ports: + - "8000:80" + - "8443:443" + volumes: + - ./projects:/shared/httpd + - ./ca:/ca + depends_on: + - php + + # PHP-FPM Server + php: + image: devilbox/php-fpm:8.2-base + hostname: php + environment: + - NEW_UID=1000 + - NEW_GID=1000 + volumes: + - ./projects:/shared/httpd diff --git a/examples/mass-vhost__php-fpm__ssl/integration-test.sh b/examples/mass-vhost__php-fpm__ssl/integration-test.sh new file mode 100755 index 0000000..5b098c1 --- /dev/null +++ b/examples/mass-vhost__php-fpm__ssl/integration-test.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +docker-compose build +docker-compose up -d +sleep 10 + +if ! curl http://localhost:8000 -H 'Host:sample.loc' | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi +if ! curl -k https://localhost:8443 -H 'Host:sample.loc' | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi + +if ! curl http://localhost:8000 -H 'Host:test.loc' | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi +if ! curl -k https://localhost:8443 -H 'Host:test.loc' | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi + +docker-compose logs || true +docker-compose stop || true +docker-compose rm -f || true diff --git a/examples/mass-vhost__php-fpm__ssl/projects/sample/htdocs b/examples/mass-vhost__php-fpm__ssl/projects/sample/htdocs new file mode 120000 index 0000000..e831038 --- /dev/null +++ b/examples/mass-vhost__php-fpm__ssl/projects/sample/htdocs @@ -0,0 +1 @@ +src \ No newline at end of file diff --git a/examples/mass-vhost__php-fpm__ssl/projects/sample/src/index.php b/examples/mass-vhost__php-fpm__ssl/projects/sample/src/index.php new file mode 100644 index 0000000..1962a1f --- /dev/null +++ b/examples/mass-vhost__php-fpm__ssl/projects/sample/src/index.php @@ -0,0 +1,4 @@ +[OK] +[PROJECT: sample] +[DOMAIN: sample.loc] +

PHP version:

diff --git a/examples/mass-vhost__php-fpm__ssl/projects/test/htdocs/index.php b/examples/mass-vhost__php-fpm__ssl/projects/test/htdocs/index.php new file mode 100644 index 0000000..9959559 --- /dev/null +++ b/examples/mass-vhost__php-fpm__ssl/projects/test/htdocs/index.php @@ -0,0 +1,4 @@ +[OK] +[PROJECT: test] +[DOMAIN: test.loc] +

PHP version:

diff --git a/examples/mass-vhost__reverse-proxy__ssl/README.md b/examples/mass-vhost__reverse-proxy__ssl/README.md new file mode 100644 index 0000000..da8af20 --- /dev/null +++ b/examples/mass-vhost__reverse-proxy__ssl/README.md @@ -0,0 +1,8 @@ +# Example: Multi + +Docker Compose example with different backends defined in each respective project directory. + +Show-cased backends: + +* PHP-FPM +* NodeJS diff --git a/examples/mass-vhost__reverse-proxy__ssl/ca/.keep b/examples/mass-vhost__reverse-proxy__ssl/ca/.keep new file mode 100644 index 0000000..e69de29 diff --git a/examples/mass-vhost__reverse-proxy__ssl/ca/devilbox-ca.crt b/examples/mass-vhost__reverse-proxy__ssl/ca/devilbox-ca.crt new file mode 100644 index 0000000..3af9c7f --- /dev/null +++ b/examples/mass-vhost__reverse-proxy__ssl/ca/devilbox-ca.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFTTCCBDWgAwIBAgIUPAyieTMNDtvlnZZ9VeYADmWQBjYwDQYJKoZIhvcNAQEL +BQAwgbwxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNVBAcMBkJl +cmxpbjERMA8GA1UECgwIRGV2aWxib3gxETAPBgNVBAsMCERldmlsYm94MRkwFwYD +VQQDDBBEZXZpbGJveCBSb290IENBMSMwIQYJKoZIhvcNAQkBFhRjeXRvcGlhQGRl +dmlsYm94Lm9yZzElMCMGA1UELhMceVF2T3hUUVJBdGN3Q2VoRmhmcFZEc2FZa1pR +PTAeFw0yMjEyMTcxNTM5MDFaFw0zMjEyMTQxNTM5MDFaMIG8MQswCQYDVQQGEwJE +RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xETAPBgNVBAoMCERl +dmlsYm94MREwDwYDVQQLDAhEZXZpbGJveDEZMBcGA1UEAwwQRGV2aWxib3ggUm9v +dCBDQTEjMCEGCSqGSIb3DQEJARYUY3l0b3BpYUBkZXZpbGJveC5vcmcxJTAjBgNV +BC4THHlRdk94VFFSQXRjd0NlaEZoZnBWRHNhWWtaUT0wggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDqa9T1nKa3YSI+pChd9CdGkbzN52XmQr9/qu9HM9KH +AfRlfFvhvS8unzuiQeqfk9+BAFd2mC1Bu3+JrIE5QyJmzT3Uf7fYzxJNxEnuLFiy +nOHD7k0bfW9MuLsmbWb47ipTTYxQ2WUP7g1PC58zvyzk8eDDFAu153kUJRXYMv3B +n/X727ri4epObRCf+gF9XL/Wm36zM7yn0zQf07Q2x2/0BwaBwI5QSFvWKC4+JH2Q +2Ju2MfWEZziYHDGdr5PKCHtNRYY6wKi3k81IKT9+WvX4o/HjmWBV7ErUArV31JF0 +jSbVxEFvzsMw79xA4Xrk6qB75M9UrG3gEBIDdOEVjdTlAgMBAAGjggFDMIIBPzAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTJC87FNBEC1zAJ6EWF+lUOxpiRlDAO +BgNVHQ8BAf8EBAMCAYYwgfwGA1UdIwSB9DCB8YAUyQvOxTQRAtcwCehFhfpVDsaY +kZShgcKkgb8wgbwxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNV +BAcMBkJlcmxpbjERMA8GA1UECgwIRGV2aWxib3gxETAPBgNVBAsMCERldmlsYm94 +MRkwFwYDVQQDDBBEZXZpbGJveCBSb290IENBMSMwIQYJKoZIhvcNAQkBFhRjeXRv +cGlhQGRldmlsYm94Lm9yZzElMCMGA1UELhMceVF2T3hUUVJBdGN3Q2VoRmhmcFZE +c2FZa1pRPYIUPAyieTMNDtvlnZZ9VeYADmWQBjYwDQYJKoZIhvcNAQELBQADggEB +AEjnm9Qj9C2iZGCYqV4anLLNNwaC14aMYPAqWR3AGSyC34Mpe8rx2ZJITiU8VC9n +zlC+XteeW7PrXhuu2kjQmNNJZVRTGNp40/YtfszUxWJwFjg8nox+8R7hf1R9ptiR +KOImhF8e4GF048rqGDEJNeeSO9bv9goY61XNh/abWY4gsLS4Zi1Y9OdN3QS7BFRL +1NomJv9vNhhzt/e+1jEJHW1A/ZnbPBACeT8zNRSgpR6TJITOMs0w04xgwlt1VWeH +GjZDWlQBzC2vVNfTeDaDr7WwjDLiV3iM1qS0ycWEuWzXEnt3lLpXDNfEFliaG4xv +L8p82kLG0TNVibkyZt88/Ws= +-----END CERTIFICATE----- diff --git a/examples/mass-vhost__reverse-proxy__ssl/ca/devilbox-ca.key b/examples/mass-vhost__reverse-proxy__ssl/ca/devilbox-ca.key new file mode 100644 index 0000000..9feb676 --- /dev/null +++ b/examples/mass-vhost__reverse-proxy__ssl/ca/devilbox-ca.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA6mvU9Zymt2EiPqQoXfQnRpG8zedl5kK/f6rvRzPShwH0ZXxb +4b0vLp87okHqn5PfgQBXdpgtQbt/iayBOUMiZs091H+32M8STcRJ7ixYspzhw+5N +G31vTLi7Jm1m+O4qU02MUNllD+4NTwufM78s5PHgwxQLted5FCUV2DL9wZ/1+9u6 +4uHqTm0Qn/oBfVy/1pt+szO8p9M0H9O0Nsdv9AcGgcCOUEhb1iguPiR9kNibtjH1 +hGc4mBwxna+Tygh7TUWGOsCot5PNSCk/flr1+KPx45lgVexK1AK1d9SRdI0m1cRB +b87DMO/cQOF65Oqge+TPVKxt4BASA3ThFY3U5QIDAQABAoIBAEKkSxNT6FVDiN+z +/UHQcgXu0nTarq5KFXSu3H0qb1QwKxFazCgdhzdCz0ouYQviluxuc27kjiEcs4Ip +B0eHHVWKTWSGtnYtT+/JuJa8Bq8oSEpSCZuiCi0Oay3ediKYWnH6HsSxOLjRnPj2 +vdiRJaskVBhBL58T4ejnLhGbVWZgjtSkkfXgJnQaoROi7QPJV7msP4n9aM46O+m1 +TIwjzYBc9MZ6WI54irm0WEI86ewS77S6oEvieqaisiQYF/IsWT2YekUFWU+mPRBj +fSWtfXHB3wtP8e0btrfJa3h95bpF+oYcG3z3F0i1zumu5vKmtKlOjXumMQbCTKwN +RUfWGCECgYEA+n72vB7DkSjvyh7zeGTAKo+bhsg9Lcqe0/SvqpsBxUp8gzm5x+op +REcl7OOy6sZ9ms5LF7JTLxw/3/St/PvqS341Vr4PIiBzmU3PsqmQtPquXtz+ASP0 +8c48J4uftImOBQI4zdh8DPWxIbl4G2bSmmcPns5q4Fjg2Ew8u9C4IT0CgYEA75Jy +qmSeyk9ekBS4+ZgJWKBa33hanpaXZtxnkZs3u1dMMpPDPWF5zetwwdjJGTNZUQSP +XcsBRhsDNTFSqGApfVHrEvt7j+SITiil2A7x68+fMLWwZEA/YMdyVcexXOwnpFw6 +GWy4LquEiScGNm2fqoOltINnCp9kDUmnLaYubMkCgYEAv7nHvcrKIuOzTP+NmFt8 +3daW0n2WneLU2CQTBECqBUhyrrnTIVlvhmvycjMBcULFRmSZAyUhGBDGLvMG7Hgg +JvINfzvvN06hS/hLfVLdiDfKmJ8K5vKPezg/wIDUlwklo13E/oCwyfaPQeHENSzp +CvbQ9NrG4LoGNmd7oMEq/X0CgYBI8Exq5kGWFL4UncqHayuFSSUBnpHwcKbd0ULT +CO/Z4MU5LNWnbXL5J7JnwknPm1uZGAtSIglcP8MlQcQJsWVQW013tQs0jv6U1TlQ +45PyGH8+BEMU8p6ZJ3/+79JnGRskplOmA/y7cMrkOvZgQdX3wycDI3KOwGJkzUTR +2COQSQKBgQDxukAoRBs5YhLSs/LpmiFwDnlHU2D/5+zxyJpxChLkfFwm4i3KurDp +oNFeHD1dJ2D6pnyg86hwkhdGoxzA4zxc4FdMFFoi7qloogZdV/JClUsb9OI39vL6 +mq2uzEI0RLx0T+O3LvQ9yWRJE16QUys08pqFoggZkCPqnY6ks/2iag== +-----END RSA PRIVATE KEY----- diff --git a/examples/mass-vhost__reverse-proxy__ssl/ca/devilbox-ca.srl b/examples/mass-vhost__reverse-proxy__ssl/ca/devilbox-ca.srl new file mode 100644 index 0000000..3f0fb4e --- /dev/null +++ b/examples/mass-vhost__reverse-proxy__ssl/ca/devilbox-ca.srl @@ -0,0 +1 @@ +5D7E92287914BFA690E6873939DDAF116B551D4A diff --git a/examples/mass-vhost__reverse-proxy__ssl/docker-compose.yml b/examples/mass-vhost__reverse-proxy__ssl/docker-compose.yml new file mode 100644 index 0000000..bb44abf --- /dev/null +++ b/examples/mass-vhost__reverse-proxy__ssl/docker-compose.yml @@ -0,0 +1,49 @@ +--- +version: '2.3' + +services: + + # HTTPD Server + httpd: + image: devilbox/nginx-stable:alpine + build: + context: ../../Dockerfiles + dockerfile: Dockerfile.alpine + hostname: httpd + environment: + - NEW_UID=1000 + - NEW_GID=1000 + - MAIN_VHOST_ENABLE=1 + - MAIN_VHOST_SSL_TYPE=both + - MASS_VHOST_ENABLE=1 + - MASS_VHOST_BACKEND=file:backend.txt + - MASS_VHOST_TLD_SUFFIX=.loc + - MASS_VHOST_SSL_TYPE=both + ports: + - "8000:80" + - "8443:443" + volumes: + - ./intranet:/var/www/default/htdocs + - ./projects:/shared/httpd + - ./ca:/ca + depends_on: + - node + - php + + # NodeJS Server + node: + image: node:19-alpine + hostname: node + command: node /app/app.js + volumes: + - ./projects/node/src:/app + + # PHP-FPM Server + php: + image: devilbox/php-fpm:8.2-base + hostname: php + environment: + - NEW_UID=1000 + - NEW_GID=1000 + volumes: + - ./projects:/shared/httpd diff --git a/examples/mass-vhost__reverse-proxy__ssl/integration-test.sh b/examples/mass-vhost__reverse-proxy__ssl/integration-test.sh new file mode 100755 index 0000000..634efc4 --- /dev/null +++ b/examples/mass-vhost__reverse-proxy__ssl/integration-test.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +docker-compose build +docker-compose up -d +sleep 10 + +if ! curl http://localhost:8000 -H 'Host:node.loc' | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi +if ! curl -k https://localhost:8443 -H 'Host:node.loc' | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi + +if ! curl http://localhost:8000 -H 'Host:php.loc' | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi +if ! curl -k https://localhost:8443 -H 'Host:php.loc' | grep '[OK]'; then + docker-compose logs || true + docker-compose stop || true + docker-compose rm -f || true + exit 1 +fi + +docker-compose logs || true +docker-compose stop || true +docker-compose rm -f || true diff --git a/examples/mass-vhost__reverse-proxy__ssl/intranet/index.html b/examples/mass-vhost__reverse-proxy__ssl/intranet/index.html new file mode 100644 index 0000000..4667ed5 --- /dev/null +++ b/examples/mass-vhost__reverse-proxy__ssl/intranet/index.html @@ -0,0 +1,14 @@ +[OK] +

Intranet

+ +

This is the default virtual host.

+ +

See NodeJS example via reverse Proxy over SSL

+
+curl -k https://localhost -H 'Host: node.loc'
+
+ +

See PHP example via PHP-FPM over SSL

+
+curl -k https://localhost -H 'Host: php.loc'
+
diff --git a/examples/mass-vhost__reverse-proxy__ssl/projects/node/REAMDE.md b/examples/mass-vhost__reverse-proxy__ssl/projects/node/REAMDE.md new file mode 100644 index 0000000..e69de29 diff --git a/examples/mass-vhost__reverse-proxy__ssl/projects/node/cfg/backend.txt b/examples/mass-vhost__reverse-proxy__ssl/projects/node/cfg/backend.txt new file mode 100644 index 0000000..69b12e3 --- /dev/null +++ b/examples/mass-vhost__reverse-proxy__ssl/projects/node/cfg/backend.txt @@ -0,0 +1 @@ +conf:rproxy:http:node:3000 diff --git a/examples/mass-vhost__reverse-proxy__ssl/projects/node/src/app.js b/examples/mass-vhost__reverse-proxy__ssl/projects/node/src/app.js new file mode 100644 index 0000000..3e01719 --- /dev/null +++ b/examples/mass-vhost__reverse-proxy__ssl/projects/node/src/app.js @@ -0,0 +1,9 @@ +const http = require('http'); +const server = http.createServer((req, res) => { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.write('[OK]\n'); + res.write('NodeJS is running\n'); + res.end(); +}); +server.listen(3000, '0.0.0.0'); diff --git a/examples/mass-vhost__reverse-proxy__ssl/projects/php/README.md b/examples/mass-vhost__reverse-proxy__ssl/projects/php/README.md new file mode 100644 index 0000000..e69de29 diff --git a/examples/mass-vhost__reverse-proxy__ssl/projects/php/cfg/backend.txt b/examples/mass-vhost__reverse-proxy__ssl/projects/php/cfg/backend.txt new file mode 100644 index 0000000..b07e9ab --- /dev/null +++ b/examples/mass-vhost__reverse-proxy__ssl/projects/php/cfg/backend.txt @@ -0,0 +1 @@ +conf:phpfpm:tcp:php:9000 diff --git a/examples/mass-vhost__reverse-proxy__ssl/projects/php/htdocs/index.php b/examples/mass-vhost__reverse-proxy__ssl/projects/php/htdocs/index.php new file mode 100644 index 0000000..2c57e96 --- /dev/null +++ b/examples/mass-vhost__reverse-proxy__ssl/projects/php/htdocs/index.php @@ -0,0 +1,2 @@ +[OK] +PHP-FPM Host with PHP ' . phpversion() . ''; ?> diff --git a/tests/00-test-html.sh b/tests/00-test-html.sh index 116353f..cc57a58 100755 --- a/tests/00-test-html.sh +++ b/tests/00-test-html.sh @@ -37,7 +37,7 @@ run "echo \"hello world via html\" > ${RAND_DIR}/index.html" run "docker run --rm --platform ${ARCH} \ -v ${RAND_DIR}:/var/www/default/htdocs \ -p 127.0.0.1:${HOST_PORT}:80 \ - -e DEBUG_ENTRYPOINT=2 \ + -e DEBUG_ENTRYPOINT=4 \ -e DEBUG_RUNTIME=1 \ -e NEW_UID=$( id -u ) \ -e NEW_GID=$( id -g ) \ diff --git a/tests/01-test-php.sh b/tests/01-test-php.sh index 3a34141..1147109 100755 --- a/tests/01-test-php.sh +++ b/tests/01-test-php.sh @@ -44,13 +44,11 @@ run "docker run -d --rm --platform ${ARCH} \ run "docker run --rm --platform ${ARCH} \ -v ${RAND_DIR}:/var/www/default/htdocs \ -p 127.0.0.1:${HOST_PORT}:80 \ - -e DEBUG_ENTRYPOINT=2 \ + -e DEBUG_ENTRYPOINT=4 \ -e DEBUG_RUNTIME=1 \ -e NEW_UID=$( id -u ) \ -e NEW_GID=$( id -g ) \ - -e PHP_FPM_ENABLE=1 \ - -e PHP_FPM_SERVER_ADDR=${RAND_NAME1} \ - -e PHP_FPM_SERVER_PORT=9000 \ + -e MAIN_VHOST_BACKEND=phpfpm:${RAND_NAME1}:9000 \ --link ${RAND_NAME1} \ --name ${RAND_NAME2} \ ${IMAGE}:${TAG} &" diff --git a/tests/02-timezone.sh b/tests/02-timezone.sh index 6dbc280..618b54e 100755 --- a/tests/02-timezone.sh +++ b/tests/02-timezone.sh @@ -43,14 +43,12 @@ run "docker run -d --rm --platform ${ARCH} \ run "docker run --rm --platform ${ARCH} \ -v ${RAND_DIR}:/var/www/default/htdocs \ -p 127.0.0.1:${HOST_PORT}:80 \ - -e DEBUG_ENTRYPOINT=2 \ + -e DEBUG_ENTRYPOINT=4 \ -e DEBUG_RUNTIME=1 \ -e TIMEZONE=Europe/Berlin \ -e NEW_UID=$( id -u ) \ -e NEW_GID=$( id -g ) \ - -e PHP_FPM_ENABLE=1 \ - -e PHP_FPM_SERVER_ADDR=${RAND_NAME1} \ - -e PHP_FPM_SERVER_PORT=9000 \ + -e MAIN_VHOST_BACKEND=phpfpm:${RAND_NAME1}:9000 \ --link ${RAND_NAME1} \ --name ${RAND_NAME2} ${IMAGE}:${TAG} &" diff --git a/tests/03-test-xargs.sh b/tests/03-test-xargs.sh index 5e7fada..4d5417f 100755 --- a/tests/03-test-xargs.sh +++ b/tests/03-test-xargs.sh @@ -27,7 +27,7 @@ RAND_NAME="$( get_random_name )" ### FILES="$( \ run "docker run --rm --platform ${ARCH} \ - -e DEBUG_ENTRYPOINT=2 \ + -e DEBUG_ENTRYPOINT=4 \ -e DEBUG_RUNTIME=1 \ -e NEW_UID=$( id -u ) \ -e NEW_GID=$( id -g ) \